【问题标题】:Cross-compile to static lib (libgcrypt) for use on iOS交叉编译到静态库 (libgcrypt) 以在 iOS 上使用
【发布时间】:2015-01-04 21:11:54
【问题描述】:

我从https://www.gnupg.org/download/index.html 下载了最新的 libgcrypt 和 libgpg-error 库。我已经使用 ./configure --enable-static --disable-shared 成功构建(命令行)两个库;制作 ;在我的 Mac 上安装(Mavericks w/OSX 10.10 和最新的 Xcode 6.1)。

我可以从我正在构建的 OS X 客户端应用程序中很好地链接到这些新库。到目前为止,一切都很好。刚刚好。但是,我还需要使用相同的源代码构建一个 iOS 客户端。

问题:

1) 为(模拟器、Mac 和 iOS)构建通用静态库需要对库的命令行构建序列进行哪些修改? 2) 还是我需要为 iOS 构建单独的静态库?如果是这样的话,我需要什么命令行魔法来完成正确的目标架构?

【问题讨论】:

    标签: ios autoconf libgcrypt


    【解决方案1】:

    请注意,无法构建适用于 iOS 模拟器和 macOS 的通用库。 iOS/Intel 和 macOS/Intel 与 C 运行时库 (Libc) 之上的 ABI 不兼容。此答案旨在向您展示如何为 iOS 目标交叉编译基于 autoconf 的项目,并且您可以轻松地将生成的静态档案合并在一起。

    你会想做这样的事情:

    #!/bin/bash -e -x
    
    OPT_FLAGS="-Os -g3"
    MAKE_JOBS=16
    
    dobuild() {
        export CC="$(xcrun -find -sdk ${SDK} cc)"
        export CXX="$(xcrun -find -sdk ${SDK} cxx)"
        export CPP="$(xcrun -find -sdk ${SDK} cpp)"
        export CFLAGS="${HOST_FLAGS} ${OPT_FLAGS}"
        export CXXFLAGS="${HOST_FLAGS} ${OPT_FLAGS}"
        export LDFLAGS="${HOST_FLAGS}"
    
        ./configure --host=${CHOST} --prefix=${PREFIX} --enable-static --disable-shared
    
        make clean
        make -j${MAKE_JOBS}
        make install
    }
    
    SDK="iphoneos"
    ARCH_FLAGS="-arch armv7"
    HOST_FLAGS="${ARCH_FLAGS} -miphoneos-version-min=8.0 -isysroot $(xcrun -sdk ${SDK} --show-sdk-path)"
    CHOST="arm-apple-darwin"
    PREFIX="${HOME}/DEVICE_ARM"
    dobuild
    
    SDK="iphoneos"
    ARCH_FLAGS="-arch arm64"
    HOST_FLAGS="${ARCH_FLAGS} -miphoneos-version-min=8.0 -isysroot $(xcrun -sdk ${SDK} --show-sdk-path)"
    CHOST="arm-apple-darwin"
    PREFIX="${HOME}/DEVICE_ARM64"
    dobuild
    
    SDK="iphonesimulator"
    ARCH_FLAGS="-arch i386"
    HOST_FLAGS="${ARCH_FLAGS} -mios-simulator-version-min=8.0 -isysroot $(xcrun -sdk ${SDK} --show-sdk-path)"
    CHOST="i386-apple-darwin"
    PREFIX="${HOME}/SIM_i386"
    dobuild
    
    SDK="iphonesimulator"
    ARCH_FLAGS="-arch x86_64"
    HOST_FLAGS="${ARCH_FLAGS} -mios-simulator-version-min=8.0 -isysroot $(xcrun -sdk ${SDK} --show-sdk-path)"
    CHOST="x86_64-apple-darwin"
    PREFIX="${HOME}/SIM_x86_64"
    dobuild
    

    我只是将该脚本放在一起并验证它是否适用于 pixman(添加了 --disable-libpng 和跳过测试)。您可能需要为 libgcrypt 定制它,但它可以展示为 iOS 构建基于 autoconf/automake/glibtool 的项目的一般模式。

    构建后,您将在 ~/{DEVICE_ARM{,64},SIM_{i386,x86_64}} 中拥有内容,您可以将静态库一起 lipo 或仅在项目中使用它们(链接器将发出有关“其他”档案丢失切片的警告,您可以忽略)。

    lipo -create -output lib.a DEVICE_ARM/lib/lib.a DEVICE_ARM64/lib/lib.a SIM_i386/lib/lib.a SIM_x86_64/lib/lib.a
    

    【讨论】:

    • 你能说清楚吗,因为我完全不熟悉配置类型构建的细微差别。我确实注意到 config.log 正在生成多个 #error Unsupported architecture。
    • 好的,我已经更新了答案,使其更加明确。我写了一个脚本并在 pixman 上进行了测试。您需要针对其他 autoconf/automake/glibtool 项目对其进行调整,但您大致了解。
    • 请注意,随着 Apple Silicon Macs 的发布,不再可能创建一个同时适用于 device 和 sim 的库,因为我们不能同时包含 sim/arm64 和 device/arm64 切片相同的胖二进制文件。 Xcode 引入了 XCFrameworks 来解决这类问题。
    【解决方案2】:

    Jeremy 给出了一个很好的答案,但我想补充一些东西并提供我的两分钱。

    更新的脚本

    #!/bin/bash
    
    OPT_FLAGS="-O3 -g3"
    MAKE_JOBS=8
    
    dobuild() {
        export CC
        CC=$(xcrun --find --sdk "${SDK}" gcc)
        export CXX
        CXX=$(xcrun --find --sdk "${SDK}" g++)
        export CPP
        CPP=$(xcrun --find --sdk "${SDK}" cpp)
        export CFLAGS
        CFLAGS="${HOST_FLAGS} ${OPT_FLAGS}"
        export CXXFLAGS
        CXXFLAGS="${HOST_FLAGS} ${OPT_FLAGS}"
        export LDFLAGS
        LDFLAGS="${HOST_FLAGS}"
    
        ./configure --host="${CHOST}" --prefix="${PREFIX}" --enable-static
    
        make clean
        make -j"${MAKE_JOBS}"
        make install
    }
    
    SDK="iphoneos"
    ARCH_FLAGS="-arch armv7 -arch armv7s -arch arm64"
    HOST_FLAGS="${ARCH_FLAGS} -miphoneos-version-min=8.0 -isysroot $(xcrun --sdk ${SDK} --show-sdk-path)"
    CHOST="arm-apple-darwin"
    PREFIX="${HOME}/DEVICE_ARM"
    dobuild
    
    SDK="iphonesimulator"
    ARCH_FLAGS="-arch x86_64"
    HOST_FLAGS="${ARCH_FLAGS} -mios-simulator-version-min=8.0 -isysroot $(xcrun --sdk ${SDK} --show-sdk-path)"
    CHOST="x86_64-apple-darwin"
    PREFIX="${HOME}/SIM_x86"
    dobuild
    

    iOS 工具链由 SDK 分开,iphonesimulator 和 macos、tvos,当然还有 iphoneos 一样,都有一个单独的 SDK。对于每个 SDK,您都需要进行一次编译。您可以将 iphonesimulator 和 iphoneos 输出合并到一个库中,因为它们包含不同的架构,但实际上它们不是使用相同的 SDK 编译的。我建议不要使用混合 SDK 的超级二进制文件。

    我为什么要这样做?

    如果您正在编译一个库并需要它,那是因为该库正在使用 autoconf,或者在 Boost 和 OpenSSL 的情况下是其他自定义构建系统。为 SDK 编译的关键是正确的 clang-sysroot-miphoneos-ver-min-arch 标志。如果-arch-sysroot 标记错误,您将看到#error Unsupported architecture 错误。

    删除--disable-shared 标志

    即使我打算使用静态库,我也喜欢保留共享库的生成。这通常意味着您将使用位置无关代码 (-fPIC) 进行编译,因此如果您决定将此库包含在共享库中,那么您就可以开始了。此外,与未链接但存档的静态库不同,共享库的链接通常会暴露丢失的对象。

    多架构上线

    您可以在行上传递多个-arch 标志,您将获得FAT 二进制文件。这可以在编译过程中为您节省一些麻烦和时间。

    $ lipo -info libwhatever.a 
    Architectures in the fat file: libwhatver.a are: i386 x86_64 
    

    移除架构

    老实说,您需要i386 支持吗?如果您不针对该设备,则不要包含架构。如果您的主机系统运行的操作系统早于 Lion,您只需要 i386。

    【讨论】:

    • 除非您确定您正在构建的库支持构建 fat,否则我会敦促您构建单独的切片并将它们一起 lipo。许多基于 autoconf 的项目在配置期间检查诸如 sizeof(long) 之类的内容,并将这些内容保存到构建期间使用的宏中。在某些情况下,这可能会导致错误编译的代码。
    • 是的,我已经处理了这个问题。很容易忘记人们喜欢编写主机测试,因此在这种情况下,您需要为每个架构独立重新编译。我已经编写了一些 Shell 脚本来完全像这样编译依赖项。不过,您可能不想继续担心 armv7。
    猜你喜欢
    • 1970-01-01
    • 2021-01-21
    • 1970-01-01
    • 2015-06-14
    • 2021-08-18
    • 2012-05-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多