.netcore在linux下使用P/invoke方式调用linux动态库

.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

时间: 2024-08-25 19:03:50

.netcore在linux下使用P/invoke方式调用linux动态库的相关文章

Linux下c函数dlopen实现加载动态库so文件代码举例

dlopen()是一个强大的库函数.该函数将打开一个新库,并把它装入内存.该函数主要用来加载库中的符号,这些符号在编译的时候是不知道的.这种机制使得在系统中添加或者删除一个模块时,都不需要重新编译了.可以在自己的程序中使用 dlopen().dlopen() 在 dlfcn.h 中定义,并在 dl 库中实现.它需要两个参数:一个文件名和一个标志.文件名就是一个动态库so文件,标志指明是否立刻计算库的依赖性.如果设置为 RTLD_NOW 的话,则立刻计算:如果设置的是 RTLD_LAZY,则在需要

Linux下基于源码方式安装MySQL 5.6

MySQL为开源数据库,因此可以基于源码实现安装.基于源码安装有更多的灵活性.也就是说我们可以针对自己的硬件平台选用合适的编译器来优化编译后的二进制代码,根据不同的软件平台环境调整相关的编译参数,选择自身需要选择不同的安装组件,设定需要的字符集等等一些可以根据特定应用场景所作的各种调整.本文描述了如何在源码方式下安装MySQL. 1.安装环境及介质#安装环境SZDB:~ # cat /etc/issueWelcome to SUSE Linux Enterprise Server 10 SP3

linux 下 用mount 挂载 samba 以及Linux 开机自动挂载 samba &nbsp;

linux 下 用mount 挂载 samba 以及Linux 开机自动挂载 samba 一.挂载匿名samba#mount -t cifs //192.168.2.2/share /151.2_share   -o guest#ls /151.2_share 二.挂载非匿名samba #mount -t cifs //192.168.2.2/share /151.2_share -o   username=samba,password=samba,iocharset=utf-8#ls /151

Linux下不借助工具实现远程linux服务器上传下载文件

# Linux下不借助工具实现远程linux服务器上传下载文件 ## 简介 - Linux下自带ssh工具,可以实现远程Linux服务器的功能- Linux下自带scp工具,可以实现文件传输功能 ## 登录服务器 - `ssh [email protected]` 登录服务器```PC:~$ ssh [email protected][email protected]'s password: ``` ## 文件传输 - 下载文件- `scp [email protected]:/data/log

Windows 下VC++6.0制作、使用动态库和静态库

Windows 下VC++6.0制作.使用动态库和静态库 一.VC++6.0制作.使用静态库 静态库制作 1.如图一在VC++6.0中new一个的为win32 static library工程并新建一个.cpp和一个.h(C++header file)文件 2..cpp程序直接照老师给的打,注意这里需要改错,去掉(long) 3. .h文件需要自己编写格式如下.以head.h为例 #ifndef _HEAD_H_ #define _HEAD_H_ unsigned long unsgn_pow(

linux下socket connect阻塞方式 阻塞时间控制

同事今天问我,如何在linux下的c代码里面控制connect的阻塞时间.应用的背景是:linux下的c程序有两个目标IP需要connect,如果用阻塞方式,当其中一个IP不能连接的情况下,程序将阻塞在connect函数上.本来以为用setsockopt修改个什么参数就可以搞定,结果baidu了半天也没有结果.倒是在网上搜到很多这样的解决方案:将connect方式设置为非阻塞方式,这样程序一旦执行就会马上返回,但问题是,到底有没有连接上呢,你需要等待一段时间,然后使用函数判断连接是否正常.试了下

linux下配置环境变量方式

linux下配置环境变量有多种方式,下面简述之 方式1.编辑 /etc/profile 文件,增加如下内容 JAVA_HOME=/usr/local/jdk1.8 export JAVA_HOME PATH=$PATH:$JAVA_HOME/bin export PATH 方式2:编辑 /etc/bashrc 文件,方式同上 方式3:在 /etc/profile.d 目录增加文件,例如:jdk.sh,内容同上 方式4:在用户目录/root下修改.bash_profile文件或者修改.bashrc

linux下文件夹归置方式

/bin:二进制可执行命令./dev:设备特殊文件./etc:系统管理和配置文件./etc/rc.d:启动的配 置文件和脚本./home:用户主目录的基点,比如用户user的主目录就是/home/user,可以用~user表示./lib:标准程序设计库,又 叫动态链接共享库,作用类似windows里的.dll文件./sbin:系统管理命令,这 里存放的是系统管理员使用的管理程序./tmp:公用的临时文件存储 点./root:系统管理员的主目 录./mnt:系统提供这个目录是 让用户临时挂载其他的

Linux下快速静态编译Qt以及Qt动态/静态版本共存

Qt下静态编译Qt,根据我的经验,如果按照Windows下那种直接拿官方sdk安装之后的文件来编译是行不通的,需要直接下载Qt的source包,目前诺基亚的源码叫做qt-everywhere-opensource-src的tar包,到网上一查,乖乖,大部分人编译这个包居然花费了12-13个小时!但是,根据我在Windows下静态编译Qt的经验,其实这之中很多东西都是可以不用编译的,最终我大约用了40分钟编译完成了全部内容.如果你直接使用官方的sdk安装,那么你就已经有了一个动态库,现在你又通过源