我在我的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
,不代表模拟器。
这当然会在设备上完美运行。