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)
相关文章
|
Ubuntu Unix Linux
Linux系统之rename命令的基本使用
Linux系统之rename命令的基本使用
555 41
|
8月前
|
存储 虚拟化 Windows
想要掌握Hyper-V如何安装,首先需要确保你的操作系统版本满足Hyper-V的安装要求
Hyper-V的安装需确保操作系统版本和硬件满足要求。硬件上,64位处理器需支持SLAT及虚拟化技术(如VT-x或AMD-V),至少4GB RAM和充足存储空间;BIOS/UEFI中启用虚拟化技术和DEP。软件方面,需Windows 10 Pro及以上或Windows Server 2016/2019及以上,并保持系统更新。安装步骤包括检查系统要求、启用Hyper-V功能、配置并创建虚拟机,最后安装操作系统。注意备份数据及网络适配器配置。
|
9月前
|
JSON API 开发者
淘宝淘口令转换API接口(淘宝API系列)
淘宝淘口令转换API是用于将淘宝商品或店铺链接与淘口令进行双向转换的接口,支持HTTP POST请求。开发者可通过此API生成或解析淘口令,方便在不同平台传播淘宝内容,吸引更多潜在客户。API返回JSON格式数据,包含转换结果和状态信息。使用前需注册并申请权限,确保调用稳定可靠。示例代码展示了如何通过Python实现淘口令的生成和解析功能。
|
存储 算法 分布式数据库
Google云计算原理与应用(二)
Google云计算原理与应用(二)
314 4
|
12月前
|
运维 Cloud Native 云计算
云原生之旅:Docker容器化实战
本文将带你走进云原生的世界,深入理解Docker技术如何改变应用部署与运维。我们将通过实际案例,展示如何利用Docker简化开发流程,提升应用的可移植性和伸缩性。文章不仅介绍基础概念,还提供操作指南和最佳实践,帮助你快速上手Docker,开启云原生的第一步。
|
关系型数据库 MySQL 应用服务中间件
SpringCloud基础3——Docker
docker镜像、容器、安装、数据卷、Dockerfile自定义镜像、Docker-Compose部署分布式项目、Docker镜像仓库
SpringCloud基础3——Docker
|
移动开发
MATLAB | SCI绘图配色第1期 | 点线图 | 刺客伍六七之暗影宿命第1集
MATLAB | SCI绘图配色第1期 | 点线图 | 刺客伍六七之暗影宿命第1集
339 0
|
存储 关系型数据库 MySQL
【MySQL技术内幕】5.5-Cardinality值
【MySQL技术内幕】5.5-Cardinality值
358 1
|
传感器 算法 vr&ar
技术心得:方向余弦矩阵(DCM)简介
技术心得:方向余弦矩阵(DCM)简介