Loading

CMake

一、CMake概述#

CMake是一个跨平台的项目构建工具。编写完CMakeLists.txt(注意文件名称是固定的,区分大小写)后,执行cmake命令,生成Makefile文件和其他中间过程文件。当然你也可以手动去编写Makefile文件,但是编写的工具量比较大,而且依赖关系也比较多,比较容易出错。

从项目源码到可执行文件的流程图:

项目的一般目录结构:

单独新建一个空目录 build 用来保存cmake命令后的中间文件,不会把原来的目录结构搞混乱,而且看起来更整洁。

二、CMakeLists.txt#

  • CMakeLists.txt语法

一些内置预定义变量以及含义:

预定义变量 含义
PROJECT_SOURCE_DIR 工程的根目录
PROJECT_NAME 返回通过project命令定义的项目名
PROJECT_BINARY_DIR 运行cmake命令的目录,通常是在项目下创建build目录,并执行命令
CMAKE_CURRENT_SOURCE_DIR 当前处理CMakeLists.txt所在目录
CMAKE_CURRENT_BINARY_DIR target编译目录(即目标文件输出目录)
CMAKE_CURRENT_LIST_DIR CMakeLists.txt的目录
CMAKE_CURRENT_LIST_LINE 当前所在行(即该变量执行时的所在行)
EXECUTABLE_OUTPUT_PATH 重新定义目标二进制可执行文件的存放位置,需要用户去set
LIBRARY_OUTPUT_PATH 重新定义目标链接库文件的存放位置,需要用户去set

通过一个具体的例子,验证表格中的内置变量是否正确:

分析上述结果,变量 EXECUTABLE_OUTPUT_PATHLIBRARY_OUTPUT_PATH 为空,内置无效。

  • CMakeLists.txt模板:
# 指定cmake版本
cmake_minimun_required(VERSION x.x)

# 指定项目名称
project(项目名称xxxx)

# 添加预处理定义,该功能已被其他命令替换(可选)
add_definitions(编译选项)

# 为源文件的添加编译选项(可选)
add_compile_options(选项1 选项2 选项...)

# 指定头文件目录,若存在多个用空格隔开
include_directories(目录1 目录2 目录...)

# 搜索指定目录下所有源文件,可以将所有源文件赋值给一个变量
# 如果不想在add_executable内一个一个写源文件的话,aux_source_directory就很有用
aux_source_directory(目录 变量)

# 设置变量,变量名一般全大写
set(变量 文件名or路径or其他)

# 指定源文件生成库文件(默认生成静态库)。可将static替换为shared,则生成动态库
add_library(库文件名 static 源文件1 源文件2 源文件...)

# 指定库文件目录
link_directories(目录)

# 指定的源文件来生成目标可执行文件
add_executable(目标可执行文件名 源文件)

# 设置链接库,即为目标可执行文件添加需要的库文件
target_link_libraries(目标可执行文件名 库文件名1 库文件名2 库文件名...)

# 输出测试,打印测试字符串,一般用于console log(可选)
message(字符串1 字符串2或变量 字符串...)

# 指定安装目录,一般需要先指定按照目标前缀,例如:/usr,执行make install后,可执行文件安装到:/usr/bin目录下(在X86主机测试)。如果没有指定前缀
# 默认会被安装到 /usr/local/bin 目录下(在树莓派4B测试)
set(CMAKE_INSTALL_PREFIX /usr)
install(TARGETS ${PROJECT_NAME} DESTINATION bin)

# 查找目标依赖包
find_package()

2024-06-20(补充)

find_package() 查找目标包

(CMakeLists.txt部分内容)


find_package(PkgConfig REQUIRED)
pkg_check_modules (DBUS REQUIRED IMPORTED_TARGET dbus-1)
pkg_check_modules (GLIB REQUIRED IMPORTED_TARGET glib-2.0)
pkg_check_modules (GIO REQUIRED IMPORTED_TARGET gio-2.0)

MESSAGE(STATUS "DBUS dirs:" ${DBUS_INCLUDE_DIRS})
MESSAGE(STATUS "DBUS lib:" ${DBUS_LIBRARIES})
MESSAGE(STATUS "glib-2.0 dirs:" ${GLIB_INCLUDE_DIRS})
MESSAGE(STATUS "glib-2.0 lib:" ${GLIB_LIBRARIES})
MESSAGE(STATUS "gio-2.0 dirs:" ${GIO_INCLUDE_DIRS})
MESSAGE(STATUS "gio-2.0 lib:" ${GIO_LIBRARIES})

message("PROJECT_SOURCE_DIR:" ${PROJECT_SOURCE_DIR})

cmake命令后的截图:

二、模块化#

项目下有多个模块:

pi@c8d2b2520c00:/workspace/distro$ tree buildroot-external/app/supervisor/
buildroot-external/app/supervisor/
├── CMakeLists.txt
├── README.md
└── src
    ├── bluetooth
    │   ├── CMakeLists.txt
    │   ├── bluetooth.cpp
    │   └── bluetooth.hpp
    ├── dbus
    │   ├── CMakeLists.txt
    │   ├── dbus.cpp
    │   └── dbus.hpp
    ├── hardware
    │   ├── CMakeLists.txt
    │   ├── hardware.cpp
    │   └── hardware.hpp
    ├── log
    │   ├── CMakeLists.txt
    │   ├── log.cpp
    │   └── log.hpp
    ├── main.cpp
    ├── mqtt
    │   ├── CMakeLists.txt
    │   ├── mqtt.cpp
    │   └── mqtt.hpp
    ├── network
    │   ├── CMakeLists.txt
    │   ├── network.cpp
    │   └── network.hpp
    └── os
        ├── CMakeLists.txt
        ├── os.cpp
        └── os.hpp

8 directories, 24 files

每一个模块下都有一个 CMakeLists.txt,在项目的顶层目录下也有一个 CMakeLists.txt。

这里看一下 bluetooth 模块的 CMakeLists.txt

add_library(bluetooth STATIC bluetooth.cpp)

target_link_libraries(bluetooth)

target_include_directories(bluetooth PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})

再看一下,项目顶层目录下的 CMakeLists.txt

cmake_minimum_required(VERSION 3.10)

project(supervisor)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED True)

find_package(PkgConfig REQUIRED)
pkg_check_modules(DBusCxx REQUIRED dbus-cxx-2.0)
pkg_check_modules(jsoncpp REQUIRED jsoncpp)
pkg_check_modules(spdlog REQUIRED spdlog)

# 设置源文件目录
set(SOURCES src/main.cpp)

# 添加子目录
add_subdirectory(src/hardware)
add_subdirectory(src/mqtt)
add_subdirectory(src/os)
add_subdirectory(src/network)
add_subdirectory(src/bluetooth)
add_subdirectory(src/dbus)
add_subdirectory(src/log)

# 创建可执行文件
add_executable(${PROJECT_NAME} ${SOURCES})

target_include_directories(${PROJECT_NAME} PRIVATE ${jsoncpp_INCLUDE_DIRS} ${DBusCxx_INCLUDE_DIRS} ${spdlog_INCLUDE_DIRS})

# 链接 Paho MQTT 和 nlohmann JSON 库
target_link_libraries(${PROJECT_NAME} 
    ${jsoncpp_LIBRARIES}
    hardware
    mqtt  # 链接 mqtt 库
    os  # 链接 os 库
    network  # 链接 network 库
    bluetooth  # 链接 bluetooth 库
    dbus  # 链接 dbus 库
    log  # 链接 log 库
)

# 安装
install(TARGETS ${PROJECT_NAME} DESTINATION bin)

疑点#

为什么直接链接下面的库就可以,而不需要指定库目录?

target_link_libraries(${PROJECT_NAME} 
    pthread
    zlog
    mqtt
    cjson
)

原因在于这几个动态库都在默认系统动态链接库配置文件记录的位置。系统动态链接库配置文件是:/etc/ld.so.conf,文件内容如下

pi@pi-NMH-WCX9:~/workspace/connectedhomeip$ cat /etc/ld.so.conf
include /etc/ld.so.conf.d/*.conf

pi@pi-NMH-WCX9:~/workspace/connectedhomeip$ ls /etc/ld.so.conf.d/
fakeroot-x86_64-linux-gnu.conf  libc.conf  x86_64-linux-gnu.conf



pi@pi-NMH-WCX9:~/workspace/connectedhomeip$ cat /etc/ld.so.conf.d/libc.conf 
# libc default configuration
/usr/local/lib

pi@pi-NMH-WCX9:~/workspace/connectedhomeip$ cat /etc/ld.so.conf.d/fakeroot-x86_64-linux-gnu.conf 
/usr/lib/x86_64-linux-gnu/libfakeroot

pi@pi-NMH-WCX9:~/workspace/connectedhomeip$ cat /etc/ld.so.conf.d/x86_64-linux-gnu.conf 
# Multiarch support
/usr/local/lib/x86_64-linux-gnu
/lib/x86_64-linux-gnu
/usr/lib/x86_64-linux-gnu

查看动态链接库登记的目录下有哪些库:

# /usr/local/lib/ 目录下可以看到有 zlog库文件
pi@pi-NMH-WCX9:~/workspace/connectedhomeip$ ll /usr/local/lib | grep zlog
-rw-rw-r--  1 caojun caojun 746678  918 15:04 libzlog.a
lrwxrwxrwx  1 root   root       12  918 15:05 libzlog.so -> libzlog.so.1*
lrwxrwxrwx  1 root   root       14  918 15:05 libzlog.so.1 -> libzlog.so.1.2*
-rwxrwxr-x  1 caojun caojun 375048  918 15:04 libzlog.so.1.2*

# /usr/lib/x86_64-linux-gnu/ 目录下有 pthread 库文件
pi@pi-NMH-WCX9:~/workspace/connectedhomeip$ ll /usr/lib/x86_64-linux-gnu/ | grep pthread
lrwxrwxrwx   1 root root        14  928  2023 libgpgme-pthread.so.11 -> libgpgme.so.11
-rw-r--r--   1 root root         8  57  2024 libpthread.a
-rw-r--r--   1 root root     21448  57  2024 libpthread.so.0

三、参考地址#

Cmake知识----编写CMakeLists.txt文件编译C/C++程序

CMakeLists.txt编写常用命令 - 星星,风,阳光 - 博客园 (cnblogs.com)

CMake 保姆级教程(上)- 爱编程的大丙

作者:caojun97

出处:https://www.cnblogs.com/caojun97/p/18122460

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @   eiSouthBoy  阅读(24)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 推荐几款开源且免费的 .NET MAUI 组件库
· 实操Deepseek接入个人知识库
· 易语言 —— 开山篇
· Trae初体验
历史上的今天:
2023-05-25 SQL Server:分页查询
点击右上角即可分享
微信分享提示
more_horiz
keyboard_arrow_up dark_mode palette
选择主题
menu