CMake 使用介绍

发布时间: 更新时间: 总字数:1485 阅读时间:3m 作者: IP上海 分享 网址

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_packagefind_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

示例

  • CMakeLists.txt 示例
# 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

参考

  1. https://cmake.org/cmake/help/v3.1/
  2. https://github.com/Kitware/CMake/blob/master/Help/guide/tutorial/A%20Basic%20Starting%20Point.rst
Home Archives Categories Tags Statistics
本文总阅读量 次 本站总访问量 次 本站总访客数