例子一单个源文件main.c例子二==分解成多个main.chello.hhello.c例子三==先生成一个静态库,链接该库例子四==将源文件放置到不同的目录例子五==控制生成的程序和库所在的目录例子六==使用动态库而不是静态库例子一一个经典的C程序,如何用cmake来进行构建程序呢?//main.c#includestdio.hintmain(){printf(HelloWorld!/n);return0;}编写一个CMakeList.txt文件(可看做cmake的工程文件):project(HELLO)set(SRC_LISTmain.c)add_executable(hello${SRC_LIST})然后,建立一个任意目录(比如本目录下创建一个build子目录),在该build目录下调用cmake注意:为了简单起见,我们从一开始就采用cmake的out-of-source方式来构建(即生成中间产物与源代码分离),并始终坚持这种方法,这也就是此处为什么单独创建一个目录,然后在该目录下执行cmake的原因cmake..-GNMakeMakefilesnmake或者cmake..-GMinGWMakefilesmake即可生成可执行程序hello(.exe)目录结构+|+---main.c+---CMakeList.txt|/--+build/|+---hello.execmake真的不太好用哈,使用cmake的过程,本身也就是一个编程的过程,只有多练才行。我们先看看:前面提到的这些都是什么呢?CMakeList.txt第一行project不是强制性的,但最好始终都加上。这一行会引入两个变量HELLO_BINARY_DIR和HELLO_SOURCE_DIR同时,cmake自动定义了两个等价的变量PROJECT_BINARY_DIR和PROJECT_SOURCE_DIR因为是out-of-source方式构建,所以我们要时刻区分这两个变量对应的目录可以通过message来输出变量的值message(${PROJECT_SOURCE_DIR})set命令用来设置变量add_exectuable告诉工程生成一个可执行文件。add_library则告诉生成一个库文件。注意:CMakeList.txt文件中,命令名字是不区分大小写的,而参数和变量是大小写相关的。cmake命令cmake命令后跟一个路径(..),用来指出CMakeList.txt所在的位置。由于系统中可能有多套构建环境,我们可以通过-G来制定生成哪种工程文件,通过cmake-h可得到详细信息。要显示执行构建过程中详细的信息(比如为了得到更详细的出错信息),可以在CMakeList.txt内加入:SET(CMAKE_VERBOSE_MAKEFILEon)或者执行make时$makeVERBOSE=1或者$exportVERBOSE=1$make例子二一个源文件的例子一似乎没什么意思,拆成3个文件再试试看:hello.h头文件#ifndefDBZHANG_HELLO_#defineDBZHANG_HELLO_voidhello(constchar*name);#endif//DBZHANG_HELLO_hello.c#includestdio.h#includehello.hvoidhello(constchar*name){printf(Hello%s!/n,name);}main.c#includehello.hintmain(){hello(World);return0;}然后准备好CMakeList.txt文件project(HELLO)set(SRC_LISTmain.chello.c)add_executable(hello${SRC_LIST})执行cmake的过程同上,目录结构+|+---main.c+---hello.h+---hello.c+---CMakeList.txt|/--+build/|+---hello.exe例子很简单,没什么可说的。例子三接前面的例子,我们将hello.c生成一个库,然后再使用会怎么样?改写一下前面的CMakeList.txt文件试试:project(HELLO)set(LIB_SRChello.c)set(APP_SRCmain.c)add_library(libhello${LIB_SRC})add_executable(hello${APP_SRC})target_link_libraries(hellolibhello)和前面相比,我们添加了一个新的目标libhello,并将其链接进hello程序然后想前面一样,运行cmake,得到+|+---main.c+---hello.h+---hello.c+---CMakeList.txt|/--+build/|+---hello.exe+---libhello.lib里面有一点不爽,对不?因为我的可执行程序(add_executable)占据了hello这个名字,所以add_library就不能使用这个名字了然后,我们去了个libhello的名字,这将导致生成的库为libhello.lib(或liblibhello.a),很不爽想生成hello.lib(或libhello.a)怎么办?添加一行set_target_properties(libhelloPROPERTIESOUTPUT_NAMEhello)就可以了例子四在前面,我们成功地使用了库,可是源代码放在同一个路径下,还是不太正规,怎么办呢?分开放呗我们期待是这样一种结构+|+---CMakeList.txt+--+src/|||+---main.c|/---CMakeList.txt|+--+libhello/|||+---hello.h|+---hello.c|/---CMakeList.txt|/--+build/哇,现在需要3个CMakeList.txt文件了,每个源文件目录都需要一个,还好,每一个都不是太复杂顶层的CMakeList.txt文件project(HELLO)add_subdirectory(src)add_subdirectory(libhello)src中的CMakeList.txt文件include_directories(${PROJECT_SOURCE_DIR}/libhello)set(APP_SRCmain.c)add_executable(hello${APP_SRC})target_link_libraries(hellolibhello)libhello中的CMakeList.txt文件set(LIB_SRChello.c)add_library(libhello${LIB_SRC})set_target_properties(libhelloPROPERTIESOUTPUT_NAMEhello)恩,和前面一样,建立一个build目录,在其内运行cmake,然后可以得到build/src/hello.exebuild/libhello/hello.lib回头看看,这次多了点什么,顶层的CMakeList.txt文件中使用add_subdirectory告诉cmake去子目录寻找新的CMakeList.txt子文件在src的CMakeList.txt文件中,新增加了include_directories,用来指明头文件所在的路径。例子五前面还是有一点不爽:如果想让可执行文件在bin目录,库文件在lib目录怎么办?就像下面显示的一样:+build/|+--+bin/|||/---hello.exe|/--+lib/|/---hello.lib一种办法:修改顶级的CMakeList.txt文件project(HELLO)add_subdirectory(srcbin)add_subdirectory(libhellolib)不是build中的目录默认和源代码中结构一样么,我们可以指定其对应的目录在build中的名字。这样一来:build/src就成了build/bin了,可是除了hello.exe,中间产物也进来了。还不是我们最想要的。另一种方法:不修改顶级的文件,修改其他两个文件src/CMakeList.txt文件include_directories(${PROJECT_SOURCE_DIR}/libhello)#link_directories(${PROJECT_BINARY_DIR}/lib)set(APP_SRCmain.c)set(EXECUTABLE_OUTPUT_PATH${PROJECT_BINARY_DIR}/bin)add_executable(hello${APP_SRC})target_link_libraries(hellolibhello)libhello/CMakeList.txt文件set(LIB_SRChello.c)add_library(libhello${LIB_SRC})set(LIBRARY_OUTPUT_PATH${PROJECT_BINARY_DIR}/lib)set_target_properties(libhelloPROPERTIESOUTPUT_NAMEhello)例子六在例子三至五中,我们始终用的静态库,那么用动态库应该更酷一点吧。试着写一下如果不考虑windows下,这个例子应该是很简单的,只需要在上个例子的libhello/CMakeList.txt文件中的add_library命令中加入一个SHARED参数:add_library(libhelloSHARED${LIB_SRC})可是,我们既然用cmake了,还是兼顾不同的平台吧,于是,事情有点复杂:修改hello.h文件#ifndefDBZHANG_HELLO_#defineDBZHANG_HELLO_#ifdefined_WIN32#ifLIBHELLO_BUILD#defineLIBHELLO_API__declspec(dllexport)#else#defineLIBHELLO_API__declspec(dllimport)#endif#else#defineLIBHELLO_API#endifLIBHELLO_APIvoidhello(constchar*name);#endif//DBZHANG_HELLO_修改libhello/CMakeList.txt文件set(LIB_SRChello.c)add_definitions(-DLIBHELLO_BUILD)add_library(libhelloSHARED${LIB_SRC})set(LIBRARY_OUTPUT_PATH${PROJECT_BINARY_DIR}/lib)set_target_properties(libhelloPROPERTIESOUTPUT_NAMEhello)恩,剩下来的工作就和原来一样了。在Cmake学习笔记一中通过一串小例子简单学习了cmake的使用方式。这次应该简单看看语法和常用的命令了。简单的语法注释#我是注释命令语法COMMAND(参数1参数2...)字符串列表A;B;C#分号分割或空格分隔的值变量(字符串或字符串列表)set(Fooabc)设置变量Foocommand(${Foo})等价于command(abc)command(${Foo})等价于command(abc)command(/${Foo})转义,和abc无关联流控制结构IF()...ELSE()/ELSEIF()...ENDIF()WHILE()...ENDWHILE()FOREACH()...ENDFOREACH()正则表达式部分常用命令INCLUDE_DIRECTORIES(dir1dir2...)头文件路径,相当于编译器参数-Idir1-Idir2LINK_DIRECTORIES(dir1