CMakeLists.txt内容
-
PROJECT(projectname [CXX] [C] [Java]):
定义工程名称,并可指定工程支持的语言,支持的语言列表是可以忽略的,默认情况表示支持所有语言。这个指令隐式的定义了两个cmake变量:< projectname >_BINARY_DIR 以
< projectname>_SOURCE_DIR,因为采用的是内部编译,两个变量目前指的都是工程所在路径~/cmake_study,后面我们会讲到外部编译,两者所指代的内容会有所不同。同时cmake系统也帮助我们预定义了PROJECT_BINARY_DIR和PROJECT_SOURCE_DIR变量,他们的值分别跟HELLO_BINARY_DIR与HELLO_SOURCE_DIR一致。为了统一起见,建议以后直接使用PROJECT_BINARY_DIR,PROJECT_SOURCE_DIR,即使修改了工程名称,也不会影响这两个变量。如果使用了< projectname >_SOURCE_DIR,修改工程名称后,需要同时修改这些变量。 -
SET(VAR [VALUE] [CACHE TYPE DOCSTRING [FORCE]]):
SET指令可以用来显式的定义变量。
比如我们用到的是SET(SRC_LIST main.c),如果有多个源文件,也可以定义成:
SET(SRC_LIST main.c t1.c t2.c)。 -
MESSAGE([SEND_ERROR | STATUS | FATAL_ERROR] “message to display”
…)
用于向终端输出用户定义的信息。包含了三种类型:
SEND_ERROR,产生错误,生成过程被跳过。
SATUS,输出前缀为—的信息。
FATAL_ERROR,立即终止所有cmake过程. -
ADD_EXECUTABLE(hello ${SRC_LIST})
生成可执行文件
定义了这个工程会生成一个文件名为hello的可执行文件,相关的源文件是SRC_LIST中
定义的源文件列表, 本例中你也可以直接写成ADD_EXECUTABLE(hello main.c)。在本例我们使用了${}来引用变量,这是cmake的变量应用方式,但是,有一些例外,比 如在IF控制语句,变量是直接使用变量名引用,而不需要${}。如果使用了${}去应用变 量,其实IF会去判断名为${}所代表的值的变量,那当然是不存在的了。实际上${}引用的是变量的值
-
ADD_SUBDIRECTORY(source_dir [binary_dir] [EXCLUDE_FROM_ALL])
用于向当前工程添加存放源文件的子目录,并可以指定中间二进制和目标二进制存
放的位置。EXCLUDE_FROM_ALL参数的含义是将这个目录从编译过程中排除,比如,工程
的example,可能就需要工程构建完成后,再进入example目录单独进行构建(当然,你
也可以通过定义依赖来解决此类问题)。
ADD_SUBDIRECTORY(src bin)
上面的例子定义了将src子目录加入工程,并指定编译输出(包含编译中间结果)路径为
bin目录。如果不进行bin目录的指定,那么编译结果(包括中间结果)都将存放在
build/src目录(这个目录跟原有的src目录对应),指定bin目录后,相当于在编译时
将src重命名为bin,所有的中间结果和目标二进制都将存放在bin目录。 -
ADD_LIBRARY(libname [SHARED|STATIC|MODULE] [EXCLUDE_FROM_ALL] source1 source2 … sourceN)
例如: ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC})
SHARED,动态库
STATIC,静态库
MODULE,在使用dyld的系统有效,如果不支持dyld,则被当作SHARED对待。
EXCLUDE_FROM_ALL参数的意思是这个库不会被默认构建,除非有其他的组件依赖或者手
工构建。如果你要指定libhello.so生成的位置,可以通过在主工程文件CMakeLists.txt中修
改ADD_SUBDIRECTORY(lib)指令来指定一个编译输出位置或者 -
SET_TARGET_PROPERTIES(target1 target2 … PROPERTIES prop1 value1 prop2 value2 …)
这条指令可以用来设置输出的名称,对于动态库,还可以用来指定动态库版本和API版本。
ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC})
ADD_LIBRARY(hello_static STATIC ${LIBHELLO_SRC})
SET_TARGET_PROPERTIES(hello_static PROPERTIES OUTPUT_NAME “hello”)
这样,我们就可以同时得到libhello.so/libhello.a两个库了。8.INSTALL(TARGETS targets… [[ARCHIVE|LIBRARY|RUNTIME] [DESTINATION < dir >]
[PERMISSIONS permissions…] [CONFIGURATIONS [Debug|Release|…] ] [COMPONENT < component >] [OPTIONAL] ] […])INSTALL指令用于定义安装规则,安装的内容可以包括目标二进制、动态库、静态库以及
文件、目录、脚本等。参数中的TARGETS后面跟的就是我们通过ADD_EXECUTABLE或者ADD_LIBRARY定义的
目标文件,可能是可执行二进制、动态库、静态库。目标类型也就相对应的有三种,ARCHIVE特指静态库,LIBRARY特指动态库,RUNTIME
特指可执行目标二进制。DESTINATION定义了安装的路径,如果路径以/开头,那么指的是绝对路径,这时候
CMAKE_INSTALL_PREFIX其实就无效了。如果你希望使用CMAKE_INSTALL_PREFIX来
定义安装路径,就要写成相对路径,即不要以/开头,那么安装后的路径就是
${CMAKE_INSTALL_PREFIX}/<DESTINATION定义的路径>例如:
INSTALL(TARGETS myrun mylib mystaticlib
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib
ARCHIVE DESTINATION libstatic
)可执行二进制myrun安装到 $ {CMAKE_INSTALL_PREFIX}/bin目录
动态库libmylib安装到$ {CMAKE_INSTALL_PREFIX}/lib目录
静态库libmystaticlib安装到${CMAKE_INSTALL_PREFIX}/libstatic目录INSTALL(TARGETS hello hello_static
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib)
安装库文件
注意,静态库要使用ARCHIVE关键字INSTALL(FILES hello.h DESTINATION include/hello) 安装文件
9. INCLUDE_DIRECTORIES([AFTER|BEFORE] [SYSTEM] dir1 dir2 …)这条指令可以用来向工程添加多个特定的头文件搜索路径,路径之间用空格分割,如果路径
中包含了空格,可以使用双引号将它括起来,默认的行为是追加到当前的头文件搜索路径的
后面,你可以通过两种方式来进行控制搜索路径添加的方式:
1,CMAKE_INCLUDE_DIRECTORIES_BEFORE,通过SET这个cmake变量为on,可以
将添加的头文件搜索路径放在已有路径的前面。
2,通过AFTER或者BEFORE参数,也可以控制是追加还是置前。INCLUDE_DIRECTORIES(/usr/include/hello)
10. LINK_DIRECTORIES(directory1 directory2 …)和TARGET_LINK_LIBRARIES(target library1
<debug | optimized> library2…)
LINK_DIRECTORIES:添加非标准的共享库搜索路径,比如,在工程内部同时存在共享库和可
执行二进制,在编译时就需要指定一下这些共享库的路径。
TARGET_LINK_LIBRARIES:这个指令可以用来为target添加需要链接的共享库
CMake基本语法规则
- 变量使用${}方式取值,但是在IF控制语句中是直接使用变量名
- 指令(参数1 参数2…)
参数使用括弧括起,参数之间使用空格或分号分开。
以上面的ADD_EXECUTABLE指令为例,如果存在另外一个func.c源文件,就要写成:
ADD_EXECUTABLE(hello main.c func.c)或者ADD_EXECUTABLE(hello main.c;func.c) - 指令是大小写无关的,参数和变量是大小写相关的。但,推荐你全部使用大写指令。
清理工程:make clean 即可对构建结果进行清理。
建议使用外部构建
内部构建和外部构建
对于cmake,内部编译上面已经演示过了,它生成了一些无法自动删除的中间文件,所以,
引出了我们对外部编译的探讨,外部编译的过程如下:
1,首先,请清除t1目录中除main.c CmakeLists.txt之外的所有中间文件,最关键
的是CMakeCache.txt。
2,在t1目录中建立build 目录,当然你也可以在任何地方建立build目录,不一定必
须在工程目录中。
3,进入build目录,运行cmake …(注意,…代表父目录,因为父目录存在我们需要的
CMakeLists.txt,如果你在其他地方建立了build目录,需要运行cmake <工程的全
路径>),查看一下build目录,就会发现了生成了编译需要的Makefile以及其他的中间
文件.
4,运行make构建工程,就会在当前目录(build目录)中获得目标文件hello。
这里需要特别注意的是:
通过外部编译进行工程构建,HELLO_SOURCE_DIR仍然指代工程路径,即~/cmake_study
而HELLO_BINARY_DIR则指代编译路径,即~/cmake_study/build
换个地方保存目标二进制
不论是SUBDIRS还是ADD_SUBDIRECTORY指令(不论是否指定编译输出目录),我们都可
以通过SET指令重新定义EXECUTABLE_OUTPUT_PATH和LIBRARY_OUTPUT_PATH变量
来指定最终的目标二进制的位置(指最终生成的hello或者最终的共享库,不包含编译生成
的中间文件)
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
可执行二进制的输出路径为build/bin和库的输出路径为build/lib.
在哪里ADD_EXECUTABLE或ADD_LIBRARY,如果需要改变目标存放路径,就在哪里加入上述的定义。
< projectname >_BINARY_DIR和PROJECT_BINARY_DIR变量,他
们指的编译发生的当前目录,如果是内部编译,就相当于PROJECT_SOURCE_DIR也就是
工程代码所在目录,如果是外部编译,指的是外部编译所在目录,也就是本例中的build
目录。
如何安装
安装的需要有两种,一种是从代码编译后直接make install安装,一种是打包时的指定目录安装。
cmake -DCMAKE_INSTALL_PREFIX=/usr
INSTALL指令用于定义安装规则,安装的内容可以包括目标二进制、动态库、静态库以及
文件、目录、脚本等。