Makefile用法总结

Makefile的编译过程

Makefile的编译过程主要为:makefile文件经过maketools编译后处理目标工程。

语法规则

target : depend1 depenp2
        command 1
        command 2
depend1 :
        ...
depend2 :
        ...

注:Makefile本质上不关注命令如何执行,只是依照规则去执行所有的命令
以下是需要关注的点:
1、目标文件的更新是晚于依赖文件的,若依赖未发生改动,则目标文件不需要重新编译,否则需要重新编译,在构建工程时时常会遇到这种情况。
2、一般情况下Makefile中第一个target就是最终需要执行的目标。
3、每条命令前必须要有tab的缩进,语法要求
4、all将打破第二点规则,会构建所有目标

变量相关内容

$符号

$符号表示取变量的值,当变量名多于一个字符时,需要使用"()"
常用方法:

  • $^ 表示所有的依赖文件
  • $@ 表示生成的目标文件
  • $< 代表第一个依赖文件

^ 表示所有的依赖文件。在规则的命令部分中使用 ^ 可以引用所有的依赖文件。例如:

all: main.o helper.o
    gcc $^ -o program

在这个例子中,$^ 将会被扩展为 “main.o helper.o”,因此最终的命令会是 “gcc main.o helper.o -o program”。

$@ 表示生成的目标文件。在规则的命令部分中使用 $@ 可以引用生成的目标文件。例如:

main.o: main.c
    gcc -c $< -o $@

在这个例子中,$@ 将会被扩展为 “main.o”,因此最终的命令会是 “gcc -c main.c -o main.o”。

< 代表第一个依赖文件。在规则的命令部分中使用 < 可以引用第一个依赖文件。例如:

main.o: main.c
    gcc -c $< -o $@

在这个例子中,$< 将会被扩展为 “main.c”,因此最终的命令会是 “gcc -c main.c -o main.o”。

变量赋值

1、"="是最普通的等号,在Makefile中容易搞错赋值等号,使用 “=”进行赋值,变量的值是整个Makefile中最后被指定的值。

VIR_A = A
VIR_B = $(VIR_A) B
VIR_A = AA

经过上面的赋值后,最后VIR_B的值是AA B,而不是A B,在make时,会把整个Makefile展开,来决定变量的值

2、“:=” 表示直接赋值,赋予当前位置的值。

VIR_A := A
VIR_B := $(VIR_A) B
VIR_A := AA

最后BIR_B的值是A B,即根据当前位置进行赋值。因此相当于“=”,“:=”才是真正意义上的直接赋值

3、“?=” 表示如果该变量没有被赋值,赋值予等号后面的值。

VIR ?= new_value

如果VIR在之前没有被赋值,那么VIR的值就为new_value。

VIR := old_value
VIR ?= new_value

这种情况下,VIR的值就是old_value
4、"+="和平时写代码的理解是一样的,表示将符号后面的值添加到前面的变量上

关键函数 wildcard patsubst

SRC = $(wildcard ./*.c)

匹配目录下所有的.c文件,将其赋值给SRC变量。

OBJ = $(patsubst %.c, %.o, $(SRC))

有三个函数,表示将SRC中所有的.c文件替换成.o文件,将结果保存在OBJ变量中,OBJ变量将包含每个.c文件对应.o目标文件名列表。

伪目标

.PHONY

将 .PHONY 添加到目标将防止Make将phony(假)目标与文件名混淆。

some_file:
	touch some_file
	touch clean

.PHONY: clean
clean:
	rm -f some_file
	rm -f clean

在此示例中,如果创建了文件 “clean”,则仍将运行 make clean。

嵌套执行Makefile

-C参数的使用

subsystem:
    $(MAKE) -C subdir

make -C指到子目录上执行

export

将某些变量传递到下级Makefile
如果需要传递所有变量,那么只要一个export就行了。后面什么也不用跟,表示传递所有变量

示例:
假设我们有一个主Makefile main.mk 和一个子Makefile sub.mk,我们希望在 main.mk 中定义的变量能够传递给 sub.mk 使用,可以使用 export 指令。

main.mk:

VAR1 = hello
export VAR1

all:
    @$(MAKE) -f sub.mk


sub.mk:

all:
    @echo "VAR1 from main.mk: $(VAR1)"


在这个示例中,我们定义了一个变量 VAR1,并使用 export 指令将其传递给子 Makefile。然后在 main.mk 的 all 目标中调用 sub.mk。在子 Makefile中,我们可以使用来自主Makefile中的 VAR1 变量。

unexport

如果不想让某些变量传递到下级Makefile,可以使用
示例:

main.mk:

VAR1 = hello
VAR2 = world
export VAR1 VAR2

all:
    @$(MAKE) -f sub.mk


sub.mk:

unexport VAR1
all:
    @echo "VAR1 from main.mk: $(VAR1)"  # 此处不会输出任何东西
    @echo "VAR2 from main.mk: $(VAR2)"  # 输出 "VAR2 from main.mk: world"


在这个示例中,我们使用了 unexport 指令取消了子Makefile对VAR1的继承。因此在子Makefile中,我们无法访问或者使用来自主Makefile的 VAR1 变量。

头文件和库文件目录添加

头文件

"-I"来指定
在Makefile中则可以这样写:

CFLAGS=-I/home/develop/include

库文件

"-L"来指定库的路径
在Makefile中则这样写:

LDFLAGS=-L/usr/lib -L/path/to/your/lib

"-l"来指定库
在Makefile中则这样写:

LIBS = -lxx -lxxxx

Makefile 显示命令和出错命令

显示相关命令

  • Makefile中添加"@"符号,则只执行,不显示命令;
  • make -n 表示只显示命令而不执行;
  • make -s 表示只执行命令而不显示;
  • Makefile中添加"-",表示命令不管怎样都要执行

出错命令

make -i 表示忽略所有错误,强制执行每一条命令;
make -k 表示终止出错指令,继续执行下面的命令;

在Makefile中添加.IGNORE:目标

表示立刻停止该目标和该目标的依赖目标的生成,但是会继续生成此目标之上的其他目标

举例说明:

all: program

program: main.o func.o
	gcc -o program main.o func.o

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

func.o: func.c
	gcc -c func.c


clean:
	rm -f *.o program

.IGNORE: clean

.PHONY: clean

当执行 make clean 时,无论是否出现了清理错误,都应该忽略这些错误,并继续执行make。

Makefile示例

#预定义变量
CC = gcc
#预定义编译目录
SUBDIRS = f1 \
        f2 \
        main \
        obj
#预定义目标
OBJS = f1.o f2.o main.o
BIN = myapp
OBJS_DIR = obj
BIN_DIR = bin
#传递预定义参数
export CC OBJS BIN OBJS_DIR BIN_DIR

all:CHECK_DIR $(SUBDIRS)
CHECK_DIR:
	@mkdir -p $(BIN_DIR)
$(SUBDIRS):ECHO
	@make -C $@ 

ECHO:
	@echo $(SUBDIRS)
	@echo begin compile
clean:
	@$(RM) $(OBJS_DIR)/*.o
	@rm -rf $(BIN_DIR)

参考:https://zhuanlan.zhihu.com/p/575852387

  • 32
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值