我已经在我的mac上安装了FreeType使用Brew。代码在我的mac上工作正常,但当我试图运行该项目在其他mac上我得到下面提到的链接错误。
dyld: Library not loaded: /usr/local/opt/freetype/lib/libfreetype.6.dylib
Referenced from: /Users/ashutosh/Library/Developer/Xcode/DerivedData/InstrumentChamp-
etytleaabhxmokadgrjzbgtmwxfl/Build/Products/Debug/instrumentchamp.app/Contents/MacOS/instrumentchamp
Reason: image not found (lldb)
当我尝试在其他Mac上运行代码时,Freetype的所有库目录和包含目录都包含在项目的“$SRCROOT/”目录中。
你在library的链接错误中看到的路径是brew在我创建这个项目的mac中安装freetype的地方。
/usr/local/opt/freetype/lib/libfreetype.6.dylib
我已经将所有需要的lib/ include/目录复制到了项目的主文件夹中。
而且我已经设置了库并在Xcode中包含了路径。
我在这里错过了什么?我还需要做什么才能让我的代码在任何其他Mac上都是可移植的。我通过安装Brew让这个项目在其他Mac上运行,但我想在不需要安装Brew的情况下完成它。
PS:我不得不使用brew安装freetype,因为我无法为32位处理器的freetype编译.dylib,一个64位的.dylib副本给了我错误,如“错误的架构!”
3条答案
按热度按时间4urapxun1#
我在评论中得到的基本想法是,OSX在搜索库的位置上相当愚蠢,它将使用编译期间使用的相同绝对路径在运行时解析它们。
通常当你想把你的应用程序部署/分发到一台与构建它的机器不同的机器上时,你会把你的库包含在安装包/包中,但是你可能希望它们在运行时使用一个相对于你的应用程序的路径,因此install_name_tool -change允许你用一些相对的东西来替换讨厌的绝对路径。
希望这是有意义的,苹果让在OS X上使用系统级框架变得非常容易,定制库就不那么容易了。如果你使用系统级框架编译,
/System/Library/Frameworks/...
在所有OS X安装上都是通用的(给定相同的目标发布版本)。要解决您的问题,我将执行以下操作:
install_name_tool -change /usr/local/opt/freetype/lib/libfreetype.6.dylib @executable_path/lib/libfreetype.6.dylib <executable_name_here>
然后,它将停止在您编译软件时所在的位置查找libfreetype.6.dylib,而是在运行时相对于可执行文件的位置(在本例中,在子目录
lib/
中)搜索它。dwbf0jvd2#
基于Andon M.科尔曼和 Alexandria Klimetschek的回答,这里有一个脚本函数,它从Homebrew中获取dylib名称,将它们复制到应用包的
Contents/Frameworks
目录中。并使用install_name_tool
设置可执行文件对应的搜索路径。dylib位置与Xcode链接器在将可执行文件放在一起时找到的位置不同,这也可以通过使用otool -L
查询exe来处理。下面的脚本将liblo库的.dylib复制到app bundle中。添加新库应该像在脚本底部添加一个新的
copy lib ###.dlyib
行一样简单。将其添加为Xcode项目中的运行脚本构建阶段。您也可以将其另存为外部文件,并在运行脚本阶段中使用
sh
调用它:构建报告输出示例:
$(find $HOMEBREW_PATH -type f -name $LIB)
可能可以通过在/usr/local/lib
中使用.dylib符号链接来改进。UPDATE:您可能还需要确保新的dylib已签名,否则代码签名步骤将在构建时失败,至少最终对我来说是这样的。在SO post之后,将
--deep
添加到项目Build Settings中的 Other Code Signing Flags 选项。也许有一个更好的方法可以只对脚本添加的文件进行签名,但我不想手动运行
codesign
。然而,据我所知,苹果建议使用--deep
只用于临时修复,因此这可能不是一个最佳实践。更新2:运行
--deep
并没有真正解决这个问题,而且这个应用程序仍然不能在其他机器上运行。最后,我需要手动对复制的.dylib进行代码签名,这相对容易。注意:我在运行codesign时遇到了一个模糊的“Mac开发人员”身份错误,似乎被Keychain中同名的两个证书混淆了:即当前的开发者证书和之前过期的开发者证书。打开Keychain Access并删除过期的证书解决了这个问题。
更新3:带引号的路径变量用于修复带有空格的路径。
更新4:这个解决方案可以很好地为最新的系统构建应用,但我在macOS 10.10上运行应用时遇到了代码签名问题。从this SO post来看,旧版本的macOS使用了不同的codesign哈希算法,该应用在10.12系统上运行良好,但在10.10上运行失败,出现代码签名错误。在这两个系统上,codesign都验证了所有内容都正确签名。
你基本上需要用
-mmacosx-version-min
集合来构建库,这样codesign就能知道使用哪种算法来支持min和最近的macOS版本。在从源代码构建liblo的时候,我试着把自定义的CFLAGS/LDFLAGS传递给Homebrew,但是如果不编辑brew公式,这是不可能的。我决定自己写一个构建脚本来从源代码构建liblo,我修改了复制脚本,这样它也可以使用本地位置。现在一切都 * 终于 * 工作了。TLDR:Homebrew库对于初始开发和测试非常有效,但是手动构建库对于部署效果更好。
hpxqektj3#
下面是一个基于Andon答案的自动化脚本,它会将所有的
@executable_path/../Frameworks/
替换为@executable_path/
,这样所有的框架都可以和可执行文件在同一个文件夹中。如果框架之间有依赖关系,这也会调整框架本身。请注意,这只对命令行应用程序有意义,如果是一个常规的OSX捆绑应用程序,可能不应该改变“../Frameworks”约定。
说明
/bin/sh
在Xcode项目构建阶段末尾将其添加为“运行脚本”。脚本
请注意,将NEW_FRAMEWORKS_PATH更改为相对子路径是不起作用的,脚本需要变得更复杂一些才能处理此问题。
结果结构
otool -L executable
看起来像这样: