.node依赖的动态链接库

node的native addon本质上就是动态链接库,按下细节不表。
但是常见的动态库会依赖其他第三方的动态链接库,这个过程具有传染性。如果对外发布的时候,不希望对系统环境产生依赖,那么我们需要把依赖的第三方库也打包到合适的位置,并且还要让node能找到正确的依赖。

先说简单的。

Windows

长话短说,windows会从当前目录,C:\Windows\System32等位置寻找需要使用的dll文件。由于本文的宗旨是避免对系统环境产生依赖,所以,最合适的位置就是.node文件所在的位置!
唯一难受的地方,就是三方的三方在windows上不是那么好分析,这里有几个工具可以使用

你唯一需要做的就是把工具列出来的DLL全部都拷贝到.node文件所在的位置。如果有很多DLL(几十上百个),那就参考微软的文档,可以把它们都列在应用程序安装目录的位置。
https://learn.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-search-order

macOS

过程中会用到以下两个工具。

  • otool
  • install_name_tool

otool

otool的作用主要有两个

  1. 列出.node文件依赖的其他第三方dylib
  2. 查看编译产物的@rpath设置

install_name_tool的作用如下

  1. 修改依赖的dylib路径
  2. 修改rpath
  3. 修改dylib的id

下面以homebrew为包管理器为例进行举例:

$ otool -L node_modules/sqlite3/build/Release/node_sqlite3.node
node_modules/sqlite3/build/Release/node_sqlite3.node:
        /usr/local/opt/sqlcipher/lib/libsqlcipher.0.dylib (compatibility version 9.0.0, current version 9.6.0)
        /usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 1700.255.0)
        /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1345.100.2)
$ otool -L /usr/local/opt/sqlcipher/lib/libsqlcipher.0.dylib
/usr/local/opt/sqlcipher/lib/libsqlcipher.0.dylib:
        /usr/local/opt/sqlcipher/lib/libsqlcipher.0.dylib (compatibility version 9.0.0, current version 9.6.0)
        /usr/lib/libz.1.dylib (compatibility version 1.0.0, current version 1.2.12)
        /usr/local/opt/openssl@3/lib/libcrypto.3.dylib (compatibility version 3.0.0, current version 3.0.0)
        /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1336.61.1)
$ otool -L /usr/local/opt/sqlcipher/lib/libsqlcipher.0.dylib
/usr/local/opt/sqlcipher/lib/libsqlcipher.0.dylib:
        /usr/local/opt/sqlcipher/lib/libsqlcipher.0.dylib (compatibility version 9.0.0, current version 9.6.0)
        /usr/lib/libz.1.dylib (compatibility version 1.0.0, current version 1.2.12)
        /usr/local/opt/openssl@3/lib/libcrypto.3.dylib (compatibility version 3.0.0, current version 3.0.0)
        /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1336.61.1)
$ otool -L /usr/local/opt/openssl@3/lib/libcrypto.3.dylib
/usr/local/opt/openssl@3/lib/libcrypto.3.dylib:
        /usr/local/opt/openssl@3/lib/libcrypto.3.dylib (compatibility version 3.0.0, current version 3.0.0)
        /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1311.100.3)
  • Intel的CPU下,homebrew安装的第三方依赖默认位于/usr/local/
  • M系列的芯片,homebrew安装的第三方依赖默认位于/opt/homebrew/
    当otool列出上述两个目录下的dylib时,就需要借助install_name_tool来进行修改了。
    大多数情况下,系统自带的第三方依赖不需要处理,如果有兼容性问题,也不会升级系统自带的dylib,而是使用homebrew安装的可选第三方依赖。
#没有设置rpath的时候 -- 没有任何显示
$ otool -l build/Release/node_sqlite3.node | grep RPATH -B 1 -A 10

#设置rpath之后
$ otool -l build/Release/node_sqlite3.node | grep RPATH -B 1 -A 10
Load command 13
          cmd LC_RPATH
      cmdsize 32
         path @loader_path (offset 12)

#修改依赖的第三方dylib从绝对路径到以@rpath为基准的相对路径
$ install_name_tool \
    -change /usr/local/opt/sqlcipher/lib/libsqlcipher.0.dylib @rpath/libsqlcipher.0.dylib \
    -add_rpath @loader_path \
    build/Release/node_sqlite3.node
# install_name_tool -id 修改id和系统文件以作区分 
$ install_name_tool \
    -change /usr/local/opt/openssl@3/lib/libcrypto.3.dylib @rpath/libcrypto.3.dylib \
    -add_rpath @loader_path \
    -id libcrypto.3.dylib \
    build/Release/libsqlcipher.0.dylib

...
# 完成后的成果
$ otool -L build/Release/* 
build/Release/libcrypto.3.dylib:
        libcrypto.3.dylib (compatibility version 3.0.0, current version 3.0.0)
        /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1311.100.3)
build/Release/libsqlcipher.0.dylib:
        libsqlcipher.0.dylib (compatibility version 9.0.0, current version 9.6.0)
        /usr/lib/libz.1.dylib (compatibility version 1.0.0, current version 1.2.12)
        @rpath/libcrypto.3.dylib (compatibility version 3.0.0, current version 3.0.0)
        /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1336.61.1)
build/Release/node_sqlite3.node:
        @rpath/libsqlcipher.0.dylib (compatibility version 9.0.0, current version 9.6.0)
        /usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 1700.255.0)
        /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1345.100.2)

这样对外发布的时候,就不依赖系统环境里的第三方dylib了。

后记:
macOS默认会校验dylib的签名,而install_name_tool会导致签名失效。
所以在向外分发的dylib【包含.node】的时候,会有概率提示SIGKILL (Code Signature Invalid)
有些用户系统会默认禁用签名校验com.apple.security.cs.disable-library-validation,就不会出现这种问题,常见于黑苹果或者其他原因关闭SIP的用户。

出现这种问题,需要先清除签名,然后在install_name_tool完成修改后重新签名。

codesign --remove-signature build/Release/${NAME_SQLCIPHER}
codesign --remove-signature build/Release/${NAME_CRYPTO}
# ...
install_name_tool build/Release/node_sqlite3.node
# 默认情况下生成的.node没有LINK相关的信息,所以直接codesign --remove-ginatrue会抛错
codesign --remove-signature build/Release/node_sqlite3.node
# ...
# 重新签名,因为默认不允许加载无签名的动态链接库
codesign -s - -v build/Release/node_sqlite3.node
codesign -s - -v build/Release/${NAME_SQLCIPHER}
codesign -s - -v build/Release/${NAME_CRYPTO}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,311评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,339评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,671评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,252评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,253评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,031评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,340评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,973评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,466评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,937评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,039评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,701评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,254评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,259评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,485评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,497评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,786评论 2 345

推荐阅读更多精彩内容