CMake笔记

本文围绕CMake展开,先介绍入门内容,包括Hello world示例、项目生成、编译安装以及库的生成和使用。进阶部分涵盖常量与变量、控制语句、函数和宏等知识,还涉及第三方库的使用、编译选项和参数设置,最后给出Windows平台的一些实用技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

第一部分 入门

一、Hello world

文件目录

./_01
	|
	+- main.cpp
	+- CMakeLists.txt
	/
// main.cpp
#include <iostream>

int main()
{
    std::cout << "Hello world!" << std::endl;
    return 0;
}
# CMakeLists.txt

# 最低版本
cmake_minimum_required(VERSION 3.5)
# 项目名称
project(helloworld)

# 生成可执行文件
add_executable(helloworld main.cpp)

二、生成项目

 // cmake [options] <path-to-source>
 // cmake [options] <path-to-existing-build>
cmake .

2.1 编译 & 安装

Linux

make
make install

Windows

cmake --build . --config Release --target install

三、生成和使用库

文件目录

./_01
	+- build/
	+- math/
			+- math.h
			+- math.cpp
			+- CMakeLists.txt
			/
	+- main.cpp
	+- CMakeLists.txt
	/
// main.cpp
#include <iostream>
#include "math/math.h"

int main()
{
    auto max = z::max(4, 5);
    std::cout << max << std::endl;
    return 0;
}
# CMakeLists.txt

cmake_minimum_required(VERSION 3.5)
project(helloworld)

set(SRC main.cpp)

add_subdirectory(math)

add_executable(${PROJECT_NAME} ${SRC})
target_link_libraries(${PROJECT_NAME} math)
// math/math.h
namespace z {
int max(int l, int r);
}
// math/math.cpp
#include "math.h"

namespace z{
int max(int l, int r)
{
    return l > r ? l : r;
}
}
# math/CMakeLists.txt
set(SRC math.cpp)

add_library(math ${SRC})

构建&编译

cd build
cmake ..
# Linux
make
# Windows
cmake --build .

第二部分 进阶

一、常量 | 全局变量

NameValueset
PROJECT_NAME项目名称project(Alchemy VERSION 0.0.1)
PROJECT_VERSION项目版本project(Alchemy VERSION 0.0.1)
PROJECT_SOURCE_DIR
EXECUTABLE_OUTPUT_PATH可执行文件输出目录set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
LIBRARY_OUTPUT_PATH生成库输出目录set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)
CMAKE_HOST_SYSTEM_NAME
CMAKE_HOST_SYSTEM_VERSION
CMAKE_HOST_SYSTEM_PROCESSOR
CMAKE_VERSION
CMAKE_GENERATOR
CMAKE_BUILD_TOOL

二、变量

CMake只有一种数据类型:string,但是在很多命令中,可以被解释为其他类型,例如bool类型。
变量使用set()unset()显示set或unset,其他命令也有修改变量值的语义。
变量拥有动态作用域,和当前声明的作用域绑定。

  • 函数作用域(Function Scope)
  • 文件夹作用域(Directory Scope)
  • 持久缓存(Persistent Cache)

2.1 环境变量

环境变量是全局变量,永不cached。

$ENV{<variable>

可以用set/unset改变其值,但只是在当前camke进程中改变,不会改变系统环境值。

2.2 列表(Lists)

在确定的上下文中,变量可以被解释为列表。
string使用;分隔为列表

set(srcs a.c b.c c.c) # sets "srcs" to "a.c;b.c;c.c"
set(x a "b;c") # sets "x" to "a;b;c", not "a;b\;c"

三、控制语句

3.1

if(<condition>)
  <commands>
elseif(<condition>) # optional block, can be repeated
  <commands>
else()              # optional block
  <commands>
endif()

3.2 循环

foreach(<loop_var> <items>)
  <commands>
endforeach()
while(<condition>)
  <commands>
endwhile()

break() continue

四、函数和宏

4.1 宏

macro(<name> [<arg1> ...])
  <commands>
endmacro()

4.2 函数

function(<name> [<arg1> ...])
  <commands>
endfunction()

五、生成库

5.1 语法

add_library(<name> [STATIC | SHARED | MODULE]
            [EXCLUDE_FROM_ALL]
            [source1] [source2 ...])

5.2 例子

add_library(math STATIC math.cpp)

六、使用第三方库

6.1 查找包

对camke支持的第三方库,可以使用find_package命令进行查找,然后链接,例如

find_package(OpenCV REQUIRED)
if(OpenCV_FOUND)
    include_directories(${OpenCV_INCLUDE_DIRS})
    list(APPEND LINK_LIBS ${OpenCV_LIBS})
endif()

通常,find_package会设置几个变量值

  • XXX_FOUND : 是否查找到
  • XXX_INCLUDE_DIRS :头文件位置
  • XXX_LIBRARIES :库列表
  • XXX_LIBRARYRARY_DIRS :库目录

6.2 编写查找包模块

对于不支持的第三发库,我们可以自行编写cmake模块
首先,在根目录下新建一个camke文件夹,然后将该模块添加到工程中

set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/;${CMAKE_MODULE_PATH}")

然后编写模块,例如FindGlog.cmake

include(FindPackageHandleStandardArgs)

set(GLOG_ROOT_DIR "" CACHE PATH "Folder contains Google glog")


find_path(GLOG_INCLUDE_DIR glog/logging.h
        HINTS ${GLOG_ROOT_DIR}
        PATH_SUFFIXES include google-glog/include)

find_library(GLOG_LIBRARY glog
        HINTS ${GLOG_ROOT_DIR}
        PATH_SUFFIXES lib lib64)

find_package_handle_standard_args(Glog DEFAULT_MSG GLOG_INCLUDE_DIR GLOG_LIBRARY)

if(GLOG_FOUND)
  set(GLOG_INCLUDE_DIRS ${GLOG_INCLUDE_DIR})
  set(GLOG_LIBRARIES ${GLOG_LIBRARY})
  message(STATUS "Found glog    (include: ${GLOG_INCLUDE_DIR}, library: ${GLOG_LIBRARY})")
  mark_as_advanced(GLOG_ROOT_DIR GLOG_LIBRARY_RELEASE GLOG_LIBRARY_DEBUG
                                 GLOG_LIBRARY GLOG_INCLUDE_DIR)
endif()

七、添加编译选项

# 添加选项,默认ON
option (USE_MATH "Use math libs" ON)

# 根据选项
if (USE_MATH)
	...
endif ()

八、设置编译参数

8.1 设置C++标准

最简单的设置

set(CMAKE_CXX_STANDARD 14)

更加完善的一些设置

# 检查编译器对C++标准的支持
include(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
CHECK_CXX_COMPILER_FLAG("-std=c++14" COMPILER_SUPPORTS_CXX14)
CHECK_CXX_COMPILER_FLAG("-std=c++17" COMPILER_SUPPORTS_CXX17)
if(NOT COMPILER_SUPPORTS_CXX14)
    message(FATAL_ERROR "The compiler ${CMAKE_CXX_COMPILER} DO NOT SUPPORT C++14.")
endif()

set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON) # 要求使用标准C++
set(CMAKE_CXX_EXTENSIONS OFF)		# 关闭编译器对C++的扩展

8.2 编译参数

# windows
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4100")
# linux
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wextra")

九 、安装

十、测试

tricks

Windows平台 设置 执行的管理员权限

set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS "/MANIFESTUAC:\"level='requireAdministrator' uiAccess='false'\"")

复制动态库到执行目录

function(copy_to_target_dir name)
    add_custom_command(TARGET ${PROJECT_NAME}
            POST_BUILD
            COMMAND ${CMAKE_COMMAND} -E copy_if_different
            ${name} $<TARGET_FILE_DIR:${PROJECT_NAME}>)
endfunction()

file(GLOB_RECURSE DLL_FILES /path/to/*.dll)

foreach(dll ${DLL_FILES})
    copy_to_target_dir(${dll})
endforeach()
<think>嗯,用户想了解CMake的使用教程和配置示例。首先,我需要回忆一下CMake的基础知识,确保自己记得正确。CMake是一个跨平台的构建工具,可以生成Makefile或者项目文件,比如Visual Studio的项目。用户可能刚开始接触,所以应该从基本语法和常用命令开始。 用户提到参考了站内的两篇引用,其中一篇是CMake的入门文章,另一篇是关于Apollo CyberRT的环境配置。可能需要结合这些内容,提供一些实际的例子,比如如何编写CMakeLists.txt,如何设置变量,添加可执行文件,链接库等。 接下来,要确保回答符合用户的要求:结构清晰,分步骤解决问题,并且保证真实可靠。可能需要分几个部分,比如基础语法、常用命令、配置示例、高级功能,以及相关问题。还要注意用户的系统级指令,比如数学公式的格式,但这个问题可能不太涉及数学内容,不过如果有的话,比如路径中的变量,需要用$符号包裹。 用户可能的需求是学习CMake的基本使用,配置项目,处理依赖库,可能还有如何管理不同平台的构建。所以需要覆盖这些方面。同时,用户可能对如何查找学习资料感兴趣,所以需要推荐一些官方文档或者教程。 另外,用户提供的示例中有Python代码,但CMake是用于C/C++项目的,所以可能需要调整示例的内容。不过用户的问题是关于CMake的,所以应该提供CMake的配置示例,比如如何编译一个简单的程序,如何添加子目录,链接库等。 需要注意引用标识,比如在提到protobuf安装时,引用[^2]。同时,生成的相关问题应该与CMake相关,比如如何管理依赖、跨平台配置、模块化设计等。 最后,检查是否所有行内代码和命令都正确,比如使用`project()`和`add_executable()`等命令,确保语法正确。还要确保使用中文回答,避免使用Markdown格式,但用户示例中使用了代码块,可能需要按照用户的示例来处理,比如用三个反引号包裹代码块。 总结一下,回答的结构应该是先介绍CMake的基础,然后逐步深入,给出配置示例,最后提供相关问题和参考资料。确保引用正确,并覆盖用户可能需要的各个方面。</think>### CMake 使用教程与配置示例 #### 一、CMake 基础语法 1. **项目定义** 使用 `project()` 定义项目名称和版本: ```cmake project(MyProject VERSION 1.0 LANGUAGES C CXX) ``` 2. **变量与条件判断** - 变量赋值:`set(VAR_NAME value)` - 条件判断:`if()...else()...endif()` 示例: ```cmake set(USE_OPENCV ON) if(USE_OPENCV) find_package(OpenCV REQUIRED) endif() ``` 3. **添加可执行文件** ```cmake add_executable(my_app main.cpp) ``` #### 二、常用命令与配置 1. **包含头文件目录** ```cmake include_directories(${PROJECT_SOURCE_DIR}/include) ``` 2. **链接库文件** ```cmake target_link_libraries(my_app PRIVATE OpenCV::OpenCV) ``` 3. **添加子目录(模块化)** ```cmake add_subdirectory(src/utils) ``` #### 三、配置示例 **示例1:基础项目** ```cmake cmake_minimum_required(VERSION 3.10) project(HelloWorld) add_executable(hello main.cpp) ``` **示例2:依赖外部库(以Protobuf为例)** ```cmake cmake_minimum_required(VERSION 3.10) project(ProtoDemo) # 查找Protobuf库 find_package(Protobuf REQUIRED) include_directories(${Protobuf_INCLUDE_DIRS}) # 生成代码 protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS proto/example.proto) # 添加可执行文件 add_executable(demo main.cpp ${PROTO_SRCS} ${PROTO_HDRS}) target_link_libraries(demo ${Protobuf_LIBRARIES}) ``` 安装依赖库的命令参考自[^2]。 #### 四、高级功能 1. **生成配置文件** 使用 `configure_file()` 将模板文件替换为实际配置: ```cmake configure_file(config.h.in config.h) ``` 2. **自定义构建选项** ```cmake option(BUILD_TESTS "Enable tests" ON) if(BUILD_TESTS) add_subdirectory(tests) endif() ``` 3. **跨平台支持** ```cmake if(WIN32) add_definitions(-DWINDOWS) elseif(UNIX) add_definitions(-DLINUX) endif() ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值