首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >.net核心- PInvoke C共享库函数,它依赖于另一个共享库

问.net核心- PInvoke C共享库函数,它依赖于另一个共享库
EN

Stack Overflow用户
提问于 2017-09-04 06:18:09
回答 1查看 1.5K关注 0票数 6

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

我的包装库如下所示:

mylib.h

代码语言:javascript
复制
#ifndef mylib_h__
#define mylib_h__
extern void read_sensor();
#endif

mylib.c

代码语言:javascript
复制
#include "mylib.h"
#include <wiringPi.h> 

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

    ...
}

然后我用gcc来编译我的图书馆:

代码语言:javascript
复制
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

代码语言:javascript
复制
class Program 
{
    [DllImport("wiringPi")]
    static extern int wiringPiSetup();

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

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

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

代码语言:javascript
复制
dontet publish -r linux-arm

复制到我的覆盆子里。

现在我执行这个C#程序,并引发以下错误:

./my-program:符号查找错误: /usr/lib/libmylib.so:未定义符号: wiringPiSetup

这里出什么问题了?

我的第一个想法是,我的程序不知道wiringPi库。因此,我为这个dll添加了一个导出,并调用wiringPiSetup()进行测试。不管有没有这句话,结果都是一样的。

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

我把链接时间搞砸了吗?

编辑:

命令ldd /usr/lib/libmylib.so给出了以下输出:

代码语言:javascript
复制
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)
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-09-11 16:43:24

这可以归结为名字装饰。C++编译器不只是将函数的名称放在对象文件中-它根据函数的定义(最显著的是它的参数)向名称中添加信息。

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

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

但是编译的C代码没有这样做--名称修饰(或名称损坏)与C++一起出现。

因此,您必须告诉C#“该函数的名称没有修饰”。

要做到这一点,请使用如下属性:

代码语言:javascript
复制
[DllImport("TestDll.dll", EntryPoint="myproc", ExactSpelling=false,CallingConvention=CallingConvention.Cdec‌​l)]

"CallingConvention“位表示”函数是C函数“。

"Cdecl“的意思是"C声明”,如果我没记错的话。

更多信息可在以下网站找到:data/article.php/c4217/Calling-Unmanaged-Code-Part-1--simple-DLLImport.htm

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/46031271

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档