CMake语法学习

一、基础语法

基础代码:

#include <iostream>
using namespace std;

int main()
{
    cout << "Hello 今天是2023/2/26" << endl;
    return 0;
}

基础cmake文件:

cmake_minimum_required (VERSION 2.8)

project (learn_cmake)

add_executable(hello hello.cpp)
  • cmake_minimum_required:表示需要的最低cmake版本

  • project (learn_cmake) : 为工程名称

  • add_executable:第一个参数为可执行文件hello,第二个为需要的依赖,如果需要依赖多个文件,可以直接在后面拼接

    add_executable(hello hello.cpp  hello2.cpp)

二、添加目录

添加源文件目录

aux_source_directory(dir var) 作用是把dir目录中的所有源文件都储存在var变量中

cmake_minimum_required(VERSION 4.0)
project(cmake_learn)
set(CMAKE_CXX_STANDARD 20)

aux_source_directory(. SRC_LIST)
add_executable(cmake_learn ${SRC_LIST})

SRC_LIST中存储这当前目录下的源文件内容

添加头文件目录

include_directories ( dir ): 他的作用是 自动去dir目录下寻找头文件,相当于 gcc中的 gcc -I dir

cmake_minimum_required(VERSION 4.0)
project(cmake_learn)
set(CMAKE_CXX_STANDARD 20)

aux_source_directory(. SRC_LIST)
include_directories(./include_header)

add_executable(cmake_learn ${SRC_LIST})

添加多个源文件和头文件目录

aux_source_directory(. SRC_LIST1)
aux_source_directory(. SRC_LIST2)
aux_source_directory(. SRC_LIST3)

include_directories(./include_header1  ./include_header2 ./include_header3)

add_executable(cmake_learn ${SRC_LIST1} ${SRC_LIST2} ${SRC_LIST3})

三、生成静/动态库

img

  • PROJECT_BINARY_DIR是cmake系统变量,意思是执行cmake命令的目录,我们计划在build目录下执行cmake命令,所以这个变量也就等同于build目录
  • add_library:生成库
add_library(lib_name STATIC/SHARED src) 
# 函数作用:生成库。
# 参数lib_name:是要生成的库名称,
# 参数STATIC/SHARED:指定生成静态库或动态库,
# 参数src:指明库的生成所需要的源文件
  • set_target_properties:重新定义了库的输出名称,如果不使用set_target_properties也可以,那么库的名称就是add_library里定义的名称。具体可以参考官方文档。
  • LIBRARY_OUTPUT_PATH 是cmake系统变量,项目生成的库文件都放在这个目录下。这里我指定库生成到lib目录。

指定头文件搜索路径target_include_directories:

target_include_directories(<target>
    <INTERFACE|PUBLIC|PRIVATE> [items1...]
    [<INTERFACE|PUBLIC|PRIVATE> [items2...] ...]
)
  • target: 你之前通过 add_executable() 或 add_library() 创建的目标名称。
  • INTERFACE|PUBLIC|PRIVATE: 指定包含目录的作用域和传播方式。
    • PRIVATE:这些包含目录仅用于编译这个目标本身。
    • INTERFACE:这些包含目录不用于编译这个目标本身,但会暴露给所有链接到这个目标的其他目标
    • PUBLIC: 这些包含目录既用于编译这个目标本身,也会暴露给所有链接到这个目标的其他目标
  • '[items...]' : 一个或多个要包含的目录路径。

示例:

目录结构:

project/
├── CMakeLists.txt
├── src/
│   └── main.cpp
├── include/
│   └── mylib/
│       └── myheader.h
└── lib/
    └── mylib.cpp
cmake_minimum_required(VERSION 3.10)
project(MyProject)

# 创建一个名为 mylib 的库
add_library(mylib lib/mylib.cpp)

# 为 mylib 库设置包含目录
# - src/ 是库内部实现可能需要的头文件路径 (PRIVATE)
# - include/ 是库的公共接口头文件路径,使用 mylib 的代码也需要 (PUBLIC)
target_include_directories(mylib
    PRIVATE ${CMAKE_SOURCE_DIR}/src
    PUBLIC ${CMAKE_SOURCE_DIR}/include
)

# 创建可执行文件
add_executable(myapp src/main.cpp)

# 将 myapp 链接到 mylib
target_link_libraries(myapp mylib)
  • 编译 mylib 时,编译器会在 src/ 和 include/ 目录中查找头文件。
  • 编译 myapp 时,由于 myapp 链接了 mylib,并且 mylib 的 include/ 目录被声明为 PUBLIC,所以 myapp 在编译时也会自动将 include/ 目录加入其包含路径,从而可以 #include <mylib/myheader.h>。

四、链接文件

# 查找库文件:FUNC_LIB为变量  myfunc为库文件 ${PROJECT_BINARY_DIR}查找路径
find_library(FUNC_LIB myfunc ${PROJECT_BINARY_DIR})

set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
# 生成可执行文件
add_executable(cmake_learn ${SRC_LIST} )

# 把库链接到执行问价年终
target_link_libraries(cmake_learn ${FUNC_LIB})
  • EXECUTABLE_OUTPUT_PATH是cmake系统变量,意思是生成的可执行文件的的目录,我这里把他改为bin目录,因此生成的可执行性文件会出现在bin目录中。

  • find_library(var lib_name lib_path1 lib_path2)
    # 函数作用:查找库,并把库的绝对路径和名称存储到第一个参数里
    # 参数var:用于存储查找到的库
    # 参数lib_name:想要查找的库的名称,默认是查找动态库,想要指定查找动态库或静态库
    #       可以加后缀,例如 funcname.so 或 funcname.a 
    # 参数lib_path:想要从哪个路径下查找库,可以指定多个路径
    
    target_link_libraries(target lib_name)
    # 函数作用:把库lib_name链接到target可执行文件中

五、其他参数

有时编译程序时想添加一些编译选项,如-Wall,-std=c++11等,可以使用add_compile_options来进行操作,例如:

add_compile_options(-Wall,-std=c++11)

参考文章