XuQi's Blog

  • 首页

  • 归档

CMake入门

发表于 2019-07-09 更新于 2019-10-20

CMake管理工程

在Linux平台下使用CMake生成Makefile并编译的流程如下:

  1. 编写CMake配置文件CMakeLists.txt
  2. 执行命令cmake PATH生成Makefile,PATH是CMakeLists.txt所在的目录。
  3. 使用make命令进行编译。

简单讲就是CMake是自动生成Makefile文件的工具

安装CMake

1
sudo apt-get install cmake

创建CMakeLists.txt 骨架

1
2
3
4
5
6
# CMake 最低版本号要求 不写会有警告
cmake_minimum_required (VERSION 2.8)
# 项目信息
project (Demo1)
# 指定生成目标
add_executable(Demo main.cpp)

CMakeLists.txt中的编写方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
project(Demo1) # App的名称,需要修改⭐️
cmake_minimum_required(VERSION 2.8)

#加载自定义模块
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake")
#设置库文件路径
set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
#设置可执行程序路径
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
#设置子目录
set(SUB_DIR_LIST "Thread" "Util") #需要修改⭐️

#安装目录
set(INSTALL_PATH_LIB lib)
set(INSTALL_PATH_INCLUDE include)


foreach(SUB_DIR ${SUB_DIR_LIST})
#遍历源文件
aux_source_directory(src/${SUB_DIR} SRC_LIST)
#安装头文件至系统目录
install(DIRECTORY src/${SUB_DIR} DESTINATION ${INSTALL_PATH_INCLUDE} FILES_MATCHING PATTERN "*.h")
endforeach()

#或者,搜集文件,并把文件列表赋给ToolKit_src_list
file(GLOB ToolKit_src_list ${ToolKit_Root}/*/*.cpp ${ToolKit_Root}/*/*.h ${ToolKit_Root}/*/*.c)



set(LINK_LIB_LIST)

set(ENABLE_OPENSSL true)

#查找openssl是否安装 需要修改⭐️
find_package(OpenSSL QUIET)
if(OPENSSL_FOUND AND ENABLE_OPENSSL)
message(STATUS "找到openssl库:\"${OPENSSL_INCLUDE_DIR}\",ENABLE_OPENSSL宏已打开")
include_directories(${OPENSSL_INCLUDE_DIR})
add_definitions(-DENABLE_OPENSSL) # 定义宏
list(APPEND LINK_LIB_LIST ${OPENSSL_LIBRARIES})
endif()

#打印库文件
message(STATUS "将链接依赖库:${LINK_LIB_LIST}")

#引用头文件路径
include_directories(${PROJECT_SOURCE_DIR}/src)
#使能c++11
add_compile_options(-std=c++11)# 需要修改⭐️

# 修改其他编译选项
add_compile_options(-Wno-deprecated-declarations)
add_compile_options(-Wno-predefined-identifier-outside-function)


#编译动态库
add_library(${CMAKE_PROJECT_NAME}_shared SHARED ${SRC_LIST})
target_link_libraries(${CMAKE_PROJECT_NAME}_shared ${LINK_LIB_LIST})
set_target_properties(${CMAKE_PROJECT_NAME}_shared PROPERTIES OUTPUT_NAME "${CMAKE_PROJECT_NAME}")
install(TARGETS ${CMAKE_PROJECT_NAME}_shared ARCHIVE DESTINATION ${INSTALL_PATH_LIB} LIBRARY DESTINATION ${INSTALL_PATH_LIB})

#编译静态库
add_library(${CMAKE_PROJECT_NAME}_static STATIC ${SRC_LIST})
set_target_properties(${CMAKE_PROJECT_NAME}_static PROPERTIES OUTPUT_NAME "${CMAKE_PROJECT_NAME}")

#安装静态库至系统目录
install(TARGETS ${CMAKE_PROJECT_NAME}_static ARCHIVE DESTINATION ${INSTALL_PATH_LIB})

#测试程序的目录中也有CMakeLists.txt
add_subdirectory(tests)

测试程序的CMakeList编写方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 执行cp命令
execute_process(COMMAND cp ${CMAKE_CURRENT_SOURCE_DIR}/ssl.p12 ${EXECUTABLE_OUTPUT_PATH}/)

# 当前目录加入TEST_SRC_LIST
aux_source_directory(. TEST_SRC_LIST)
# 遍历TEST_SRC_LIST
foreach(TEST_SRC ${TEST_SRC_LIST})
# 去掉后缀
STRING(REGEX REPLACE "^\\./|\\.c[a-zA-Z0-9_]*$" "" TEST_EXE_NAME ${TEST_SRC})
message(STATUS "添加测试程序:${TEST_EXE_NAME}")
# 每个cpp作为一个可执行文件
add_executable(${TEST_EXE_NAME} ${TEST_SRC})
# 连接动态库
target_link_libraries(${TEST_EXE_NAME} ${CMAKE_PROJECT_NAME}_shared ${LINK_LIB_LIST} pthread)

endforeach(TEST_SRC ${TEST_SRC_LIST})
cmake find_package的基本原理

比如说,我们需要一个第三方库 curl,那么我们的 CMakeLists.txt 需要指定头文件目录,和库文件,类似

1
2
include_directiories(/usr/include/curl)
target_link_libraries(myprogram path/curl.so)

如果借助于cmake提供的finder会怎么样呢?使用cmake的Modules目录下的FindCURL.cmake,相应的CMakeList.txt 文件:

1
2
3
find_package(CURL REQUIRED)
include_directories(${CURL_INCLUDE_DIR})
target_link_libraries(curltest ${CURL_LIBRARY})

那么cmake是如何查找的呢?

find_package()命令首先会在模块路径中寻找Find.cmake,这是查找库的一个典型方式。具体查找路径依次为CMake:变量{CMAKE_MODULE_PATH}中的所有目录。如果没有,然后再查看它自己的模块目录/share/cmake-x.y/Modules/($CMAKE_ROOT的具体值可以通过CMake中message命令输出)。这称为模块模式。

为了能支持各种常见的库和包,CMake自带了很多模块。可以通过命令 cmake –help-module-list (输入cmake –help,然后双击Tab会有命令提示)得到你的CMake支持的模块的列表: 直接查看模块路径。比如Ubuntu linux上,模块的路径是 ls /usr/share/cmake/Modules/:

1
2
3
4
5
6
7
8
ll -th /usr/share/cmake-3.5/Modules/
......
-rw-r--r-- 1 root root 76K Sep 27 2016 FindBoost.cmake
-rw-r--r-- 1 root root 2.7K Mar 24 2016 FindCoin3D.cmake
-rw-r--r-- 1 root root 77K Mar 24 2016 FindCUDA.cmake
-rw-r--r-- 1 root root 3.1K Mar 24 2016 FindCups.cmake
-rw-r--r-- 1 root root 2.4K Mar 24 2016 FindCURL.cmake
........

让我们以bzip2库为例。CMake中有个 FindBZip2.cmake 模块。只要使用 find_package(BZip2) 调用这个模块,cmake会自动给一些变量赋值,然后就可以在CMake脚本中使用它们了。变量的列表可以查看cmake模块文件,或者使用命令:

1
2
3
4
5
6
7
8
9
10
11
root@xy:~/cmake_practice/cmake_build/build_demo10# cmake --help-module FindBZip2
FindBZip2
Try to find BZip2

Once done this will define
::
BZIP2_FOUND - system has BZip2
BZIP2_INCLUDE_DIR - the BZip2 include directory
BZIP2_LIBRARIES - Link these to use BZip2
BZIP2_NEED_PREFIX - this is set if the functions are prefixed with BZ2_
BZIP2_VERSION_STRING - the version of BZip2 found (since CMake 2.8.8)
Filesystem
1
2
3
4
5
6
file(GLOB <variable>
[LIST_DIRECTORIES true|false] [RELATIVE <path>] [CONFIGURE_DEPENDS]
[<globbing-expressions>...])
file(GLOB_RECURSE <variable> [FOLLOW_SYMLINKS]
[LIST_DIRECTORIES true|false] [RELATIVE <path>] [CONFIGURE_DEPENDS]
[<globbing-expressions>...])

产生一个匹配 <globbing-expressions> 的文件列表并将它存储到变量 <variable> 中。文件名替代表达式和正则表达式相似,但更简单。如果 RELATIVE 标志位被设定,将返回指定路径的相对路径。结果将按字典顺序排序。

如果 CONFIGURE_DEPENDS 标志位被指定,CMake 将在编译时给主构建系统添加逻辑来检查目标,以重新运行 GLOB 标志的命令。如果任何输出被改变,CMake都将重新生成这个构建系统。

注意:我们不推荐使用 GLOB 来从源文件树收集源文件列表。如果当源文件添加或删除时没有 CMakeLists.txt 文件被修改,那么在 CMake 重新生成时并不会识别出它们。CONFIGURE_DEPENDS 标志位可能不会再所有生成器上可靠的工作,如果一个新的生成器在以后被添加,并不会被支持。如果项目使用它将会被卡主。即使 CONFIGURE_DEPENDS 可靠的工作,在每个重新构建的过程中做检查也十分浪费性能。

交叉编译配置

1
2
3
4
5
6
7
8
9
10
11
12
SET(TOOLSCHAIN_PATH /home/zero/sdk/gcc-4.6.2-glibc-2.13-linaro-multilib-2011.12/fsl-linaro-toolchain/)
set(TOOLCHAIN_HOST "${TOOLSCHAIN_PATH}bin/arm-none-linux-gnueabi")

set(TOOLCHAIN_CC "${TOOLCHAIN_HOST}-gcc")
set(TOOLCHAIN_CXX "${TOOLCHAIN_HOST}-g++")

# Define the compiler
set(CMAKE_C_COMPILER ${TOOLCHAIN_CC})
set(CMAKE_CXX_COMPILER ${TOOLCHAIN_CXX})

#告诉cmake是进行交叉编译
set(CMAKE_CROSSCOMPILING TRUE)

编译传参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
CMake option
使用场景 : 编译脚本传递参数 -> CMake脚本接收option -> 源代码宏

编译脚本传入参数
传入一个cmake option TEST_DEBUG

#!/bin/sh

cmake -DTEST_DEBUG=ON .
cmake --build .


CMake脚本接收option
cmake 脚本定义TEST_DEBUG 默认关闭OFF

project(test)

option(TEST_DEBUG "option for debug" OFF)
if (TEST_DEBUG)
add_definitions(-DTEST_DEBUG)
endif()
...


源代码宏 test.c

#include "test.h"

#ifdef TEST_DEBUG
...
#endif
# CMake入门
V2X之V2I介绍
C-V2X之ASN.1
  • 文章目录
  • 站点概览

XuQi

44 日志
30 标签
  1. 1. CMake管理工程
    1. 1.1. 安装CMake
    2. 1.2. 创建CMakeLists.txt 骨架
    3. 1.3. CMakeLists.txt中的编写方法
    4. 1.4. 测试程序的CMakeList编写方法
      1. 1.4.1. cmake find_package的基本原理
      2. 1.4.2. Filesystem
    5. 1.5. 交叉编译配置
    6. 1.6. 编译传参数
© 2019 XuQi
由 Hexo 强力驱动 v3.9.0
|
主题 – NexT.Muse v7.3.0