文章

cmake 常用总结

很多时候不常用容易忘一些语法,自己总结自己看会更快早会感觉。后期持续添加

cmake

  1. target 前缀都是在 add_library , add_executable 之后编写
  2. Modern CMake 推荐使用 target 前缀方法 命令:
    1
    2
    
    cmake --build build //编译
    cmake --install 路径
    

基本内容语法

部分常用的函数和变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
message("ok") #SEND_ERROR,STATUS: -- OK,FATAL_ERROR
#if else
if(aaa)
    #如果是 1、ON、YES、TRUE、Y或非零数(包括浮点数),则为 True。
    #如果是 0、OFF、 NO、FALSE、N、IGNORE、NOTFOUND、空字符串或以 -NOTFOUND 后缀结尾,则为 False
    #布尔常量不区分大小写
elseif(bbb)
    #if(COMMAND command-name) 命令、宏或函数是否存在
    #if(<variable|string> IN_LIST <variable>) 列表中是否存在
    #if(EXISTS path-to-file-or-directory) 文件存在检查
    # 还有一些比较少用的字符串 数字 版本号比较大于小于等,还有些冷门
else()
   # ...
endif()

变量

1
2
3
4
5
6
7
8
9
10
11
12
${PROJECT_BINARY_DIR} #项目生成后的地址  后缀不带/
${PROJECT_SOURCE_DIR} #资源路径 后缀不带/
$<TARGET_OBJECTS:对象名字> #add_library OBJECT 时候,使用添加 OBJECT 的变量名: add_library,add_executable
CMAKE_PREFIX_PATH #用于指示CMake在查找包和项目所需库文件时的路径。在构建项目时,它可以帮助CMake定位库文件,头文件和执行文件等 -D CMAKE_PREFIX_PATH=/path/to/libA;/path/to/libB

#默认存放静态库的目录
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${CMAKE_SYSTEM_NAME}/lib)
#默认存放动态库的目录
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${CMAKE_SYSTEM_NAME}/lib)
#默认存放可执行文件的目录
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${CMAKE_SYSTEM_NAME}/bin)

设置环境变量

一般都是大写和下划线,可以多个值

1
2
3
    set(CMAKE_CXX_STANDARD 20)
    set(CMAKE_LIST "A" "B") 
    #与上面一样set(CMAKE_LIST "A;B")

其他目录cmake添加进构建

1
2
    #映入cmake文件 默认是同级  可以有目录在前
    add_subdirectory(file)

引入头文件文件夹

target_include_directories ( PUBLIC|PRIVATE|INTERFAC AFTER|BEFORE <INTERFACE|PUBLIC|PRIVATE> ...)

target_include_directories 颗粒度更小,如果是PUBLIC 父级引用它时候就不需要添加 target_include_directories

1
    target_include_directories(target PRIVATE dir )

编译添加库文件

link_libraries 和 target_link_libraries 添加库文件不需要后缀 target_link_libraries 更细粒度

  1. link_libraries用于链接静态库,设置全局链接库,影响所有后续的编译过程‌
  2. target_link_libraries‌:用于链接导入库,即动态库的.lib文件,适用于特定的目标对象‌
  3. link_libraries 作为全局链接库设置,需要在add_library或者add_executable命令之前使用,
  4. target_link_libraries 为特定的目标指定链接库,则需要在add_library 或者add_executable命令之后使用

link_libraries([item1 [item2 […]]] [[debug|optimized|general] ] ...)

target_link_libraries( <PRIVATE|PUBLIC|INTERFACE> ... )

1
    target_link_libraries(target PUBLIC lib)

搜索包

  1. 需要目录下有xxx(OpenCV)Config.cmake,大小写敏感
  2. 环境变量查找,${CMAKE_MODULE_PATH} 查找
    1
    
    find_package(OpenCV REQUIRED)
    

    生成库

window 动态库有点不一样

  • SHARED 动态
  • STATIC 静态
  • MODULE 类似于 SHARED 库,但通常用于运行时通过 dlopen (Linux) 或 LoadLibrary (Windows) 等函数显式加载的插件,而不是在链接时链接。
  • OBJECT 作为一编译连接,可以被使用当作是自己一个整体整体 例如: exe -> b(STATIC) -> a(OBJECT) ,会被连接成一个整体
  • UNKNOWN 当你使用的外部库的类型未知或不重要时,可以使用 UNKNOWN 类型。例如,你可能只知道库文件的路径和包含目录,但不知道它是静态库还是动态库。
  • INTERFACE 没使用过

add_library(名字 <SHARED动态|STATIC静态|MODULE|OBJECT|UNKNOWN|INTERFACE> IMPORTED [GLOBAL])

1
    add_library(name STATIC file )

生成可执行文件

1
2
    #文件名后是多个管理所需要生成的源码文件 默认是同级 可以有目录在前
    add_executable(文件名 main.cpp )

安装

  1. install(TARGETS ... [...])
    1. RUNTIME DESTINATION : 安装运行时组件(例如可执行文件和动态库)到 目录。
    2. PUBLIC_HEADER DESTINATION : 安装公共头文件到 目录 (适用于库目标)。
    3. PRIVATE_HEADER DESTINATION : 安装私有头文件到 目录 (适用于库目标)。
    4. INCLUDES DESTINATION : 通常用于安装头文件,等同于PUBLIC_HEADER DESTINATION
    5. COMPONENT : 将目标与名为 的组件关联起来。组件可以用于分组安装目标,并允许用户选择性地安装部分组件。
    6. NAMELINK_COMPONENT : (自 CMake 3.14 起) 指定处理符号链接的版本化库文件的组件。
    7. NAMELINK_ONLY / NAMELINK_SKIP: (针对支持 soname 的平台,例如 Linux) NAMELINK_ONLY: 只安装符号链接文件,不安装实际的库文件。 NAMELINK_SKIP: 只安装实际的库文件,不安装符号链接文件。
    8. RUNTIME DESTINATION : 安装运行时组件(例如可执行文件和动态库)到 目录。
  2. install({FILESPROGRAMS} ... [...]) 用于安装文件或外部程序。
    1. FILES: 安装普通文件。
    2. PROGRAMS: 安装可执行程序(非 CMake 构建的目标,例如脚本)。
    3. ...: 要安装的文件或程序路径列表。
    4. […]:
      1. DESTINATION : 安装文件到 目录。
      2. PERMISSIONS: 设置安装文件的权限(例如 OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ)。
      3. COMPONENT : 将文件与名为 的组件关联起来。
      4. RENAME : 安装文件时重命名为
      5. OPTIONAL: 如果文件不存在,则不产生错误。
  3. install(DIRECTORY ... [...]) 用于安装整个目录及其内容。
    1. DESTINATION : 安装目录到 目录。
    2. FILES_MATCHING: 只安装匹配指定模式的文件。
    3. PATTERN [EXCLUDE]: 指定匹配模式(可以使用通配符 * 和 ?),EXCLUDE 表示排除匹配的文件。
    4. COMPONENT : 将目录与名为 的组件关联起来。
  4. install(SCRIPT [...]) 用于在安装阶段执行指定的 CMake 脚本文件。 COMPONENT : 指定组件
  5. install(CODE [...]) 用于在安装阶段执行指定的 CMake 代码片段。
  6. install(EXPORT [...]) : 导出的目标集名称,它通过 export 命令或 install(EXPORT) 命令创建。
    1. DESTINATION : 安装导出文件到 目录。
    2. NAMESPACE : 为导入的目标添加命名空间前缀。
    3. FILE .cmake: 指定导出文件的名称(默认为 .cmake)。
    4. COMPONENT : 将导出文件与名为 的组件关联起来。

tips > 文件归属权限是安装者

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#windows 动态库是 runtime 属性,动态库 cmake 也要添加,写在 install 后面都是 install 相关参数
install(TARGETS cmake_test
        RUNTIME DESTINATION bin
        LIBRARY DESTINATION lib
        ARCHIVE DESTINATION lib/static
)
set(CMAKE_INSTALL_PREFIX "./test") #指定目录
#=======
# 安装 icons 目录
install(DIRECTORY icons/ DESTINATION share/my_project)
install(FILES config.conf DESTINATION etc/my_project)
# 在安装阶段执行 post_install.cmake 脚本
install(SCRIPT post_install.cmake) # 执行一些自定义的安装后操作
# 在安装阶段打印一条消息
install(CODE "message(\"Installation completed!\")")

编译运行程序例子

库+运行文件

1
2
3
4
5
6
7
8
9
10
11
12
目录
|   CMakeLists.txt
|   main.cpp
\---demo1
    |   CMakeLists.txt
    |
    +---header
    |       add.h
    |
    \---svc
            add.cpp

demo1 CMakeLists.txt

1
2
3
4
5
project(demo1)
add_library(demo1 svc/add.cpp) #改为动态库也是一样

target_include_directories(demo1 PUBLIC header)
#这里使用 PRIVATE  `根目录 CMakeLists.txt `也需要引入 target_include_directories(cmake_test PUBLIC demo1/header)

根目录 CMakeLists.txt

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
cmake_minimum_required(VERSION 3.30)
project(cmake_test)


set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${CMAKE_SYSTEM_NAME}/lib)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${CMAKE_SYSTEM_NAME}/lib)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${CMAKE_SYSTEM_NAME}/bin)


set(CMAKE_CXX_STANDARD 20)
add_subdirectory(demo1)
add_executable(cmake_test main.cpp)

target_link_libraries(cmake_test demo1)

运行文件 和一些特殊参数说明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#声明cmake 最小最小版本
cmake_minimum_required(VERSION 3.30)
#项目名
project(cmake_test)
#设置 变量 : c++ 版本
set(CMAKE_CXX_STANDARD 20)

#CMAKE_PREFIX_PATH用于指示CMake在查找包和项目所需库文件时的路径。在构建项目时,它可以帮助CMake定位库文件,头文件和执行文件等
#-DCMAKE_PREFIX_PATH=/path/to/libA;/path/to/libB
set(CMAKE_PREFIX_PATH D:/app/qt/6.8.1/msvc2022_64)


#编译
add_executable(cmake_test main.cpp)

windows 与 linux 不同点

动态库和静态库跟linux是有区别的

windows

文件类型与扩展:动态库通常被创建为 .dll 文件,伴随着一个 .lib 文件(导入库),后者包含了需要链接到主可执行文件的符号。

导出符号:需要使用 __declspec(dllexport) 声明 和 __declspec(dllimport) 实现 来显式导出和导入类、函数或变量。

linux

文件类型与扩展:动态库被创建为 .so 文件(Shared Object)。

导出符号:Linux 平台通常不需要像 Windows 那样显式定义导入导出符号,编译器默认会导出所有符号。但为了隐藏不需要公开的符号,可能会使用 GCC 的 attribute((visibility(“default”))) 和 attribute((visibility(“hidden”))) 属性。

链接动态库的 CMake 指令也是相同的,但在 Windows 上需要链接到导入库 .lib 文件,而在 linux 上直接链接到 .so 文件。

1
2
3
4
5
6
7
#windows 防止乱码
#regedit 注册表> 计算机\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Nls\CodePage  >> `OEMCP` 和 `ACP`修改 65001
#程序输出 防止乱码
if(CMAKE_HOST_WIN32)
   add_compile_options("$<$<C_COMPILER_ID:MSVC>:/utf-8>")
   add_compile_options("$<$<CXX_COMPILER_ID:MSVC>:/utf-8>")
endif()

Reference

本文由作者按照 CC BY 4.0 进行授权