CMake使用教程


CMake是一个比make更高级的编译配置工具,它可以根据不同平台、不同的编译器,生成相应的Makefile或者vcproj项目。
通过编写CMakeLists.txt,可以控制生成的Makefile,从而控制编译过程。CMake自动生成的Makefile不仅可以通过make命令构建项目生成目标文件,还支持安装(make install)、测试安装的程序是否能正确执行(make test,或者ctest)、生成当前平台的安装包(make package)、生成源码包(make package_source)、产生Dashboard显示数据并上传等高级功能,只要在CMakeLists.txt中简单配置,就可以完成很多复杂的功能,包括写测试用例。
如果有嵌套目录,子目录下可以有自己的CMakeLists.txt。
总之,CMake是一个非常强大的编译自动配置工具,支持各种平台,KDE也是用它编译的,感兴趣的可以试用一下。
准备活动:
(1)安装cmake。
根据自己的需要下载相应的包即可,Windows下可以下载zip压缩的绿色版本,还可以下载源代码。
(2)运行cmake的方法。(GUI、命令行)

CMake使用步骤:
运行GUI的cmake界面:
cmake-2.8.1-win32-x86/bin/cmake-gui.exe

执行Configure:
运行之后,生成了如下文件:

生成Makefile:
执行Generate之后生成如下文件:
运行make进行编译:
编译完成后,在build目录生成Tutorial.exe,运行Tutorial.exe 25就可以看到运行结果:
运行make install安装程序:
运行make test进行测试:

通过cmake tutorial学习CMake配置方法
http://www.cmake.org/cmake/help/cmake_tutorial.html
可以在源代码的Tests/Turorial目录中找到这个手册对应的代码。
1、Step1。
(如果不知道如何使用cmake,以及如何使用编译产生的Turorial.exe,可先看下前面“CMake使用步骤”的说明,它以Step4为例详细介绍了使用过程,Step1的配置可能不够完全,比如无法运行make install,无法运行make test,但可以参考。)
简单的程序编译。
(1)运行GUI的cmake,指定要编译的源代码路径和二进制文件路径(会自动创建)。
(2)点击Configure,配置成功后,再点击Generate。
配置需要选择合适的编译器,虽然我安装了VC2008,但没有配置成功;选择Unix Makefiles,配置成功,它自动找到了DevC++下的gcc.exe等编译器。
(3)在build3目录执行make,就能够编译生成Turorial.exe了。
D:/Projects/Lab/testngpp/cmake-2.8.1/Tests/Tutorial/Step1/build3> make
Linking CXX executable Tutorial.exe
[100%] Built target Tutorial
可以运行一下Turorial.exe:
D:/Projects/Lab/testngpp/cmake-2.8.1/Tests/Tutorial/Step1/build3>Tutorial.exe
Tutorial.exe Version 1.0
Usage: Tutorial.exe number
D:/Projects/Lab/testngpp/cmake-2.8.1/Tests/Tutorial/Step1/build3>Tutorial.exe 4
The square root of 4 is 2
2、Step2
把子目录编译为库,并且链接到最终的可执行文件。
include_directories ("${PROJECT_SOURCE_DIR}/MathFunctions") 
add_subdirectory (MathFunctions)  # 使得子目录MathFunctions也能被编译
# add the executable
add_executable (Tutorial tutorial.cxx)
target_link_libraries (Tutorial MathFunctions)
产生makefile:
在GUI上点击Configure,之后Generate还是灰色,再次点击Configure,Generate就可以点击了。
编译:
在build目录运行make,即可开始编译,但是开始会报告sh.exe运行异常,应该是Tools下的UnxUtils的sh.exe与Win7不兼容,发现有如下make文件,估计是它导致的,于是把它重命名,不使用UnxUtils下的make,就OK乐。
D:/Tools/CMD/UnxUtils/usr/local/wbin/make.exe
编译过程:
D:/Projects/Lab/testngpp/cmake-2.8.1/Tests/Tutorial/Step2/build>make
[ 50%] Building CXX object MathFunctions/CMakeFiles/MathFunctions.dir/mysqrt.cxx
.obj
Linking CXX static library libMathFunctions.a
[ 50%] Built target MathFunctions
Linking CXX executable Tutorial.exe
[100%] Built target Tutorial

3、Step3
支持make install把程序安装到系统指定目录,并且运行一些测试检查它是否能够正常工作。
a、安装时使用的基础目录,由CMAKE_INSTALL_PREFIX指定。
b、可以通过一个很简单的用例检查程序是否运行起来,没有出现异常。(TurotialRuns只是一个用例名字)
add_test (TutorialRuns Tutorial 25)
c、macro方式进行多组数据的测试是非常简洁方便的。
#define a macro to simplify adding tests, then use it
macro (do_test arg result)
add_test (TutorialComp${arg} Tutorial ${arg})
set_tests_properties (TutorialComp${arg}
PROPERTIES PASS_REGULAR_EXPRESSION ${result})
endmacro (do_test)
# do a bunch of result based tests
do_test (25 "25 is 5")
do_test (-25 "-25 is 0")
执行make install:
D:/Projects/Lab/testngpp/cmake-2.8.1/Tests/Tutorial/Step3/build>make install
[ 50%] "Built target MathFunctions"
[100%] "Built target Tutorial"
Install the project...
-- Install configuration: ""
-- Installing: C:/Program Files/Tutorial/bin/Tutorial.exe
-- Installing: C:/Program Files/Tutorial/include/TutorialConfig.h
-- Installing: C:/Program Files/Tutorial/bin/libMathFunctions.a
-- Installing: C:/Program Files/Tutorial/include/MathFunctions.h
安装结果:
C:/Program Files/Tutorial>tree /f
C:.
├─bin
│ libMathFunctions.a
│ Tutorial.exe

└─include
MathFunctions.h
TutorialConfig.h
执行make test:
D:/Projects/Lab/testngpp/cmake-2.8.1/Tests/Tutorial/Step3/build>make test
Running tests...
Test project D:/Projects/Lab/testngpp/cmake-2.8.1/Tests/Tutorial/Step3/build
Start 1: TutorialRuns
1/5 Test #1: TutorialRuns ..................... Passed 0.01 sec
Start 2: TutorialComp25
2/5 Test #2: TutorialComp25 ................... Passed 0.01 sec
Start 3: TutorialNegative
3/5 Test #3: TutorialNegative ................. Passed 0.01 sec
Start 4: TutorialSmall
4/5 Test #4: TutorialSmall .................... Passed 0.00 sec
Start 5: TutorialUsage
5/5 Test #5: TutorialUsage .................... Passed 0.00 sec
100% tests passed, 0 tests failed out of 5
Total Test time (real) = 0.13 sec
修改一个测试用例,让它不过:
修改顶层CMakeLists.txt,然后重新Configure和Generate,然后make test即可看到结果。
D:/Projects/Lab/testngpp/cmake-2.8.1/Tests/Tutorial/Step3/build>make test
Running tests...
Test project D:/Projects/Lab/testngpp/cmake-2.8.1/Tests/Tutorial/Step3/build
Start 1: TutorialRuns
1/5 Test #1: TutorialRuns ..................... Passed 0.01 sec
Start 2: TutorialComp25
2/5 Test #2: TutorialComp25 ...................***Failed Required regular expre
ssion not found.Regex=[25 is 3
] 0.01 sec
Start 3: TutorialNegative
3/5 Test #3: TutorialNegative ................. Passed 0.01 sec
Start 4: TutorialSmall
4/5 Test #4: TutorialSmall .................... Passed 0.01 sec
Start 5: TutorialUsage
5/5 Test #5: TutorialUsage .................... Passed 0.01 sec
80% tests passed, 1 tests failed out of 5
Total Test time (real) = 0.13 sec
The following tests FAILED:
2 - TutorialComp25 (Failed)
Errors while running CTest
make: *** [test] Error 8

4、Step4
检查系统是否支持log和exp函数。(log和exp都是数学运算函数)
检查方法:
(1)顶层配置中使用CheckFunctionExists.cmake
# does this system provide the log and exp functions?
include (CheckFunctionExists.cmake)
check_function_exists (log HAVE_LOG)
check_function_exists (exp HAVE_EXP)
(2)修改.in文件,定义宏。(修改TutorialConfig.h.in,cmake执行中会把宏定义为合适的值,生成TurorialConfig.h,供编译时使用)
// does the platform provide exp and log functions?
#cmakedefine HAVE_LOG
#cmakedefine HAVE_EXP
(3)在代码中使用宏和log函数等。
// if we have both log and exp then use them
#if defined (HAVE_LOG) && defined (HAVE_EXP)
result = exp(log(x)*0.5);
#else // otherwise use an iterative approach
Step4的完整配置、生成Makefile、编译、运行、安装、测试过程,参见最前面的“CMake使用步骤”。

5、Step5
动态生成源文件,自动把源文件编译进系统中。
make的时候出错了:
D:/Projects/Lab/testngpp/cmake-2.8.1/Tests/Tutorial/Step5/build>make
Scanning dependencies of target MakeTable
[ 25%] Building CXX object MathFunctions/CMakeFiles/MakeTable.dir/MakeTable.cxx.
obj
Linking CXX executable MakeTable.exe
[ 25%] "Built target MakeTable"
[ 50%] Generating Table.h
'.' 不是内部或外部命令,也不是可运行的程序
或批处理文件。
make[2]: *** [MathFunctions/Table.h] Error 1
make[1]: *** [ MathFunctions/CMakeFiles/MathFunctions.dir/all] Error 2
make: *** [all] Error 2
问题分析:
首先看build/makefile文件,关于MakeTable有如下规则:
# Build rule for target.
MakeTable: cmake_check_build_system
$(MAKE) -f CMakeFiles/Makefile2 MakeTable
.PHONY : MakeTable
再看Makefile2文件,找到出错时正在编译的目标。
# All Build rule for target.
MathFunctions/CMakeFiles/MakeTable.dir/all:
$(MAKE) -f MathFunctions/CMakeFiles/MakeTable.dir/build.make MathFunctions/CMakeFiles/MakeTable.dir/depend
$(MAKE) -f MathFunctions/CMakeFiles/MakeTable.dir/build.make MathFunctions/CMakeFiles/MakeTable.dir/build
$(CMAKE_COMMAND) -E cmake_progress_report D:/Projects/Lab/testngpp/cmake-2.8.1/Tests/Tutorial/Step5/build/CMakeFiles 1
@echo "Built target MakeTable"
.PHONY : MathFunctions/CMakeFiles/MakeTable.dir/all
Make规则的执行顺序是按照命令的先后顺序:
如果Makefile内容如下:
all:
echo "First line."
echo "Second line."
那么make结果:
D:/Users/Desktop>make
echo "First line."
First line.
echo "Second line."
Second line.
由此,Built target MakeTable输出之后才失败的。

6、Step6
生成各种平台Windows/Ubuntu/etc.上的安装包,包括二进制安装包和源码安装包。
可以把依赖的系统库也打包。include (InstallRequiredSystemLibraries)
使用CPack。
由于Step1-7,后面一步的配置都包含了前面一步的配置,所以从Step5开始,就会遇到make的问题。
为了编译通过,可以修改MathFunctions目录下的CMakeLists.txt和mysqrt.cxx,去掉所有对Table.h 的依赖。
运行make package可以生成安装包:
第一次,因为没有安装nsis,提示如下问题:
D:/Projects/Lab/testngpp/cmake-2.8.1/Tests/Tutorial/Step6/build>make package
[ 50%] "Built target MathFunctions"
[100%] "Built target Tutorial"
Run CPack packaging tool...
CPack Error: Cannot find NSIS registry value. This is usually caused by NSIS not
being installed. Please install NSIS from http://nsis.sourceforge.net
CPack Error: Cannot initialize the generator NSIS
make: *** [package] Error 1
安装NSIS之后,运行成功:
D:/Projects/Lab/testngpp/cmake-2.8.1/Tests/Tutorial/Step6/build>make package
[ 50%] "Built target MathFunctions"
[100%] "Built target Tutorial"
Run CPack packaging tool...
CPack: Create package using NSIS
CPack: Install projects
CPack: - Run preinstall target for: Tutorial
CPack: - Install project: Tutorial
CPack: Compress package
CPack: Finalize package
CPack: Package D:/Projects/Lab/testngpp/cmake-2.8.1/Tests/Tutorial/Step6/build/T
utorial-1.0.1-win32.exe generated.
生成了如下的Windows安装包文件:
安装完成后,还可以很方便的卸载它:
运行make package_source可以产生源代码包。(我的电脑上提示找不到合适的zip程序)
D:/Projects/Lab/testngpp/cmake-2.8.1/Tests/Tutorial/Step6/build>make package_sou
rce
Run CPack packaging tool for source...
CPack Error: Cannot find a suitable ZIP program
CPack Error: Cannot initialize the generator ZIP
make: *** [package_source] Error 1
7、Step7
把结果发布到dashboard。
下面网址是一个公开的dashboard:
http://www.cdash.org/CDash/index.php?project=PublicDashboard
dashboard上显示的项目名称通过如下方式设置:
需要先把cmake/bin目录加入path中,然后执行ctest -D Experimental。这里遇到了一个错误。
D:/Projects/Lab/testngpp/cmake-2.8.1/Tests/Tutorial/Step7/build>ctest -D Experim
ental
Site: JELLY-PC2
Build name: Win32-make
Create new tag: 20100521-1833 - Experimental
Configure project
Each . represents 1024 bytes of output
. Size of output: 0K
Build project
Each symbol represents 1024 bytes of output.
'!' represents an error and '*' a warning.
. Size of output: 0K
0 Compiler errors
0 Compiler warnings
Test project D:/Projects/Lab/testngpp/cmake-2.8.1/Tests/Tutorial/Step7/build
Start 1: TutorialRuns
1/9 Test #1: TutorialRuns ..................... Passed 0.01 sec
Start 2: TutorialUsage
2/9 Test #2: TutorialUsage .................... Passed 0.01 sec
Start 3: TutorialComp4
3/9 Test #3: TutorialComp4 .................... Passed 0.01 sec
Start 4: TutorialComp9
4/9 Test #4: TutorialComp9 .................... Passed 0.01 sec
Start 5: TutorialComp5
5/9 Test #5: TutorialComp5 .................... Passed 0.01 sec
Start 6: TutorialComp7
6/9 Test #6: TutorialComp7 .................... Passed 0.01 sec
Start 7: TutorialComp25
7/9 Test #7: TutorialComp25 ................... Passed 0.01 sec
Start 8: TutorialComp-25
8/9 Test #8: TutorialComp-25 .................. Passed 0.01 sec
Start 9: TutorialComp0.0001
9/9 Test #9: TutorialComp0.0001 ............... Passed 0.01 sec
100% tests passed, 0 tests failed out of 9
Total Test time (real) = 0.19 sec
Performing coverage
Cannot find any coverage files. Ignoring Coverage request.
Submit files (using http)
Using HTTP submit method
Drop site:http://
Error when uploading file: D:/Projects/Lab/testngpp/cmake-2.8.1/Tests/Tutoria
l/Step7/build/Testing/20100521-1833/Build.xml
Error message was: couldn't connect to host
Problems when submitting via HTTP
Errors while running CTest
产生了如下一些文件:

一、      基本使用

安装:下载二进制包后可直接解压使用

从源码安装则执行命令:./bootstrap; make; make install——尝试执行bootstrap失败

使用:cmake dir_path,生成工程文件或makefile文件

二、      概念

out-of-source build,与in-source build相对,即将编译输出文件与源文件放到不同目录中;

三、      基本结构

1,依赖CMakeLists.txt文件,项目主目标一个,主目录中可指定包含的子目录;

2,在项目CMakeLists.txt中使用project指定项目名称,add_subdirectory添加子目录

3,子目录CMakeLists.txt将从父目录CMakeLists.txt继承设置(TBD,待检验)

四、      语法

1.       #注释

2.       变量:使用set命令显式定义及赋值,在非if语句中,使用${}引用,if中直接使用变量名引用;后续的set命令会清理变量原来的值;

3.       command (args ...)  #命令不分大小写,参数使用空格分隔,使用双引号引起参数中空格

4.       set(var a;b;c) <=> set(var a b c)  #定义变量var并赋值为a;b;c这样一个string list

5.       Add_executable(${var}) <=> Add_executable(a b c)   #变量使用${xxx}引用

6.       条件语句:

if(var) #var 非empty 0 N No OFF FALSE... #非运算使用NOT

       …

else()/elseif() … endif(var)

7.       循环语句

Set(VAR a b c)

Foreach(f ${VAR})       …Endforeach(f)

8.       循环语句

WHILE() … ENDWHILE()

五、      内部变量

CMAKE_C_COMPILER:指定C编译器

CMAKE_CXX_COMPILER

CMAKE_C_FLAGS:编译C文件时的选项,如-g;也可以通过add_definitions添加编译选项

EXECUTABLE_OUTPUT_PATH:可执行文件的存放路径

LIBRARY_OUTPUT_PATH:库文件路径

CMAKE_BUILD_TYPE::build 类型(Debug, Release, ...),CMAKE_BUILD_TYPE=Debug

BUILD_SHARED_LIBS:Switch between shared and static libraries

内置变量的使用:

>> 在CMakeLists.txt中指定,使用set

>> cmake命令中使用,如cmake -DBUILD_SHARED_LIBS=OFF

六、      命令

project (HELLO)   #指定项目名称,生成的VC项目的名称;

>>使用${HELLO_SOURCE_DIR}表示项目根目录

include_directories:指定头文件的搜索路径,相当于指定gcc的-I参数

>> include_directories (${HELLO_SOURCE_DIR}/Hello)  #增加Hello为include目录

link_directories:动态链接库或静态链接库的搜索路径,相当于gcc的-L参数

       >> link_directories (${HELLO_BINARY_DIR}/Hello)     #增加Hello为link目录

add_subdirectory:包含子目录

       >> add_subdirectory (Hello)

add_executable:编译可执行程序,指定编译,好像也可以添加.o文件

       >> add_executable (helloDemo demo.cxx demo_b.cxx)   #将cxx编译成可执行文件——

add_definitions:添加编译参数

>> add_definitions(-DDEBUG)将在gcc命令行添加DEBUG宏定义;

>> add_definitions( “-Wall -ansi –pedantic –g”)

target_link_libraries:添加链接库,相同于指定-l参数

>> target_link_libraries(demo Hello) #将可执行文件与Hello连接成最终文件demo

add_library:

>> add_library(Hello hello.cxx)  #将hello.cxx编译成静态库如libHello.a

add_custom_target:

message( status|fatal_error, “message”):

set_target_properties( ... ): lots of properties... OUTPUT_NAME, VERSION, ....

link_libraries( lib1 lib2 ...): All targets link with the same set of libs

七、      说明

1,CMAKE生成的makefile能够处理好.h文件更改时只编译需要的cpp文件;

八、      FAQ

1)  怎样获得一个目录下的所有源文件

>> aux_source_directory(<dir> <variable>)

>> 将dir中所有源文件(不包括头文件)保存到变量variable中,然后可以add_executable (ss7gw ${variable})这样使用。

2)  怎样指定项目编译目标

>>  project命令指定

3)  怎样添加动态库和静态库

>> target_link_libraries命令添加即可

4)  怎样在执行CMAKE时打印消息

>> message([SEND_ERROR | STATUS | FATAL_ERROR] "message to display" ...)

>> 注意大小写

5)  怎样指定头文件与库文件路径

>> include_directories与link_directories

>>可以多次调用以设置多个路径

>> link_directories仅对其后面的targets起作用

6)  怎样区分debug、release版本

>>建立debug/release两目录,分别在其中执行cmake -DCMAKE_BUILD_TYPE=Debug(或Release),需要编译不同版本时进入不同目录执行make即可;

Debug版会使用参数-g;Release版使用-O3 –DNDEBUG

>> 另一种设置方法——例如DEBUG版设置编译参数DDEBUG

IF(DEBUG_mode)

    add_definitions(-DDEBUG)

ENDIF()

在执行cmake时增加参数即可,例如cmake -D DEBUG_mode=ON

7)  怎样设置条件编译

例如debug版设置编译选项DEBUG,并且更改不应改变CMakelist.txt

>> 使用option command,eg:

option(DEBUG_mode "ON for debug or OFF for release" ON)

IF(DEBUG_mode)

    add_definitions(-DDEBUG)

ENDIF()

>> 使其生效的方法:首先cmake生成makefile,然后make edit_cache编辑编译选项;Linux下会打开一个文本框,可以更改,该完后再make生成目标文件——emacs不支持make edit_cache;

>> 局限:这种方法不能直接设置生成的makefile,而是必须使用命令在make前设置参数;对于debug、release版本,相当于需要两个目录,分别先cmake一次,然后分别make edit_cache一次;

>> 期望的效果:在执行cmake时直接通过参数指定一个开关项,生成相应的makefile——可以这样做,例如cmake –DDEBUGVERSION=ON

8)  怎样添加编译宏定义

>> 使用add_definitions命令,见命令部分说明

9)  怎样添加编译依赖项

用于确保编译目标项目前依赖项必须先构建好

>>add_dependencies

10)        怎样指定目标文件目录

>> 建立一个新的目录,在该目录中执行cmake生成Makefile文件,这样编译结果会保存在该目录——类似

>> SET_TARGET_PROPERTIES(ss7gw PROPERTIES

                      RUNTIME_OUTPUT_DIRECTORY "${BIN_DIR}")

11)        很多文件夹,难道需要把每个文件夹编译成一个库文件?

>> 可以不在子目录中使用CMakeList.txt,直接在上层目录中指定子目录

12)        怎样设定依赖的cmake版本

>>cmake_minimum_required(VERSION 2.6)

13)        相对路径怎么指定

>> ${projectname_SOURCE_DIR}表示根源文件目录,${ projectname _BINARY_DIR}表示根二进制文件目录?

14)        怎样设置编译中间文件的目录

>> TBD

15)        怎样在IF语句中使用字串或数字比较

>>数字比较LESS、GREATER、EQUAL,字串比STRLESS、STRGREATER、STREQUAL,

>> Eg:

set(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS ON)

set(AAA abc)

IF(AAA STREQUAL abc)

    message(STATUS "true")   #应该打印true

ENDIF()

16)        更改h文件时是否只编译必须的cpp文件

>> 是

17)        机器上安装了VC7和VC8,CMAKE会自动搜索编译器,但是怎样指定某个版本?

>> TBD

18)        怎样根据OS指定编译选项

>> IF( APPLE ); IF( UNIX ); IF( WIN32 )

19)        能否自动执行某些编译前、后命令?

>> 可以,TBD

20)        怎样打印make的输出

make VERBOSE=1

参考文献:

[1] CMake_Tutorial.pdf

[2] CMake使用总结,http://blog.csdn.net/keensword007/archive/2008/07/16/2663235.aspx

[3] http://www.cmake.org/

[4] 安装包中文档

[5] Andrej Cedilnik,HOWTO: Cross-Platform Software Development Using CMake,October, 2003

[6] Cjacker,CMake实践.PDF


看了好多网上的文章,都说PROJECT_BINARY_DIR和PROJECT_SOURCE_DIR是等价的。

实际不然。

一般来说,都是这样用 

cmake ./

这样PROJECT_BINARY_DIR和PROJECT_SOURCE_DIR是等价的。也就是当前源码的目录。

如果执行cmake的时候,并不在源码的路径的话,比如

cmake ../src

这样的好处是cmake生成的文件和编译出来的东西,就不放在源码路径下了,保证了源码路径的干净整洁。

比如可以在src的同级目录下建立build目录。

然后在build目录下执行cmake ../src。

这样编译出来的东西和cmake生成的东西,都放到了build目录下了。并且

PROJECT_BINARY_DIR=全路径/build

PROJECT_SOURCE_DIR=全路径/src




2
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值