目次
英語版
このページの英語版を見る
LinuxでのDを使った共有ライブラリの作成
比較目的で仕組みを理解するために、まずC言語での方法を説明する。
Cの静的リンク
CモジュールをCプログラムに静的にリンクするには、
main.c:#include <stdio.h> extern int dll(); int main() { printf("+main()\n"); dll(); printf("-main()\n"); return 0; }dll.c:
#include <stdio.h> int dll() { printf("dll()\n"); return 0; }ビルド:
gcc -c dll.c gcc -c main.c gcc -o main main.o dll.o ./main結果:
+main() dll() -main()
C言語で共有ライブラリを静的に読み込む
ビルド:gcc -c dll.c -fpic gcc -shared -o libdll.so dll.o gcc -c main.c gcc -L/home/username/tmp -Wl,-rpath=/home/username/tmp main.o -o main -ldll
(ソースファイル、実行、結果は同一であるべきである。)
rpathは、libdll.soへのパスをmainに埋め込むために使用され、実行時に見つけられるようにする。 他の方法としては、以下のようなものがある(ただし、ここではこれ以上説明しない):-rpathは、libdll.soへのパスをmainに埋め込むために使用され、実行時に見つけられるようにする。 それを行う他の方法としては(ここでは説明しないが)、
- 環境変数 LD_LIBRARY_PATH を設定する。
- 共有ライブラリを標準の場所にコピーし、ldconfigを使用してld.soを変更する。
C言語での共有ライブラリの動的ロード
実行時にライブラリをロードするためのコードをmain.cに追加する。
main.c:#include <stdio.h> #include <stdlib.h> #include <dlfcn.h> int main() { printf("+main()\n"); void *lh = dlopen("/home/walter/tmp/libdll.so", RTLD_LAZY); if (!lh) { fprintf(stderr, "dlopen error: %s\n", dlerror()); exit(1); } printf("libdll.so is loaded\n"); int (*fn)() = dlsym(lh, "dll"); char *error = dlerror(); if (error) { fprintf(stderr, "dlsym error: %s\n", error); exit(1); } printf("dll() function is found\n"); (*fn)(); printf("unloading libdll.so\n"); dlclose(lh); printf("-main()\n"); return 0; }ビルド:
gcc -c dll.c -fpic gcc -shared -o libdll.so dll.o gcc -c main.c gcc -rdynamic main.o -o main -ldl ./main結果:
+main() libdll.so is loaded dll() function is found dll() unloading libdll.so -main()
C++の共有ライブラリをCで動的にロードする
ここで問題となるのは、共有ライブラリの静的コンストラクタとデストラクタが実行されるタイミングを把握することである。 dll.c(現在はC++コード)に、それらの静的コンストラクタとデストラクタを挿入する。
dll.c:#include <stdio.h> extern "C" int dll() { printf("dll()\n"); return 0; } struct S { S() { printf("libdll.so construction\n"); } ~S() { printf("~libdll.so destruction\n"); } }; S ss;ビルド:
g++ -c dll.c -fpic g++ -shared -o libdll.so dll.o gcc -c main.c gcc -rdynamic main.o -o main -ldl ./main結果:
+main() libdll.so construction libdll.so is loaded dll() function is found dll() unloading libdll.so libdll.so destruction -main()
libphobos2.aとのDプログラムの静的リンク
main.d:import core.stdc.stdio; import dll; int main() { printf("+main()\n"); dll.dll(); printf("-main()\n"); return 0; }dll.d:
import core.stdc.stdio; extern (C) int dll() { printf("dll()\n"); return 0; }ビルド:
dmd -c dll.d dmd -c main.d dmd main.o dll.o ./main結果:
+main() dll() -main()
libphobos2.soとDプログラムの静的リンク
ビルド:dmd -c dll.d dmd -c main.d dmd main.o dll.o -defaultlib=libphobos2.so -L-rpath=/path/to/where/shared/library/is ./main
D共有ライブラリの作成とlibphobos2.soとの静的リンク
D共有ライブラリを使用する際には、コードをlibphobos2.soとリンクする必要があり、 libphobos2.aではない。これは、ガベージコレクタのインスタンスが1つだけになるようにするためである。
ビルド:dmd -c dll.d -fPIC dmd -oflibdll.so dll.o -shared -defaultlib=libphobos2.so -L-rpath=/path/to/where/shared/library/is dmd -c main.d dmd main.o -L-l:libdll.so -defaultlib=libphobos2.so -L-rpath=.:/path/to/where/shared/library/is ./main
DプログラムからC++ DLLを動的にロードする
main.d:import core.stdc.stdio; import core.stdc.stdlib; import core.sys.posix.dlfcn; extern (C) int dll(); int main() { printf("+main()\n"); void* lh = dlopen("libdll.so", RTLD_LAZY); if (!lh) { fprintf(stderr, "dlopen error: %s\n", dlerror()); exit(1); } printf("libdll.so is loaded\n"); int function() fn = cast(int function())dlsym(lh, "dll"); char* error = dlerror(); if (error) { fprintf(stderr, "dlsym error: %s\n", error); exit(1); } printf("dll() function is found\n"); fn(); printf("unloading libdll.so\n"); dlclose(lh); printf("-main()\n"); return 0; }dll.c:
#include <stdio.h> extern "C" int dll() { printf("dll()\n"); return 0; } struct S { S() { printf("libdll.so construction\n"); } ~S() { printf("libdll.so destruction\n"); } }; S ss;ビルド:
g++ -c dll.c -fpic g++ -shared -o libdll.so dll.o dmd -c main.d dmd main.o -L-ldl -L-rpath=. ./main結果:
+main() libdll.so construction libdll.so is loaded dll() function is found dll() unloading libdll.so libdll.so destruction -main()
CプログラムからD DLLを動的にロードする
main.c:#include <stdio.h> #include <stdlib.h> #include <dlfcn.h> int main() { printf("+main()\n"); void *lh = dlopen("/home/walter/tmp/libdll.so", RTLD_LAZY); if (!lh) { fprintf(stderr, "dlopen error: %s\n", dlerror()); exit(1); } printf("libdll.so is loaded\n"); int (*fn)() = dlsym(lh, "dll"); char *error = dlerror(); if (error) { fprintf(stderr, "dlsym error: %s\n", error); exit(1); } printf("dll() function is found\n"); (*fn)(); printf("unloading libdll.so\n"); dlclose(lh); printf("-main()\n"); return 0; }dll.d:
import core.stdc.stdio; extern (C) int dll() { printf("dll()\n"); return 0; } shared static this() { printf("libdll.so shared static this\n"); } shared static ~this() { printf("libdll.so shared static ~this\n"); }ビルド:
dmd -c dll.d -fPIC dmd -oflibdll.so dll.o -shared -defaultlib=libphobos2.so -L-rpath=/path/to/where/shared/library/is gcc -c main.c gcc -rdynamic main.o -o main -ldl ./main結果:
+main() libdll.so shared static this libdll.so is loaded dll() function is found dll() unloading libdll.so libdll.so shared static ~this -main()
libphobos2.soも自動的に動的に読み込まれることに注意。
DプログラムからD DLLを動的にロードする
メインプログラムをlibphobos2.soとリンクさせることが重要であり、libphobos2.aとリンクさせてはならない。そうでないと、 Dランタイムの複数のインスタンスが互いに競合する結果となる。
main.d:import core.stdc.stdio; import core.stdc.stdlib; import core.sys.posix.dlfcn; extern (C) int dll(); int main() { printf("+main()\n"); void* lh = dlopen("libdll.so", RTLD_LAZY); if (!lh) { fprintf(stderr, "dlopen error: %s\n", dlerror()); exit(1); } printf("libdll.so is loaded\n"); int function() fn = cast(int function())dlsym(lh, "dll"); char* error = dlerror(); if (error) { fprintf(stderr, "dlsym error: %s\n", error); exit(1); } printf("dll() function is found\n"); fn(); printf("unloading libdll.so\n"); dlclose(lh); printf("-main()\n"); return 0; } shared static this() { printf("main shared static this\n"); } shared static ~this() { printf("main shared static ~this\n"); }ビルド:
dmd -c dll.d -fPIC dmd -oflibdll.so dll.o -shared -defaultlib=libphobos2.so -L-rpath=/path/to/where/shared/library/is dmd -c main.d dmd main.o -L-ldl -defaultlib=libphobos2.so -L-rpath=.:/path/to/where/shared/library/is -map ./main結果:
main shared static this +main() libdll.so shared static this libdll.so is loaded dll() function is found dll() unloading libdll.so libdll.so shared static ~this -main() main shared static ~this
dlopen() が返す前に DLL の静的コンストラクタが呼び出され、 dlclose() によって静的デストラクタが呼び出されることに注目してほしい。
Copyright © 1999-2024 by the D Language Foundation
DEEPL APIにより翻訳、ところどころ修正。
このページの最新版(英語)
このページの原文(英語)
翻訳時のdmdのバージョン: 2.109.1
ドキュメントのdmdのバージョン: 2.109.1
翻訳日付 :
HTML生成日時:
編集者: dokutoku