CMake 使用实例 
 
 
  13.1  
  例子一  
 
 
  
  一个经典的  
  C  
  程序,如何用  
  cmake  
  来进行构建程序呢?  
 
 
  
  //main.c  
 
 
  
  #include <stdio.h>  
 
 
  
  int main()  
 
 
  
  {  
 
 
  
  printf("Hello World!/n");  
 
 
  
  return 0;  
 
 
  
  }  
 
 
  
  编写一个  
  CMakeList.txt  
  文件 
  ( 
  可看做  
  cmake  
  的工程文件 
  ) 
  :  
 
 
  
  project(HELLO)  
 
 
  
  set(SRC_LIST main.c)  
 
 
  
  add_executable(hello ${SRC_LIST})  
 
 
  
  然后,建立一个任意目录(比如本目录下创建一个  
  build  
  子目录),在该  
  build  
  目录下调用  
 
 
  
  cmake  
 
 
  
    
  注意:为了简单起见,我们从一开始就采用  
  cmake  
  的  
  out-of-source  
  方式来构建  
 
 
  
  (即生成中间产物与源代码分离),并始终坚持这种方法,这也就是此处为什么单  
 
 
  
  独创建一个目录,然后在该目录下执行  
  cmake  
  的原因  
 
 
  
  cmake .. -G "NMake Makefiles"  
 
 
 
 
  
  nmake  
 
 
 
 
  
  或者  
 
 
  
  cmake .. -G "MinGW Makefiles"  
 
 
  
  make  
 
 
  
  即可生成可执行程序  
  hello(.exe)  
 
 
 
 
  
  目录结构  
 
 
  
  +  
 
 
  
  |  
  +--- main.c  
 
 
  
  +--- CMakeList.txt  
 
 
  
  |  
 
 
  
  /--+ build/  
 
 
  
   |  
 
 
  
   +--- hello.exe  
 
 
 
 
  
  cmake  
  真的不太好用哈,使用  
  cmake  
  的过程,本身也就是一个编程的过程,只有多练才  
 
 
  
  行。  
 
 
  
  我们先看看:前面提到的这些都是什么呢?  
 
 
  
  13.1.1 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  
  文件中,命令名字是不区分大小写的,而参数和变量是大小写  
 
 
  
  相关的。  
 
 
  
  13.1.2 cmake  
  命令  
 
 
  
  cmake  
  命令后跟一个路径 
  (..) 
  ,用来指出  
  CMakeList.txt  
  所在的位置。  
 
 
  
  由于系统中可能有多套构建环境,我们可以通过 
  -G  
  来制定生成哪种工程文件,通  
 
 
  
  过  
  cmake -h  
  可得到详细信息。 
  要显示执行构建过程中详细的信息 
  ( 
  比如为了得到更详细的出错信息 
  ) 
  ,可以在  
 
 
  
  CMakeList.txt  
  内加入:  
 
 
  
    
  SET( CMAKE_VERBOSE_MAKEFILE on )  
 
 
  
  或者执行  
  make  
  时  
 
 
  
    
  $ make VERBOSE=1  
 
 
  
  或者  
 
 
  
    
  $ export VERBOSE=1  
 
 
  
    
  $ make  
 
 
  
  13.2  
  例子二  
 
 
  
  一个源文件的例子一似乎没什么意思,拆成  
  3  
  个文件再试试看:  
 
 
  
    
  hello.h  
  头文件  
 
 
  
  #ifndef DBZHANG_HELLO_  
 
 
  
  #define DBZHANG_HELLO_  
 
 
  
  void hello(const char* name);  
 
 
  
  #endif //DBZHANG_HELLO_  
 
 
  
    
  hello.c  
 
 
  
  #include <stdio.h>  
 
 
  
  #include "hello.h"  
 
 
  
  void hello(const char * name)  
 
 
  
  {  
 
 
  
  printf ("Hello %s!/n", name);  
 
 
  
  }  
 
 
  
    
  main.c  
 
 
  
  #include "hello.h"  
 
 
  
  int main() 
  {  
 
 
  
  hello("World");  
 
 
  
  return 0;  
 
 
  
  }  
 
 
  
    
  然后准备好  
  CMakeList.txt  
  文件  
 
 
  
  project(HELLO)  
 
 
  
  set(SRC_LIST main.c hello.c)  
 
 
  
  add_executable(hello ${SRC_LIST})  
 
 
  
  执行  
  cmake  
  的过程同上,目录结构  
 
 
  
  +  
 
 
  
  |  
 
 
  
  +--- main.c  
 
 
  
  +--- hello.h  
 
 
  
  +--- hello.c  
 
 
  
  +--- CMakeList.txt  
 
 
  
  |  
 
 
  
  /--+ build/  
 
 
  
   |  
 
 
  
   +--- hello.exe  
 
 
  
  例子很简单,没什么可说的。  
 
 
 
 
  
  13.3  
  例子三  
 
 
  
  接前面的例子,我们将  
  hello.c  
  生成一个库,然后再使用会怎么样?  
 
 
  
  改写一下前面的  
  CMakeList.txt  
  文件试试:  
 
 
  
  project(HELLO)  
 
 
  
  set(LIB_SRC hello.c)  
 
 
  
  set(APP_SRC main.c)  
 
 
  
  add_library(libhello ${LIB_SRC})  
 
 
  
  add_executable(hello ${APP_SRC}) 
 
 
  
  target_link_libraries(hello libhello)  
 
 
  
  和前面相比,我们添加了一个新的目标  
  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(libhello PROPERTIES OUTPUT_NAME "hello")  
 
 
  
  就可以了  
 
 
 
 
 
 
  
  13.4  
  例子四  
 
 
  
  在前面,我们成功地使用了库,可是源代码放在同一个路径下,还是不太正规,怎么办  
 
 
  
  呢?分开放呗  
 
 
  
  我们期待是这样一种结构 
  +  
 
 
  
  |  
 
 
  
  +--- 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_SRC main.c)  
 
 
  
  add_executable(hello ${APP_SRC})  
 
 
  
  target_link_libraries(hello libhello)  
 
 
  
    
  libhello  
  中的  
  CMakeList.txt  
  文件  
 
 
  
  set(LIB_SRC hello.c)  
 
 
  
  add_library(libhello ${LIB_SRC})  
 
 
  
  set_target_properties(libhello PROPERTIES OUTPUT_NAME "hello") 
 
 
  
  恩,和前面一样,建立一个  
  build  
  目录,在其内运行  
  cmake 
 
 
 
 
 
 
  
  然后可以得到  
 
 
  
    
  build/src/hello.exe  
 
 
  
    
  build/libhello/hello.lib  
 
 
  
 
 
 
 
  
  回头看看,这次多了点什么,顶层的  
  CMakeList.txt  
  文件中使用  
  add_subdirectory  
  告诉  
 
 
  
  cmake  
  去子目录寻找新的  
  CMakeList.txt  
  子文件  
 
 
 
 
  
  在  
  src  
  的  
  CMakeList.txt  
  文件中,新增加了  
  include_directories 
  ,用来指明头文件所在的路  
 
 
  
  径。  
 
 
  
  
  13.5  
  例子五  
 
 
  
  前面还是有一点不爽:如果想让可执行文件在  
  bin  
  目录,库文件在  
  lib  
  目录怎么办?  
 
 
  
  就像下面显示的一样:  
 
 
  
  + build/  
 
 
  
  |  
 
 
  
  +--+ bin/  
 
 
  
  | |  
 
 
  
  | /--- hello.exe  
 
 
  
  |  
 
 
  
  /--+ lib/  
 
 
  
  |  
 
 
  
  /--- hello.lib  
 
 
  
    
  一种办法:修改顶级的  
  CMakeList.txt  
  文件  
 
 
  
  project(HELLO)  
 
 
  
  add_subdirectory(src bin)  
 
 
  
  add_subdirectory(libhello lib)  
 
 
  
  不是  
  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_SRC main.c)  
 
 
  
  set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)  
 
 
  
  add_executable(hello ${APP_SRC})  
 
 
  
  target_link_libraries(hello libhello)  
 
 
  
  
  libhello/CMakeList.txt  
  文件  
 
 
  
  set(LIB_SRC hello.c)  
 
 
  
  add_library(libhello ${LIB_SRC})  
 
 
  
  set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)  
 
 
  
  set_target_properties(libhello PROPERTIES OUTPUT_NAME "hello")  
 
 
  
  13.6  
  例子六  
 
 
  
  在例子三至五中,我们始终用的静态库,那么用动态库应该更酷一点吧。 试着写一下  
 
 
  
  如果不考虑  
  windows  
  下,这个例子应该是很简单的,只需要在上个例子的  
 
 
  
  libhello/CMakeList.txt  
  文件中的  
  add_library  
  命令中加入一个  
  SHARED  
  参数:  
 
 
  
  add_library(libhello SHARED ${LIB_SRC})  
 
 
  
  可是,我们既然用  
  cmake  
  了,还是兼顾不同的平台吧,于是,事情有点复杂:  
 
 
  
    
  修改  
  hello.h  
  文件  
 
 
  
  #ifndef DBZHANG_HELLO_  
 
 
  
  #define DBZHANG_HELLO_  
 
 
  
  #if defined _WIN32  
 
 
  
  #if LIBHELLO_BUILD  
 
 
  
  #define LIBHELLO_API __declspec(dllexport)  
 
 
  
  #else  
 
 
  
  #define LIBHELLO_API __declspec(dllimport) 
   #endif  
 
 
  
  #else  
 
 
  
  #define LIBHELLO_API  
 
 
  
  #endif  
 
 
  
  LIBHELLO_API void hello(const char* name);  
 
 
  
  #endif //DBZHANG_HELLO_  
 
 
  
    
  修改  
  libhello/CMakeList.txt  
  文件  
 
 
  
  set(LIB_SRC hello.c)  
 
 
  
  add_definitions("-DLIBHELLO_BUILD")  
 
 
  
  add_library(libhello SHARED ${LIB_SRC})  
 
 
  
  set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)  
 
 
  
  set_target_properties(libhello PROPERTIES OUTPUT_NAME "hello")  
 
 
  
  恩,剩下来的工作就和原来一样了。  
 
 
  
  14 CMake  
  的局限性  
 
 
  
  世界上没有完美的东西。 
  CMake  
  也有其局限性:  
 
 
  
  - CMake  
  并不遵守  
  GNU  
  规则。这使得  
  CMake  
  对一些开源软件的支持不够。例如,  
 
 
  
  CMake  
  生成出的工程在  
  Linux  
  下不支持  
  make uninstall 
  。  
 
 
  
  - CMake  
  和其他编译系统会打架。处理起来不容易。例如,如果不用  
  Qt  
  自带的  
 
 
  
  QMake 
  ,而是用  
  CMake  
  去编译  
  Qt  
  工程,那是一件费时费力的事情。  
 
 
  
  - CMake  
  不会认识开发者在  
  IDE  
  中新增加的文件。必须通过修改  
  CMakeLists.txt 
  ,才  
 
 
  
  能让  
  CMake  
  知道有新的文件。  
 
 
  
  15  
  常用网络资源  
 
 
  
  15.1 CMake  
  文档  
 
 
  
  http://www.cmake.org/cmake/help/v2.8.8/cmake.html  
 
 
  
  15.2 CMake Wiki  
 
 
  
  http://www.cmake.org/Wiki/CMake 
  15.3 CMake  
  入门  
 
 
  
  http://zh.wikibooks.org/wiki/CMake_%E5%85%A5%E9%96%80  
 
 
  
  16  
  附录  
 
 
  
  引用资源列表如下。时间仓促,难免有遗漏。如果您发现我引用了你的文章请告知。如果  
 
 
  
  您不希望您的文章被引用也请告知。可以到我的博客留言 
 
 
  
    
  http://blog.csdn.net/dbzhang800/article/details/6314073  
 
 
  
    
  http://tzc.is-programmer.com/show/476.html  
 
 
  
    
  http://blog.csdn.net/vagrxie/article/details/4743484  
 
 
  
    
  http://www.cs.swarthmore.edu/~adanner/tips/cmake.php  
 
 
  
    
  http://www.cnblogs.com/doujiu/archive/2009/11/04/1596155.html  
 
 
  
    
  http://blog.csdn.net/onion_autotest/article/details/7222954  
 
 
  
    
  http://www.cnblogs.com/coderfenghc/archive/2013/01/20/2846621.html  
 
 
  
    
  http://blog.csdn.net/gubenpeiyuan/article/details/8667279  
 
 
  
    
  http://name5566.com/1795.html  
 
 
  
    
  http://blog.sina.com.cn/s/blog_9ce5a1b501015avz.html  
 
 
  
    
  http://nullget.sourceforge.net/?q=node/94  
 
 
  
    
  http://blog.csdn.net/gubenpeiyuan/article/details/8667035  
 
 
  
    
  http://blogs.gnome.org/swilmet/2012/09/05/switch-from-cmake-to-autotools/  
 
 
  
    
  http://tech.uc.cn/?p=914 
 
 















![[SpingBoot] 3个扩展点](https://img-blog.csdnimg.cn/direct/af4af2bc98a449babec7d7cfab429290.png)



