平时开发中我们已经习惯了让IDE为我们做好一切,大部分情况下基本上不需要手动去编写项目的make文件,但是在规模较大的项目中,make其实非常重要,甚至可以说会不会make决定了你是否真的了解项目的整体架构并驾驭它。因为自己在Android开发中发现项目中的NDK部分已经抛弃了传统的Android.mk,与时俱进用上了CMake,因此打算静下心来好好学习学习,本文开始对学习CMake的过程做个笔记,以加深印象。参考书籍是《mastering cmake》,这应该算得上是关于cmake的一部经典之作,感兴趣的读者可以下载电子书或者购买一本学习。
1 为什么要用CMake
大家可能发现现在CMake用的越来越多,就以Android为例,以前NDK开发时都是用的安卓特有的Android.mk,但是现在基本上都用CMake了,虽然Android.mk依然支持,但是笔者所参与的项目中,它已经被无情的抛弃了。为什么用CMake?简单一句话概括就是:
跨平台:一份make可以支持多个平台。
想象一下牛逼的你写了一个牛逼的库,然后你想让多个平台的开发者都能享用你的库。假如写这个库的时候还没有CMake这个东西,那么你要怎么办呢?你必须写一份unix系统上的make file以便这个库能够在类unix系统上构建;然后你得搞份Android.mk以便它同样能在Android上构建;你还得考虑Windows上用visual studio的开发者......,如此众多的平台,想想都头疼。
CMake就是帮我们解决这个问题的,它让make的编写对特定的平台透明:开发者只需要按照CMake的语法写make,不需要考虑具体平台,最终由CMake为我们生成原生的构建工具(比如Windows上的visual studio,Mac上的XCode,unix/linux的make)所需要的构建文件。使用CMake可以让我们享受到很多的福利,我们列举出一些来感受下:
(1) 自动搜索你的软件所依赖的库、头文件,CMake在搜索的时候会将环境变量和注册表(Windows平台)也包含在内;
(2) 项目的构建目录和源码目录分离:也就是说可以在项目源码目录之外单独建立一个构建目录,用于存放构建过程中生成的文件。比如下面这样的目录结构:
+ src //项目的源码
|
-------- main.cpp
|
+ bin //项目的构建目录
|
-------- test.so
构建目录和源码目录分离,使得我们可以随时删除构建文件而不用担心会误删掉项目的源码文件。
(3) 在配置阶段选择可选的组件:例如你的项目需要用到某个功能,有两个库都可以完成此功能,其中一个库体积大但是效率很高,另一个库体积小但是效率较低。通过CMake你可以方便的根据你项目的情况决定选择哪个库链接,例如Window平台,你可以选择体积大,效率高的库,而Android平台考虑到移动终端容量限制,你可以选择使用体积小,效率低一点的库。
(4) 很容易在共享库和静态库的构建上进行切换:你可以方便的指定是要构建共享库还是静态库,CMake在背后帮我们处理了构建共享库所需要的平台相关的链接器选项。
(5) CMake能自动生成项目文件的依赖关系,同时绝大多数平台上支持并行构建。
如果你在开发一个跨平台项目,比如说一个跨平台的视频播放器,CMake还会带来一些额外福利:
(1) CMake可以帮我们检测机器的字节序以及一些特定于硬件的信息,这一点很重要,在跨平台项目中,忘记字节序是一些很难追查的bug的根源之一;
(2) 如前文所说:一份cmake构建脚本在多个平台上使用。
2 CMake的历史
CMake如此牛逼,它是怎么来滴呢?CMake最初是ITK项目的一部分,ITK项目始于1999年,由美国麦迪逊国家实验室赞助。ITK项目规模比较庞大,并且需要在多个平台上运行,同时还依赖于其他一些软件库。为了满足软件的构建需求,需要一个功能足够强大同时又简单易用的构建工具,于是ITK项目的开发者设计出了CMake来满足需求。当CMake诞生以后,因为它的灵活易用和强大的功能,越来越多的项目中都用上了它,这其中最著名的案例就是KDE,一个庞大的开源项目,KDE采用了cmake来进行构建,这也证明了cmake确实是一个能够解决大型项目构建问题的解决方案。
CMake最近一次的更新中,加入了CTest和CPack,CMake能够支持软件测试,而CPack则支持跨平台的软件发布,CPack利用已有的比较受大众青睐的工具包比如RPM,Cygwin,PackageMaker等,创建各种原生系统上的软件安装包。
当然CMake还加入了其他一些有用特性,例如支持XCdoe和Visual Studio 10。CMake现在还支持嵌入式设备和其他操作系统的交叉编译。总之CMake作为一个开源项目,自身在不断的进化,功能也会越来越强大