cmake 基本使用

简介: cmake 基本使用

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)
相关文章
|
4月前
cmake的基本使用
cmake的基本使用
52 0
|
4月前
CMake 教程2
CMake 教程
27 0
|
6月前
|
C++ Unix Windows
面向 C++ 的现代 CMake 教程(四)(3)
面向 C++ 的现代 CMake 教程(四)
58 0
|
6月前
|
C++ 开发者 Unix
面向 C++ 的现代 CMake 教程(四)(5)
面向 C++ 的现代 CMake 教程(四)
66 0
|
6月前
|
C++ 缓存 存储
面向 C++ 的现代 CMake 教程(一)(3)
面向 C++ 的现代 CMake 教程(一)
152 0
|
6月前
|
C++ 存储 索引
面向 C++ 的现代 CMake 教程(一)(5)
面向 C++ 的现代 CMake 教程(一)
109 0
|
6月前
|
缓存 存储 C++
面向 C++ 的现代 CMake 教程(一)(4)
面向 C++ 的现代 CMake 教程(一)
75 0
|
Java Linux 编译器
CMake从入门到弃坑
CMake 说明 cmake的定义是什么 ?-----高级编译配置工具 当多个人用不同的语言或者编译器开发一个项目,最终要输出一个可执行文件或者共享库(dll,so等等)这时候神器就出现了-----CMake!
139 1
CMake实战(一)
CMake和Autotools一样,都是项目构建工具。可以简单理解为,帮助我们生成Makefile,方便编译。
CMake实战(三)
前面两篇《CMake实战(一)》,《CMake实战(二)》,主要是介绍单目录和多目录的编译,接下来看一下自定义编译选项和交叉编译。