Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/macos/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何使带有自制库的Xcode项目可移植?_Xcode_Macos_Opengl_Homebrew_Freetype - Fatal编程技术网

如何使带有自制库的Xcode项目可移植?

如何使带有自制库的Xcode项目可移植?,xcode,macos,opengl,homebrew,freetype,Xcode,Macos,Opengl,Homebrew,Freetype,我已经使用Brew在mac上安装了FreeType。我的mac电脑上的代码工作正常,但当我尝试在其他mac电脑上运行该项目时,会出现下面提到的链接错误 dyld: Library not loaded: /usr/local/opt/freetype/lib/libfreetype.6.dylib Referenced from: /Users/ashutosh/Library/Developer/Xcode/DerivedData/InstrumentChamp- etytleaabhxmo

我已经使用Brew在mac上安装了FreeType。我的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的所有库目录和include目录都包含在project的“$SRCROOT/”目录中

在库的链接错误中看到的路径是brew在我创建此项目的mac中安装freetype的位置。

/usr/local/opt/freetype/lib/libfreetype.6.dylib
我已将所需的所有lib/include/目录复制到项目的主文件夹中。
我已经在Xcode中设置了库和包含路径

我在这里错过了什么?我还需要做什么才能使我的代码在任何其他Mac上都可以移植。 我通过安装Brew在其他mac上运行了该项目,但我想在不需要安装Brew的情况下完成该项目


PS:我必须使用brew安装freetype,因为我无法为32位处理器编译freetype的.dylib,这是.dylib的64位副本,它给了我错误,例如“错误的体系结构!”

我在评论中得到的基本想法是,OSX在搜索库的位置上非常愚蠢,它将使用编译过程中使用的绝对路径在运行时解析库

通常,当您希望将应用程序部署/分发到与构建应用程序的计算机不同的计算机时,您将在安装包/捆绑包中包含您的库。但是您可能希望它们在运行时使用相对于您的应用程序的路径,因此install_name_tool-change允许您使用相对的路径替换讨厌的绝对路径

希望这是有意义的,苹果让在OSX上使用系统范围的框架变得非常容易,而定制库就不那么容易了。如果使用系统范围的框架进行编译,
/system/Library/Frameworks/..
在所有OS X安装上都是通用的(给定相同的目标发布版本)


为了解决您的问题,我将执行以下操作:

install_name_tool-change/usr/local/opt/freetype/lib/libfreetype.6.dylib@executable_path/lib/libfreetype.6.dylib


然后它将停止在编译软件时所在的位置查找libfreetype.6.dylib,而是在运行时相对于可执行文件的位置搜索它(在本例中,在子目录
lib/
).

这是一个基于Andon答案的自动脚本,它将所有
@executable\u path/./Frameworks/
替换为
@executable\u path/
,以便所有框架都可以与可执行文件位于同一文件夹中。如果框架之间存在依赖关系,这也会调整框架本身

注意,这只对命令行应用程序有意义。如果它是一个普通的OSX捆绑应用程序,可能不应该改变“./Frameworks”惯例

说明书
  • 在Xcode项目构建阶段结束时,使用Shell=
    /bin/sh
    将其添加为“运行脚本”

  • 还要确保所有框架的“复制文件”步骤都带有“Destination=Products目录”

剧本 而otool-L可执行文件将如下所示:

executable:
    @executable_path/Some.framework/Versions/A/Some (...)
    @executable_path/Another.framework/Versions/A/Another (...)
    ...
最后,这并不像我原来想的那么容易。这是可行的,但也有一些警告

基于Andon M.Coleman&Alexander Klimetschek的答案,这里有一个脚本函数,它从自制软件中获取动态库名称,将它们复制到应用程序包的
目录/框架
中,并使用
安装名称工具
设置可执行文件的相应搜索路径。我注意到有时实际的.dylib位置与Xcode链接器在组合可执行文件时发现的位置不同,这也通过使用
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\u PATH-type f-name$LIB)
可以通过遵循
/usr/local/LIB
中的.dylib符号链接来改进

更新:您可能还需要确保对新的dylib进行签名,否则在构建时代码签名步骤将失败,至少对我来说最终会失败。接下来,将
--deep
添加到项目生成设置中的其他代码签名标志选项中会起作用

可能有更好的方法只对脚本添加的文件进行签名,但我不想深入研究手动运行
codesign
。然而,从我读到的内容来看,苹果公司除了临时修复之外,不建议使用
--deep
,所以这可能不是一种最佳做法

更新2:运行
--deep
实际上并没有解决问题,应用程序仍然无法在其他机器上运行。最后,我需要手动对复制的.dylib进行代码签名,这相对比较容易

注意:我在运行codesign时遇到了一个模棱两可的“Mac开发者”身份错误,它似乎被密钥链中两个同名的证书混淆了:即当前的开发者证书和以前过期的开发者证书。打开密钥链访问并删除过期证书解决了问题

更新3:引用路径变量用法以修复带有空格的路径

更新4:此解决方案适用于为最新系统构建应用程序,但我在macOS 10.10上运行应用程序时遇到了代码签名问题。从中可以看出,较旧的macOS版本使用不同的代码设计哈希alg
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)