以下笔记部分来自于cmake practice
- 最基本的几个命令:
PROJECT(projectname [CXX] [C] [Java])
你可以用这个指令定义工程名称,并可指定工程支持的语言,支持的语言列表是可以忽略的,
默认情况表示支持所有语言。 这个指令隐式的定义了两个 cmake 变量:<projectname>_BINARY_DIR 以及<projectname>_SOURCE_DIR,同时PROJECT_BINARY_DIR和PROJECT_SOURCE_DIR和这两个变量同值。推荐使用PROJECT开头的。
SET(VAR [VALUE] [CACHE TYPE DOCSTRING [FORCE]])
现阶段,你只需要了解 SET 指令可以用来显式的定义变量即可。
MESSAGE([SEND_ERROR | STATUS | FATAL_ERROR] "message to display" ...)
这个指令用于向终端输出用户定义的信息,包含了三种类型:
SEND_ERROR,产生错误,生成过程被跳过。
SATUS,输出前缀为—的信息。
FATAL_ERROR,立即终止所有 cmake 过程.
ADD_EXECUTABLE(hello ${SRC_LIST})
定义了这个工程会生成一个文件名为 hello 的可执行文件 - cmake的语法:
${name}: 引用名为name的变量的值。
指令(参数 1 参数 2...): 其中指令的大小写不区分,参数用空格或分号隔开。
值可以用双引号括起来,也可以不用。 - 当在cmake之后的make出现错误,可以用make VERBOSE=1来看详细的错误是什么。
- cmake不会生成make distclean,这是因为cmake鼓励使用out-of-source build,也就是在source tree之外建一个build目录,这样cmake完全不会在source tree生成任何中间文件。
- 在source tree中,需要在每个目录下都放一个CMakeLists.txt文件。
- ADD_SUBDIRECTORY(source_dir [binary_dir] [EXCLUDE_FROM_ALL])
这个指令用于向当前工程添加存放源文件的子目录,并可以指定中间二进制和目标二进制存
放的位置。EXCLUDE_FROM_ALL 参数的含义是将这个目录从编译过程中排除 - cmake里面指定binary的安装方法:
CMAKE_INSTALL_PREFIX 变量类似于 configure 脚本的 –prefix,常见的使用方法看
起来是这个样子:
cmake -DCMAKE_INSTALL_PREFIX=/usr .
INSTALL命令 :
目标文件的安装:
INSTALL(TARGETS targets...
[[ARCHIVE|LIBRARY|RUNTIME]
[DESTINATION <dir>]
[PERMISSIONS permissions...]
[CONFIGURATIONS
[Debug|Release|...]]
[COMPONENT <component>]
[OPTIONAL]
] [...])
参数中的 TARGETS 后面跟的就是我们通过 ADD_EXECUTABLE 或者 ADD_LIBRARY 定义的
目标文件,可能是可执行二进制、动态库、静态库。
目标类型也就相对应的有三种,ARCHIVE 特指静态库,LIBRARY 特指动态库,RUNTIME
特指可执行目标二进制。
DESTINATION 定义了安装的路径,如果路径以/开头,那么指的是绝对路径,这时候
CMAKE_INSTALL_PREFIX 其实就无效了。如果你希望使用 CMAKE_INSTALL_PREFIX 来
定义安装路径,就要写成相对路径,即不要以/开头,那么安装后的路径就是
${CMAKE_INSTALL_PREFIX}/<DESTINATION 定义的路径>
普通文件的安装:
INSTALL(FILES files... DESTINATION <dir>
[PERMISSIONS permissions...]
[CONFIGURATIONS [Debug|Release|...]]
[COMPONENT <component>]
[RENAME <name>] [OPTIONAL])
可用于安装一般文件,并可以指定访问权限,文件名是此指令所在路径下的相对路径。如果
默认不定义权限 PERMISSIONS,安装后的权限为:
OWNER_WRITE, OWNER_READ, GROUP_READ,和 WORLD_READ,即 644 权限。
非目标文件的可执行程序安装(比如脚本之类):
INSTALL(PROGRAMS files... DESTINATION <dir>
[PERMISSIONS permissions...]
[CONFIGURATIONS [Debug|Release|...]]
[COMPONENT <component>]
[RENAME <name>] [OPTIONAL])
跟上面的 FILES 指令使用方法一样,唯一的不同是安装后权限为:
OWNER_EXECUTE, GROUP_EXECUTE, 和 WORLD_EXECUTE,即 755 权限
目录的安装:
INSTALL(DIRECTORY dirs... DESTINATION <dir>
[FILE_PERMISSIONS permissions...]
[DIRECTORY_PERMISSIONS permissions...]
[USE_SOURCE_PERMISSIONS]
[CONFIGURATIONS [Debug|Release|...]]
[COMPONENT <component>]
[[PATTERN <pattern> | REGEX <regex>]
[EXCLUDE] [PERMISSIONS permissions...]] [...])
这里主要介绍其中的 DIRECTORY、PATTERN 以及 PERMISSIONS 参数。
DIRECTORY 后面连接的是所在 Source 目录的相对路径,但务必注意:
abc 和 abc/有很大的区别。
如果目录名不以/结尾,那么这个目录将被安装为目标路径下的 abc,如果目录名以/结尾,
代表将这个目录中的内容安装到目标路径,但不包括这个目录本身。
PATTERN 用于使用正则表达式进行过滤,PERMISSIONS 用于指定 PATTERN 过滤后的文件
权限。 - 如果不明确指定CMAKE_INSTALL_PREFIX,那么默认的值是/usr/local
- 编译静态/动态库的命令:
ADD_LIBRARY(libname [SHARED|STATIC|MODULE]
[EXCLUDE_FROM_ALL]
source1 source2 ... sourceN)
EXCLUDE_FROM_ALL 参数的意思是这个库不会被默认构建,除非有其他的组件依赖或者手
工构建。
同时注意,一个target名(指用ADD_EXECUTABLE,ADD_LIBRARY的文件),不能够重复在ADD_命令中使用,否则cmake会忽略。
如果需要同时添加同名的动态和静态库,那么可以通过下面的命令来实现:
SET_TARGET_PROPERTIES(target1 target2 ...
PROPERTIES prop1 value1
prop2 value2 ...)
对应的一个获取参数值的命令是:
GET_TARGET_PROPERTY(VAR target property)
比如:GET_TARGET_PROPERTY(OUTPUT_VALUE hello_static OUTPUT_NAME)
就是获取target名为hello_static的里面的OUTPUT_NAME属性的值,并将其设置到OUTPUT_VALUE中。 - 当想要设置动态库的版本时候,使用如下命令:
SET_TARGET_PROPERTIES(hello PROPERTIES VERSION 1.2 SOVERSION 1)
其中VERSION是版本,SOVERSION是API版本。 - 当构建程序的时候,如果需要添加头文件搜索路径的话:
INCLUDE_DIRECTORIES([AFTER|BEFORE] [SYSTEM] dir1 dir2 ...)
这条指令可以用来向工程添加多个特定的头文件搜索路径,路径之间用空格分割,如果路径
中包含了空格,可以使用双引号将它括起来,默认的行为是追加到当前的头文件搜索路径的
后面,你可以通过两种方式来进行控制搜索路径添加的方式:
1,CMAKE_INCLUDE_DIRECTORIES_BEFORE,通过 SET 这个 cmake 变量为 on,可以
将添加的头文件搜索路径放在已有路径的前面。
2,通过 AFTER 或者 BEFORE 参数,也可以控制是追加还是置前。 - 为target添加链接共享库的路径:
LINK_DIRECTORIES(directory1 directory2 ...)
注意这个命令添加的目录只对在之后声明的target有效。如果给这个命令添加相对路径,该路径会原封不动的传递给ld。
TARGET_LINK_LIBRARIES(target library1
<debug | optimized> library2
...)
这个命令可以做到单独为一个target指定链接库路径。 - CMAKE_INCLUDE_PATH 和 CMAKE_LIBRARY_PATH
这两个环境变量是用来在cmake中的FIND_命令中设置默认的搜索路径,如果在cmake里面使用FIND而不设定路径,那么cmake就是会使用这两个变量的值,注意这两个变量并不是直接用在编译过程中的参数。 - 如果在一个模块里面有一个子库的话,可以使用TARGET_LINK_LIBRARIES来添加这些子模块。
比如有下面的文件结构:
top
|---- sub1
|----- subsub1
|----- subsub2
那么如果我们在subsub1和subsub2里面都有定义ADD_LIBRARY,而我们在使用sub1的时候需要隐藏里面的细节,也就是使用sub1自动会把subsub1和subsub2也包含进去的话,那么就是使用TARGET_LINK_LIBRARIES这个指令,如下:
TARGET_LINK_LIBRARIES(sub1 subsub1 subsub2)
这个命令并不会将subsub1和subsub2在创建sub1的时候将他们包含进去,而是在当其他库需要链接sub1的时候把这种依赖关系传递过去。这种性质在cmake里面transitive(传递性)。 - 注意在 TARGET_LINK_LIBRARIES的时候,里面添加的库之间如果有关系的话,那么使用某些函数的库必须在定义的库的前面。
比如有如下的一个关系:
ADD_EXECUTABLE(test test.cpp)
TARGET_LINK_LIBRARIES(test A B)
其中在A里面用到了B的函数foo,而B里面定义了函数foo。那么如果上面的A B的位置对调,在链接的时候就会出现undefined reference的错误,具体的原因和linker有关。