node-gyp 在 macOS 上未正确链接库
node-gyp not linking libraries correctly on macos
我正在开发一个节点插件,但是在使用node-gyp构建后查找库时出错。
这是我的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' ]
}]
}
这正确构建,如果我将 so 文件放在项目的根文件夹中,一切正常。但是我想运行一个带有 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
链接的第三方库的问题在于,您必须提供搜索它们的位置。 节点插件是动态链接的共享库,因此每当您需要插件时,相应的动态加载器都必须加载所有必需的库。
我们如何检查我们需要哪些库?
- macOS:
otool -L your_addon.node
- Linux:
ldd you_addon.node
为了加载这些需要库,我们的加载器将在多个地方进行搜索,例如在 Linux 上LD_LIBRARY_PATH
中列出的所有路径中。
但是我们正在发布我们自己的库,它不在标准搜索路径之一中?
库或可执行文件(Linux 上的 ELF 格式或 Mach-O 格式,例如 macOS)可以指定运行时加载程序路径。这些路径被硬编码到二进制文件中,并且可以指定其他路径来搜索库。
我们如何检索二进制文件RPATH
?
- macOS:
otool -l your_addon.node | grep RPATH -A2
- Linux:
objdump -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/Release
- 在 Linux 和 macOS 上将
rpath
设置为$ORIGIN
或@loader_path
这样,我们指示 Linux 和 macOS 上的动态加载程序在与生成的二进制文件相同的文件夹中搜索我们的库,这是 Windows 上的默认行为。
复制文件可以通过我们的gyp文件中的附加目标完成:
{
"target_name": "action_before_build",
"type": "none",
"copies": [{
"files": [ "/your/lib.dylib" ],
"destination": "<(PRODUCT_DIR)"
}]
}
- node-gyp 在 macOS 上未正确链接库
- 链接阶段在Ubuntu上失败,但在MacOS上失败
- 链接器命令失败,macOS 上的退出代码为 1(使用 -v 查看调用)
- std::to_chars在MacOS/clang上编译但不链接
- 是什么导致macOS Mojave上的GoogleTest链接错误
- 在 CLion (MacOS) 中使用 OpenGL 和 GLUT 库时出现链接错误
- 我无法编译谷歌测试,告诉链接器输入未使用(macOS)
- EDSDK 3.6 macOS - 32 位与 64 位和链接错误
- 在MacOS上使用Bazel链接动态库
- 在带有brew的MacOS上链接时缺少增强ICU正则表达式符号
- 在macOS High Sierra上使用Boost.Filesystem编译时的链接器错误
- MacOS中的LIBC 的如何使用(链接)调试版本
- 无法链接 ipopt 库(在 MacOS Mojave 上C++)
- 与LLVM LLD链接不起作用[MACOS]
- 如何使用Clang在MacOS上链接核心框架
- 使用CMAKE链接MacOS中的.SO库时的错误
- MacOS QT项目中的链接Dylib
- Linker使用CMAKE在MacOS上共享库的链接器
- 链接错误-C++Clang MacOs
- 如何在Qt-Creator上链接Qt API和GStreamer(MacOS)