编译工具

1 CMake

  • 推荐 out of source builds,输出不混在一起,git 工具好管理,可以创建多个 build,如 debug/release。build 与 source 同一等级,不在 source 内部

  • 在多个平台测试以避免写出平台相关的 cmake

  • 选择编译器和 Generator,两者不同搭配可有不同的 build 目录,只需指定一次

    1
    cmake -B build -G "MinGW Makefiles" -D CMAKE_MAKE_PROGRAM="D:/soft/mingw64/bin/mingw32-make.exe"
  • 生成和编译始终在源码根目录

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    # 生成 build system
    cmake -B build
    # 编译
    cmake --build build
    # verbose and N parallel build
    cmake --build build -v -j N
    # 列出 target
    cmake --build build -t help
    # 编译 target
    cmake --build build -t Tutorial
    cmake --build /pathTo/build --config Debug --target MyApp
    # 列出可设置的选项
    cmake -LH build
    # 设置选项
    -
  • 调试 CMake

    1
    2
    # 用 --trace 打印太多了,所以一般 --trace-source 指定源码根目录的 CMakeLists.txt
    cmake -B build --trace-source="CMakeLists.txt" -DUSE_MYMATH:BOOL=OFF
  • target 可以是虚拟的

  • 变量都是字符串类型,值有空格要加引号,多个值用分号连起来。未定义的变量是空字符串。${} 可以嵌套引用,可作为变量名

  • unset(myVar) / set(myVar) 用来 unset 变量

  • ENV{varName} 修改环境变量,环境变量只影响这次 cmake 执行

  • cache 和普通变量同名,普通变量会掩盖 cache 变量,但在一些情况 P26 会相反,cache 变量会被使用。正因为有同名情况,所以要给一个变量明确置空 set(foo “”) 而非使用 unset(foo)

  • cache 变量的修改需要 force 关键字

  • 命令行定义 cache 变量,建议指定类型;-U 取消定义

  • cmake-gui 一直 (配置 + 点 Configure) 直到没有红色然后点 Generate

  • 给 cache 变量一个下划线结尾的前缀方便 cmake-gui 分组,项目相关的也用前缀方便以后给其它项目使用

  • 文件的 IS_NEWER_THAN 要用 NOT 方式使用,因为 P44

  • 不使用加引号的字符串,避免 3.1 以下版本解释为变量,进行变量替换

  • 函数传参,引号分割的字符串会被当作不同的参数,要注意何时用引号括起来

  • 尽量用函数而非宏来更好隔离

    ubuntu 安装最新 cmake

2 介绍

  • 编译、链接、库 等原理
  • 三要素,目标、依赖、命令,依赖比目标或目标不存在新就执行命令。找到关系树的末端再从末端进行判断,末端比根旧则什么都不做,新则执行命令。
  • 不要用环境变量 MAKEFILES
  • Makefile 的组成
    • 显示规则,我们写的
    • 隐含规则,.o 自动生成 .c 依赖的关系 和 编译命令
    • 变量定义
    • 文件指示
      • include <filename>
      • #if
      • 多行命令
    • 注释,# 转义

3 规则

  • 规则中可以用通配符

  • 变量中的通配符不会展开,除非

    1
    2
    3
    4
    # 文件夹下所有的 .c
    objects := $(wildcard *.c)
    # 文件夹下所有的 .o
    objects := $(patsubst %.c,%.o,$(wildcard *.c))
  • 用 vpath 指定多个搜索目录

  • 伪目标两个作用 1. clean 2. 一次生成多个目标

  • 静态模式与多目标 %,具体看参考

  • 依赖的头文件自动生成的方法,具体看参考

4 命令

  • @ 可以不显示这条命令
  • 语句前加 - 可以忽略错误继续执行
  • 嵌套执行 makefile
    • $(MAKE) -C subdir
    • export variable = value 或者 unexport 或者 export 导出所有变量到下级
    • MAKEFLAGS 和 SHELL 永远被传递给下级,除非见参考文档
  • 常用命令可以定义成命令包

5 变量

建议小写作为变量名,大写作为控制隐含规则和用户重载命令选项时使用

  • 递归展开,无法追加 VAR=var

  • 简单展开 VAR:=var

  • ?= 被定义过什么都不做,没定义则赋值

    变量使用 $(VAR)

  • 预定义变量,比如 CC、RM、CFLAGS

  • 自动变量,比如 $@、$<、$^

  • make 启动时自动创建与系统相同数值的环境变量

6 make

有一些 GNU 约定好的目标表示名称,可以作为写 makefile 的参考,比如 install

用来调试 makefile

参数 作用
-n dry run
-t 只更新(touch)目标的时间,假装编译
-q 看看某个目标在 makefile 中存在吗
–debug 打印调试
-w 打印目录,用来调试嵌套 make 调用

其它参数见 man 或者 上面的参考文档

7 隐含规则

  • C程序隐含规则,$(CC) –c $(CPPFLAGS) $(CFLAGS),其它程序规则见参考文档
  • 隐含规则使用的变量,如 CC、CFLAGS 具体见文档
  • 模式规则 %,与自动化变量。if 判断中不能使用自动化变量