最后,这并没有我最初想象的那么容易。它有效,但有一些警告。
基于 Andon M. Coleman 和 Alexander Klimetschek 的答案,这里有一个脚本函数,它从 Homebrew 中获取 dylib 名称,将它们复制到应用程序包的Contents/Frameworks
目录中,并使用install_name_tool
. 我注意到有时实际的 .dylib 位置与 Xcode 链接器在将可执行文件放在一起时发现的位置不同,这也可以通过使用 .dylib 查询 exe 来处理otool -L
。
下面的脚本将 liblo 库的 .dylib 复制到应用程序包中。添加新库应该像copy lib ###.dlyib
在脚本底部添加新行一样简单。
# exit on error
set -e
# paths
LOCALLIBS_PATH="$SRCROOT/libs"
HOMEBREW_PATH="/usr/local"
FRAMEWORKS_PATH="$BUILT_PRODUCTS_DIR/$FRAMEWORKS_FOLDER_PATH"
EXE_PATH="$BUILT_PRODUCTS_DIR/$EXECUTABLE_FOLDER_PATH/$EXECUTABLE_NAME"
# code signing identity
IDENTITY="$EXPANDED_CODE_SIGN_IDENTITY_NAME"
if [ "$IDENTITY" == "" ] ; then
IDENTITY="$CODE_SIGN_IDENTITY"
fi
# copy lib into Contents/Frameworks and set lib search path
# $1: library .dylib
# $2: optional path to libs folder, otherwise use Homebrew
copylib() {
LIB=$1
if [ "$2" == "" ] ; then
# use homebrew
LIB_PATH=$(find "$HOMEBREW_PATH" -type f -name $LIB)
else
# use given path
LIB_PATH="$2/$LIB"
fi
echo "$LIB:"
echo " $LIB_PATH -> $FRAMEWORKS_FOLDER_PATH/$LIB"
# copy lib, set permissions, and sign
mkdir -p "$FRAMEWORKS_PATH"
cp "$LIB_PATH" "$FRAMEWORKS_PATH/"
chmod 755 "$FRAMEWORKS_PATH/$LIB"
codesign --verify --force --sign "$IDENTITY" "$FRAMEWORKS_PATH/$LIB"
# set new path within executable
OLD=$(otool -L "$EXE_PATH" | grep $LIB | awk '{print $1}')
NEW="@executable_path/../Frameworks/$LIB"
install_name_tool -change "$OLD" "$NEW" "$EXE_PATH"
# print to confirm new path
otool -L "$EXE_PATH" | grep $LIB
}
##### GO
# use lib from homebrew
copy lib liblo.7.dylib
# or use local lib
#copylib liblo.7.dylib "$LOCALLIBS_PATH/liblo/lib"
将此添加为 Xcode 项目中的运行脚本构建阶段。您还可以将其保存为外部文件并sh
在运行脚本阶段使用以下命令调用它:
sh $PROJECT_DIR/path-to/copy-libs.sh
示例构建报告输出:
liblo.7.dylib:
/usr/local/Cellar/liblo/0.29/lib/liblo.7.dylib ->> YOURAPP.app/Contents/Frameworks/liblo.7.dylib
@executable_path/../Frameworks/liblo.7.dylib (compatibility version 11.0.0, current version 11.0.0)
$(find $HOMEBREW_PATH -type f -name $LIB)
可能可以通过遵循 .dylib 符号链接来改进/usr/local/lib
。
更新:您可能还需要确保对新的 dylib 进行签名,否则代码签名步骤将在构建时失败,至少它最终对我有用。在此SO post 之后,添加--deep
到项目 Build Settings 中的Other Code Signing Flags选项有效。
可能有更好的方法来仅对脚本添加的文件进行签名,但我不想深入研究codesign
手动运行。然而,从我所读到的内容来看,--deep
Apple 并未建议仅用于临时修复,因此这可能不是最佳实践。
更新2:运行--deep
实际上并没有解决问题,应用程序仍然无法在其他机器上运行。最后,我需要手动对复制的 .dylib 进行代码签名,结果证明相对容易。
注意:我在运行代码设计时遇到了一个模棱两可的“Mac 开发人员”身份错误,这似乎被钥匙串中两个同名的证书混淆了:即。当前的开发者证书和之前过期的开发者证书。打开钥匙串访问并删除过期的证书解决了这个问题。
更新 3:引用路径变量使用来修复带有空格的路径。
更新 4:此解决方案适用于为最近的系统构建应用程序,但我在 macOS 10.10 上运行应用程序时遇到了代码签名问题。从这个 SO post判断,旧的 macOS 版本使用不同的代码签名哈希算法,该应用程序可以在 10.12 系统上正常运行,但在 10.10 上会因代码签名错误而失败。在这两个系统上,codesign 都验证了所有内容都已正确签名。
您基本上需要使用该-mmacosx-version-min
集合构建库,以便 codesign 能够判断使用哪些算法来支持最小和最近的 macOS 版本。在从源代码构建 liblo 时,我尝试将自定义 CFLAGS/LDFLAGS 传递给 Homebrew,但如果不编辑 brew 公式,这是不可能的。最后,我决定自己编写一个构建脚本来从源代码构建 liblo,并修改了复制脚本,使其也可以获取本地位置。现在一切终于正常了。
TLDR:自制库非常适合初始开发和测试,但手动构建库更适合部署。