Linux学习----Makefile

一. Makefile规则

        一个简单的 Makefile 文件包含一系列的“规则”,其样式如下:

目标(target)…: 依赖(prerequiries)…
<tab>命令(command)

        目标(target):通常是要生成的文件的名称,可以是可执行文件或 OBJ文件,
也可以是一个执行的动作名称
        依赖:用来产生目标的材料(比如源文件),一个目标经常有几个依赖。
        命令:生成目标时执行的动作,一个规则可以含有几个命令,每个命令占一
行。        

        例1:

test:a.o b.o
    gcc -o test a.o b.o
a.o : a.c 
    gcc -c -o a.o a.c
b.o : b.c 
    gcc -c -o b.o b.c
clean :
    rm *.o test

        test是要生成的目标文件,a.o b.o是依赖的两个文件,命令是输入<tab>键后的三条语句

        注意:每个命令行前面必须是一个 Tab 字符,即命令行第一个字符是 Tab。这是
容易出错的地方。

        Makefile的核心规则:当“目标文件(test)”不存在,或者某个依赖文件(a.o或者b.o)比目标文件“”,则执行“命令”,此处的“”指的是依赖文件最后的编写时间比目标文件晚。
        

二. Makefile的简单语法

1. 通配符:%.o

        当你需要匹配一组具有相同前缀或后缀的文件时,可以使用通配符。使用通配符后可以将例1改为如下

                例2:

test:a.o b.o
    gcc -o test $^
%.o : %.c
    gcc -c -o $@ $<
clean :
    rm *.o test

       第二行中,$^表示所有依赖文件

        第四行中, $@表示要生成的目标文件$<表示依赖,“<”表示第一个依赖文件,也可在第三行%.c后放其他依赖文件

2. 即时变量、延时变量、export

即时变量(简单变量)的定义:

A := xxx      # A的值即刻确定,在定义时即确定

 延时变量的定义:

B = xxx       # B的值使用到时才确定,在定义/等于时并没有确定下来
B ?= xxx      # 延时变量, 如果是第1次定义才起效, 如果在前面该变量已定义则忽略这句

 附加定义:

C \+= xxx      #它是即时变量还是延时变量取决于前面的定义
D  ?=xxx       #如果这个变量在前面已经被定义了,这句话就会不会起效果,

 综合示例:

A := $(C)    #$表示引用
B = $(C)   
C = abc


D ?= R      #D已经被定义了,所以次表达式不会生效


all:
    @echo A = $(A)  #echo前使用@就不会打印echo
    @echo B = $(B)  #延时变量
    @echo D = $(D)


C += 123   #不管C在哪儿定义,B输出结果都是C

 我们使用命令:make D=1234

最后输出结果时是:

A = 
B = abc 123
D = 1234

 D被定义了,所以代码中的赋值不起作用

3. 假想目标:.PHONY

使用makefile:

make [目标]    # 若无目标,默认第一个目标(示例中的test)

 我们执行 make clean 命令当该路径下不存在名为clean的目标文件时,可以删除test文件,但是当存在一个名为clean的文件时,判断存在clean目标文件,并且没有新的依赖,无法删除test。此时引入假想目标.PHONY,机器就不会判断名为clean的文件是否存在。代码如下:

        例3:

test:a.o b.o
    gcc -o test $^
%.o : %.c
    gcc -c -o $@ $<
clean :
    rm *.o test
.PHONY: clean

三. Makefile相关函数

1. $(foreach var,list,text)

2. $(filter pattern…,text)         #在text中取出符合patten格式的值

    $(filter-out pattern…,text)         #在text中取出不符合patten格式的值 

3. $(wildcard pattern)        #pattern定义了文件名的格式,wildcard取出其中存在的文件

4. $(patsubst pattern ,replacement,$(var))   #将变量var中所有pattern替换成replacement

 综合示例,例4:

A = a b c
B = $(foreach f, $(A), $(f).o)
C = a b c d/
D = $(filter %/,$(C))
E = $(filter-out %/,%(C))
files = $(wildcard *.c)

files2 = a.c b.c c.c d.c e.c
files3 = $(wildcard $(files2))
 
dep_files $(%.c,%.d,$(files2))
all:
    @echo B = $(B)             
    @echo D = $(D)             #输出C中,包含/的值
    @echo E = $(E)             #输出C中,没有/的值
    @echo files = $(files)     #输出当前目录下满足.c结尾文件的名称
    @echo files3 = $(files3)   #输出files2中存在的文件
    @echo dep_files = $(dep_files)  #将files2中的.c后缀替换成.d后缀输出

 使用make命令输出,结果为

B = a.o b.o c.o 
D = d/
E = a b c
files = a.c b.c c. d
files3 = a.c b.c c.c 
dep_files = a.d b.d c.d d.d e.d

四. Makefile示例

 1. 改进:支持头文件依赖

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

gcc -M -MF c.d.c.d                         #把依赖写入文件c.d

gcc -c -o c.o c.c -MD -MF c.d         #编译C.o,把依赖写入文件c.d

2. 添加CFLAGS---编译选项

 例5:

objs = a.o b.o c.o 
dep_files := $(patsubst %,.%d, $(objs))
dep_files := $(wildcard $(dep_files))

CFLAGS = -Werror -I.          #-Werror是将所有警告都改为错误输出
                              #—I.是指定当前目录是编译默认的头文件目录
      
test: $(objs)
    gcc -o test $^

ifneq ($(dep_files),)
include $(dep_files)
endif 

%.o : %.c
    gcc -c -o $@ $< -MD -MF .$@.d            #自动生成依赖

clean:
    rm *.o test
distclean:
    rm $(dep_files)        #删除依赖
.PHONY:clean

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值