uboot和系统移植----------2、补基础之Makefile

Author: 想文艺一点的程序员
自动化专业 工科男
再坚持一点,再自律一点
CSDN@想文艺一点的程序员
来自朱有鹏嵌入式的学习笔记

一、Makefile基础回顾

1、Makefile的作用和意义

  • 工程项 目中c文件太多管理不方便,因此用Makefile来做项目管理,方便编译链接过程。

  • uboot和linux kernel本质上都是C语言的项目,都由很多个文件组成,因此都需要通过Makefile来管理。所以要分析uboot必须对Makefile有所了解。

2、目标、依赖、命令

  • 目标就是我们要去make xxx的那个xxx,就是我们最终要生成的东西
    最上面的目标是默认目标,所以我们直接make 210.bin 和 make 得到的效果是一样的
  • 依赖是用来生成目录的原材料
  • 命令就是加工方法,

所以make xxx的过程其实就是使用命令将依赖加工成目标的过程

3、通配符%和Makefile自动推导(规则)

  • %是Makefile中的通配符,代表一个或几个字母。也就是说%.o就代表所有以.o为结尾的文件

  • 所谓自动推导其实就是Makefile的规则。
    当Makefile需要某一个目标时,他会把这个目标去套规则说明,一旦套上了某个规则说明,则Makefile会试图寻找这个规则中的依赖,如果能找到则会执行这个规则用依赖生成目标。
    理解:

led.bin: start.o led.o
	arm-linux-ld -Ttext 0x0 -o led.elf $^
	arm-linux-objcopy -O binary led.elf led.bin
	arm-linux-objdump -D led.elf > led_elf.dis
	gcc mkv210_image.c -o mkx210
	./mkx210 led.bin 210.bin
	
%.o : %.S
	arm-linux-gcc -o $@ $< -c -nostdlib

%.o : %.c
	arm-linux-gcc -o $@ $< -c -nostdlib

当我们在 linux 界面下make 的时候,我们渴望生成一个 led.bin

第一步:需要依赖(原材料), .o 文件。
第二步:如果没有 .o 文件,我们就会找对应的规则, 我们找到了下面的编译命令。
第三步:编译命令,将我们的 .S 文件编译成 .O 文件,需要的依赖就是所有的 .S 文件。
第四步:依靠下面的命令,来进行加工,生成 .o 文件, 然后再用所有的 .o 文件加工生成 .bin 文件

4、Makefile中定义和使用变量

Makefile中定义和使用变量,和shell脚本中非常相似。相似是说:都没有变量类型,直接定义使用,引用变量时用$var

objs := start.o led.o clock.o uart.o main.o pwm.o
objs += lib/libc.a

pwm.bin: $(objs)

5、伪目标(.PHONY)

clean:
	rm *.o *.elf *.bin *.dis mkx210 -f
	cd lib; make clean; cd ..

这里的 clean 目标:并不是一个文件,也不是为了生成一个 clean 文件。
我们这样做只是单纯,想执行下面的命令。

  • 伪目标意思是这个目标本身不代表一个文件执行这个目标不是为了得到某个文件或东西,而是单纯为了执行这个目标下面的命令

  • 伪目标一般都没有依赖,因为执行伪目标就是为了执行目标下面的命令。既然一定要执行命令了那就不必加依赖,因为不加依赖意思就是无条件执行。

  • 伪目标可以直接写,不影响使用;但是有时候为了明确声明这个目标是伪目标会在伪目标的前面用.PHONY来明确声明它是伪目标

.PHONY clean
clean:
	rm *.o *.elf *.bin *.dis mkx210 -f
	cd lib; make clean; cd ..

6、Makefile的文件名
Makefile的文件名合法的一般有2个:Makefile或者makefile

7、Makfile中 引用其他Makefile(include指令)
有时候Makefile总体比较复杂,因此分成好几个Makefile来写。然后在主Makefile中引用其他的,用include指令来引用。引用的效果也是原地展开,和C语言中的头文件包含非常相似。

二、Mafile补充学习

1、Makefile中的注释用#
Makefile中注释使用#,和shell一样。

2、命令前面的@用来静默执行

  • 在makefile的命令行中前面的@表示静默执行。
  • Makefile中默认情况下在执行一行命令前会先把这行命令给打印出来然后再执行这行命令
  • 如果你不想看到命令本身,只想看到命令执行就静默执行即可。

3、Makefile中几种变量赋值运算符

(1) = 最简单的赋值
(2 ) := 一般也是赋值
以上这两个大部分情况下效果是一样的,但是有时候不一样。

  • 用=赋值的变量,在被解析时他的值取决于最后一次赋值时的值,所以你看变量引用的值时不能只往前面看,还要往后面看。
A=abc
B=$(A)def
A=gh
all:
        echo $(B)

执行结果:
echo ghdef
ghdef
  • 用:=来赋值的,则是就地直接解析,只用往前看即可。
A=abc
B:=$(A)def
A=gh
all:
        echo $(B)

执行结果:
echo abcdef
abcdef

(3) ?= 如果变量前面没有定义则执行这条赋值如果前面已经定义过了则本行被忽略。(实验可以看出:所谓的没有赋值过其实就是这个变量没有被定义过,)

举例: 我们只进行定义。

var=               // 表示定义了一个 var 的变量
var ?= "efgh"
all:
        echo $(var)

执行结果: //说明现在这个变量并没有被赋值为 "efgh"
echo 

(4) += 用来给一个已经赋值的变量接续赋值,意思就是把这次的值加到原来的值的后面,有点类似于strcat。(在shell makefile等文件中,可以认为所有变量都是字符串,+=就相当于给字符串stcat接续内容)(注意一个细节,+=续接的内容和原来的内容之间会自动加一个空格隔开)

var="abcd"               // 表示定义了一个 var 的变量
var += "efgh"
all:
        echo $(var)

执行结果: 
echo "abcd" "efgh"    // 上面命令行前面没有 @ ,所以会默认将命令打印出来
abcd efgh			// 会自动添加空格

注意:Makefile中并不要求赋值运算符两边一定要有空格或者无空格,这一点比shell的格式要求要松一些。

4、Makefile的环境变量

  • makefile中用export导出的就是环境变量。一般情况下要求环境变量名用大写普通变量名用小写

  • 环境变量和普通变量不同,可以这样理解:环境变量类似于整个工程中所有Makefile之间可以共享的全局变量,而普通变量只是当前本Makefile中使用的局部变量。所以要注意:定义了一个环境变量会影响到工程中别的Makefile文件,因此要小心

  • Makefile中可能有一些环境变量可能是makefile本身自己定义的内部的环境变量或者是当前的执行环境提供的环境变量

(譬如我们在make执行时给makefile传参。make CC=arm-linux-gcc,其实就是给当前Makefile传了一个环境变量CC,值是arm-linux-gcc。我们在make时给makefile传的环境变量值优先级最高的,可以覆盖makefile中的赋值)。

这就好像C语言中编译器预定义的宏 __LINE__ __FUNCTION__ 等一样。

5、Makefile中使用通配符

(1) * 若干个任意字符
(2) ? 1个任意字符
(3) [] 将[]中的字符依次去和外面的结合匹配

还有个%,也是通配符,表示任意多个字符,和*很相似,但是%一般只用于规则描述中,又叫做规则通配符
在这里插入图片描述

6、Makefile的自动变量

  • 为什么使用自动变量。在有些情况下文件集合中文件非常多,描述的时候很麻烦,所以我们Makefile就用一些特殊的符号来替代符合某种条件的文件集,这就形成了自动变量。

  • 自动变量的含义:预定义的特殊意义的符号。就类似于C语言编译器中预制的那些宏__FILE__一样。

  • 常见自动变量:
    在这里插入图片描述

$@ :规则的目标文件名
$< :规则的依赖文件名
$^ :依赖的文件集合

猜你喜欢

转载自blog.csdn.net/vincent3678/article/details/108338745