首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在macos上没有正确链接库的节点-gyp

在macos上没有正确链接库的节点-gyp
EN

Stack Overflow用户
提问于 2020-07-13 08:11:10
回答 1查看 1.6K关注 0票数 2

我正在处理一个节点加载项,但是在使用node构建库时出现了一个错误。

这是我的binging.gyp文件:

代码语言:javascript
复制
{
"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文件夹而不是根文件夹中运行项目所以文件时,这就是错误。

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

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-07-13 13:48:26

有了链接的第三方库,你将不得不提供搜索它们的位置。节点加载项是动态链接的共享库,因此每当您需要一个插件时,相应的动态加载器都必须加载所有所需的库。

如何检查所需的库?

  • macOS:otool -L your_addon.node
  • Linux:ldd you_addon.node

为了加载这些所需的库,我们的加载程序将在几个地方进行搜索,例如在Linux上的LD_LIBRARY_PATH中列出的所有路径。

但是我们要发布我们自己的库,这不是标准的搜索路径之一吗?

库或可执行文件( Linux或Mach-O格式(例如macOS)上的ELF格式)可以指定一个运行时加载器路径。这些路径被硬编码到二进制文件中,并且可以指定搜索库的其他路径。

如何检索二进制文件RPATH

  • macOS:otool -l your_addon.node | grep RPATH -A2
  • Linux:objdump -x your_addon.node | grep RPATH

好的,rpath是的!

我们可以通过链接器标志配置我们的rpath

代码语言:javascript
复制
"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就不会在尝试替换值时搞砸事情了)

有关这个主题的一个好读物是这篇文章

示例

代码语言:javascript
复制
.
├── 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替换。

代码语言:javascript
复制
              {
                "link_settings": {
                  "libraries": [
                    "-Wl,-rpath,@loader_path/../../lib",
                  ],
                }
              }

在运行时,这将导致/whatever/path/to/our/package/build/Release/../../lib,这正是我们的库所在的位置。

那Windows呢?

Windows二进制文件没有/使用rpath属性。

但是,DLL搜索顺序将开始在加载应用程序的目录中进行搜索。

跨平台方法

发送所需库的我的方法如下所示:

  1. 在构建过程中链接库
  2. 将库复制到结果输出目录,例如build/Release
  3. rpath设置为Linux和macOS上的$ORIGIN@loader_path

这样,我们就可以指示Linux和macOS上的动态加载程序在与生成的二进制文件相同的文件夹中搜索库,这是Windows上的默认行为。

复制文件可以通过我们的gyp文件中的另一个目标来完成:

代码语言:javascript
复制
{
    "target_name": "action_before_build",
    "type": "none",
    "copies": [{
        "files": [ "/your/lib.dylib" ],
        "destination": "<(PRODUCT_DIR)"
    }]
}
票数 8
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/62871714

复制
相关文章

相似问题

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