我正在处理一个节点加载项,但是在使用node构建库时出现了一个错误。
这是我的binging.gyp文件:
{
"targets": [{
"target_name": "xaddon",
"cflags!": [ "-fno-exceptions" ],
"cflags_cc!": [ "-fno-exceptions" ],
"sources": [
"cppsrc/main.cc"
],
'include_dirs': [
"<!@(node -p \"require('node-addon-api').include\")", "lib"
],
"libraries": ["<(module_root_dir)/lib/xaddon.so"],
'dependencies': [
"<!(node -p \"require('node-addon-api').gyp\")"
],
'defines': [ 'NAPI_DISABLE_CPP_EXCEPTIONS' ]
}]
}如果我把这样的文件放在项目的根文件夹中,那么一切都会正常工作。但是我想运行一个包含lib文件夹中文件的项目。
当我尝试在lib文件夹而不是根文件夹中运行项目所以文件时,这就是错误。
Error: dlopen(#PATH_TO_PROJECT#/build/Release/xaddon.node, 1): Library not loaded: xaddon.so
Referenced from: #PATH_TO_PROJECT#/build/Release/xaddon.node
Reason: image not found发布于 2020-07-13 13:48:26
有了链接的第三方库,你将不得不提供搜索它们的位置。节点加载项是动态链接的共享库,因此每当您需要一个插件时,相应的动态加载器都必须加载所有所需的库。
如何检查所需的库?
otool -L your_addon.nodeldd you_addon.node为了加载这些所需的库,我们的加载程序将在几个地方进行搜索,例如在Linux上的LD_LIBRARY_PATH中列出的所有路径。
但是我们要发布我们自己的库,这不是标准的搜索路径之一吗?
库或可执行文件( Linux或Mach-O格式(例如macOS)上的ELF格式)可以指定一个运行时加载器路径。这些路径被硬编码到二进制文件中,并且可以指定搜索库的其他路径。
如何检索二进制文件RPATH?
otool -l your_addon.node | grep RPATH -A2objdump -x your_addon.node | grep RPATH好的,rpath是的!
我们可以通过链接器标志配置我们的rpath:
"conditions": [
["OS==\"mac\"",
{
"link_settings": {
"libraries": [
"-Wl,-rpath,@loader_path",
"-Wl,-rpath,@loader_path/..",
],
}
}
],
["OS==\"linux\"",
{
"link_settings": {
"libraries": [
"-Wl,-rpath,'$$ORIGIN'",
"-Wl,-rpath,'$$ORIGIN'/.."
],
}
}
]
],$$ORIGIN?@loader_path?这是什么?
rpath条目是硬编码的,所以当您试图在另一台机器上使用您的插件时,如果将其修复到例如/home/youruser/libs/foo/bar/就会中断。
$ORIGIN和@loader_path都是标记,我们的动态加载程序将用包含二进制文件的目录替换它们。因此,无论我们的库将在哪里安装,如果我们指定相对于二进制文件位置的路径,动态加载程序将能够找到它。('$$ORIGIN'只是一个小的变通方法,这样node-gyp就不会在尝试替换值时搞砸事情了)
有关这个主题的一个好读物是这篇文章。
示例
.
├── build
│ └── Release
│ └── addon.node
├── index.js
├── lib
│ └── my_library.dylib
├── package-lock.json
└── package.json我们的构建生成./build/Release/addon.node文件,该文件在构建时与./lib/my_library.dylib链接。
使用@loader_path,我们现在可以指定一个相对于二进制文件位置的rpath,因为@loader_path将被/whatever/path/to/our/package/build/Release替换。
{
"link_settings": {
"libraries": [
"-Wl,-rpath,@loader_path/../../lib",
],
}
}在运行时,这将导致/whatever/path/to/our/package/build/Release/../../lib,这正是我们的库所在的位置。
那Windows呢?
Windows二进制文件没有/使用rpath属性。
但是,DLL搜索顺序将开始在加载应用程序的目录中进行搜索。
跨平台方法
发送所需库的我的方法如下所示:
build/Releaserpath设置为Linux和macOS上的$ORIGIN或@loader_path这样,我们就可以指示Linux和macOS上的动态加载程序在与生成的二进制文件相同的文件夹中搜索库,这是Windows上的默认行为。
复制文件可以通过我们的gyp文件中的另一个目标来完成:
{
"target_name": "action_before_build",
"type": "none",
"copies": [{
"files": [ "/your/lib.dylib" ],
"destination": "<(PRODUCT_DIR)"
}]
}https://stackoverflow.com/questions/62871714
复制相似问题