dllとsoのトラブルシューティング覚書
OSの課題でずっと詰まってたubuntu環境での共有ライブラリのパスが通らない案件の解決策+αをメモ.
ubuntuで共有ライブラリのパスが通らなかったときの解決策
まずlddで対象ファイルの依存ライブラリを確認してみる.
# ldd main linux-vdso.so.1 (0x00007fffecd45000) libshare.so => not found libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f5b67b10000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f5b67710000) libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f5b67370000) /lib64/ld-linux-x86-64.so.2 (0x00007f5b68400000) libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f5b67150000)
ここでnot foundになってるファイルのパスが通ってない.
大体ネットで検索すると
- /etc/ld.so.confに追記
- 環境変数を設定する
- ダイナミックリンクを貼る
辺りがヒットするが今回は/etc/ld.so.confに追記を試してみた.
普通にパスを書いてsudo ldconfig(sudoがないとtmpファイルが作成できない的なエラーが出る)でエラー解決...かと思いきやパスが通らない.
うちの環境ではこれに加えて環境変数を設定すればうまくいきました.
コマンドは
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./
これでlddすると
# ldd main linux-vdso.so.1 (0x00007fffca35a000) libshare.so (0x00007f37753f0000) libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f3775060000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f3774c60000) libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f37748c0000) /lib64/ld-linux-x86-64.so.2 (0x00007f3775a00000) libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f37746a0000)
ちゃんとパス通ってますね.
ちなみにdllをコンパイルするときは
g++ -shared -fPIC -o libshare.so share.cpp
出力ファイルの名前の先頭がlibじゃないとうまくいかないらしい(?)(なんかそんな記事を見たし実際これでうまくいったのでそうしておく)
-fPICは付けないとコンパイラに怒られるので付けておきましょう.
dllを利用する側をコンパイルする時は
g++ -I./ -L./ -o second second.cpp -lshare
-Iオプションとか-Lオプションとかは調べたらわかるので割愛.-lの後ろはlibと.soを除いた共有ライブラリファイルの名前を入れましょう.
clコマンドでdllを作る
課題だとwindows環境でって明記してあったのでやった後に気づいて絶望しました.
clだとソースコードにdllexportを明記する必要があるようです.
dllにするファイルのソースコードはこんな感じ.
#include <stdio.h> __declspec(dllexport) int cal(int x){ int y=x+10; return y; }
コンパイルもubuntuと違って面倒なオプションがいらなくて/LDを付けるだけでいいらしい.
> cl /LD dll.c
ライブラリと実行ファイルをリンクする方法が明示的リンクと暗黙的リンクの2種類あるみたいなんだけど,今回は汎用性がありそうな明示的リンクを選択(ubuntuで暗黙的リンクはやってあったのもある)
この場合の実行ファイルのソースコードはこんな感じ.
#include <stdio.h> #include <windows.h> int main(void){ HINSTANCE hDLL; int (*func1)(int); if((hDLL=LoadLibrary("change.dll"))==NULL) printf("LoadLibrary is failed.\n"); else{ if((func1=(int (*)(int))GetProcAddress(hDLL,"cal"))==NULL) printf("GetProcAddress is failed.\n"); else int x; printf("input value : "); scanf("%d",&x); printf("calc value : %d",func1(x)); FreeLibrary(hDLL); } return 0; }
こっちは普通にコンパイルすればいいらしいので
> cl main.c
これで実行ファイルが出力される.
実際にdllファイルの方だけを書き換えて再コンパイルすると動作内容が変わるので試してみるといいかも.