在Mac OSX下编译用于iOS的FreeType静态库

记得上学的时候自己研究DirectDraw的文字绘制时,曾经用过FreeType开源库做过一些简单的TTF字库文字绘制操作,那时没什么强力CPU、GPU,而且又是用的DirectDraw,Alpha混合这种操作都是CPU计算,量稍微大一些的时候FPS是相当的不尽人意,就算做了MMX、SSE等的SIMD优化,感觉也不是很理想,而FreeType画文字没有半透明的抗锯齿的话效果也不是很好,所以当时就留下个印象:FreeType的确是非常强力的文字绘图解决方案。现在在像iOS、Android等移动设备的硬件都已经相当强大了(相对而言),所以我又忍不住想要继续一下当年的小研究了!

首先,先做好准备工作。因为是在Mac下编译,所以Xcode是必不可少的,这里需要注意一点,最近的某个版本(好像是4.3)开始Xcode被变成了独立app的形式发布,而这个默认是不带command line tools,而我们要做的FreeType编译是需要用到make等命令行工具的,所以进入Preferences->Downloads里把它下载下来吧,相对1.6G的Xcode来说,180M的命令行工具应该没什么痛苦。

接下来需要搞到FreeType的source,去sf吧,记得不要下载zip版本的源代码,否则sh脚本会是以windows换行规矩的文本存的,在Mac下执行会遇到这个错误:

/bin/sh: ./configure: /bin/sh^M: bad interpreter: No such file or directory ,一定要下载tar版本的,我写这篇记录的时候用的是freetype-2.4.9!

然后开始编译,参考文章中编译了4种cpu arch的库文件,但实际纯iOS应用中应该只需要i386 armv6 armv7这3种,(以下部分原文有误,见最后UPDATE!)不过还是带上x64吧,反正pc版的非交叉编译,也简单:

i386
$ ./configure CFLAGS=”-arch i386″
$ make

编译完成后,复制.a文件:
$ cp objs/.libs/libfreetype.a libfreetype-i386.a

x86_64:
$ ./configure CFLAGS=”-arch x86_64″;make clean;make
$ cp objs/.libs/libfreetype.a libfreetype-x86_64.a
当然编译完成后如法炮制。
下面开始重头戏arm!

armv6

$ ./configure –prefix=/usr/local/iphone –host=arm-apple-darwin –enable-static=yes –enable-shared=no CC=/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/llvm-gcc-4.2 CFLAGS=”-arch armv6 -pipe -mdynamic-no-pic -std=c99 -Wno-trigraphs -fpascal-strings -O2 -Wreturn-type -Wunused-variable -fmessage-length=0 -fvisibility=hidden -miphoneos-version-min=4.0 -I/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.1.sdk/usr/include/libxml2 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.1.sdk” CPP=/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/llvm-cpp-4.2 AR=/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/ar LDFLAGS=”-arch armv6 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.1.sdk -miphoneos-version-min=4.0″
$ make clean;make
$ cp objs/.libs/libfreetype.a libfreetype-arm6.a
注解一下:参考文章里面用的是gcc4.2和iOS 3.2的target,我这Xcode都已经4.3.2了,再用这么老的target有点对不起苹果了,所以直接换上了llvm-gcc和4.0的target!另外由于之前说过的Xcode.app问题,所以所有的include library等搜索路径都要用app包的写法,导致路径非常长。

armv7
$ ./configure –prefix=/usr/local/iphone –host=arm-apple-darwin –enable-static=yes –enable-shared=no CC=/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/llvm-gcc-4.2 CFLAGS=”-arch armv7 -pipe -mdynamic-no-pic -std=c99 -Wno-trigraphs -fpascal-strings -O2 -Wreturn-type -Wunused-variable -fmessage-length=0 -fvisibility=hidden -miphoneos-version-min=4.0 -I/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.1.sdk/usr/include/libxml2 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.1.sdk” CPP=/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/llvm-cpp-4.2 AR=/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/ar LDFLAGS=”-arch armv7 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.1.sdk -miphoneos-version-min=4.0″
$ make clean;make
$ cp objs/.libs/libfreetype.a libfreetype-arm7.a
这个就简单了,直接把armv6的arch参数改一下就可以了!

然后用lipo生成组合库:
$ lipo -create -output libfreetype.a libfreetype-i386.a libfreetype-x86_64 libfreetype-arm6.a libfreetype-arm7.a

最后可以校验一下:
$ lipo -info libfreetype.a
Architectures in the fat file: libfreetype.a are: armv6 armv7 i386 x86_64

至此静态库的编译工作就完成了!

PS:注意应用的时候iOS项目中需要加入libbz2.dylib和libz.dylib,否则一些压缩相关函数会导致整体link失败!

UPDATE1:尝试iOS device时链接期提示警告信息:

ld: warning: PIE disabled. Absolute addressing (perhaps -mdynamic-no-pic) not allowed in code signed PIE, but used in _FT_Stream_Open from /Users/kres/Downloads/freetype-2.4.9/libfreetype.a(ftsystem.o). To fix this warning, don’t compile with -mdynamic-no-pic or link with -Wl,-no_pie

查了一下,所谓的PIE是指position independent executable,即地址无关exe,换句话说也就是生成的机器码中不能出现lea rax, some_symbol_name这样的绝对寻址,而只能以:lea rax, [rel some_symbol_name]这种形式出现,目的是为了提高安全性,这样OS可以以随机的地址加载exe。去掉CFLAGS中的-mdynamic-no-pic后重新编译链接armv6 armv7两个版本的free type代码,警告去除,不知是否会有副作用,继续体验…

UPDATE2:发现现在这样build出来的.a在simulator上跑时,执行到FT_New_Face时会报出如下异常:

Detected an attempt to call a symbol in system libraries that is not present on the iPhone:

open$UNIX2003 called from function FT_Stream_Open in image HelloGLSL.

而直接在device上运行则不会报错,最后发现,参考文章中的i386和x86_64编译方式configure不妥,不能直接用于iPhoneSimulator运行,还是得用类似arm的方式configure编译,而由于iPhoneSimulator的运行编码是i386的,所以x86_64的部分确实没必要,可以舍弃了,修改后的i386编译configure参数如下:

./configure –prefix=/usr/local/iphone –enable-static=yes –enable-shared=no CC=/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/usr/bin/llvm-gcc-4.2 CFLAGS=”-arch i386 -pipe -std=c99 -Wno-trigraphs -fpascal-strings -O2 -Wreturn-type -Wunused-variable -fmessage-length=0 -fvisibility=hidden -miphoneos-version-min=4.0 -I/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator5.1.sdk/usr/include/libxml2 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator5.1.sdk” CPP=/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/usr/bin/llvm-cpp-4.2 AR=/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/usr/bin/ar LDFLAGS=”-arch i386 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator5.1.sdk -miphoneos-version-min=4.0″

编译后lipo重新创建无x86_64的.a后模拟器运行无错!

UPDATE3:可能有朋友喜欢直接把bin拿来用,附上这个版本FT编译好的iOS的静态库.a文件:

http://www.k-res.net/dl/libfreetype.a

参考文章:
Building FreeType for iOS
http://librocket.com/wiki/documentation/BuildingFreeTypeForiOS
Mac OS configure file bugged out
http://savannah.nongnu.org/bugs/?32979

博主友情提示:

如在您的评论中需要提及如QQ号、微信号、电子邮件地址或其他隐私敏感信息,欢迎通过>>博主专用加密工具v2<<加密后发布,原文只有博主可以看到。