介绍
1. 初始格式
CMakeList.txt
文件
# 设立工程名字
PROJECT (HELLO)
# 设置变量, SRC_LIST=main.c
SET(SRC_LIST main.c)
# 显示信息,其中的${HELLO_BINARY_DIR}和${HELLO_SOURCE_DIR}是在构建工程HELLO会自动生成的隐式变量
MESSAGE(STATUS "This is BINARY dir " ${HELLO_BINARY_DIR})
MESSAGE(STATUS "This is SOURCE dir "${HELLO_SOURCE_DIR})
# 生成可执行文件
ADD_EXECUTABLE(hello SRC_LIST)
- 之后便是
cmake && make
cmake .
# use make VERBOSE=1 to show the details of 'make'
make
- 总结
SET(VAR [VALUE] [CACHE TYPE DOCSTRING [FORCE]])
, 可以变量为list, 空格隔开SET(SRC_LIST main.c t1.c t2.c)
, 如果有特殊字符,比如文件名有空格,可以用双引号,如SET(SRC_LIST "fn abc.c")
MESSAGE([SEND_ERROR | STATUS | FATAL_ERROR] "message to display"...)
,SEND_ERROR
产生错误,STATUS
输出前缀为-的信息,FATAL_ERROR
立即终止所有cmake过程ADD_SUBDIRECTORY(lib)
,在主目录下的CMakeLists.txt文件里,对子文件的设置.
2. 子目录,规范
子目录,主目录,都需要有一个CMakeLists.txt,建立build来放置生成的文件,以及安装目录
-
参数含义
- 指示安装目录, 需要注意,如果在
DESTINATION
后使用/bin
之类的,那么就是用的绝对路径,CMAKE_INSTALL_PREFIX
就不管用了,
# 直接在Cmake命令时利用-D来设置 cmake -DCMAKE_INSTALL_PREFIX=/usr . # 在CMakeLists.txt文件中, INSTALL命令,TARGETS是固定的,后面接的是要安装的文件,RUNTIME表示 # 可执行文件安装到bin目录下,LIBRARY动态库安装到lib下,ARCHIVE静态库安装到libstatic,当然,bin, # lib, libstatic都是在${CMAKE_INSTALL_PREFIX}主目录下的 INSTALL(TARGETS myrun mylib mystaticlib RUNTIME DESTINATION bin LIBRARY DESTINATION lib ARCHIVE DESTINATION libstatic )
- 普通文件的安装
INSTALL(FILES files... DESTINATION <dir> [PERMISSIONS permissions...] [CONFIGURATIONS [Debug|Release|...]] [COMPONENT <component>] [RENAME <name>] [OPTIONAL])
- 非目标文件的可执行程序安装(比如脚本之类)
INSTALL(PROGRAMS files... DESTINATION <dir> [PERMISSIONS permissions...] [CONFIGURATIONS [Debug|Release|...]] [COMPONENT <component>] [RENAME <name>] [OPTIONAL])
- 目录的安装:
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...]] [...]) # 栗子 # 将 " icons 目录" 安装到 <prefix>/share/myproj,将 "scripts/中的内容" 安装到 # <prefix>/share/myproj,不包含目录名为 CVS 的目录,对于 scripts/* 文件指定权限为 # OWNER_EXECUTE OWNER_WRITE OWNER_READ GROUP_EXECUTE GROUP_READ INSTALL(DIRECTORY icons scripts/ DESTINATION share/myproj PATTERN "CVS" EXCLUDE PATTERN "scripts/*" PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ GROUP_EXECUTE GROUP_READ)
- 指示安装目录, 需要注意,如果在
3. 静态库和动态库构建
栗子
- 文件目录
- 主目录文件夹下
CMakeLists.txt
, 如果要指定 libhello.so 生成的位置,可以通过在主工程文件CMakeLists.txt
中修改ADD_SUBDIRECTORY(lib ${path})
指令来指定一个编译输出位置或者在lib/CMakeLists.txt
中添加SET(LIBRARY_OUTPUT_PATH <路径>)
来指定一个新的位置。PROJECT(HELLOLIB) ADD_SUBDIRECTORY(lib)
- lib下CMakeLists.txt,其中
SET(LIBHELLO_SRC hello.c) ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC})
- 总结
但是这样子单纯的去生成静态库动态库会导致名字重复而无效, 为了得到libhello.so动态库和libhello.a静态, 使用# 不需要写全 libhello.so,只需要填写 hello 即可,cmake 系统会自动生成libhello.X # SHARED 动态库, STATIC 静态库, MODULE 在使用dyld系统 [苹果系统相关] 时有效,如果不支持dyld,当作SHARED对待 # EXCLUDE_FROM_ALL 参数的意思是这个库不会被默认构建,除非有其他的组件依赖或者手工构建。 # ADD_LIBRARY(libname [SHARED|STATIC|MODULE] [EXCLUDE_FROM_ALL] source1 source2 ... sourceN) 栗子,添加为静态库 ADD_LIBRARY(hello STATIC ${LIBHELLO_SRC})
SET_TARGET_PROPERTIES
来操作SET_TARGET_PROPERTIES(target1 target2 ... PROPERTIES prop1 value1 prop2 value2 ...)
SET(LIBHELLO_SRC hello.c) ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC}) ADD_LIBRARY(hello_static STATIC ${LIBHELLO_SRC}) # 静态库hello_static重命名输出hello, 以下几句输出可省略 SET_TARGET_PROPERTIES(hello_static PROPERTIES OUTPUT_NAME "hello") # OUTPUT_VALUE 赋值 hello_static. OUTPUT_NAME GET_TARGET_PROPERTY(OUTPUT_VALUE hello_static OUTPUT_NAME) MESSAGE(STATUS "This is the hello_static OUTPUT_NAME:"${OUTPUT_VALUE}) # 设置版本信息, SOVERSION指代API版本, VERSION指代动态库版本 SET_TARGET_PROPERTIES(hello PROPERTIES VERSION 1.2 SOVERSION 1) # 安装, CMAKE时, cmake -DCMAKE_INSTALL_PREFIX=./install .. INSTALL(TARGETS hello hello_static LIBRARY DESTINATION lib ARCHIVE DESTINATION lib) INSTALL(FILES hello.h DESTINATION include/hello)
4. 使用外部共享库和头文件
- 主目录
CMakeLists.txt
PROJECT(NEWHELLO) ADD_SUBDIRECTORY(src)
- 子目录下
CMakeLists.txt
在上面,可以对# 这里貌似应该使用绝对路径,使用相对路径会报错,不知原因 INCLUDE_DIRECTORIES(/home/coder/Desktop/backup/cmake/t3/build/install/include/hello) LINK_DIRECTORIES(/home/coder/Desktop/backup/cmake/t3/build/install/lib) ADD_EXECUTABLE(main main.c) TARGET_LINK_LIBRARIES(main libhello.so)
INCLUDE_DIRECTORIES
进行另一种方式的修改, 使用两个环境变量CMAKE_INCLUDE_PATH
和CMAKE_LIBRARY_PATH
.- 使用方法:使用方法是要在 bash 中用 export 或者在 csh 中使用 set 命令设置或者
CMAKE_INCLUDE_PATH=/home/include cmake …等方式
然后在头文件中将CMAKE_INCLUDE_PATH=/home/include cmake ..
INCLUDE_DIRECTORIES(/home/coder/Desktop/backup/cmake/t3/build/install/include/hello)
替换为# FIND_PATH使用方式:FIND_PATH(myHeader NAMES hello.h PATHS /usr/include/usr/include/hello) FIND_PATH(myHeader hello.h) IF(myHeader) INCLUDE_DIRECTORIES(${myHeader}) ENDIF(myHeader)
- 使用方法:使用方法是要在 bash 中用 export 或者在 csh 中使用 set 命令设置或者
5. cmake 常用变量和常用环境变量
- 引用方式
使用 进 行 变 量 的 引 用 。 在 I F 等 语 句 中 , 是 直 接 使 用 变 量 名 而 不 通 过 {}进行变量的引用。在 IF 等语句中,是直接使用变量名而不通过 进行变量的引用。在IF等语句中,是直接使用变量名而不通过{}取值 - 定义变量
主要有隐式定义和显式定义两种PROJECT
指令:(PROJECT(HELLO))
隐式的定义<projectname>_BINARY_DIR
和<projectname>_SOURCE_DIR
两个变量- 显式定义使用
SET
指令
- cmake常用变量
1.CMAKE_BINARY_DIR, PROJECT_BINARY_DIR, <projectname>_BINARY_DIR
,这三个变量指代的内容一致,工程编译发生的目录.
2.CMAKE_SOURCE_DIR,PROJECT_SOURCE_DIR,<projectname>_SOURCE_DIR
都指代工程顶层目录。
3.CMAKE_CURRENT_SOURCE_DIR
指的是当前处理的 CMakeLists.txt 所在的路径
4.EXECUTABLE_OUTPUT_PATH
和LIBRARY_OUTPUT_PATH
分别用来重新定义最终结果的存放目录
5. cmake 常用指令
ADD_DEFINITIONS
向 C/C++编译器添加-D 定义, 比如:ADD_DEFINITIONS(-DENABLE_DEBUG -DABC),参数之间用空格分割ADD_DEPENDENCIES
定义 target 依赖的其他 target,确保在编译本 target 之前,其他的 target 已经被构
建。AUX_SOURCE_DIRECTORY
基本语法是:AUX_SOURCE_DIRECTORY(dir VARIABLE)
作用是发现一个目录下所有的源代码文件并将列表存储在一个变量中,这个指令临时被用来自动构建源文件列表。因为目前 cmake 还不能自动发现新添加的源文件。FIND_指令
FIND_FILE(<VAR> name1 path1 path2 ...)
, VAR 变量代表找到的文件全路径,包含文件名FIND_LIBRARY(<VAR> name1 path1 path2 ...)
,VAR 变量表示找到的库全路径,包含库文件名FIND_LIBRARY 示例: FIND_LIBRARY(libX X11 /usr/lib) IF(NOT libX) MESSAGE(FATAL_ERROR “libX not found”) ENDIF(NOT libX)
FIND_PATH(<VAR> name1 path1 path2 ...)
,VAR 变量代表包含这个文件的路径FIND_PROGRAM(<VAR> name1 path1 path2 ...)
,VAR 变量代表包含这个程序的全路径。FIND_PACKAGE(<name> [major.minor] [QUIET] [NO_MODULE] [[REQUIRED|COMPONENTS] [componets...]])
用来调用预定义在 CMAKE_MODULE_PATH 下的 Find.cmake 模块,你也可以自己定义 Find模块,通过 SET(CMAKE_MODULE_PATH dir)将其放入工程的某个目录中供工程使用,我们在后面的章节会详细介绍 FIND_PACKAGE 的使用方法和 Find 模块的编写