我的目标是动态链接到来自 brew 的库。如何捆绑分发?

My target is dynamically linked against libraries from brew. How to bundle for distribution?

我构建了一个音频插件。我的目标是 .app.component.

我动态地 link 针对 brew 安装的库,libfluidsynth

我复制了libfluidsynth.app/.component.
我使用 install_name_tool 重新 link 二进制文件以指向捆绑的 libfluidsynth.

libfluidsynth 依赖于 glib, gthread, intl.
我将这些库复制到捆绑包中,重新linked libfluidsynth 以更喜欢捆绑副本。
我也对这些库及其依赖项做了同样的事情。

快速浏览一下它的样子:

ls /Users/me/git/juicysfplugin/Builds/MacOSX/build/Release/juicysfplugin.app/Contents/Frameworks
    libfluidsynth.1.7.1.dylib
    libglib-2.0.0.dylib
    libgthread-2.0.0.dylib
    libintl.8.dylib
    libpcre.1.dylib

otool -L \
/Users/me/git/juicysfplugin/Builds/MacOSX/build/Release/juicysfplugin.app/Contents/MacOS/juicysfplugin \
/Users/me/git/juicysfplugin/Builds/MacOSX/build/Release/juicysfplugin.app/Contents/Frameworks/* \
| grep -vE '\t(/System/Library|/usr/lib)'

/Users/me/git/juicysfplugin/Builds/MacOSX/build/Release/juicysfplugin.app/Contents/MacOS/juicysfplugin:
    @executable_path/../Frameworks/libfluidsynth.1.7.1.dylib (compatibility version 1.0.0, current version 1.7.1)
/Users/me/git/juicysfplugin/Builds/MacOSX/build/Release/juicysfplugin.app/Contents/Frameworks/libfluidsynth.1.7.1.dylib:
    @loader_path/../Frameworks/libfluidsynth.1.dylib (compatibility version 1.0.0, current version 1.7.1)
    @loader_path/../Frameworks/libgthread-2.0.0.dylib (compatibility version 5401.0.0, current version 5401.3.0)
    @loader_path/../Frameworks/libglib-2.0.0.dylib (compatibility version 5401.0.0, current version 5401.3.0)
    @loader_path/../Frameworks/libintl.8.dylib (compatibility version 10.0.0, current version 10.5.0)
/Users/me/git/juicysfplugin/Builds/MacOSX/build/Release/juicysfplugin.app/Contents/Frameworks/libglib-2.0.0.dylib:
    @loader_path/../Frameworks/libglib-2.0.0.dylib (compatibility version 5401.0.0, current version 5401.3.0)
    @loader_path/../Frameworks/libpcre.1.dylib (compatibility version 4.0.0, current version 4.9.0)
    @loader_path/../Frameworks/libintl.8.dylib (compatibility version 10.0.0, current version 10.5.0)
/Users/me/git/juicysfplugin/Builds/MacOSX/build/Release/juicysfplugin.app/Contents/Frameworks/libgthread-2.0.0.dylib:
    @loader_path/../Frameworks/libgthread-2.0.0.dylib (compatibility version 5401.0.0, current version 5401.3.0)
    @loader_path/../Frameworks/libglib-2.0.0.dylib (compatibility version 5401.0.0, current version 5401.3.0)
    @loader_path/../Frameworks/libpcre.1.dylib (compatibility version 4.0.0, current version 4.9.0)
    @loader_path/../Frameworks/libintl.8.dylib (compatibility version 10.0.0, current version 10.5.0)
/Users/me/git/juicysfplugin/Builds/MacOSX/build/Release/juicysfplugin.app/Contents/Frameworks/libintl.8.dylib:
    @loader_path/../Frameworks/libintl.8.dylib (compatibility version 10.0.0, current version 10.5.0)
/Users/me/git/juicysfplugin/Builds/MacOSX/build/Release/juicysfplugin.app/Contents/Frameworks/libpcre.1.dylib:
    @loader_path/../Frameworks/libpcre.1.dylib (compatibility version 4.0.0, current version 4.9.0)

这对 .app 非常有效。这里,看文件打开(opensnoop | grep 'dylib'):

EXECNAME      PATH
juicysfplugin  juicysfplugin.app/Contents/MacOS/../Frameworks/libfluidsynth.1.7.1.dylib
juicysfplugin  juicysfplugin.app/Contents/MacOS/../Frameworks/../Frameworks/libgthread-2.0.0.dylib
juicysfplugin  juicysfplugin.app/Contents/MacOS/../Frameworks/../Frameworks/libglib-2.0.0.dylib
juicysfplugin  juicysfplugin.app/Contents/MacOS/../Frameworks/../Frameworks/libintl.8.dylib
juicysfplugin  juicysfplugin.app/Contents/MacOS/../Frameworks/../Frameworks/../Frameworks/libpcre.1.dylib

.app 仅在其捆绑的 Frameworks 文件夹中查找动态库。完美。

然后我在我的 .component 目标上做了相同的副本并重新 links。 这没有用。

我将 .component 加载到音频插件主机中,并检查文件是否打开:

EXECNAME     PATH
Plugin Host  /Users/me/Library/Audio/Plug-Ins/Components/juicysfplugin.component/Contents/MacOS/juicysfplugin
Plugin Host  /usr/local/lib/libfluidsynth.1.7.1.dylib
Plugin Host  /usr/local/opt/glib/lib/libgthread-2.0.0.dylib
Plugin Host  /usr/local/opt/glib/lib/libglib-2.0.0.dylib
Plugin Host  /usr/local/opt/gettext/lib/libintl.8.dylib
Plugin Host  /usr/local/opt/pcre/lib/libpcre.1.dylib

它正在寻找 /usr/local 下的图书馆。为什么?作为完整性检查,我使用 otool 来确认我确实 link 编辑正确:

otool -L \
/Users/me/Library/Audio/Plug-Ins/Components/juicysfplugin.component/Contents/MacOS/juicysfplugin \
/Users/me/Library/Audio/Plug-Ins/Components/juicysfplugin.component/Contents/Frameworks/* \
| grep -vE '\t(/System/Library|/usr/lib)'

/Users/me/Library/Audio/Plug-Ins/Components/juicysfplugin.component/Contents/MacOS/juicysfplugin:
    @executable_path/../Frameworks/libfluidsynth.1.7.1.dylib (compatibility version 1.0.0, current version 1.7.1)
/Users/me/Library/Audio/Plug-Ins/Components/juicysfplugin.component/Contents/Frameworks/libfluidsynth.1.7.1.dylib:
    @loader_path/../Frameworks/libfluidsynth.1.dylib (compatibility version 1.0.0, current version 1.7.1)
    @loader_path/../Frameworks/libgthread-2.0.0.dylib (compatibility version 5401.0.0, current version 5401.3.0)
    @loader_path/../Frameworks/libglib-2.0.0.dylib (compatibility version 5401.0.0, current version 5401.3.0)
    @loader_path/../Frameworks/libintl.8.dylib (compatibility version 10.0.0, current version 10.5.0)
/Users/me/Library/Audio/Plug-Ins/Components/juicysfplugin.component/Contents/Frameworks/libglib-2.0.0.dylib:
    @loader_path/../Frameworks/libglib-2.0.0.dylib (compatibility version 5401.0.0, current version 5401.3.0)
    @loader_path/../Frameworks/libpcre.1.dylib (compatibility version 4.0.0, current version 4.9.0)
    @loader_path/../Frameworks/libintl.8.dylib (compatibility version 10.0.0, current version 10.5.0)
/Users/me/Library/Audio/Plug-Ins/Components/juicysfplugin.component/Contents/Frameworks/libgthread-2.0.0.dylib:
    @loader_path/../Frameworks/libgthread-2.0.0.dylib (compatibility version 5401.0.0, current version 5401.3.0)
    @loader_path/../Frameworks/libglib-2.0.0.dylib (compatibility version 5401.0.0, current version 5401.3.0)
    @loader_path/../Frameworks/libpcre.1.dylib (compatibility version 4.0.0, current version 4.9.0)
    @loader_path/../Frameworks/libintl.8.dylib (compatibility version 10.0.0, current version 10.5.0)
/Users/me/Library/Audio/Plug-Ins/Components/juicysfplugin.component/Contents/Frameworks/libintl.8.dylib:
    @loader_path/../Frameworks/libintl.8.dylib (compatibility version 10.0.0, current version 10.5.0)
/Users/me/Library/Audio/Plug-Ins/Components/juicysfplugin.component/Contents/Frameworks/libpcre.1.dylib:
    @loader_path/../Frameworks/libpcre.1.dylib (compatibility version 4.0.0, current version 4.9.0)

我认为我 link 编辑正确。我使用了完全相同的脚本(它是自动化和参数化的)。 我做错了什么?音频插件宿主如何知道在 /usr/local 下查找依赖项?为什么我的图书馆 links 被忽略了?

我已将二进制文件发布到:https://github.com/Birch-san/juicysfplugin/releases/tag/1.0.1

我重新link的脚本在这里:https://github.com/Birch-san/juicysfplugin/blob/master/Builds/MacOSX/relink-build-for-distribution.sh

.app.component 目标使用方式的主要区别在于:

那么,当父进程负责加载我们的可执行文件时,运行时依赖性解析可能会有所不同?

好的,我got it working

macOS load-time 链接记录在 man dyld

问题是我告诉我的二进制文件查找与 @executable_path 相关的库。

这适用于 .app,因为 .app 的二进制文件可执行文件。

但是对于我的 .vst 和 .component 插件,二进制文件被加载到不同的可执行文件中:音频插件主机。

因此,如果我们要查找与我们的 binary (juicysfplugin.component/Contents/MacOS/juicysfplugin) 相关的库,我们需要使用 @loader_path , 不是 @executable_path.


现在,进入其他谜团……为什么 load-time 链接器忽略我的安装路径 (@executable_path/../Frameworks/libfluidsynth.1.7.1.dylib),而是在 /usr/local/lib/libfluidsynth.1.7.1.dylib 下寻找 find fluidsynth?

因为DYLD_FALLBACK_LIBRARY_PATH!

It is used as the default location for libraries not found in their install path. By default, it is set to $(HOME)/lib:/usr/local/lib:/lib:/usr/lib.

我认为未能在安装路径中找到库。然后它在几个目录下查找叶文件名 — libfluidsynth.1.7.1.dylib —,包括 /usr/local/lib(成功)。

为什么我在 opensnoop 中没有看到失败的文件查找?可能它使用与 open/open_nocancel/open_extended 不同的系统调用。例如,文件上的 运行 stat 不会显示在 opensnoop 中。

也有可能 load-time 链接是由 dyld 进程完成的。 SIP 将不允许将 DTrace 附加到此进程。