以下内容为本人的著作,如需要转载,请声明原文链接 微信公众号「englyf」https://www.cnblogs.com/englyf/p/16667896.html
cmake
是什么?这些年大型 C/C++ 工程都纷纷转到了 cmake
环境下,那么这个工具到底有什么魅力吸引着大家呢?无它,软件工程崇尚实用主义,而 cmake
的功能强悍而灵活,趁手的工具用起来!为了从 makefile
下解放大伙的双手,cmake
在设计之初的目标就是奔着用于对程序构建过程进行管理,它会自动对工程生成相应的 makefile
和其它辅助构建信息。
注意:cmake
不是编译器,仅是构建管理工具,比如调度编译器/链接器等等。
cmake
的配置文件 CMakeLists.txt
使用 cmake
来构建工程成功输出目标文件,这个过程需要依赖于配置的设定。而这个设定存放在文件 CMakeLists.txt
中,每个构建工程都至少有一个这样的文件(如果工程有子工程,那么每个子工程又会有对应的配置文件),该文件可按需定制。一般会在工程的根目录下创建这个文件 CMakeLists.txt
。举个栗子,这里有个最简单的配置示例(假设本工程不包含子工程,只有一个源文件 main.cpp 而且存放于工程根目录下):
# 指定最低要求的 cmake 版本 3.10 cmake_minimum_required(VERSION 3.10) # 设置工程名 test project(test) # 指定编译输出可执行结果文件 test, 指定编译源文件 main.cpp add_executable(test main.cpp)
当然,除了把配置内容写在配置文件 CMakeLists.txt
中,还可以在执行 cmake
指令时传入多样化的参数,不过通过传参的方式用起来不灵活而且不利于持续输出的开发理念。同一套产品输出给不同的客户时,可以将不同客户的需求转化为不同的配置文件,分别调用于构建目标结果文件。
CMakeLists.txt
变量CMakeLists.txt
文件内部同样支持变量,包括变量定义和引用等。
eg. 定义变量 USE_CUSTOM_SRC
,并设置默认值 OFF
(如果引用该变量前,没有赋值,那么当前值为默认值):
option (USE_CUSTOM_SRC "something you want to mark" OFF)
或者只是定义变量 USE_CUSTOM_SRC
,并赋值 true
SET(USE_CUSTOM_SRC true)
或者通过调用其它程序并接收输出值,跳过定义,如在调用变量 CMAKE_CURRENT_SOURCE_DIR
代表的目录下执行程序 git
带上参数 "log --format='%h' -1"
以获取 SHA1
值并且保存到变量 GIT_SHA1
中。
exec_program( "git" ${CMAKE_CURRENT_SOURCE_DIR} ARGS "log --format='%h' -1" OUTPUT_VARIABLE GIT_SHA1 )
在调用 cmake
时同样可以在传入的参数中指定变量 USE_CUSTOM_SRC
并赋值,变量前加 -D
,如:
cmake -DUSE_CUSTOM_SRC=ON
在 CMakeLists.txt
中,已定义的变量可直接引用:
if(USE_CUSTOM_SRC) xxx else() xxx endif()
CMakeLists.txt
定义源码相关的宏定义如果需要为源码编译器添加宏定义呢?
如下:
add_definitions(-DUSE_CUSTOM_SRC)
这段语句定义了适用于源代码中的预编译宏 USE_CUSTOM_SRC
, 以 -D
为前缀。
注意:这里的 USE_CUSTOM_SRC
(适用范围是被 cmake 管理的工程源代码) 与上面的 CMakeLists.txt 变量 USE_CUSTOM_SRC
(适用范围是 cmake 读取的 CMakeLists.txt 文件内容内) 不一样。
先说一下我的环境:
WIN10 + WSL Ubuntu 18.4
wsl 环境下要求安装有cmake、gcc、g++ 等基本工具。
首先进入 wsl 环境,看一下当前的工作目录内容:
admin@DESKTOP:/mnt/g/test$ ls -l total 0 -rwxrwxrwx 1 root root 89 Jun 26 16:12 CMakeLists.txt -rwxrwxrwx 1 root root 354 Jun 26 17:13 main.cpp
源文件 main.cpp 实现了执行指令 ls -l .
的功能,下面是文件内容
#include <unistd.h> #include <stdio.h> int main() { pid_t pid = fork(); if (pid == -1) { perror("fork error"); } if (pid == 0) { execl("/bin/ls", "ls", "-l", ".", (char *)NULL); } return 0; }
创建构建输出目录 build,然后导航到输出目录
mkdir build cd build
执行 cmake,输入参数是存放 CMakeLists.txt 文件的相对目录,目的是配置构建工程和生成用于原生构建的必需信息并保存到当前目录文件中,也就是所谓的配置构建系统
admin@DESKTOP:/mnt/g/test/build$ cmake ../ -- The C compiler identification is GNU 7.5.0 -- The CXX compiler identification is GNU 7.5.0 -- Check for working C compiler: /usr/bin/cc -- Check for working C compiler: /usr/bin/cc -- works -- Detecting C compiler ABI info -- Detecting C compiler ABI info - done -- Detecting C compile features -- Detecting C compile features - done -- Check for working CXX compiler: /usr/bin/c++ -- Check for working CXX compiler: /usr/bin/c++ -- works -- Detecting CXX compiler ABI info -- Detecting CXX compiler ABI info - done -- Detecting CXX compile features -- Detecting CXX compile features - done -- Configuring done -- Generating done -- Build files have been written to: /mnt/g/test/build
再次执行 cmake,调用当前目录的构建系统实现项目构建,包括编译/链接和输出二进制目标文件。
admin@DESKTOP:/mnt/g/test/build$ cmake --build . Scanning dependencies of target test [ 50%] Building CXX object CMakeFiles/test.dir/main.cpp.o [100%] Linking CXX executable test [100%] Built target test
这一步的操作其实也可以直接调用make
实现,比如需要用到加速的选项-j
等就比较推荐这样子调用
make -jn
看一下输出的二进制目标文件是否存在
admin@DESKTOP:/mnt/g/test/build$ ls -l total 40 -rwxrwxrwx 1 root root 12704 Jul 12 21:34 CMakeCache.txt drwxrwxrwx 1 root root 512 Jul 12 21:39 CMakeFiles -rwxrwxrwx 1 root root 4847 Jul 12 21:34 Makefile -rwxrwxrwx 1 root root 1552 Jul 12 21:34 cmake_install.cmake -rwxrwxrwx 1 root root 8392 Jul 12 21:39 test
最后执行一下目标文件,看看实际执行结果和代码的意图是否一致
admin@DESKTOP:/mnt/g/test/build$ ./test total 40 -rwxrwxrwx 1 root root 12704 Jul 12 21:34 CMakeCache.txt drwxrwxrwx 1 root root 512 Jul 12 21:39 CMakeFiles -rwxrwxrwx 1 root root 4847 Jul 12 21:34 Makefile -rwxrwxrwx 1 root root 1552 Jul 12 21:34 cmake_install.cmake -rwxrwxrwx 1 root root 8392 Jul 12 21:39 test
好了,简简单单介绍到这里,欢迎留言交流_