.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命令进行查看
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命令查找是否确实缺少了依赖
strings /usr/lib64/libstdc++.so.6 |grep GLIBCXX 得到结果 GLIBCXX_3.4 GLIBCXX_3.4.1 GLIBCXX_3.4.2 GLIBCXX_3.4.3 GLIBCXX_3.4.4 GLIBCXX_3.4.5 GLIBCXX_3.4.6 GLIBCXX_3.4.7 GLIBCXX_3.4.8 GLIBCXX_3.4.9 GLIBCXX_3.4.10 GLIBCXX_3.4.11 GLIBCXX_3.4.12 GLIBCXX_3.4.13 GLIBCXX_3.4.14 GLIBCXX_3.4.15 GLIBCXX_3.4.16 GLIBCXX_3.4.17 GLIBCXX_DEBUG_MESSAGE_LENGTH
确实缺少了文件,这种情况下,我们需要使用find命令来查找依赖文件
find / -name libstdc++.so.6*
如果能找到依赖的so文件,可以使用cp命令将文件复制到lib64目录
cp /usr/local/lib64/libstdc++.so.6.0.20 /usr/lib64 //复制文件
Centos下系统目录是/usr/lib64,Suse下可能系统目录会有不同
如果有旧文件,可以使用rm命令,先删除旧文件
sudo rm -rf /usr/lib64/libstdc++.so.6 //删除旧文件
最后在使用ln命令,链接到新文件
sudo ln -s /usr/lib64/libstdc++.so.6.0.20 /usr/lib64/libstdc++.so.6 //链接到新版本
这些都做好之后,旧可以测试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 }
原文地址:https://www.cnblogs.com/twinhead/p/9256518.html