侧边栏壁纸
博主头像
Into The Abyss 博主等级

My Life is a Death Race

  • 累计撰写 34 篇文章
  • 累计创建 7 个标签
  • 累计收到 4 条评论

目 录CONTENT

文章目录

Makefile学习

Administrator
2023-11-17 / 0 评论 / 0 点赞 / 317 阅读 / 0 字

当前文件目录如下

├── includes
│   ├── a.h
│   └── b.h
├── lib
├── Makefile
└── src
    ├── a.c
    └── b.c

基本语法规则

目标:依赖
[tab]命令

目标:要生成的目标文件名

依赖:生成目标文件所依赖的文件名

[tab]键不能少,且必须为[tab],不能是空格

命令:生成目标文件要执行的命令

main:main.c
    gcc main.c -o main

上面的Makefile就等价于gcc main.c -o main,只需要执行make命令就可以。

赋值

=:使用赋值符“=”设置的变量,它的值在运行时才能确定,这称为“延时变量”。

PARA = 100
CURPARA = $(PARA)
PARA = ask

print:
    @echo $(CURPARA)

输出为:ask

:=:使用“:=”设置的变量被称为“即时变量”,在赋值时就确定了它的值。

PARA = 100
CURPARA := $(PARA)
PARA = ask

print:
    @echo $(CURPARA)

输出为:100

?=:使用“?=”给变量设置值时,如果这个变量之前没有被设置过,那么“?=”才会起效果;如果曾经设置过这个变量,那么“?=”不会起效果。

+=:需要给前面已经定义好的变量添加一些字符串进去,此时就要使用到符号“+=”

系统自带变量

  1. CC C 编译器的名称,默认为 “cc”。

  2. CXX C++ 编译器的名称,默认为 “g++”。

  3. CPP C 预处理器的名称,默认为 “cc -E”。

  4. LD 链接器的名称,默认为 “cc”。

  5. AR 静态库归档工具的名称,默认为 “ar”。

  6. AS 汇编器的名称,默认为 “as”。

  7. RM 删除文件的命令,默认为 “rm -f”。

  8. CFLAGS C 编译器的选项。

    优化选项: 通过设置 -O(或 -O1-O2-O3 等级)来控制代码的优化级别。更高的优化级别可能会使生成的可执行文件更高效,但也可能增加编译时间。

    警告选项: 使用 -Wall 开启更多的警告信息,帮助发现潜在的代码问题。你也可以使用 -Werror 将警告视为错误。

    调试信息: 使用 -g 选项添加调试信息,以便在调试时能够更容易地跟踪代码。

    宏定义: 使用 -D 选项定义预处理宏。这对于在编译时为代码中插入条件编译非常有用。

    其他选项: 你可以根据需要添加其他编译选项,如指定头文件搜索路径 -I,链接库路径 -L,链接库 -l 等。

  9. CXXFLAGS C++ 编译器的选项。可选和CFLAGS类似

    C++ 标准: 使用 -std 选项指定要使用的 C++ 标准版本。例如,-std=c++11 表示使用 C++11 标准。

  10. LDFLAGS 链接器的选项。

    库搜索路径: 使用 -L 选项指定链接器搜索库文件的路径。这对于链接需要的库文件位于非标准路径的情况非常有用。

    库链接: 使用 -l 选项指定要链接的库。例如,-lmylibrary 将链接名为 libmylibrary.so(或 libmylibrary.a)的库。

    其他库链接选项: 你可以添加其他与库链接相关的选项,如 -static(静态链接)或 -shared(共享库)。

    输出文件名: 使用 -o 选项指定生成的可执行文件的名称。

    其他链接选项: 你可以添加其他与链接器相关的选项,如 -Wl,--export-dynamic

  11. CPPFLAGS C 预处理器的选项。

    头文件搜索路径: 使用 -I 选项指定预处理器搜索头文件的路径。这对于包含不在标准路径中的头文件非常有用。

    宏定义: 使用 -D 选项定义预处理宏。这对于在编译时为代码中插入条件编译非常有用。

    其他预处理器选项: 你可以添加其他与预处理器相关的选项,如 -E(只运行预处理器)。

  12. LIBS 需要链接的库。

    链接标准库: 使用 -l 选项指定要链接的标准库。例如,链接数学库可以使用 -lm

    链接自定义库: 使用 -l 选项指定要链接的自定义库。

    指定库文件路径: 使用 -L 选项指定链接器搜索库文件的路径。LIBS = -L/path/to/lib -lmylibrary

  13. SHELL Shell 的名称,默认为 “/bin/sh”。

自动变量

  • $@:规则中的目标
  • $<:规则中的第一个依赖文件
  • $^:规则中的所有依赖文件

规则模式

模式规则是在目标及依赖中使用%来匹配对应的文件

CC = gcc
OBJ = main.o add.o sub.o
output: $(OBJ)
    $(CC) -o $@ $^
%.o: %.c
    $(CC) -c $<

clean:
    rm $(OBJ) output

在上述例子之中,output依赖于$(OBJ)$(OBJ)又代表了main.o add.o sub.o,系统发现没有main.o add.o sub.o这三个.o文件,发现了Makefile中的%.o: %.c命令,执行了对应文件的编译。

伪目标

.PHONY: clean

clean:
    rm -f *.o my_program

.PHONY 是一个在 Makefile 中常见的用法,用于定义伪目标,防止与实际文件冲突。

常用函数

wildcard:用于查找指定目录下指定类型的文件

patsubst:用于匹配替换

foreach:用于遍历

subst:用于文本匹配替换

strip:去掉前导和结尾空格,并将中间的多个空格压缩为单个空格

findstring:用于字符串查找

filter:用于过滤出格式匹配的项

filter-out:函数 filter 的反函数,过滤出格式不匹配的项

sort:将输入列表按字母顺序排序,并去掉重复的项

dir:获取输入中每一个文件名的路径部分,文件名的路径部分包括从文件名的首字符到最后一个斜杠(含斜杠)之前的一切字符

notdir:获取输入列表中每一个文件名中除路径部分外一切字符(真正的文件名)

suffix:获取输入列表中每一个文件名的后缀

basename:获取输入列表中每一个文件名中除后缀外一切字符

addsuffix:为输入列表中的每个项添加后缀

addprefix:为输入列表中的每个项添加前缀

测试makefile

SRC = $(wildcard ./src/*.c)  
OBJ = $(patsubst %.c, %.o, $(SRC))
dirs := includes src
files := $(foreach dir,$(dirs),$(wildcard $(dir)/*))
print:
    @echo "SRC = $(SRC)"
    @echo "OBJ = $(OBJ)"
    @echo "files = $(files)"
    @echo "$(subst ee,EE,feet on the street)"
    @echo "$(strip  a   b   c  )"
    @echo "$(findstring a,a b c)"
    @echo "$(findstring a,b c)"
    @echo "$(filter %.c %.s,foo.c bar.c baz.s ugh.h)"
    @echo "$(filter-out %.c %.s,foo.c bar.c baz.s ugh.h)"
    @echo "$(sort foo bar lose baa)"
    @echo "$(dir $(SRC))"
    @echo "$(notdir $(SRC))"
    @echo "$(suffix src/foo.c src-1.0/bar.c hacks)"
    @echo "$(basename src/foo.c src-1.0/bar.c hacks)"
    @echo "$(addsuffix .c,foo bar)"
    @echo "$(addprefix src/,foo bar)"

输出

SRC = ./src/a.c ./src/b.c  
OBJ =  ./src/a.o  ./src/b.o
files = includes/a.h includes/b.h src/a.c src/b.c
fEEt on the strEEt
a b c
a

foo.c bar.c baz.s
ugh.h
baa bar foo lose
./src/ ./src/
a.c b.c
.c .c
src/foo src-1.0/bar hacks
foo.c bar.c
src/foo src/bar

makefile模板

VERSION = 1.0.0
SOURCE = $(wildcard ./src/*.c)
OBJECT = $(patsubst %.c, %.o, $(SOURCE))

INCLUEDS = -I ./includes

TARGET = test
CC = gcc
CFLAGS = -Wall -g

$(TARGET): $(OBJECT)
    @mkdir -p output/
    $(CC) $^ $(CFLAGES) -o output/$(TARGET)_$(VERSION)

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

.PHONY:clean
clean:
    @rm -rf $(OBJECT) output/

补充

gcc -M c.c            // 打印出依赖

gcc -M -MF c.d c.c            // 把依赖写入c.d

gcc -c -o c.o c.c -MD -MF c.d           // 编译c.o,把依赖写入c.d

-M 只生成包含头文件依赖关系的 Makefile 规则,而不生成目标文件

-MD 让 GCC 生成一个 Makefile 依赖关系文件

-MF c.d 指定生成的依赖关系文件的名称为 c.d

一般来说,-MD-MF不是 CFLAGS 的一部分,而是作为额外的选项传递给编译器。在 Makefile 中,你可以将它们添加到相应的规则中,

CFLAGS = -Wall -O2
CC = gcc

%.o: %.c
    $(CC) -c -o $@ $< $(CFLAGS) -MD -MF $*.d
0

评论区