CMake
是比make
更为高级跨平台编译工具,它跨平台、开源的构建系统。
介绍
CMake
通过CMakeLists.txt
文件,使用cmake
命令将CMakeLists.txt
转化为makefile
文件,通过make
命令将源码编译为如下之一:
可执行程序(bin)
共享库(so, shared object)
安装
apt install cmake gcc -y
cmake --help-command add_custom_target
使用
# 设置变量
set(varName value... [PARENT_SCOPE])
# 输出字符串
message([mode] msg1 [msg2]...)
# 字符串
string(SUBSTRING input index length outVar)
# 列表
list(LENGTH listVar outVar)
list(GET listVar index [index...] outVar)
# 数学计算
math(EXPR outVar mathExpr)
参数
CMake
参数说明
add_library
主要作用就是将指定的源文件生成链接文件,然后添加到工程中STATIC 库
是目标文件的归档文件,在链接其它目标的时候使用SHARED 库
会被动态链接(动态链接库
),在运行时会被加载MODULE 库
是一种不会被链接到其它目标中的插件,但是可能会在运行时使用 dlopen- 系列的函数
add_library(<name> [STATIC | SHARED | MODULE]
[EXCLUDE_FROM_ALL]
[source1] [source2] [...])
link_directories
指定要链接的库文件的路径,可通过 find_package
和 find_library
替代target_link_libraries
将目标文件与库文件进行链接
target_link_libraries(<target> [item1] [item2] [...]
[[debug|optimized|general] <item>] ...)
add_subdirectory (source_dir [binary_dir] [EXCLUDE_FROM_ALL])
添加一个子目录并构建该子目录find_library(EXAMPLE_LIB libexample /usr/local/lib)
查找并定位系统上的库文件target_include_directories()
用于为指定的目标添加包含目录
编译
CMake
通常的编译步骤:
mkdir build && cd build
cmake ..
make
说明:
mkdir build
创建编译目录cmake ..
指向CMakeLists.txt
所在的目录,cmake
会生成很多编译的中间文件以及makefile文件make
根据生成makefile
文件,编译程序
CMAKE_BUILD_TYPE
cmake 模式:
cmake -DCMAKE_BUILD_TYPE=Release
cmake -DCMAKE_BUILD_TYPE=Debug
cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo
区别:
man objcopy
Release
--strip-debug
不从源文件中复制调试符号或部分- 调试时,可以指定 symbol
gdb -s xxx.symbol
或在 gdb 命令中加载 symbol-file xxx.symbol
Debug
--only-keep-debug
剥离文件,删除不会被 –strip-debug 剥离的部分内容,保留调试部分
CMAKE_VERBOSE_MAKEFILE
set(CMAKE_VERBOSE_MAKEFILE ON)
或
# 方式一
make VERBOSE=1
# 方式二
export VERBOSE=1
make
compile_commands.json
compile_commands.json 文件能够有效提高一些工具(比如说ccls1, vscode2)的代码跳转、补全等功能,参考
cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON --build .
make
示例
# 1. 要求的cmake最低版本
cmake_minimum_required(VERSION 3.2)
# 2. 添加c++11标准支持
#set( CMAKE_CXX_FLAGS "-std=c++11" )
# 3. 指定项目的名称,一般和项目的文件夹名称对应
PROJECT(test_sqrt)
# 4. 头文件
INCLUDE_DIRECTORIES(
include
)
# 源文件目录
AUX_SOURCE_DIRECTORY(src DIR_SRCS)
# 5. 通过设定SRC变量,将源代码路径都给SRC,如果有多个,可以直接在后面继续添加。若不添加编译能够通过,但是执行的时候会出现各种问题,比如 "symbol lookup error xxxxx , undefined symbol"
SET(SRC
${DIR_SRCS}
)
# 6. 编译主函数,生成可执行文件
# 设置路径
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/build/bin)
# 可执行文件生成
ADD_EXECUTABLE(${PROJECT_NAME} ${SRC})
# 7. 创建共享库/静态库
# 设置路径
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/build/lib)
set(LIB_NAME test_sqrt_lib)
# 创建共享库(把工程内的cpp文件都创建成共享库文件,方便通过头文件来调用)
# 这时候只需要cpp,不需要有主函数
# ${PROJECT_NAME}是生成的库名 表示生成的共享库文件就叫做 lib工程名.so
# 也可以专门写cmakelists来编译一个没有主函数的程序来生成共享库,供其它程序使用
# SHARED为生成动态库,STATIC为生成静态库
add_library(${LIB_NAME} STATIC ${SRC})
# 8. 链接库文件
# 把刚刚生成的${PROJECT_NAME}库和所需的其它库链接起来
# 如果需要链接其他的动态库,-l后接去除lib前缀和.so后缀的名称,以链接 libtestsqrt.so 为例,-ltestsqrt
TARGET_LINK_LIBRARIES(${PROJECT_NAME} m)
# 容器内编译
$ docker run --rm -it gcc:9.5.0 bash
# 安装依赖
$ sed "s#http://deb.debian.org/debian#https://mirrors.tuna.tsinghua.edu.cn/debian/#g" -i /etc/apt/sources.list
$ apt update
$ apt install cmake -y
# 源码初始化,CMakeLists.txt 参考示例文件
mkdir -p test_sqrt/src/ test_sqrt/include/
cat << EOF > test_sqrt/src/main.c
#include "../include/m.h"
#include <stdio.h>
int main(int argc, char** argv)
{
double a = 81.0;
double b = 0.0;
printf("input a: %f\n", a);
b = cal_sqrt(a);
printf("sqrt result: %f\n",b);
return 0;
}
EOF
cat << EOF > test_sqrt/src/m.c
#include "../include/m.h"
double cal_sqrt(double value)
{
return sqrt(value);
}
EOF
cat << EOF > test_sqrt/include/m.h
#ifndef B_FILE_HEADER_INC
#define B_FIEL_HEADER_INC
#include<math.h>
double cal_sqrt(double value);
#endif
EOF
root@2f5346b34906:/# mkdir build && cd build
root@2f5346b34906:/test_sqrt/build# cmake ..
-- The C compiler identification is GNU 9.5.0
-- The CXX compiler identification is GNU 9.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/local/bin/c++
-- Check for working CXX compiler: /usr/local/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: /test_sqrt/build
root@2f5346b34906:/test_sqrt/build# make
Scanning dependencies of target test_sqrt
[ 16%] Building C object CMakeFiles/test_sqrt.dir/src/m.c.o
[ 33%] Building C object CMakeFiles/test_sqrt.dir/src/main.c.o
[ 50%] Linking C executable bin/test_sqrt
[ 50%] Built target test_sqrt
Scanning dependencies of target test_sqrt_lib
[ 66%] Building C object CMakeFiles/test_sqrt_lib.dir/src/m.c.o
[ 83%] Building C object CMakeFiles/test_sqrt_lib.dir/src/main.c.o
[100%] Linking C static library libtest_sqrt_lib.a
[100%] Built target test_sqrt_lib
# 二进制
root@2f5346b34906:/test_sqrt/build# bin/test_sqrt
input a: 81.000000
sqrt result: 9.000000