.netcore下已经实现了通过p/invoke方式调用linux的动态链接库(*.so)文件
1 [DllImport(@"libdl.so.2")]
2 public static extern IntPtr dlopen(string filename, int flags);
3 [DllImport("libdl.so.2")]
4 public static extern IntPtr dlsym(IntPtr handle, string symbol);
5
6 [DllImport("libdl.so.2", EntryPoint = "dlopen")]
7 private static extern IntPtr UnixLoadLibrary(String fileName, int flags);
8
9 [DllImport("libdl.so.2", EntryPoint = "dlclose", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
10 private static extern int UnixFreeLibrary(IntPtr handle);
11
12 [DllImport("libdl.so.2", EntryPoint = "dlsym", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
13 private static extern IntPtr UnixGetProcAddress(IntPtr handle, String symbol);
14
15 [DllImport("libdl.so.2", EntryPoint = "dlerror", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
正常情况下,都是可以调用成功的
如果出现调用失败的情况,可能是so文件缺少了一些依赖文件,可以通过ldd命令进行查看
|
1
|
ldd libzmq.so |

如果有某些依赖文件找不到,会出现not found的字样,比如下面这种
/usr/lib64/libstdc++.so.6: version `GLIBCXX_3.4.20‘ not found (required by */3rd-party/protobuf-2.4.1/src/.libs/libprotobuf.so.7)
/usr/lib64/libstdc++.so.6: version `GLIBCXX_3.4.20‘ not found (required by */3rd-party/protobuf-2.4.1/src/.libs/libprotoc.so.7)
可以使用string命令查找是否确实缺少了依赖
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
strings /usr/lib64/libstdc++.so.6 |grep GLIBCXX 得到结果GLIBCXX_3.4GLIBCXX_3.4.1GLIBCXX_3.4.2GLIBCXX_3.4.3GLIBCXX_3.4.4GLIBCXX_3.4.5GLIBCXX_3.4.6GLIBCXX_3.4.7GLIBCXX_3.4.8GLIBCXX_3.4.9GLIBCXX_3.4.10GLIBCXX_3.4.11GLIBCXX_3.4.12GLIBCXX_3.4.13GLIBCXX_3.4.14GLIBCXX_3.4.15GLIBCXX_3.4.16GLIBCXX_3.4.17GLIBCXX_DEBUG_MESSAGE_LENGTH |
确实缺少了文件,这种情况下,我们需要使用find命令来查找依赖文件
|
1
|
find / -name libstdc++.so.6* |

如果能找到依赖的so文件,可以使用cp命令将文件复制到lib64目录
|
1
|
cp /usr/local/lib64/libstdc++.so.6.0.20 /usr/lib64 //复制文件 |
Centos下系统目录是/usr/lib64,Suse下可能系统目录会有不同
如果有旧文件,可以使用rm命令,先删除旧文件
|
1
|
sudo rm -rf /usr/lib64/libstdc++.so.6 //删除旧文件 |
最后在使用ln命令,链接到新文件
|
1
|
sudo ln -s /usr/lib64/libstdc++.so.6.0.20 /usr/lib64/libstdc++.so.6 //链接到新版本 (libstdc++.so.6.0.20是复制到linux中的文件的文件名) |
这些都做好之后,旧可以测试dlopen命令是否能正常打开文件了,如果可以正常打开,那dllimport方式就可以正常使用
没有开发dllimport的源码,很怀疑它内部也是调用了linux下的dlopen命令来调用so文件

除了直接使用dllimport方式来调用,还可以使用委托的方式,来调用so文件
下面是测试代码,可以比较完整说明.netcore下p/invoke方式调用so文件
1 public class SoTester
2 {
3 private const string LibraryName = "libzmq";
4
5 const int RTLD_NOW = 2; // for dlopen‘s flags
6 const int RTLD_GLOBAL = 8;
7
8 [DllImport(@"libdl.so.2")]
9 public static extern IntPtr dlopen(string filename, int flags);
10 [DllImport("libdl.so.2")]
11 public static extern IntPtr dlsym(IntPtr handle, string symbol);
12
13 [DllImport("libdl.so.2", EntryPoint = "dlopen")]
14 private static extern IntPtr UnixLoadLibrary(String fileName, int flags);
15
16 [DllImport("libdl.so.2", EntryPoint = "dlclose", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
17 private static extern int UnixFreeLibrary(IntPtr handle);
18
19 [DllImport("libdl.so.2", EntryPoint = "dlsym", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
20 private static extern IntPtr UnixGetProcAddress(IntPtr handle, String symbol);
21
22 [DllImport("libdl.so.2", EntryPoint = "dlerror", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
23 private static extern IntPtr UnixGetLastError();
24
25 public delegate int sumHandler(int a, int b);
26 public static sumHandler sumfunc = null;
27
28 [DllImport("libNativeLib.so", EntryPoint = "sum", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
29 public static extern int Sum(int a, int b);
30
31 public void Start()
32 {
33 IntPtr libPtr = IntPtr.Zero;
34
35 string libName = $"{AppContext.BaseDirectory}libNativeLib.so";
36
37 libPtr = UnixLoadLibrary(libName, 2 | 8);
38
39 //libPtr = dlopen(libName, RTLD_NOW);
40
41 if (libPtr != IntPtr.Zero)
42 Console.WriteLine($"调用dlopen打开{libName}成功");
43 else
44 Console.WriteLine($"调用dlopen打开{libName}失败");
45
46 var sumPtr = UnixGetProcAddress(libPtr, "sum");
47
48 if (sumPtr != IntPtr.Zero)
49 Console.WriteLine($"dlopen调用sum成功");
50 else
51 Console.WriteLine($"dlopen调用sum失败");
52
53 sumfunc = Marshal.GetDelegateForFunctionPointer<sumHandler>(sumPtr);
54
55 int ret = sumfunc(1, 3);
56
57 Console.WriteLine($"调用sum结果:{ret}");
58
59 var sumRet = Sum(5, 7);
60
61 Console.WriteLine($"DllImport调用sum结果:{sumRet}");
62
63 //var libname2 = $"libc.so.6";
64 var libname2 = $"{AppContext.BaseDirectory}libzmq.so";
65 //var libname2 = $"{AppContext.BaseDirectory}libAdminConsole.so";
66 var consolePtr = UnixLoadLibrary(libname2, 2 | 8);
67 var erroPtr = UnixGetLastError();
68 Console.WriteLine($"错误描述:{Marshal.PtrToStringAnsi(erroPtr)}");
69
70 if (consolePtr != IntPtr.Zero)
71 Console.WriteLine($"打开{libname2}成功");
72 else
73 Console.WriteLine($"打开{libname2}失败");
74 }
75 }
ps:目前测试过CentOS7和suse12 SP3,个人感觉,如果项目中需要使用P/INVOKE最好还是放在suse上跑,centos默认的gcc版本比较低,升级gcc又很麻烦。suse各个组件齐全,只是免费版无法更新组件,p/invoke直接可以使用。其他版本linux没有使用。
