学习了Creating a Static Library in iOS Tutorial,本想做一下翻译的工作,但是在网上已经有人翻译过了,因此不添足。译文请见:《在iOS中创建静态库》
在实践中,发现了一些奇怪的错误。
根据文章编写了程序,ImageFilters,写了脚本生成通用静态库,在CoreImageFun工程中使用。
1、在iPhone5s上编译,必须按照如下设置:
否则会出现如下错误:
也就是ImageFilters静态库不支持armv7
2、假如在模拟器上编译,必须按照如下设置:
否则会出现如下错误:
也就是说ImageFilters静态库不支持x86_64
那么从问题来看,也就是我的ImageFilters静态库不包含armv7、x86_64指令集。
那么问题来了,x86_64、arm7分别是什么?
《iOS开发~制作同时支持armv7,armv7s,arm64,i386,x86_64的静态库.a》中说明这些属于的意思。
而我的问题应该就是在生成的静态库不是通用类型的。然而文章中推荐的做法是先分别编译模拟器和真机,在lipo合成。而我是脚本(如下),因此问题的关键就是xcodebuild命令的设置,至少在脚本中,我并没有特别设置ValidArchitecture为armv7 | armv7s | arm64 | i386 | x86_64,因为貌似在工程中直接设置是行不通的。
# define output folder environment variable
UNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/${CONFIGURATION}-universal
# Step 1. Build Device and Simulator versions
xcodebuild -target ImageFilters ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphoneos BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}"
xcodebuild -target ImageFilters -configuration ${CONFIGURATION} -sdk iphonesimulator -arch i386 BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}"
# make sure the output directory exists
mkdir -p "${UNIVERSAL_OUTPUTFOLDER}"
# Step 2. Create universal binary file using lipo
lipo -create -output "${UNIVERSAL_OUTPUTFOLDER}/lib${PROJECT_NAME}.a" "${BUILD_DIR}/${CONFIGURATION}-iphoneos/lib${PROJECT_NAME}.a" "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/lib${PROJECT_NAME}.a"
# Last touch. copy the header files. Just for convenience
cp -R "${BUILD_DIR}/${CONFIGURATION}-iphoneos/include" "${UNIVERSAL_OUTPUTFOLDER}/"
于是,做了一下小尝试,先分别编译真机和模拟器再lipo,发现成功编译。因此我们可以确定,在跑脚本的时候一定要加上Architecture
的设置。
因此接下来的目标是深入了解xcodebuild命令。
学习了xcodebuild官方文档
其中,xcodebuild语法知识简单的介绍了xcodebuild的语法,但是说的不是很明白,因此实践了下,语法总结就是:
xcodebuild [-project projectname] [-target targetname ...] [-configuration configurationname]
[-sdk [sdkfullpath | sdkname]] [buildaction ...] [setting=value ...]
[-userdefault=value ...]
1、xcodebuild可以带多个参数,[…]就是一个参数,参数之间用空格隔开;
2、参数有两种,一种是空格链接,一种是用等号链接,如BUILD_ROOT=”${BUILD_ROOT}”
2、参数就是一个对,即-project和projectname是一对,分别为参数名和参数值,如-sdk iphoneos;
3、假如同个参数名需要设置多个参数值,那就需要重复多个,如-arch armv7 -arch armv7s -arch arm64。
因此,我们可以完善下脚本,如下:
# define output folder environment variable
UNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/${CONFIGURATION}-universal
# Step 1. Build Device and Simulator versions
xcodebuild -target ImageFilters -configuration ${CONFIGURATION} -sdk iphoneos -arch armv7 -arch armv7s -arch arm64 BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}"
xcodebuild -target ImageFilters -configuration ${CONFIGURATION} -sdk iphonesimulator -arch x86_64 -arch i386 BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}"
# make sure the output directory exists
mkdir -p "${UNIVERSAL_OUTPUTFOLDER}"
# Step 2. Create universal binary file using lipo
lipo -create -output "${UNIVERSAL_OUTPUTFOLDER}/lib${PROJECT_NAME}.a" "${BUILD_DIR}/${CONFIGURATION}-iphoneos/lib${PROJECT_NAME}.a" "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/lib${PROJECT_NAME}.a"
# Last touch. copy the header files. Just for convenience
cp -R "${BUILD_DIR}/${CONFIGURATION}-iphoneos/include" "${UNIVERSAL_OUTPUTFOLDER}/"
中文版的简介:Xcode 自动构建命令——xcodebuild,后面有彩蛋。
学习了TUTORIAL: USING SUB-PROJECTS & GIT SUBMODULES TO CREATE A FRAMEWORK IN IOS,真正实践中发现其实不用文章那么复杂的设置。
整理下,新建静态库就这几步:
- 打开xcode,New/File/Project/Libraries & Framework/Cocoa Touch Static Library
- 你可以在静态库里面添加类,所添加的类,添加的类的头文件必须在Target/Build Phases/Copy Files 添加,这样头文件才会出现编译后的include文件夹中,父工程才能看到。
- 假如你要弄一个通用的静态库,那你还需要进行如下设置:
- 假如你有图片文件,建议放在.xcassets文件中,假如你有nib文件,建议放在.bundle文件中。
而使用静态库,就下面几步:
1. 将静态库工程.xcodeproj文件拖进父工程中,添加依赖工程 Target/Build Phases/Target Dependencies
添加链接库 Target/Build Phases/Link Binary with Libraries
2. 添加静态库头文件地址,参数“$(BUILT_PRODUCTS_DIR)” “Recursive”:
3. 设置“other linker flags”“-ObjC”,这个设置保证所有静态库的OC文件都会被连接进来,而不是被到得文件而已:
4. 如果你有其他的.bundle文件,那么添加在这里Target/Build Phases/Copy Bundle Resources:
然而,还没有完,如今Xcode6也是可以制作动态库了,不是说好的苹果自己用的么?规则还是会改变的。
学习了《Xcode 6制作动态及静态Framework》,发现步骤类似。
总结:
在xcode6之前,苹果是不主动支持静态库制作的,于是就有了开源工程Github:iOS Universal Framework。方便了静态库的制作。
xcode6出来之后,开源工程宣布不再维护,因此就可以直接用xcode玩耍。