快速编写“专家级”makefile(2.创建基本编译环境)

一、运用规则:
先来创建 simple 项目的两个源程序:
foo.c
  
  
  1. #include <stdio.h>
  2. void foo()
  3. {
  4. printf("This is foo ()!\n");
  5. }
main.c
  
  
  1. #include <stdio.h>
  2. extern void foo();
  3. int main()
  4. {
  5. foo();
  6. return 0;
  7. }
    对于项目,在编写 Makefile 时,应该首先在脑子里勾勒出 Makefile 的依赖关系。
    对于 simple 可执行程序来说,上图就是它的 “依赖树” 。有了它,Makefile 的编写就会变得轻松许多。
 
    上图展示了依赖关系与规则间的映射。
   
   
  1. all : main.c foo.o
  2. gcc -o simple main.c foo.o
  3. main.o : main.c
  4. gcc -o main.c -c main.c
  5. foo.o : foo.c
  6. gcc -o foo.o -c foo.c
  7. clean :
  8. rm simple main.o foo.o
    运行结果(终端):
$ make
gcc -c main.c -o main.o    
gcc -c foo.c -o foo.o 
gcc -o simple main.o foo.o
$ make clean
rm simple main.o foo.o
    在不修改源程序文件的情况下再执行一次 make ,出现以下结果:
$ make
gcc -o simple main.o foo.o
    第二次编译并没有构建目标文件的动作,但有构建 simple 的动作。
  1. make 在第二次执行时,首先查找是否存在 all 目标,若有就不执行其后面的命令,若没有,则执行。
  2. make 是通过文件的时间戳来判断哪些文件需要重新编译。 make 在分析一个规则以创建目标时,如果发现先决条件中文件的时间戳大于目标文件的时间戳,即目标文件比先决条件中的文件更新,就需要运行规则中命令重新构建目标。

假目标:
  
  
  1. .PHONY : clean
  2. simple : main.o foo.o
  3. gcc -o simple main.o foo.o
  4. main.o : main.c
  5. gcc -o main.o -c main.c
  6. foo.o : foo.c
  7. gcc -o foo.o -c foo.c
  8. clean:
  9. rm -rf simple main.o foo.o
    运行结果:
$ make clean
rm -rf simple main.o foo.o
    采用 .PHONY 关键字声明一个目标后,make 并不会将其当作一个文件来处理。由于假目标不与一个文件关联,故无论 clean 文件是否存在,它都执行;

运用 “变量”
   
   
  1. .PHONY : clean
  2. CC = gcc
  3. RM = rm
  4. EXE = simple.exe
  5. OBJS = main.o foo.o
  6. $(EXE) : $(OBJS)
  7. $(CC) -o $(EXE) $(OBJS)
  8. main.o : main.c
  9. $(CC) -o main.o -c main.c
  10. foo.o : foo.c
  11. $(CC) -o foo.o -c foo.c
  12. clean :
  13. $(RM) -rf $(EXE) $(OBJS)
    引用变量需要采用 “$(变量名)” 或 “${变量名}” 的形式。

1.自动变量:
  • $@ : 用于表示一个规则中的目标。当一个规则中有多个目标时,$@ 所指的是其中任何造成规则命令被运行的目标
  • $^:表示规则中所有的先决条件
  • $<:表示规则中第一个先决条件
    
    
  1. .PHONY : all
  2. all : first second third
  3. @echo "\$$@ = $@"
  4. @echo "$$^ = $^"
  5. @echo "$$< = $<"
  6. first second third :
    运行结果:
$make
$@ = all
$^ =  first second third
$< = first
         注意:
  1. 在 Makefile 中 “$” 具有特殊含义,如果采用 echo 输出 “$” ,则必须用两个连着的 “$”;
  2. “$@” 对于 Bash Shell 也有特殊含义,需要在 “$$@” 之前再加一个脱字符 “\” (引号不包括在内)
          
          
    1. .PHONY : clean
    2. CC = gcc
    3. RM = rm
    4. EXE = simple
    5. OBJS = main.o foo.o
    6. &(EXE) : $(OBJS)
    7. $(CC) -o $@ $^
    8. main.o : main.c
    9. $(CC) -o $@ -c $^
    10. foo.o : foo.c
    11. $(CC) -o $@ -c $^
    12. clean :
    13. $(RM) -rf $(EXE) $(OBJS)
2.特殊变量:
  • MAKE
  • MAKECMDGOALS
    
    
  1. .PHONY : all
  2. all :
  3. @echo "MAKE = $(MAKE)"
    运行结果:
$make
MAKE = make
    $(MAKE) 的值就是 “make” ,当在一个 Makefile 中运行另一个 Makefile 时,需要用到这个变量。
   
   
  1. .PHONY : all clean
  2. all clean :
  3. $echo "\$$@ = $@"
  4. $echo "MAKECMDGOALS = $MAKECMDGOALS"
    运行结果:
$make
$@ = all
MAKECMDGOALS =
$make all
$@ = all
MAKECMDGOALS = all
$make clean
$@ = clean
MAKECMDGOALS = clean
$make all clean
$@ = all
MAKECMDGOALS = all
$@ = cleanl
MAKECMDGOALS = clean
    从运行结果:
  1. MAKECMDGOALS 变量指的是用户输入的目标,当 make 不带参数时,MAKECMDGOALS 为空,即使前面我们所提到 make 不带参数时 即生成默认目标。
  2. make 后可带多个参数,表示构建多个目标,其将从左到右逐个构建目标。

3.变量的类别与赋值:        
       =       
  
  
  1. .PHONY : all
  2. foo = $(bar)
  3. bar = $(ugh)
  4. ugh = Huh?
  5. all :
  6. @echo $(foo)
    运行结果
$make
Huh?
    只用 “=” 符号定义的变量称为递归扩展变量,它的引用时递归的,容易出现死循环。

     :=
   
   
  1. .PHONY : all
  2. x = foo
  3. y = $(x) b
  4. x = later
  5. xx := foo
  6. yy := &(xx) b
  7. xx := later
  8. all :
  9. @echo "x = $(y), xx = $(yy)"
    运行结果
$make
x = later  b, xx = foo  b
     用 “:=” 定义的变量称为简单扩展变量,make 只对其展开一次。
实例:
   
   
  1. .PHONY : all
  2. obj = main.o foo.o bar.o
  3. obj := $(obj) another.o
  4. all :
  5. @echo $(obj)
    运行结果
$make
main.o foo.o bar.o another.o
 
     ?=
  
  
  1. .PHONY : all
  2. foo = x
  3. foo ?= y
  4. bar ?= y
  5. all :
  6. @echo "foo = $(foo), bar = $(bar)"
    运行结果
$make
foo = x, bar = y
    当用到 “?= ” 若变量被定义了,不改变其原值,若变量没有被定义,则将右边的值赋值给它。

     +=
  
  
  1. .PHONY : all
  2. obj = main.o foo.o bar.o
  3. obj += another.o
  4. all :
  5. @echo $(obj)
    运行结果
$make
main.o foo.o bar.o another.o
    通过 “+=” 实现追加赋值,其效果与 “:=” 完全一样。

4.变量的来源:
     除了在 Makefile 中直接定义变量外,还可以有其他几种方式是 make 获得变量值
  1. 对于自动变量,它的值是每一条规则根据上下文自动获取。
  2. 在运行 make 时, 可以使用 “make bar = x” 的形式对变量 bar 进行赋值。
  3. 变量也可以来自于 Shell 环境, 采用 export 命令定义变量,如(?=):
$make
foo = x, bar = y
$export bar = x
$make
foo = x, bar = x

5.高级变量的引用:
  
  
  1. .PHONY : all
  2. foo = a.c b.c c.c
  3. bar := $(foo : .c = .o)
  4. all :
  5. @echo "bar = $(bar)"
    运行结果
$make
bar = a.o b.o c.o
    从运行结果:
  1. bar 变量中的文件名从 .c 后缀变成了 .o
  2. 这种功能可用后面介绍的 patsubst 函数

6.避免变量被覆盖:
  
  
  1. .PHONY : all
  2. override foo = x
  3. all :
  4. @echo "foo = $(foo)"
    运行结果
$make foo = ha
foo = x
    从运行结果:
          根据上面的 “4.变量的来源” 所提, 变量的值可以有 make 来获取,若我们在设计 Makefile 时不希望它的值自定义后再被修改,可在变量前加上 “override“ 来进行保护。

二、采用精简规则
  
  
  1. .PHONY : clean
  2. CC = gcc
  3. RM = rm
  4. EXE = simple.exe
  5. OBJS = main.o foo.o
  6. $(EXE) : $(OBJS)
  7. $(CC) -o $@ $^
  8. %.o : %.c
  9. $(CC) -o $@ -c $^
  10. clean :
  11. $(RM) -rf $(EXE) $(OBJS)
参考文献:《专业嵌入式软件开发》李云·著                                                                                      2016年7月2日,星期六
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值