Introduction

前回は、自作のSharedライブラリに定義された関数をP/Invokeで呼び出してみました。

しかしながら、毎回毎回 /usr/local/lib とかにコピーするのってどうなんでしょう?
Windowsみたいに、実行ファイルと同じディレクトリにSharedライブラリを配置しても動作するのでしょうか?
Windowsの場合、exeが呼び出すdllは、実行ファイルから以下の順序で検索されます。

  1. 実行中のプロセスの実行形式モジュールがあるフォルダー。
  2. 現在のフォルダー。
  3. Windows システム フォルダー。
    このフォルダーへのパスは、GetSystemDirectory 関数が取得します。
  4. Windows ディレクトリ。
    このフォルダーへのパスは、GetWindowsDirectory 関数が取得します。
  5. 環境変数 PATH 内に記述されたフォルダー。

Linuxの場合、3,4以外は同じ条件で試すことができそうです。
ただ、.NET Coreの場合、dotnet runで動作する場合のカレントディレクトリに関して情報がないので、2もちょっと先送り。
最終的に下記の内容をテストしてみます。

  1. Sharedライブラリをシステムから削除
  2. Sharedライブラリを実行ファイルと同じフォルダに配置
  3. LD_LIBRARY_PATHと実行ファイルと同じフォルダの優先順位

Try

サンプルは、.NETでLinuxと遊んでみる Visual Studio Code編 第7回と同じものを使います。

Sharedライブラリをシステムから削除

これは動かないはずです。
実行ファイルと同じディレクトリ、/usr/local/lib64にSharedライブラリが存在しないことを確認してから実行してみます。

1
2
3
4
5
6
7
8
9
10
11
12
$ sudo updatedb
$ sudo locate libCppLib.so
/home/xxxxxx/Work/Demo/DotNetCoreLinux6/CppLib/build/libCppLib.so
/home/xxxxxx/Work/Demo/DotNetCoreLinux6/CsharpApp/bin/Debug/netcoreapp2.0/libCppLib.so.bak
$ export | grep LD_LIBRARY_PATH
$ pwd
/home/xxxxxx/Work/Demo/DotNetCoreLinux6/CsharpApp
$ dotnet run 20 50
Unhandled Exception: System.DllNotFoundException: Unable to load DLL 'libCppLib.so': The specified module or one of its dependencies could not be found.
(Exception from HRESULT: 0x8007007E)
at CsharpApp.Program.Add(Int32 x, Int32 y)
at CsharpApp.Program.Main(String[] args) in /home/xxxxxx/Work/Demo/DotNetCoreLinux6/CsharpApp/Program.cs:line 15

Windowsと同じように、System.DllNotFoundExceptionがスローされました。
期待通りです。

Sharedライブラリを実行ファイルと同じフォルダに配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ pwd
/home/xxxxxx/Work/Demo/DotNetCoreLinux6/CsharpApp
$ ls -la bin/Debug/netcoreapp2.0/
合計 32
drwxrwxr-x 2 xxxxxx xxxxxx 171 8月 21 23:50 .
drwxrwxr-x 3 xxxxxx xxxxxx 27 8月 19 06:58 ..
-rw-rw-r-- 1 xxxxxx xxxxxx 437 8月 19 07:41 CsharpApp.deps.json
-rw-rw-r-- 1 xxxxxx xxxxxx 4608 8月 21 23:43 CsharpApp.dll
-rw-rw-r-- 1 xxxxxx xxxxxx 568 8月 21 23:43 CsharpApp.pdb
-rw-rw-r-- 1 xxxxxx xxxxxx 206 8月 19 07:41 CsharpApp.runtimeconfig.dev.json
-rw-rw-r-- 1 xxxxxx xxxxxx 146 8月 19 07:41 CsharpApp.runtimeconfig.json
-rwxr-xr-x 1 root root 8016 8月 19 07:56 libCppLib.so
$ dotnet run 20 50
20 + 50 = 70

きちんと動作しました。

LD_LIBRARY_PATHと実行ファイルと同じフォルダの優先順位

これは気になりますね。
別に.NET Coreに関係なく、Linuxの仕組みと同じような気がしますが… 実行時、どちらが呼び出されたかわかるように、Sharedライブラリ側を修正します。
実行ファイルに配置するSharedライブラリ

1
2
3
#include <iostream>

extern "C" int Add(int x, int y){ printf("from executed directory\n");return x + y; }

/usr/local/lib64に配置するSharedライブラリ

1
2
3
#include <iostream>

extern "C" int Add(int x, int y){ printf("from /usr/local/lib64\n");return x + y; }

これらをそれぞれビルドして、**/usr/local/lib64、実行ファイルと同じディレクトリである **bin/Debug/netcoreapp2.0/ にコピーします。
また、環境変数LD_LIBRARY_PATHに/usr/local/lib64を追加します。
一応、各ディレクトリにSharedライブラリがコピーされたことも確認しておきます。
そして、dotnet runで実行します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ pwd
/home/xxxxxx/Work/Demo/DotNetCoreLinux6/CsharpApp
$ export LD_LIBRARY_PATH=/usr/local/lib64
$ sudo updatedb
$ locate libCppLib.so
/home/xxxxxx/Work/Demo/DotNetCoreLinux6/CppLib/build/libCppLib.so
/home/xxxxxx/Work/Demo/DotNetCoreLinux6/CsharpApp/bin/Debug/netcoreapp2.0/libCppLib.so
/usr/local/lib64/libCppLib.so
$ dotnet run 20 53
from executed directory
20 + 53 = 73
$ rm bin/Debug/netcoreapp2.0/libCppLib.so
$ dotnet run 20 53
from /usr/local/lib64
20 + 53 = 73

結果としては、実行フォルダのSharedライブラリが優先されました。
また、実行フォルダのSharedライブラリを削除しても、/usr/local/lib64のSharedライブラリが使用され、きちんと動作することもわかりました。

Conclusion

結論としては、Windowsと同じく、実行ファイルのあるディレクトリに配置されているライブラリが優先のようですね。