.net core - PInvoke C 共享库函数依赖于另一个共享库
.net core - PInvoke C shared library function which depends on another shared library
我为现有库 (wiringPi) 编写了一些包装代码来读取温度传感器,但在使用该库时出现错误。
我的包装库看起来像:
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: symbol lookup error: /usr/lib/libmylib.so: undefined symbol: wiringPiSetup
这里出了什么问题?
我的第一个想法是,我的程序不知道 wiringPi 库。所以我为这个 dll 添加了一个导出并调用 wiringPiSetup()
进行测试。使用或不使用此语句的结果相同。
我还在自定义库中添加了一个不依赖 wiringPi 的测试函数。这被 C# 称为 fine。
我在链接时搞砸了吗?
编辑:
命令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)
归结为名称装饰。 C++ 编译器不只是将函数的名称放入对象文件中——它根据函数的定义(最显着的是它的参数)向名称添加信息。
来自https://msdn.microsoft.com/en-us/library/56h2zst2.aspx
Functions, data, and objects in C and C++ programs are represented
internally by their decorated names. A decorated name is an encoded
string created by the compiler during compilation of an object, data,
or function definition. It records calling conventions, types,
function parameters and other information together with the name. This
name decoration, also known as name mangling, helps the linker find
the correct functions and objects when linking an executable.
但是编译的 C 代码不会这样做 - 名称装饰(或名称修改)随 C++ 一起出现。
所以,你必须告诉 C# "this function's name is not decorated."
为此使用如下属性:
[DllImport("TestDll.dll", EntryPoint="myproc", ExactSpelling=false,CallingConvention=CallingConvention.Cdecl)]
"CallingConvention" 位表示 "the function is a C function."
"Cdecl"意思是"C declaration",没记错的话
可以在以下位置找到更多信息:http://www.codeguru.com/csharp/csharp/cs_data/article.php/c4217/Calling-Unmanaged-Code-Part-1--simple-DLLImport.htm
我为现有库 (wiringPi) 编写了一些包装代码来读取温度传感器,但在使用该库时出现错误。
我的包装库看起来像:
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: symbol lookup error: /usr/lib/libmylib.so: undefined symbol: wiringPiSetup
这里出了什么问题?
我的第一个想法是,我的程序不知道 wiringPi 库。所以我为这个 dll 添加了一个导出并调用 wiringPiSetup()
进行测试。使用或不使用此语句的结果相同。
我还在自定义库中添加了一个不依赖 wiringPi 的测试函数。这被 C# 称为 fine。
我在链接时搞砸了吗?
编辑:
命令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)
归结为名称装饰。 C++ 编译器不只是将函数的名称放入对象文件中——它根据函数的定义(最显着的是它的参数)向名称添加信息。
来自https://msdn.microsoft.com/en-us/library/56h2zst2.aspx
Functions, data, and objects in C and C++ programs are represented internally by their decorated names. A decorated name is an encoded string created by the compiler during compilation of an object, data, or function definition. It records calling conventions, types, function parameters and other information together with the name. This name decoration, also known as name mangling, helps the linker find the correct functions and objects when linking an executable.
但是编译的 C 代码不会这样做 - 名称装饰(或名称修改)随 C++ 一起出现。
所以,你必须告诉 C# "this function's name is not decorated."
为此使用如下属性:
[DllImport("TestDll.dll", EntryPoint="myproc", ExactSpelling=false,CallingConvention=CallingConvention.Cdecl)]
"CallingConvention" 位表示 "the function is a C function."
"Cdecl"意思是"C declaration",没记错的话
可以在以下位置找到更多信息:http://www.codeguru.com/csharp/csharp/cs_data/article.php/c4217/Calling-Unmanaged-Code-Part-1--simple-DLLImport.htm