历程:
led.bin: led.o
al-ld -Ttext 0x0 -o led.elf $^
al-objcopy -O binary led.elf led.bin
al-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
%.o : %.c
arm-linux-gcc -o $@ $< -c
clean:
rm *.o *.elf *.bin *.dis mkx210 -f
Makefile
目标: 目标是定格写, 在于冒号的前面
依赖:依赖是用来产生的原材料。
命令:命令的前面一定是Tab,命令就是执行的动作,执行命令之后生成目标。
譬如上面的led.bin 就是目标.
led.o 就是依赖,
后面的几句都是命令,
具体分析命令
arm-linux-ld -Ttext 0x0 -o led.elf $^
将所有的依赖的目标文件进行链接,以-Ttext 0x0 为链接基地址, -o 指定名字为 ledl.elf 链接所得到的东西
$^ : 所有的依赖目标的集合,以空格分隔。 如果在依赖目标中有多个重复的,那这个变量会去除重复的依赖目标,只保留一份。
arm-linux-ld 为交叉编译工具包中的一个工具。 这里是一个链接符号。 实际工作的是gcc的链接器。
al-objcopy -O binary led.elf led.bin
al-objcopy 也是gcc交叉编译工具包中的一个工具,作用是制作镜像的, 将led.elf 制作成 led.bin
al-objdump -D led.elf > led_elf.dis
al-objdump 也是gcc交叉编译工具包中的一个工具 , 这个是反汇编的一个工具, 将led.elf 给反编译成对应的程序。
gcc mkv210_image.c -o mkx210
./mkx210 led.bin 210.bin
最后那两句是使用 gcc 编译 mkv210_image.c 程序 得到mkx210 执行程序
接着./mkx210执行 而这个执行程序是将 led.bin 得到 210.bin。具体要看这个mkv210_image.c的代码.
%.o : %.S
arm-linux-gcc -o $@ $< -c
@表示规则中的目标文件集,在模式规则中,如果有多个目标,那么,@ 表示规则中的目标文件集, 在模式规则中,如果有多个目标, 那么,@表示规则中的目标文件集,在模式规则中,如果有多个目标,那么,@ 就是匹配于目标中模式定义的集合。 这里表示所有的.o文件
$< 依赖目标中的第一个目标名字,如果依赖目标是以模式(即“%”)定义的。 那么 $< 将是符合模式的一系列的文件集, 注意,其实是一个一个取出来的。
-c 为只编译不链接
clean:
rm *.o *.elf *.bin *.dis mkx210 -f
clean 不是一个文件, 它只不过是一个动作的名字, 有点像C语言中的lable一样, 其冒号后什么也没有,那么, make就不会自动去找文件的依赖性,也就不会自动执行其后所定义的命令。
像clean 这种, 没有被第一个目标文件直接或间接关联,那么它后面所定义的命令将不会自动被执行。 不过,我们可以显示要make执行,即 “make clean”, 以此来执行其命令, 即为rm 删除命令
2019年3月26日22:07:02
在学习 移植 uart stdio 的时候学到的makefile 的知识
首先说一下 linux 中的.a文件其实就是一个静态库, 由多个.o文件集合在一起. 用于静态链接
Makefile 的变量
CC = al-gcc
LD = al-ld
OBJCOPY = al-abjcopy
OBJDUMP = al-objdump
AR = al-ar
objs := start.o led.o clock.o uart.o main.o
代码中的CC LD OBJCOPY OBJDUMP AR objs其实都是变量
所代表的值就是 后面= 或者 := 后面的含义
至于 = 和 := 的区别
有段代码
x = nihao
y = $(x)
x = shijie
test1: test1.cpp
@echo $(y)
执行make后, 结果为shijie,
x = nihao
y := $(x)
x = shijie
test1: test1.cpp
@echo $(y)
执行make后, 结果为nihao
按照自己的理解 使用= 赋值, 当所赋的值为变量, 当变量发生改变, 那么 被赋给的值变量也会随之改变.
而使用:= 是当所赋值的值为变量, 当变量发生改变, 则被赋给的值的变量不会随之改变, 只保留赋值时的状态.
调用变量就是$(变量名)
INCDIR := $(shell pwd)
#C预处理器的flag, flag就是编译器可选的选项
CPPFLAGS := -nostdlib -nostdinc -I$(INCDIR)/include
# C编译器的flag
CFLAGS := -Wall -O2 -fno-builtin
CPPFLAGS C预处理器的flag, flag就是编译器可选的选项
CFLAGS C编译器的flag
-nostdlib 不调用编译器的标准库文件
-nostdinc 不调用编译器的标准头文件
-I 指制定路径 例子中的 -I$(INCDIR)/include 表示 先 $ (shell pwd) 指定当前路径,随后/include 即表示当前路径下的include文件夹
-Wall 表示所有的警告都报警告
-O2表示编译器的优化程度, 数字越大,优化越厉害, 譬如 -O1就没有比-O2优化的多
-fno-builtin 同样的表示编译链接只编译工程中的文件, 不包含其他标准库或头文件信息.
2019年4月7日10:29:46
在以往中会出现多层makefile, 并且,多层makefile不在同一层目录中, 就需要到子文件夹中去make里面的makefile.
有两种方式:
第一种:
lib/libc.a:
cd lib; make; cd ..
先定义一个目标, 然后分三步, 先cd lib(一个子文件夹)
然后执行make 指令, 然后再cd …
这是make的
同样的, 需要make clean,
clean:
cd lib; make clean; cd ..
一样的, 定义一个clean目标, 然后进入子目录, 接着make clean 最后退出来
第二种方式:
all:
make -C ./BL1
make -C ./BL2
clean:
make clean -C ./BL1
make clean -C ./BL2
这个是直接 直接用-C make ./BL1 当前目录的子文件夹,
这里是不需要进入子目录. 直接在当前就可以编译到子的makefile
2019年4月10日21:02:57
关于
(1) =
(2) :=
(3) ?=
(4) +=
之前已经说过=和:=
这里说?= 和+=
?= 意思是变量如果没有赋值过, 则会执行这条代码进行赋值, 如果之前已经被赋值过了, 那么这句代码,就会被忽略,(其实从实验可以看出,所谓的没有赋值过,其实就是这个变量有没有被定义过.)
var1=""
var="abcd"
var ?= "efgh"
var1 ?= "efgh"
var2 ?= "efgh"
all:
@echo "hello world"
@echo $(var) #打印出来是abcd
@echo $(var1) #打印出来是空的一行话
@echo $(var2) #打印出来是efgh
从观察上面代码即可发现?=符号的作用
+= 用来给已经赋值过的接续赋值, 意思就是把现在的值添加到原来值的后面. 有点类似于strcat
var ="1234"
var +="5678"
all:
@echo "hello world"
@echo $(var) # 打印出来是1234 5678
注意在每次添加时会发现在添加之间会有一个空格,
Makefile 中用export导出的就是环境变量, 一般情况下,要求环境变量名用大写,普通变量名用小写,
#导出这些变量到全局,其实就是给子文件夹下面的Makefile使用
export CC LD OBJCOPY OBJDUMP AR CPPFLAGS CFLAGS
Makefile 中使用的通配符
(1) * 若干任意字符
(2)? 1个任意字符
(3) [ ] 将[ ] 中的字符依次去和外面的结合匹配
$@ // 规则的目标文件名
$< // 规则的依赖文件名
$^ // 依赖的文件集合.
%_config:: unconfig
@$(MKCONFIG) -A $(@:_config=)
% 是一个万能的匹配符, 然后
$(@:_config=) :
$@就是目标, 然后: 表示替换, 最终的实现是目标中的_config =替换成空
从这里分析得出结论, 实际配置时调用mkconfig脚本 然后传参2个: -A 还有就是那个%所传进来的那个字符