是否可以使用位码创建通用 iOS 框架?

Posted

技术标签:

【中文标题】是否可以使用位码创建通用 iOS 框架?【英文标题】:Is it possible to create a universal iOS framework using bitcode? 【发布时间】:2016-02-23 19:33:09 【问题描述】:

据我了解,bitcode 允许生成具有中间二进制格式的二进制文件。所以这是编译到 ARM 或 x64 架构之前的步骤。

ios 8 开始,可以为 iOS 创建“真实的”.framework 文件。但是,默认情况下,框架文件仅针对一种架构(模拟器、iPhone)进行编译。当一个人想要分发.framework 文件时,最好提供一个与iOS 模拟器兼容并且也可以部署到iPhone 的文件。可以找到不同的脚本示例来使用lipo 创建这样的胖文件。

但是,是否可以只分发编译为位码的.framework 而不必创建具有不同架构的胖文件?

不幸的是,即使为我的.framework 启用了位码:

根据目标架构默认创建不同的文件 即使似乎为框架目标启用了“归档”菜单,我也找不到结果,即使在我的管理器视图中也是如此

我对bitcode的概念有什么误解,还是我错过了什么?

【问题讨论】:

【参考方案1】:

您需要提供一个通用的平面框架。由lipo创建。

启用位码,Targets->Build Setting->Enable BitcodeYes

添加构建目标以创建通用框架

创建一个Aggregate 目标并将以下脚本复制到Build Phrase -> Run Script

###################### # 选项 ###################### #详细 设置-x REVEAL_ARCHIVE_IN_FINDER=false FRAMEWORK_NAME="$PROJECT_NAME" SIMULATOR_LIBRARY_PATH="$BUILD_DIR/$CONFIGURATION-iphonesimulator/$FRAMEWORK_NAME.framework" DEVICE_LIBRARY_PATH="$BUILD_DIR/$CONFIGURATION-iphoneos/$FRAMEWORK_NAME.framework" UNIVERSAL_LIBRARY_DIR="$BUILD_DIR/$CONFIGURATION-iphoneuniversal" FRAMEWORK="$UNIVERSAL_LIBRARY_DIR/$FRAMEWORK_NAME.framework" ###################### # 构建框架 ###################### # 为模拟器构建 xcodebuild -target $PROJECT_NAME -sdk iphonesimulator -configuration $CONFIGURATION ARCHS="i386 x86_64" ONLY_ACTIVE_ARCH=NO clean build CONFIGURATION_BUILD_DIR=$BUILD_DIR/$CONFIGURATION-iphonesimulator # 为设备构建 xcodebuild -scheme $PROJECT_NAME -sdk iphoneos -configuration $CONFIGURATION ARCHS="armv7 armv7s arm64" ONLY_ACTIVE_ARCH=NO clean archive CONFIGURATION_BUILD_DIR=$BUILD_DIR/$CONFIGURATION-iphoneos ###################### # 创建通用目录 ###################### rm -rf "$UNIVERSAL_LIBRARY_DIR" mkdir "$UNIVERSAL_LIBRARY_DIR" mkdir "$FRAMEWORK" ###################### # 复制文件框架 ###################### cp -r "$DEVICE_LIBRARY_PATH/." “$框架” ###################### # 制作通用二进制 ###################### lipo "$SIMULATOR_LIBRARY_PATH/$FRAMEWORK_NAME" "$DEVICE_LIBRARY_PATH/$FRAMEWORK_NAME" -create -output "$FRAMEWORK/$FRAMEWORK_NAME" |回声 # 对于 Swift 框架,需要将 Swiftmodule 复制到通用框架中 if [ -d "$SIMULATOR_LIBRARY_PATH/Modules/$FRAMEWORK_NAME.swiftmodule/" ];然后 cp -f $SIMULATOR_LIBRARY_PATH/Modules/$FRAMEWORK_NAME.swiftmodule/* "$FRAMEWORK/Modules/$FRAMEWORK_NAME.swiftmodule/" |回声 菲 if [ -d "$DEVICE_LIBRARY_PATH/Modules/$FRAMEWORK_NAME.swiftmodule/" ];然后 cp -f $DEVICE_LIBRARY_PATH/Modules/$FRAMEWORK_NAME.swiftmodule/* "$FRAMEWORK/Modules/$FRAMEWORK_NAME.swiftmodule/" |回声 菲 ###################### # 在发布时,将结果复制到发布目录 ###################### OUTPUT_DIR="$PROJECT_DIR/build/$FRAMEWORK_NAME-$CONFIGURATION-iphoneuniversal/" rm -rf "$OUTPUT_DIR" mkdir -p "$OUTPUT_DIR" cp -r "$FRAMEWORK" "$OUTPUT_DIR" 如果 [ $REVEAL_ARCHIVE_IN_FINDER = true ];然后 打开“$OUTPUT_DIR/” 菲

注意

bitcode 仅打包在archive iphoneos sdk 构建上

otool -l -arch arm64 <yourframework_binary>|grep __LLVM检查是否包含bitcode,如果不指定arch参数,则不会有__LLVM,因为otool只打印一个主机arch(模拟器)。

【讨论】:

请再读一遍问题。这正是我想避免的(我在我的问题中提到了lipo)。如果我无论如何都需要创建通用二进制文件,我不明白将某些东西编译为位码的目的。而且我找不到使用archive 构建创建的框架文件。 bitcode 是由 Xcode 编译的中间 LLVM IR,并且依赖于 arch,不像 java 字节码,因此每个 slice 都需要自己的 bitcode 部分。既然是中间代码,所以苹果以后不用上传新版本就可以用它优化到最终的机器码,这是主要目的 并且使用脚本中的archive 创建的框架位于$DEVICE_LIBRARY_PATH/Modules/$FRAMEWORK_NAME 上,参见here 非常感谢这个脚本!还应添加“跳过安装 = 是”以避免从 Build/Products/Release-iphoneos 中删除设备版本【参考方案2】:

我花了很多时间修复/更改 xfaid 答案的设置,最终获得了一个带有位码的通用包,可与 XCode 10 一起使用。

我无法让“xcodebuild archive”命令工作,所以我使用了以下链接中描述的设置:http://iosre.com/t/enable-bitcode-for-frameworks-in-xcode/12581

然后我将脚本稍微更改为:

# Fix for bitcode:
unset TOOLCHAINS

######################
# Options
######################

#verbose
#set -x

REVEAL_ARCHIVE_IN_FINDER=true

FRAMEWORK_NAME="$PROJECT_NAME"

SIMULATOR_LIBRARY_PATH="$BUILD_DIR/$CONFIGURATION-iphonesimulator/$FRAMEWORK_NAME.framework"

DEVICE_LIBRARY_PATH="$BUILD_DIR/$CONFIGURATION-iphoneos/$FRAMEWORK_NAME.framework"

UNIVERSAL_LIBRARY_DIR="$BUILD_DIR/$CONFIGURATION-iphoneuniversal"

FRAMEWORK="$UNIVERSAL_LIBRARY_DIR/$FRAMEWORK_NAME.framework"


######################
# Build Frameworks
######################
# Build for simulator
xcodebuild -target $PROJECT_NAME -sdk iphonesimulator -configuration $CONFIGURATION ARCHS="i386 x86_64" ONLY_ACTIVE_ARCH=NO clean build CONFIGURATION_BUILD_DIR=$BUILD_DIR/$CONFIGURATION-iphonesimulator
# Build for device
xcodebuild -scheme $PROJECT_NAME -sdk iphoneos -configuration $CONFIGURATION ARCHS="armv7 armv7s arm64" ONLY_ACTIVE_ARCH=NO build  ENABLE_BITCODE=YES OTHER_CFLAGS="-fembed-bitcode"  OBJROOT="$OBJROOT/DependantBuilds" CONFIGURATION_BUILD_DIR=$BUILD_DIR/$CONFIGURATION-iphoneos

######################
# Create directory for universal
######################

rm -rf "$UNIVERSAL_LIBRARY_DIR"

mkdir "$UNIVERSAL_LIBRARY_DIR"

mkdir "$FRAMEWORK"


######################
# Copy files Framework
######################

cp -r "$DEVICE_LIBRARY_PATH/." "$FRAMEWORK"


######################
# Make an universal binary
######################

lipo "$SIMULATOR_LIBRARY_PATH/$FRAMEWORK_NAME" "$DEVICE_LIBRARY_PATH/$FRAMEWORK_NAME" -create -output "$FRAMEWORK/$FRAMEWORK_NAME" | echo

# For Swift framework, Swiftmodule needs to be copied in the universal framework
if [ -d "$SIMULATOR_LIBRARY_PATH/Modules/$FRAMEWORK_NAME.swiftmodule/" ]; then
cp -f $SIMULATOR_LIBRARY_PATH/Modules/$FRAMEWORK_NAME.swiftmodule/* "$FRAMEWORK/Modules/$FRAMEWORK_NAME.swiftmodule/" | echo
fi

if [ -d "$DEVICE_LIBRARY_PATH/Modules/$FRAMEWORK_NAME.swiftmodule/" ]; then
cp -f $DEVICE_LIBRARY_PATH/Modules/$FRAMEWORK_NAME.swiftmodule/* "$FRAMEWORK/Modules/$FRAMEWORK_NAME.swiftmodule/" | echo
fi

######################
# On Release, copy the result to release directory
######################
OUTPUT_DIR="$PROJECT_DIR/build/$FRAMEWORK_NAME-$CONFIGURATION-iphoneuniversal/"

rm -rf "$OUTPUT_DIR"
mkdir -p "$OUTPUT_DIR"

cp -r "$FRAMEWORK" "$OUTPUT_DIR"

if [ $REVEAL_ARCHIVE_IN_FINDER = true ]; then
open "$OUTPUT_DIR/"
fi

以防万一它可以帮助你们中的一些人:)

【讨论】:

以上是关于是否可以使用位码创建通用 iOS 框架?的主要内容,如果未能解决你的问题,请参考以下文章

pod install 后 iOS 通用框架编译器版本发生变化

在客户端获取 iOS 通用框架的版本号

iOS 通用框架不构建 i386?

IOS-如何在情节提要上为通用设备的 UIscrollview 设置框架?

创建通用 Cocoapods 框架

创建有效的通用实体框架 linq 语句