cmake 是一个跨平台的编译工具,可以用简单的语句来描述所有平台的编译过程。输出 Makefile 文件,再去执行构建 Build。make 定义构建过程的文件为 CMakeLists.txt。
1、安装 cmake
# 卸载已经安装的旧版cmake,非必须 apt-get autoremove cmake # 文件下载和解压 wget https://cmake.org/files/v3.9/cmake-3.9.1-Linux-x86_64.tar.gz tar zxvf cmake-3.9.1-Linux-x86_64.tar.gz # 查看解压后的目录 tree -L 2 cmake-3.9.1-Linux-x86_64 # 创建软链接,文件路径一般放在 /opt 或 /usr 路径下 mv cmake-3.9.1-Linux-x86_64 /opt/cmake-3.9.1 ln -sf /opt/cmake-3.9.1/bin/* /usr/bin/
2、cmake 规则
2.1、cmake 变量
cmake 预定义变量
CMAKE_CURRENT_LIST_DIR
:CMakeLists 所在的路径PROJECT_SOURCE_DIR
:包含项目名的最近一个 CMakeLists.txt 文件所在的文件夹CMAKE_BINARY_DIR 、PROJECT_BINARY_DIR、<projectname>_BINARY_DIR
: 工程编译发生的目录CMAKE_SOURCE_DIR、PROJECT_SOURCE_DIR、<projectname>_BINARY_DIR
: 工程顶层目录CMAKE_C_COMPILER
:指定 C 编译器CMAKE_CXX_COMPILER
:指定 C++ 编译器EXECUTABLE_OUTPUT_PATH
:可执行文件输出的存放路径LIBRARY_OUTPUT_PATH
:库文件输出的存放路径CMAKE_BUILD_TYPE
: 构建的类型,例如 Debug(默认有-g) ,Release
2.2、cmake 语法
cmake_minimum_required
指定 cmake 的最小版本要求
cmake_minimum_required(VERSION versionnumber [FATAL_ERROR]
project
定义工程名称,并可指定工程支持的语言
project(projectname [CXX] [C] [Java])
set
显式的定义变量
set(VAR [VALUE] [CACHE TYPE DOCSTRING [FORCE]])
常见的使用例子:
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") # 在编译选项后追加c++11标准 set(CMAKE_BUILD_TYPE Debug) # 设定编译类型为debug,调试时选择debug; set(CMAKE_BUILD_TYPE Release) # 设定编译类型为release,发布时选择release;
message
向终端输出用户定义的信息,包含了三种类型:
SEND_ERROR
:产生错误,生成过程被跳过STATUS
:输出前缀为 - 的信息。FATAL_ERROR
:立即终止所有cmake过程。
MESSAGE([SEND_ERROR | STATUS | FATAL_ERROR] "message to display" ...)
include_directories
添加特定的头文件搜索路径
include_directories([AFTER|BEFORE] [SYSTEM] dir1 dir2...) # gcc -I
link_directories
添加特定的库文件搜索路径
link_directories(dir1 dir2 ...) # gcc -L
add_subdirectory
添加存放源文件的子目录
# source_dir 存放源文件的子目录; binary_dir 指定中间二进制和目标二进制存放位置; # EXCLUDE_FROM_AL 将这个目录从编译过程中排除,例 example 目录,工程构建完成后单独构建 add_subdirectory(source_dir [binary_dir] [EXCLUDE_FROM_ALL])
add_executable
生成可执行文件
# exename 生成的可执行文件; source...依赖的源文件列表 add_executable(exename source1 source2 ... sourceN)
add_library
生成库文件,默认是静态库。
# SHARED生成动态库libx.so,STATIC生成静态库libx.a add_library(libname [SHARED|STATIC|MODULE] [EXCLUDE_FROM_ALL] source1...n)
add_compile_options
添加编译参数,如 -wall, -std=c++11, -fPIC
add_compile_options(...)
target_link_libraries
链接库文件,如果同时存在动态库和静态库,则优先链接动态库,强制链接静态库 libX.a。
target_link_libraries(target library1<debug | optimized> library2 ...) # gcc -l
如果同时链接动态库和静态库,前缀名相同 x.so/x.a,产生同名冲突,解决方法
# 在生成库文件时,库文件名后添加_shread, _static # 这样编译的时候 x_shared, x_static 前缀名不同,避免了冲突 add_library(target_shared SHARED ${SRC_LIST}) target_link_libraries(target_shared ${LINK_LIB_LIST}) # 在输出时,希望以本来的名字显示,x.so, x.a set_target_properties(target_shared PROPERTIES OUTPUT_NAME "target")
aux_source_directory
查找 dir 路径下的所有源文件,并将列表存储到变量中,用来自动构建源文件列表
aux_source_directory(dir VARIABLE)
install
指定安装规时运行的规则,包含了各种安装类型:目标文件、普通文件、目录等。
变量 CMAKE_INSTALL_PREFIX
指定 camke install 时的相对路径前缀,默认安装路径。
cmake -DCMAKE_INSTALL_PREFIX=安装路径 # 指定cmake安装目录的前缀,默认/usr/local
目标文件
最常见的是通过ADD_EXECUTABLE
或者ADD_LIBRARY
定义的目标文件,即可执行二进制 RUNTIME、动态库 LIBRARY、静态库 ARCHIVE
install(TARGETS targets... [EXPORT <export-name>] [[ARCHIVE|LIBRARY|RUNTIME|OBJECTS|FRAMEWORK|BUNDLE| PRIVATE_HEADER|PUBLIC_HEADER|RESOURCE] [DESTINATION <dir>] [PERMISSIONS permissions...] [CONFIGURATIONS [Debug|Release|...]] [COMPONENT <component>] [NAMELINK_COMPONENT <component>] [OPTIONAL] [EXCLUDE_FROM_ALL] [NAMELINK_ONLY|NAMELINK_SKIP] ] [...] [INCLUDES DESTINATION [<dir> ...]] )
普通文件
install(<FILES|PROGRAMS> files... TYPE <type> | DESTINATION <dir> [PERMISSIONS permissions...] [CONFIGURATIONS [Debug|Release|...]] [COMPONENT <component>] [RENAME <name>] [OPTIONAL] [EXCLUDE_FROM_ALL])
非目标文件的可执行文件:如脚本
INSTALL(PROGRAMS files... DESTINATION <dir> [PERMISSIONS permissions...] # 权限,默认 755 权限 [CONFIGURATIONS [Debug|Release|...]] [COMPONENT <component>] [RENAME <name>] [OPTIONAL])
目录
install(DIRECTORY dirs... TYPE <type> | DESTINATION <dir> [FILE_PERMISSIONS permissions...] [DIRECTORY_PERMISSIONS permissions...] [USE_SOURCE_PERMISSIONS] [OPTIONAL] [MESSAGE_NEVER] [CONFIGURATIONS [Debug|Release|...]] [COMPONENT <component>] [EXCLUDE_FROM_ALL] [FILES_MATCHING] [[PATTERN <pattern> | REGEX <regex>] [EXCLUDE] [PERMISSIONS permissions...]] [...])
3、cmake 实战
例1:子目录编译成库文件
├── CMakeLists.txt ├── doc │ ├── darren.txt │ └── README.MD └── src ├── CMakeLists.txt ├── dir1 │ ├── CMakeLists.txt │ ├── dir1.c │ └── dir1.h ├── dir2 │ ├── CMakeLists.txt │ ├── dir2.c │ └── dir2.h └── main.c
├── CMakeLists.txt
# CMake 最低版本号要求 cmake_minimum_required (VERSION 2.8) # 工程名称 PROJECT(0VOICE) # 添加存放源文件的子目录 add_subdirectory(src bin) # 指定安装位置 INSTALL(DIRECTORY doc/ DESTINATION share/doc/cmake/darren)
└── src ├── CMakeLists.txt
# CMake 最低版本号要求 cmake_minimum_required (VERSION 2.8) # 定义变量,手动加入文件 SET(SRC_LIST main.c) # 设置子目录列表 set(SUB_DIR_LIST "dir1" "dir2") # 遍历子目录列表 foreach(SUB_DIR ${SUB_DIR_LIST}) # 添加子目录中的源文件 add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/${SUB_DIR}") # 添加子目录头文件路径 INCLUDE_DIRECTORIES("${CMAKE_CURRENT_SOURCE_DIR}/${SUB_DIR}") endforeach() # 生成可执行文件 ADD_EXECUTABLE(darren ${SRC_LIST}) # 链接库文件 TARGET_LINK_LIBRARIES(darren ${SUB_DIR_LIST}) # 将执行文件安装到bin目录 # INSTALL(TARGETS darren RUNTIME DESTINATION bin)
├── dir1 / dir2
# 查找源文件,将当前目录下的所有源文件保存到DIR_SRCS变量中 AUX_SOURCE_DIRECTORY(. DIR_SRCS) # 生成库文件 ADD_LIBRARY(dir2 ${DIR_SRCS})
例2:子目录使用源码编译
. ├── CMakeLists.txt ├── doc │ ├── darren.txt │ └── README.MD └── src ├── CMakeLists.txt ├── dir1 │ ├── dir1.c │ └── dir1.h ├── dir2 │ ├── dir2.c │ └── dir2.h └── main.c
├── CMakeLists.txt
# CMake 最低版本号要求 cmake_minimum_required (VERSION 2.8) # 项目名 PROJECT(0VOICE) # 添加子目录 ADD_SUBDIRECTORY(src bin)
└── src ├── CMakeLists.txt
# CMake 最低版本号要求 cmake_minimum_required (VERSION 2.8) # 工程名称 # PROJECT(0VOICE) # 手动添加文件 SET(SRC_LIST main.c) # 设置子目录列表 SET(SUB_DIR_LIST "${CMAKE_CURRENT_SOURCE_DIR}/dir1" "${CMAKE_CURRENT_SOURCE_DIR}/dir2") # 遍历子目录列表 foreach(SUB_DIR ${SUB_DIR_LIST}) # 遍历源文件,保存到SRC_LIST中 aux_source_directory(${SUB_DIR} SRC_LIST) # 添加头文件路径 INCLUDE_DIRECTORIES("${SUB_DIR}") endforeach() # 生成可执行文件 ADD_EXECUTABLE(darren ${SRC_LIST} ) # 将执行文件安装到bin目录 # INSTALL(TARGETS darren RUNTIME DESTINATION bin)
例3:生成库
# 设置release版本还是debug版本 if(${CMAKE_BUILD_TYPE} MATCHES "Release") MESSAGE(STATUS "Release版本") SET(BuildType "Release") else() SET(BuildType "Debug") MESSAGE(STATUS "Debug版本") endif() # 设置lib库目录 SET(RELEASE_DIR ${PROJECT_SOURCE_DIR}/release) # 设置生成的库文件的输出路径,debug和release版本目录不一样 SET(LIBRARY_OUTPUT_PATH ${RELEASE_DIR}/linux/${BuildType}) # 添加编译参数-fPIC ADD_COMPILE_OPTIONS(-fPIC) # 查找当前目录下的所有源文件,并保存到 DIR_LIB_SRCS 变量 AUX_SOURCE_DIRECTORY(. DIR_LIB_SRCS) # 生成静态库链接库Dir1 # ADD_LIBRARY (Dir1 ${DIR_LIB_SRCS}) # 生成动态库 ADD_LIBRARY (Dir1 SHARED ${DIR_LIB_SRCS}) # 将库文件安装到lib目录 INSTALL(TARGETS Dir1 DESTINATION lib) # 将头文件安装到include目录 INSTALL(FILES dir1.h DESTINATION include)
例4:调用库
# CMake 最低版本号要求 cmake_minimum_required (VERSION 2.8) # 手动加入文件 SET(SRC_LIST main.c) # 添加头文件路径 INCLUDE_DIRECTORIES("${CMAKE_CURRENT_SOURCE_DIR}/include") # 添加库的路径 LINK_DIRECTORIES("${CMAKE_CURRENT_SOURCE_DIR}/lib") # 生成可执行文件 ADD_EXECUTABLE(darren ${SRC_LIST}) # 链接库。同时存在静态库、动态库,优先链接动态库。名称写全可指定想要链接的库 # 强制使用静态库ibDir1.a,使用动态库ibDir1.so TARGET_LINK_LIBRARIES(darren Dir1)