使用 xcodebuild 和 lipo 命令创建 iOS 通用静态库

使用 Xcode 可以很容易的创建一个静态库的 Project 或者在一个 Project 里面创建一个静态库的 Target,分别如下图所示:

我们知道对于 iOS 来讲,有真机设备和模拟器两种,真机就是你使用的 iPhone7 等,真机的指令架构师 arm 架构的,有 armv7、armv7s、arm64三种;而模拟器师运行在 Mac 电脑上的,所以模拟器的指令架构是和你的 Mac 电脑的指令架构相同的,老版本的是 i386 指令架构,新版的 Mac 都是 x86_64 指令架构。
静态库既然是代码库,那必然需要考虑指令架构的问题。Xcode 默认创建的静态库要么支持真机指令架构,要么支持模拟器指令架构,Xcode 这个软件没有在界面操作层面让用户选择同时支持真机和模拟器两类指令架构。但是,在很多情况下,我们需要静态库既能在真机上运行,也能在模拟器上运行,这就需要我们的静态库是一个胖静态库,armv7、armv7s、arm64、i386、x86_64 的指令架构都能得到支持。
虽然 Xcode 在界面层面不能同时设置支持两类不同的架构,但是我们可以使用 xcodebuild 命令通过命令行的形式分别生成支持 armv7、armv7s、arm64 的真机的静态库和支持 i386 、x86_64 的模拟器的静态库,然后再使用 lipo 命令把这两个库合并成一个通用库,这个通用库就支持所有的指令架构了。
原理很简单,我们来看一下具体的 Shell 脚本是怎么写的吧。

# The Parameters for Build Static Lib
xcode_project_path=/Users/jiahan/Documents/codingcoder/ios-wrapper-flurry-analytic/FlurryAnalytics/FlurryAnalytics.xcodeproj
configuration=Release
target_name=FlurryAnalyticsIOS
output_folder=/Users/jiahan/Documents/codingcoder/ios-wrapper-flurry-analytic/output

mkdir -p ${output_folder}

 
# Step 1. Build Device and Simulator versions for each arch
xcodebuild -project ${xcode_project_path} -target ${target_name} ONLY_ACTIVE_ARCH=NO -configuration ${configuration} clean build -sdk iphoneos -arch "armv7" VALID_ARCHS="armv7 armv7s arm64" BUILD_DIR="${output_folder}/armv7"
xcodebuild -project ${xcode_project_path} -target ${target_name} ONLY_ACTIVE_ARCH=NO -configuration ${configuration} clean build -sdk iphoneos -arch "armv7s" VALID_ARCHS="armv7 armv7s arm64" BUILD_DIR="${output_folder}/armv7s"
xcodebuild -project ${xcode_project_path} -target ${target_name} ONLY_ACTIVE_ARCH=NO -configuration ${configuration} clean build -sdk iphoneos -arch "arm64" VALID_ARCHS="armv7 armv7s arm64" BUILD_DIR="${output_folder}/arm64"
xcodebuild -project ${xcode_project_path} -target ${target_name} ONLY_ACTIVE_ARCH=NO -configuration ${configuration} clean build -sdk iphonesimulator -arch "i386" VALID_ARCHS="i386 x86_64" BUILD_DIR="${output_folder}/i386"
xcodebuild -project ${xcode_project_path} -target ${target_name} ONLY_ACTIVE_ARCH=NO -configuration ${configuration} clean build -sdk iphonesimulator -arch "x86_64" VALID_ARCHS="i386 x86_64" BUILD_DIR="${output_folder}/x86_64"


# Step 2. Create universal binary file using lipo
lipo -create -output "${output_folder}/lib${target_name}_universal.a" \
"${output_folder}/armv7/${configuration}-iphoneos/lib${target_name}.a" \
"${output_folder}/armv7s/${configuration}-iphoneos/lib${target_name}.a" \
"${output_folder}/arm64/${configuration}-iphoneos/lib${target_name}.a" \
"${output_folder}/i386/${configuration}-iphonesimulator/lib${target_name}.a" \
"${output_folder}/x86_64/${configuration}-iphonesimulator/lib${target_name}.a"

运行完毕后,打包出来的各个静态库如下所示,libFlurryAnalyticsIOS_universal.a 就是把各个指令架构整合在一起的通用架构静态库。

可能出现的错误及解决方案:

  1. xcode-select: error: tool 'xcodebuild' requires Xcode, but active developer directory '/Library/Developer/CommandLineTools' is a command line tools instance

这个错误可以使用下面的命令解决:
sudo xcode-select -s /Applications/Xcode.app/Contents/Developer

  1. 本来想一次 xcodebuild 里面构建 armv7 armv7s arm64 架构的静态库,后面一直不成功,只能多次调用 xcodebuild 命令。
  2. 可以使用下面的命令查看打出来的通用库包含哪些指令架构:

    lipo -info libFlurryAnalyticsIOS_universal.a

    Architectures in the fat file: libFlurryAnalyticsIOS_universal.a are: armv7 armv7s i386 x86_64 arm64

  1. Shell 脚本 create_universal_static_lib.sh