.net core - PInvoke C共享库函数,它依赖于另一个共享库

时间:2017-09-04 06:18:09

标签: c# raspberry-pi shared-libraries .net-core pinvoke

我为现有的库(wiringPi)编写了一些包装代码来读取温度传感器,但在使用此库时却出错了。

我的包装器lib看起来像:

mylib.h

#ifndef mylib_h__
#define mylib_h__
extern void read_sensor();
#endif

mylib.c

#include "mylib.h"
#include <wiringPi.h> 

void read_sensor() {
    //here is the first call on the wiringPi lib
    if (wiringPiSetup() == -1)
        exit(1);

    ...
}

然后我使用gcc编译我的库:

gcc -Wall -Werror -fPIC -c mylib.c
gcc -shared -o libmylib.so mylib.o -lwiringPi
cp libmylib.so /usr/lib/

提示:如果这个库的C程序正常消耗,一切正常。

现在我的C#程序使用PInvoke从此库中调用read_sensor()

Program.cs的

class Program 
{
    [DllImport("wiringPi")]
    static extern int wiringPiSetup();

    [DllImport("mylib")]
    static extern void read_sensor();

    static void Main(string[] args)
    {
        wiringPiSetup();
        read_sensor();
    }
}

使用以下参数编译此程序:

dontet publish -r linux-arm

并复制到我的Raspberry-Pi。

现在我执行这个C#程序并抛出以下错误:

  

./ my-program-name:符号查找错误:/usr/lib/libmylib.so:undefined symbol:wiringPiSetup

这里出了什么问题?

我的第一个想法是,我的程序不知道wiringPi库。所以我为这个dll添加了一个导出,并调用wiringPiSetup()进行测试。有或没有此陈述的结果相同。

我还在我的自定义库中添加了一个没有wiringPi依赖关系的测试函数。这被C#称为罚款。

我在连结时间搞砸了什么?

修改

命令ldd /usr/lib/libmylib.so给出了这个输出:

linux-vdso.so.1 (0x7efad000)
/usr/lib/arm-linux-gnueabihf/libarmmem.so (0x76f73000)
libwiringPi.so => /usr/local/lib/libwiringPi.so (0x76f40000)
libc.so.6 => /lib/arm-linux-gnueabihf/libc.so.6 (0x76dff000)
libm.so.6 => /lib/arm-linux-gnueabihf/libm.so.6 (0x76d84000)
libpthread.so.0 => /lib/arm-linux-gnueabihf/libpthread.so.0 (0x76d5c000)
librt.so.1 => /lib/arm-linux-gnueabihf/librt.so.1 (0x76d45000)
libcrypt.so.1 => /lib/arm-linux-gnueabihf/libcrypt.so.1 (0x76d05000)
/lib/ld-linux-armhf.so.3 (0x54abc000)

1 个答案:

答案 0 :(得分:2)

归结为命名装饰。 C ++编译器并不只是将函数的名称放在目标文件中 - 它根据函数的定义(最值得注意的是它的参数)向名称添加信息。

来自https://msdn.microsoft.com/en-us/library/56h2zst2.aspx

  

表示C和C ++程序中的函数,数据和对象   内部装饰名称。装饰名称是编码的   编译器在编译对象,数据时创建的字符串,   或功能定义。它记录了调用约定,类型,   功能参数和其他信息以及名称。这个   名称修饰,也称为名称修改,帮助链接器找到   链接可执行文件时的正确函数和对象。

但是编译后的C代码不会这样做 - 使用C ++进行名称装饰(或名称修改)。

所以,你必须告诉C#&#34;这个功能的名字没有装饰。&#34;

为此,请使用如下属性:

[DllImport("TestDll.dll", EntryPoint="myproc", ExactSpelling=false,CallingConvention=CallingConvention.Cdec‌​l)]

&#34; CallingConvention&#34;说&#34;该功能是C功能。&#34;

&#34; CDECL&#34;如果我没记错的话,意味着&#34; C声明&#34;

可在以下网址找到更多信息:http://www.codeguru.com/csharp/csharp/cs_data/article.php/c4217/Calling-Unmanaged-Code-Part-1--simple-DLLImport.htm