使用go build为Iphone模拟器构建静态库



我在我的iOS项目中建立了一个c存档:

GOOS=ios GOARCH=arm64 CGO_ENABLED=1 SDK=iphonesimulator CGO_CFLAGS="-fembed-bitcode" CC=pwd/clangwrap.sh go build -buildmode=c-archive -o libuplink.a

Clangwrap.sh看起来像这样

#!/bin/sh
# go/clangwrap.sh
SDK_PATH=`xcrun --sdk $SDK --show-sdk-path`
CLANG=`xcrun --sdk $SDK --find clang`
if [ "$GOARCH" == "amd64" ]; then
CARCH="x86_64"
elif [ "$GOARCH" == "arm64" ]; then
CARCH="arm64"
fi
exec $CLANG -arch $CARCH -isysroot $SDK_PATH -mios-version-min=10.0 "$@"

当我在XCode中链接它并尝试运行模拟器时,我只能在设备本身上运行它:

building for iOS Simulator, but linking in object file built for iOS ... for architecture arm64

我如何针对一个go build的模拟器在Swift项目中使用的静态库?

需求

  • 为iPhone模拟器创建一个静态库
  • 使用苹果芯片代替英特尔模拟器
  • 能够指定最小版本

TL;博士

如果你选择一个模拟器作为运行目标,你可以做一些类似于Xcode的事情。

所以基本上用-target arm64-apple-ios16.2-simulator代替-arch arm64。也省略-mios-version-min=10.0,因为实际的最小版本是在-target中编码的(例如16.2),它优先(无论如何,模拟器的正确选项应该是-miphonesimulator-version-min)。

然后作为CGO_LDFLAGS也指定-target选项加上-syslibroot与路径到SDK。

你的构建脚本稍微调整一下,它可能看起来像这样:

指定模拟器作为目标,最小版本为15。

build.sh

#!/bin/sh
export GOOS=ios
export GOARCH=arm64
export CGO_ENABLED=1
export SDK=iphonesimulator
export CGO_CFLAGS="-fembed-bitcode"
export MIN_VERSION=15
. ./target.sh
export CGO_LDFLAGS="-target ${TARGET} -syslibroot "${SDK_PATH}""
CC="$(pwd)/clangwrap.sh"
export CC
go build -buildmode=c-archive -o libuplink.a

target.sh

#!/bin/sh
SDK_PATH=$(xcrun --sdk "$SDK" --show-sdk-path)
export SDK_PATH
if [ "$GOARCH" = "amd64" ]; then
CARCH="x86_64"
elif [ "$GOARCH" = "arm64" ]; then
CARCH="arm64"
fi
if [ "$SDK" = "iphoneos" ]; then
export TARGET="$CARCH-apple-ios$MIN_VERSION"
elif [ "$SDK" = "iphonesimulator" ]; then
export TARGET="$CARCH-apple-ios$MIN_VERSION-simulator"
fi

clangwrap.sh

clangwrap.sh然后简化为:

#!/bin/zsh
CLANG=$(xcrun --sdk "$SDK" --find clang)
exec "$CLANG" -target "$TARGET" -isysroot "$SDK_PATH" "$@"
细节


不同sdk

必须为iOS设备和iPhone模拟器指定不同的sdk。你可以在Xcode支持的其他平台旁边找到它们/Applications/Xcode.app/Contents/Developer/Platforms。例如,在Xcode 14.2中,其中有一个iPhoneOS平台与iPhoneOS16.2.sdk,一个iPhoneSimulator平台与iPhoneSimulator16.2.sdk

苹果开发者论坛上有一个苹果员工的帖子:https://developer.apple.com/forums/thread/673387#662260022

要检查生成的静态库以显示load命令,可以调用:

otool -l libuplink.a

为Apple Silicon模拟器生成的静态库应该显示如下内容:

...
Load command 1
cmd LC_BUILD_VERSION
cmdsize 24
platform 7
minos 15.0
sdk 16.2
...    

注意:platform 7表示模拟器,minos表示最低部署目标,sdk表示使用的实际SDK版本。

请参阅include文件loader.h中的部分:

/* Known values for the above platform field. */
#define PLATFORM_UNKNOWN 0
#define PLATFORM_ANY 0xFFFFFF
#define PLATFORM_MACOS 1
#define PLATFORM_IOS 2
#define PLATFORM_TVOS 3
#define PLATFORM_WATCHOS 4
#define PLATFORM_BRIDGEOS 5
#define PLATFORM_MACCATALYST 6
#define PLATFORM_IOSSIMULATOR 7
#define PLATFORM_TVOSSIMULATOR 8
#define PLATFORM_WATCHOSSIMULATOR 9
#define PLATFORM_DRIVERKIT 10

您可以在自己的系统中查看它们,如下所示:

cat `xcrun --sdk iphonesimulator --show-sdk-path`/usr/include/mach-o/loader.h

Build for iPhone device

要为iPhone SDK构建一个静态库,您可以这样修改:

export SDK=iphoneos

在上面的build.sh脚本。

如果您尝试在模拟器中使用此库,它将失败并显示building for iOS Simulator, but linking in object file built for iOS, file 'libuplink.a' for architecture arm64

otool -l的输出为:

...
Load command 1
cmd LC_BUILD_VERSION
cmdsize 24
platform 2
minos 15.0
sdk 16.2
ntools 0
...

注意:Platform 2代表PLATFORM_IOS,不代表模拟器。

这当然会在设备上完美运行。

最新更新