How 2 GNU Makefile

GCC、CMake、CMakelist、Make、Makefile、Ninja啥关系?

https://zhuanlan.zhihu.com/p/638986464

Makefile advantage

  1. 管理代码的编译,决定该编译什么文件,编译顺序,以及是否需要重新编译;
  2. 节省编译时间。如果文件有更改,只需重新编译此文件即可,无需重新编译整个工程;
  3. 一劳永逸。Makefile通常只需编写一次,后期就不用过多更改。

命名规则

Makefilemakefile

其他名字需要 make -f filename

基本规则

<target> : <prerequisites> 
[tab] <commands>
  • 只有当target不存在,或这prerequisites里的文件比target新是才会执行commands

  • 多个目标文件用空格隔开,可以用\来换行

  • 注释 #单行

  • make 没有指定文件时,默认会执行Makefile文件的第一个目标

  • .PHONY 多个可以用空格分开

    .PHONY: clean
    clean:
    rm *.o temp
    # make clean

    声明clean是”伪目标”之后,make就不会去检查是否存在一个叫做clean的文件,而是每次运行都执行对应的命令,解决当前文件夹下有个clean的冲突

  • 伪目标,即没有commands

    source: file1 file2 file3

    make source相当于

    $ make file1
    $ make file2
    $ make file3
  • @可以关闭commands的回显

  • %模式匹配,匹配文件夹下每一个符合文件

    模式规则是在目标及依赖条件中使用%来匹配对应的文件,比如在目录下有main.c, func1.c, func2.c三个文件,对这三个文件的编译可以由一条规则完成:

    %.o:%.c $(CC) –c $< -o $@

  • - :表示此命令即使执行出错,也依然继续执行后续命令

  • include 引用其它的Makefile

变量

类似于c语言的macro

用=号赋值

用$()取值

VARIABLE = value
# 在执行时扩展,允许递归扩展。

VARIABLE := value
# 在定义时扩展。恒等于

VARIABLE ?= value
# 只有在该变量为空时才设置值。

VARIABLE += value
# 将值追加到变量的尾端。

自动变量

$@    规则中的目标

$< 规则中的第一个依赖条件

$^ 规则中的所有依赖条件
app: main.c func1.c fun2.c
gcc $^ - o $@
其中:$^表示main.c func1.c fun2.c,$<表示main.c,$@表示app。

$*   不包含扩展名的目标文件名称。

$+   所有的依赖文件,以空格分开,并以出现的先后为序,可能包含重复的依赖文件。

$?   所有的依赖文件,以空格分开,这些依赖文件的修改日期比目标的创建日期晚。

$@   目标的完整名称。

函数

wildcard:

用于查找指定目录下指定类型的文件,参数就是目录+文件类型,比如:

src = $(wildcard ./src/*.c)

这句话表示:找到./src 目录下所有后缀为.c的文件,并赋给变量src。

patsubst:

匹配替换,例如以下例子,用于从src目录中找到所有.c 结尾的文件,并将其替换为.o文件,并赋值给obj。

obj = $(patsubst %.c ,%.o ,$(src))

把src变量中所有后缀为.c的文件替换成.o。

特别地,如果要把所有.o文件放在obj目录下,可用以下方法:

ob = $(patsubst ./src/%.c, ./obj/%.o, $(src))

subst

subst 函数用来文本替换,格式如下

$(subst from,to,text)
$(subst ee,EE,feet on the street)
将字符串"feet on the street"替换成"fEEt on the strEEt"。

例子

目录

hello/
├──main.c
├──factorial.c
├──printhello.c
└──functions.h
CC = gcc
TARGET = hello
SRC=$(wildcard ./*.c)
OBJ=$(patsubst ./%.c,./%.o,$(SRC))

GCCFLAGS= -c -Wall

$(TARGET):$(OBJ)
$(CC) -o $@ $^

%.o:%.c
$(CC) $(GCCFLAGS) $< -o $@

.PHONY: clean
clean :
rm -f *.o $(TARGET)