CMake配置

本文介绍CMake的常用命令以及库的相关概念

项目地址:cmake教程

安装Cmake

在ubuntu18.04下安装cmake

1
sudo apt install cmake

安装后查看版本

1
cmake -version

CMake编写

【C++】Cmake使用教程(看这一篇就够了)_隐居的遮天恶鬼的博客-CSDN博客

【C++】静态库和动态库文件的生成和使用_c++ 生成静态库和动态库命令-CSDN博客

本文项目结构

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
MyProject/
|-- CMakeLists.txt # 主CMake文件
|-- external/ # 外部依赖目录
| |-- CMakeLists.txt
| `-- libExternal # 模拟的外部库
| |-- include/ # 外部库的头文件
| | `-- libExternal.h
| `-- src/ # 外部库的源文件
| `-- libExternal.cpp
|-- app/ # 应用程序目录
| |-- CMakeLists.txt
| `-- src/
| `-- main.cpp
|-- lib/ # 库文件目录
| |-- libA/ # 静态库A
| | |-- CMakeLists.txt
| | `-- src/
| | `-- libA.cpp
| `-- libB/ # 动态库B
| |-- CMakeLists.txt
| `-- src/
| `-- libB.cpp
|-- include/ # 公共头文件目录
| |-- libA/
| | `-- libA.h
| `-- libB/
| `-- libB.h
|-- tests/ # 测试目录
| |-- CMakeLists.txt
| `-- testA/
| |-- CMakeLists.txt
| `-- src/
| `-- testA.cpp
|-- docs/ # 文档目录
|-- README.md
`-- .gitignore

需要明确一些点

  1. include”head.h”仅仅是将文件内容复制,所以一个项目可以完全没有头文件

  2. 如果指定库文件(或者可执行文件)的头文件搜索路径,则首先在库文件搜索路径下找,然后在当前cpp文件目录下,然后在编译器的默认搜索路径中寻找

  3. CMake是一个跨平台的自动化构建系统,主要用于生成Makefile,所以一般cmake不会报错,在make的时候会报错

  4. 无法解析的外部命令

    • 函数仅在头文件中声明,而没有在任何编译单元(.cpp文件)中实现。
    • 相应的库文件没有被正确链接到您的项目中。
    • 如果涉及动态库,可能是动态库没有被正确安装或找不到
  5. 编译和链接的关系

    每个源文件(.cpp)可以独立编译,生成对象文件。链接阶段将这些对象文件组合成最终的可执行文件或库文件。如果只有函数声明没有实现,编译时不会报错,但链接时会报错,因为链接器找不到这些函数的定义。并且链接器会自动处理依赖关系,不需要指定对象文件的链接顺序。

  6. 动态库链接的代码执行

    当您的程序链接了动态库,运行时,操作系统会加载这些库并解析所需的符号。如果您删除了动态库,程序可能无法运行,因为它找不到必要的函数实现。动态库的代码不是写入可执行文件中,而是在运行时动态加载的。

  7. 库文件和头文件

    库文件必须包含函数的定义,但不一定要包含头文件。头文件通常包含函数声明,使得其他源文件能够知道这些函数的存在。即使不包含头文件,只要函数在库内部定义,链接时就不会报错。

  8. 动态库搜索

    可执行文件本身不包含库代码,而是包含对库函数的引用。在运行时,操作系统的动态链接器负责找到并加载这些动态库。这通常是通过以下方式实现的:

    1. 链接时信息: 当可执行文件被创建时,链接器会在可执行文件中存储有关它依赖的动态库的信息(如库的名称和版本)。
    2. 运行时搜索: 在程序启动时,动态链接器会根据这些信息查找并加载必要的动态库。库的搜索可以基于多个因素,包括操作系统的库搜索路径、环境变量(如 LD_LIBRARY_PATH 在Linux上)等。

cmake知识点

一些常量

  1. 项目和源代码相关

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    # 获取包含顶层CMakeLists.txt的目录的路径
    set(TOP_LEVEL_SOURCE_DIR ${CMAKE_SOURCE_DIR})

    # 获取当前处理的CMakeLists.txt的目录的路径
    set(CURRENT_LIST_DIR ${CMAKE_CURRENT_SOURCE_DIR})

    # 获取最近通过project()命令定义的子项目的源目录(cmake目录)
    set(LAST_PROJECT_SOURCE_DIR ${PROJECT_SOURCE_DIR})

    # 获取包含当前正在处理的列表文件的目录
    set(CURRENT_LIST_FILE_DIR ${CMAKE_CURRENT_LIST_DIR})
  2. 构建和输出相关

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    # 获取顶层构建目录的路径(build)
    set(TOP_LEVEL_BINARY_DIR ${CMAKE_BINARY_DIR})

    # 获取当前处理的CMakeLists.txt对应的构建目录的路径
    set(CURRENT_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})

    # 设置可执行文件的输出目录
    set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/bin)

    # 设置库文件(动态)的输出目录
    set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/lib)

    # 设置静态库的输出目录
    set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/archive)
  3. 系统和平台相关

    1
    2
    3
    4
    5
    # 获取系统名称,例如Linux、Windows
    set(SYSTEM_NAME ${CMAKE_SYSTEM_NAME})

    # 获取系统处理器,例如x86_64、AMD64
    set(SYSTEM_PROCESSOR ${CMAKE_SYSTEM_PROCESSOR})
  4. C++ 和编译器相关

    1
    2
    3
    4
    5
    6
    7
    8
    9
    # 设置C++标准
    set(CMAKE_CXX_STANDARD 17)
    set(CMAKE_CXX_STANDARD_REQUIRED ON)

    # 设置C++编译器的标志
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")

    # 获取编译器的完整路径
    set(COMPILER_PATH ${CMAKE_CXX_COMPILER})

注意:
CMAKE_BINARY_DIR是执行cmake命令的目录,外部构建的时候是build目录
CMAKE_SOURCE_DIR是项目的根CMakeLists.txt所在目录
CMAKE_CURRENT_SOURCE_DIR是当前CMakeLists.txt所在目录

区分预定义变量和自定义变量

  • 预定义变量:这些是CMake系统提供的变量,通常以 CMAKE_ 开头。它们用于获取关于构建环境和项目配置的信息。
  • 自定义变量:您可以通过 set() 命令创建自己的变量。您可以使用这些变量来存储自己的数据,或者修改和存储预定义变量的值。

构建camke工程的步骤

  1. 首先要在每个目录下创建CMakeLists.txt文件

  2. 嵌套的目录需要使用add_subdirectory调用

  3. 动态库链接静态库需要添加**-fPIC编译选项**

    1
    2
    # 添加-fPIC编译选项,libA是静态库名
    set_property(TARGET libA PROPERTY POSITION_INDEPENDENT_CODE ON)

常用命令大全

  1. 设置全局c++标准

    1
    2
    3
    # 设置全局C++标准
    set(CMAKE_CXX_STANDARD 17)
    set(CMAKE_CXX_STANDARD_REQUIRED ON)
  2. 指定文件生成目录

    1
    2
    3
    # 设置可执行文件和库文件的输出目录
    set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/bin)
    set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/libs)
  3. 添加子目录

    1
    2
    3
    4
    5
    # 添加子目录,括号内是子目录名称
    add_subdirectory(external)
    add_subdirectory(lib)
    add_subdirectory(app)
    add_subdirectory(tests)
  4. 生成库文件

    1
    2
    add_library(libname SHARED src/mylib.cpp)  #生成动态库文件libname
    add_library(libname STATIC src/mylib.cpp) #生成静态库文件libname
  5. 为目标添加头文件搜索路径

    1
    target_include_directories(libA PUBLIC ${CMAKE_SOURCE_DIR}/include/libA)
  6. 为目标添加库文件搜索路径

    1
    target_include_directories(libA PRIVATE ${CMAKE_SOURCE_DIR}/lib)
  7. 为目标链接库

1
2
3
target_link_libraries(myApp PRIVATE libA libB libExternal)
#myqpp是可执行文件(也可以是库文件)
#libA,libB,libExternal是库文件
  1. file命令

    文件操作

    1. file(READ)

      用于将文件内容读取到变量中。

      1
      file(READ <filename> <variable> [OFFSET <offset>] [LIMIT <max-in>] [HEX])
    2. file(WRITE)

      用于将内容写入文件。

      1
      file(WRITE <filename> "<content>")
    3. file(APPEND)

      用于向文件中追加内容。

      1
      file(APPEND <filename> "<content>")
    4. file(TOUCH)

      用于创建空文件或者更新文件的时间戳。

      1
      file(TOUCH <filename>)

    文件夹操作

    1. file(GLOB)

      用于匹配规则在指定的目录内匹配到所需要的文件。

      1
      file(GLOB <variable> [LIST_DIRECTORIES true[false]] [RELATIVE <path>] [CONFIGURE_DEPENDS] [<globbing-expression> ...])
    2. file(GLOB_RECURSE)

      用于递归匹配文件,包括子目录中的文件。

    3. file(RENAME)

      用于重命名文件。

      1
      file(RENAME <old-name> <new-name>)
    4. file(REMOVE)

      1
      file(REMOVE <filename>)
    5. file(MAKE_DIRECTORY)

      用于创建目录。

      1
      file(MAKE_DIRECTORY <directory>)
    6. file(COPY)

      1
      file(COPY <files>... DESTINATION <dir> [...])
    7. file(INSTALL)

      用于将文件安装到指定目录中。

      1
      file(INSTALL <files>... DESTINATION <dir> [...])

    路径转换

    1. file(RELATIVE_PATH)

      用于获取相对路径。

      1
      2
      cmakeCopy code
      file(RELATIVE_PATH <variable> <directory> <file>)
    2. file(TO_CMAKE_PATH)

      用于将路径转换为CMake风格的路径。

      1
      2
      cmakeCopy code
      file(TO_CMAKE_PATH <path> <variable>)
    3. file(TO_NATIVE_PATH)

      用于将路径转换为本地操作系统风格的路径。

      1
      2
      cmakeCopy code
      file(TO_NATIVE_PATH <path> <variable>)
  2. find_package

    查ai

添加外部库实战

boost库

  1. 执行命令

    1
    2
    sudo apt-get update
    sudo apt-get install libboost-all-dev
  2. 在CMake中找到Boost库

    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
    cmake_minimum_required(VERSION 3.15)
    project(MyComplexProject VERSION 1.0)

    # 设置全局C++标准
    set(CMAKE_CXX_STANDARD 17)
    set(CMAKE_CXX_STANDARD_REQUIRED ON)

    #设置可执行文件和库的输出目录
    set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/bin)
    set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/libs)#动态库
    set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/archive)#静态库

    # 找到Boost库
    find_package(Boost 1.65 REQUIRED COMPONENTS system filesystem)

    # 如果找到了Boost,包括Boost的头文件目录
    if(Boost_FOUND)
    message(STATUS "找到了Boost库 ${Boost_VERSION_MAJOR}.${Boost_VERSION_MINOR}.${Boost_VERSION_PATCH} in ${Boost_INCLUDE_DIRS}")
    include_directories(${Boost_INCLUDE_DIRS})
    endif()

    # 添加子目录
    add_subdirectory(external)
    add_subdirectory(lib)
    add_subdirectory(app)
    add_subdirectory(tests)
  3. 链接Boost库

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    add_executable(myApp src/main.cpp)
    # 链接Boost库
    if(Boost_FOUND)
    message("链接成功:Boost_INCLUDE_DIRS: ${Boost_INCLUDE_DIRS}")
    target_link_libraries(myApp PRIVATE ${Boost_LIBRARIES})
    endif()
    target_link_libraries(myApp PRIVATE libA libB libExternal)
    target_include_directories(myApp PRIVATE
    ${PROJECT_SOURCE_DIR}/include/libA
    ${PROJECT_SOURCE_DIR}/include/libB
    )

opencv库

Json库

根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
# 设置CMake的最低版本要求
cmake_minimum_required(VERSION 3.15)

# 设置项目名称和版本
project(MyComplexProject VERSION 1.0)

# 设置全局 C++ 标准
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# 如果没有指定构建类型,则默认设置为 Debug
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Debug)
endif()

message(STATUS "构建类型: ${CMAKE_BUILD_TYPE}")

# 设置可执行文件和库的输出目录
message(STATUS "CMAKE_SOURCE_DIR: ${CMAKE_SOURCE_DIR}")
message(STATUS "可执行文件输出目录: ${CMAKE_SOURCE_DIR}/bin")
message(STATUS "动态库输出目录: ${CMAKE_SOURCE_DIR}/lib")
message(STATUS "静态库输出目录: ${CMAKE_SOURCE_DIR}/archive")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/bin) # 可执行文件
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/lib) # 动态库
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/archive) # 静态库

# 设置 CMake 以查找 Boost 的动态库
set(Boost_USE_STATIC_LIBS OFF) # 只使用 Boost 的动态库
set(Boost_USE_MULTITHREADED ON) # 使用多线程版本的 Boost
set(Boost_USE_STATIC_RUNTIME OFF) # 不使用 Boost 静态运行时库

# 查找 Boost 库
find_package(Boost 1.65 REQUIRED COMPONENTS system filesystem)

# 如果找到了 Boost,则包含 Boost 的头文件目录
if(Boost_FOUND)
message(STATUS "找到了 Boost 库 ${Boost_VERSION_MAJOR}.${Boost_VERSION_MINOR}.${Boost_VERSION_PATCH} 在 ${Boost_INCLUDE_DIRS}")
include_directories(${Boost_INCLUDE_DIRS})
endif()


# 添加源代码子目录
add_subdirectory(server)
add_subdirectory(src)

# 根据构建类型添加编译器标志
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
add_compile_options(-g -O0 -Wall -Wextra -Werror) # Debug模式的编译器标志
else()
add_compile_options(-O2) # 非Debug模式的优化选项
endif()

CMake配置
http://example.com/2024/01/03/cpp/CMake配置以及库概念/
作者
Mrxiad
发布于
2024年1月3日
许可协议