欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

CMake安装使用

程序员文章站 2024-03-14 11:14:34
...

官方在线文档

安装与新建工程 (Ubuntu)

CMake 官网下载: https://cmake.org/download/ .

找个地方解压并进入.

tar -zxvf cmake-3.14.5.tar.gz
cd cmake-3.14.5/

根据目录下的 README 文件, 执行以下命令安装.

./bootstrap && make && sudo make install

编译好慢啊…

CMake 会默认安装在 /usr/local/bin 下面.

用 CMake 编译安装 CMake

cd build/
cmake ..
make
sudo make install

构建一个简单的 CMake 项目

新建一个文件夹作为项目文件夹, 新建文件 CMakeLists.txt. 以下为一个典型的配置:

# 项目名称
PROJECT(CMakeTest CXX)

# CMake最低版本需求,不加入此行会受到警告信息
CMAKE_MINIMUM_REQUIRED(VERSION 3.14)

# 把目录src下所有源代码文件和头文件加入变量SRC_LIST
AUX_SOURCE_DIRECTORY(src SRC_LIST)

# 生成应用程序 hello
ADD_EXECUTABLE(hello ${SRC_LIST})

src 文件夹写好源码后 (比如写个 hello_world.cpp), 在项目目录新建文件夹 build.

然后执行

cd build/
cmake ..
make

build 文件夹下就会生成编译文件和最终的可执行文件 hello.

GitHub 优秀 CMake 项目参考

CMake | OpenCV

Visual Studio 对 CMake 的支持

CMake 语法

语法特性

赋值语句

# 在当前及其子项目定义变量 VAR (不影响父域)
# 使用 ${<var>} 访问
# set(VAR a b c) 以定义 LIST (set(VAR "a b c") 则定义了个字符串)
set(<var> <value>)


# 在父域定义 VAR (而不影响当前环境!!)
set(<var> <value> PARENT_SCOPE)

# Cache 变量, 定义后全局访问, 且存在 CMakeCache.txt 中
# 使用 $CACHE{<var>} 访问, 或当同名常规变量未被定义时也可用 ${<var>} 访问
set(<var> <value> CACHE <STRING | BOOL | FILEPATH | PATH> INTERNAL)

# 环境变量
# 使用 $ENV{<var>} 访问
set(ENV{<var>} <path>)

# 不再定义
unset(<var> [CACHE | PARENT_SCOPE])
unset(ENV{<variable>})

LIST 操作

# 读
list(LENGTH <list> <out-var>)
list(GET <list> <element index> [<index> ...] <out-var>)
list(JOIN <list> <glue> <out-var>)
list(SUBLIST <list> <begin> <length> <out-var>)

# 查
list(FIND <list> <value> <out-var>)

# 删改
list(APPEND <list> [<element>...])
list(FILTER <list> {INCLUDE | EXCLUDE} REGEX <regex>)
list(INSERT <list> <index> [<element>...])
list(POP_BACK <list> [<out-var>...])
list(POP_FRONT <list> [<out-var>...])
list(PREPEND <list> [<element>...])
list(REMOVE_ITEM <list> <value>...)
list(REMOVE_AT <list> <index>...)
list(REMOVE_DUPLICATES <list>)
list(TRANSFORM <list> <ACTION> [...])

# 排序
list(REVERSE <list>)
list(SORT <list> [...])

条件语句

if(<condition>)
    <commands>
elseif(<condition>)
    <commands>
else()          # 或在括号内填上与 if 一模一样的 <condition>
    <commands>
endif()         # 或在括号内填上与 if 一模一样的 <condition>

函数

function(<func_name> [arg1 [arg2 [arg3 ...]]])
    <commands>
endfunction()       # 或在括号内一字不差地填上 function 括号内内容

macro(<name> [arg1 [arg2 [arg3 ...]]])
  <commands>
endmacro()          # 或在括号内一字不差地填上 macro 括号内内容

内置函数

# 确定所需 CMake 版本 (最好放在文件的最开头)
# cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
cmake_minimum_required(VERSION <min>[...<max>] [FATAL_ERROR])

# 确定项目名
project(<project>)

# 添加并构建一个子项目 (即包含 CMakeLists.txt 的文件夹)
add_subdirectory(<project_dir> [binary_dir] [EXCLUDE_FROM_ALL])

# 将一整个文件夹里的 c/cpp 文件添加到源文件列表,
# 得到如 "src/main.cpp;src/s.cpp;..." 的字符串
# aux_source_directory(src SRC_LIST)
aux_source_directory(<src_dir> <source_list>)

# 根据提供的源文件参数生成可执行文件
# add_executable(CMakeTest.exe ${SRC_LIST})
add_executable(<target_exe> [WIN32] [MACOSX_BUNDLE]
               [EXCLUDE_FROM_ALL]
               [source1] [source2 ...])

# 同上, 生成库
# add_library(Dependency.lib d1.cpp)
add_library(<target_lib> [STATIC | SHARED | MODULE]
            [EXCLUDE_FROM_ALL]
            [source1] [source2 ...])

# 添加头文件目录 (添加后可识别 #include "xxx.h" 而不用使用相对路径)
# include_directories(Dependency)
include_directories([AFTER|BEFORE] [SYSTEM] dir1 [dir2 ...])

# 给指定目标添加头文件目录
# target_include_directories(CMakeTest.exe PRIVATE Dependency)
target_include_directories(<target> [SYSTEM] [BEFORE]
  <INTERFACE|PUBLIC|PRIVATE> [items1...]
  [<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])

# 链接先前已经生成的可执行文件和库
# target_link_libraries(CMakeTest.exe Dependency.lib)
target_link_libraries(<target> ... <item>... ...)

内置变量

CMAKE_SOURCE_DIR | PROJECT_SOURCE_DIR | CMAKE_CURRENT_SOURCE_DIR | <PROJECT_NAME>_SOURCE_DIR

都指向项目的源目录的绝对路径 (CMakeLists.txt 所在的绝对路径).

CMAKE_SOURCE_DIR 指向当前最顶层项目 (父项目) CMakeLists.txt 的路径.

PROJECT_SOURCE_DIR 指向当前项目 (子项目) CMakeLists.txt 的路径.

CMAKE_CURRENT_SOURCE_DIR 指向当前正在处理的 CMakeLists.txt 的路径 (感觉和 PROJECT_SOURCE_DIR 没啥区别啊???).

<PROJECT_NAME>_SOURCE_DIR 就是指定某项目的 CMakeLists.txt 的路径. 但是当该项目还未被调用过之前, 该变量未定义.

所以当没有子项目时这几个都相同.


例如对于父项目 Outer 与子项目 Inner:

# Outer/CMakeLists.txt
...
project(Outer)
add_subdirectory(Inner)
...

# Outer/Inner/CMakeLists.txt
...
project(Inner)
...

Outer/CMakeLists.txt 中的变量值为:

CMAKE_SOURCE_DIR PROJECT_SOURCE_DIR CMAKE_CURRENT_SOURCE_DIR Outer_SOURCE_DIR Inner_SOURCE_DIR
/.../Outer /.../Outer /.../Outer /.../Outer /.../Outer/Inner

Outer/Inner/CMakeLists.txt 中的变量值为:

CMAKE_SOURCE_DIR PROJECT_SOURCE_DIR CMAKE_CURRENT_SOURCE_DIR Outer_SOURCE_DIR Inner_SOURCE_DIR
/.../Outer /.../Outer/Inner /.../Outer/Inner /.../Outer /.../Outer/Inner

TODO: PROJECT_SOURCE_DIRCMAKE_CURRENT_SOURCE_DIR 区别.

CMAKE_BINARY_DIR | PROJECT_BINARY_DIR | CMAKE_CURRENT_BINARY_DIR | <PROJECT_NAME>_BINARY_DIR

指向工程编译发生的绝对路径. 区别同上.

如果是 in source 编译, 指的就是工程顶层目录, 即与 <?>_SOURCE_DIR 一样. 而如果是:

cd build/
cmake ..
make

这种, 则其路径为 /.../CMake_Project/build .

踩坑

项目依赖作图 (graphviz)

生成依赖图的文件:

cd build/
cmake .. --graphviz=<graph>.dot

build/ 下生成 <graph>.dot 文件, <graph>.dot.<target> 文件和 <graph>.dot.<target>.dependers 文件.

安装 graphviz 以生成 png:

sudo apt-get install graphviz

导出依赖为图片:

dot <graph>.dot -T png -o <figure>.png

例如对于 cmake-3.14.5 项目:

mkdir Build
cd Build
cmake .. --graphviz=graph.dot
ls | grep graph
# graph.dot
# graph.dot.cmake
# graph.dot.cmake.dependers
# graph.dot.CMakeLib
# graph.dot.CMakeLib.dependers
...
# graph.dot.testConsoleBufChild
# graph.dot.testConsoleBufChild.dependers
# graph.dot.testEncoding
# graph.dot.testEncoding.dependers

dot graph.dot -T png -o graph.png

打开 graph.png:

CMake安装使用

emmmm, 好丑的图.

相关标签: CMake