一套交叉编译脚本
文章目录
现在移动平台非常火热,我们在使用C/C++开发一些移动应用的时候,经常可能需要将一些第三方c/c++库编译成对应的iOS/Android/WP/Tizen上面的静态库。 之前我介绍过如何使用CMake来编译跨平台库。 那种方法有一个局限性,它只针对一些提供了CMake支持或者源码本身不需要configure的库来说,使用会非常方便,但是如果库本身没有提供CMake或者 在编译之前需要configure的库,使用起来就会很麻烦了。最好的做法,其实是重用它本身提供的编译系统,然后提供交叉编译所需要的一些参数即可。
问题描述
对于提供了configure/make/make install编译系统的库来说,交叉编译只需要指定–build, –host,然后提供CC,CXX,AR,LD,RANLIB,STRIP等编译所需要的变量,最后可能还需要指定arch,CFLAGS,CXXFLAGS和LDFLAGS即可。
而对于提供了CMake支持的库来说,我们只需要为CMake提供一个交叉编译所需要的toolchain文件即可。一般来说,一个CMake的toolchain文件如下所示:
|
|
这里重要的是指定编译器,sysroot和编译时的CFLAGS,CXXFLAGS等参数。具体就不在这里展开了。
为什么我要研究这些东西呢?因为cocos2d-x现在依赖20多个第三方库,如果全部采用源码的形式,那开发编译的时间会变得非常长。为了减少编译等待时间,我们一般会把第三方库事先编译好,形成一堆.a文件。然后在程序运行的时候,指定链接参数给链接器就ok了。
但是,目前我们这些库都是临时编译的。当时编译的脚本没有保留下来了,也就是不清楚编译时候所指定的参数。 另外,编译各个平台下面的静态库,这本身也不是一件简单的事。如果没有相关经验,可能会无从下手。所以,我们为了解决这个问题,现在新建了一个仓库cocos2d-x-3rd-party-libs-src. 这个仓库会把cocos2d-x所需要编译的第三方库的编译脚本全部保存在这里,如果哪一天,我们需要升级第三方库,或者发现现有的第三方库有问题,也可以从编译脚本找问题。
交叉编译一般步骤
一般来讲,我们编译一个第三方库有以下几个步骤。
下载第三方库的源码(一般下载稳定版本)
阅读它自带的Install或者Readme文件,看看如何在本机上编译这个库
如果在本机上不能顺利编译的,可能需要自己给第三方库写patch,这样做的好处是,下次别人下载这个库,只要应用你的patch就可以顺利编译了。
指定交叉编译器,sysroot, CFLAGS, CXXFLAG等参数
./configure, make, make install就搞定了。
一套成形的脚本看起来,大概是这样子的.
解决办法
如果我们为每一个库都编写这样一套脚本,那会显得非常浪费。因为基本上每个平台的脚本都大同小异,如果可以把共用的部分抽取出来就最好了。 要抽取出公共的部分其实是有难度的,但是世界上做这件事情的人绝对不只你一个。本着不重复造轮子的原则,我们直接把VLC 所使用的编译系统拿来改造一下就ok啦。
这套系统主要组成如下
它有一个bootstrap脚本,主要用来配置一些交叉编译的平台参数,如果是Android,则需要指定NDK路径,ANDROID ABI和ANDROID API的版本,是否使用neon等。
一堆rules.mk文件,每一个第三库都会编译一个rules.mk文件,用来指定交叉编译时的参数
一个SHA512SUMS文件,主要用来对下载的第三库进行md5的验证。
一些patch,这部分是可选的。当下载的第三方库在编译时遇到困难时可能需要自己编译一些patch.编写patch非常简单,使用git diff > xxx.patch即可。
具体的文档介绍,请看README文件
结论
编译链接这件事情,其实我之前是没有整得非常清楚的。尤其是configure, make, makefile, cmake这些东西。通过这次折腾这堆编译脚本,我学到了很多东西,对编译链接理解地更加深入了。 另外,我觉得在做任何一件比较棘手的事情之前,先想想是否别人也会遇到同样的问题。他们是怎么解决的,站在巨人的肩膀上会看得更远。 还有,Don’t repeat yourself!