cmake
cmake是kitware公司及开源开发者在开发工具套件时的衍生品,目前是一个独立的开源项目,诞生于2001年,访问官网获取更多信息:www.cmake.org 。
cmake的优缺点:
- 跨平台,并可生成native编译配置文件。支持在Linux平台生成Makefile,在Apple平台生成xcode,在Windows平台生成MSVC工程文件
- 能够管理大型项目,如KDE4
- 编译构建简单,只需要cmake + make
- 高效、可扩展,可以为cmake编写特定功能的模块
- 需要学习cmake语法
- 与已有体系的配合不是特别理想,如pkgconfig
建议:
- 在实践中学习才有效
- 对于只有几个文件的小项目,直接写Makefile更简单
- 只适用于c/c++/java
- 如果已经具备构建体系,如java的ant,则不需要学习
以下内容,需要cmake的支持,请自行安装。
开始编译Hello World
以下2步,完成cmake对Hello World程序的管理:
- 建立main.c文件,编写经典代码:
#include <stdio.h>
int main()
{
printf("Hello, world\n");
return 0;
}
- 建立 CMakeLists.txt 文件,注意不要漏写最后的s,内容如下:
PROJECT (HELLO)
ADD_EXECUTABLE(hello main.c)
ok,现在可以开始构建和编译了:
- 执行
cmake .
,后面的点号表示当前目录
会出现cmake的一系列输出,执行完成后,当前目录下会生成一些文件,如 CMakeFiles, CMakeCache.txt, cmake_install.cmake 等,当然,还有Makefile。
- 执行
make
,完成编译。使用make VERBOSE=1
查看make的详细过程。
至此,当前目录下已经生成可执行文件 hello,运行即可。
说明:
- PROJECT 指令指定工程名称,可以任意填写,也可以指定支持的语言,默认支持所有语言。语法为:
PROJECT(projectname [CXX] [C] [Java])
- ADD_EXECUTABLE 指定该工程生成文件名为hello的可执行文件,依赖于main.c源文件,多个文件使用空格或者分号分开
注意:以上过程是内部构建,即在工程目录下直接运行命令,这样生成的临时文件无法自动清理,会影响项目管理。后面会说外部构建。
语法规则
- CMakeLists.txt 的内容不区分大小写,建议内置命令全部使用大写。文件名区别大小写。
- 如果工程中有多个目录,每个要管理的目录都要有一个CMakeLists.txt文件
- 变量使用${}取值,注意在IF控制语句中直接使用变量名
- 建议使用外部构建,不要使用内部构建,即不要直接在工程目录运行命令,建议在新建的build目录下执行指令
多目录管理
目前的目录如下所示:
.
COPYRIGHT
README
CMakeLists.txt
runhello.sh
src/CMakeLists.txt
src/main.c
doc/
doc/hello.txt
主目录下的CMakeLists.txt内容如下:
% cat CMakeLists.txt
PROJECT (HELLO)
ADD_SUBDIRECTORY(src bin)
INSTALL(FILES COPYRIGHT README DESTINATION share/doc/cmake/t2)
INSTALL(PROGRAMS runhello.sh DESTINATION bin)
INSTALL(DIRECTORY doc/ DESTINATION share/doc/cmake/t2)
src目录下的CMakeLists.txt内容如下:
ADD_EXECUTABLE(hello main.c)
在主目录下,建立build目录,进入该目录,运行 cmake .. && make
,开始构建和编译,完成后hello位于build/bin下。
其中,
- ADD_SUBDIRECTORY(source_dir [binary_dir] [EXCLUDE_FROM_ALL]) 指令用于向当前工程添加源文件子目录、二进制文件目录及不参与编译的目录。
- 上述指令可以使用 SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin) 替换
- 执行
make install
进行安装。可以指定cmake -DCMAKE_INSTALL_PREFIX=/tmp/t2/usr ..
安装路径前缀
构建动态库和静态库
主目录下的CMakeLists.txt内容如下:
PROJECT(HELLOLIB)
ADD_SUBDIRECTORY(lib)
lib目录下有hello.c和hello.h,内容如下:
// hello.c
#include <stdio.h>
void HelloFunc()
{
printf("hello world\n");
}
// hello.h
#ifndef HELLO_H_
#define HELLO_H_
#include <stdio.h>
void HelloFunc();
#endif
lib目录下CMakeLists.txt内容如下:
% cat lib/CMakeLists.txt
SET(LIBHELLO_SRC hello.c)
ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC}) # 以源文件生成共享库
ADD_LIBRARY(hello_static STATIC ${LIBHELLO_SRC}) # 以源文件生成静态库,目标名字与动态库区分
SET_TARGET_PROPERTIES(hello_static PROPERTIES OUTPUT_NAME "hello") # 静态库的输出名字依然使用hello
SET_TARGET_PROPERTIES(hello PROPERTIES CLEAN_DIRECT_OUTPUT 1) # 不要清除我
SET_TARGET_PROPERTIES(hello_static PROPERTIES CLEAN_DIRECT_OUTPUT 1) # 不要清除我
SET_TARGET_PROPERTIES(hello PROPERTIES VERSION 1.2 SOVERSION 1) # 为动态库设置版本号
构建方法如下,在build/lib/下分别生成如下库文件:
使用共享库
主目录CMakeLists.txt内容如下:
PROJECT(NEWHELLO)
ADD_SUBDIRECTORY(src)
src目录下的main.c文件:
#include <hello.h>
int main()
{
HelloFunc();
return 0;
}
src目录下的CMakeLists.txt内容如下:
ADD_EXECUTABLE(main main.c)
INCLUDE_DIRECTORIES(/home/demo/cmake/t3/lib) # 依赖的h文件路径
LINK_DIRECTORIES(/home/demo/cmake/t3/build/lib) # 依赖的库文件路径
TARGET_LINK_LIBRARIES(main hello) # 链接时依赖的库
外部构建即可。
总结
cmake为跨平台的应用提供了一种简便的管理方式,值得学习。
它的强实践性就像make和scons,在使用中才能学的更多。
我只是入门,更多内容继续学习。
参考资料
《Cmake实践》