‘=’‘:=’‘?=’‘+=’四种赋值方式的区别
‘=’:基本赋值。是整个makefile展开后,再决定变量的值。
x = foo
y = $(x) bar
x = xyz
y的值将会是 xyz bar ,而不是 foo bar
‘:=’:变量的值决定于它在makefile中的位置,而不是整个makefile展开后的最终值。
x := foo
y := $(x) bar
x := xyz
y的值将会是 foo bar ,而不是 xyz bar 了
‘?=’:如果之前定义过,就什么都不做;如果之前没有被定义过,那么执行定义赋值。
‘+=’:如果变量之前没有定义过,那么“+=”会自动变成“=”,如果前面有变量的定义,那么“+=”会集成于前次操作的赋值符。如果前一次的是“:=”,那么“+=”会以“:=”作为其赋值符。
Makefile 经典范例
/* 一个LED.s文件的编译 */
led.bin:led.s
arm-linux-gnueabihf-gcc -g -c led.s -o led.o
arm-linux-gnueabihf-ld -Ttext 0x87800000 led.o -o led.elf
arm-linux-gnueabihf-objcopy -O binary -S -g led.elf led.bin
arm-linux-gnueabihf-objdump -D led.elf > led.dis
clean:
rm -rf *.o led.bin led.elf led.dis
/* c语言的led闪烁 */
//Makefile
objs := start.o main.o
ledc.bin:$(objs)
arm-linux-gnueabihf-ld -Ttext 0x87800000 -o ledc.elf $^
/* 使用arm-linux-gnueabihf-ld连接;连接地址0x87800000;"$<"所有依赖文件的合集,即objs */
arm-linux-gnueabihf-objcopy -O binary -S ledc.elf $@
/* 使用arm-linux-gnueabihf-objcopy 来将ledc.elf文件转为ledc.bin; "$@"目标集合,即ledc.bin */
arm-linux-gnueabihf-objdump -D -m arm ledc.elf > ledc.dis
/* 使用arm-linux-gnueabihf-objdump来反汇编,生成 ledc.dis文件 */
%.o:%.s
arm-linux-gnueabihf-gcc -Wall -nostdlib -c -O2 -o $@ $<
%.o:%.S
arm-linux-gnueabihf-gcc -Wall -nostdlib -c -O2 -o $@ $<
%.o:%.c
arm-linux-gnueabihf-gcc -Wall -nostdlib -c -O2 -o $@ $<
clean:
rm -rf *.o ledc.bin ledc.elf ledc.dis
/**
* 有时候我们很多文件需要连接到指定的区域,或者叫做段里面,因此我们需要能够自定义一些段,段的起始地址自
* 由指定。同样,我们也可以指定一个文件或者函数存放到哪一个段里面去。要完成这个工作就需要使用到链接脚本
* 控制输出文件的内存排布
*/
/* 使用变量更改LED的Makefile */
CROSS_COMPILE ?= arm-linux-gnueabihf-
NAME ?= ledc
CC := $(CROSS_COMPILE)gcc
LD := $(CROSS_COMPILE)ld
OBJCOPY := $(CROSS_COMPILE)objcopy
OBJDUMP := $(CROSS_COMPILE)objdump
OBJS := start.o main.o
$(NAME).bin:$(OBJS)
$(LD) -Timx6ul.lds -o $(NAME).elf $^
$(OBJCOPY) -O binary -S $(NAME).elf $@
$(OBJDUMP) -D -m arm $(NAME).elf > $(NAME).dis
%.o : %.s
$(CC) -Wall -nostdlib -c -O2 -o $@ $<
%.o : %.S
$(CC) -Wall -nostdlib -c -O2 -o $@ $<
%.o : %.c
$(CC) -Wall -nostdlib -c -O2 -o $@ $<
clean:
rm -rf *.o $(NAME).bin $(NAME).elf $(NAME).dis
裸机通用Makefile
/* BSP 工程管理实验 - 裸机通用Makefile */
CROSS_COMPILE ?= arm-linux-gnueabihf-
TARGET ?= bsp
CC := $(CROSS_COMPILE)gcc
LD := $(CROSS_COMPILE)ld
OBJCOPY := $(CROSS_COMPILE)objcopy
OBJDUMP := $(CROSS_COMPILE)objdump
INCDIRS := imx6ul \
bsp/clk \
bsp/led \
bsp/delay
SRCDIRS := project \
bsp\clk \
bsp\led \
bsp\delay
/* 应Makefile语法要求指明头文件目录的时候需要加上“-I”,通过patsubst给变量INCDIRS添加一个"I"
* 即: INCLUDE := -I imx6ul -I bsp/clk -I bsp/led -I bsp/delay
*/
INCLUDE := $(patsubst %, -I %, $(INCDIRS))
SFILES := $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.S))
/* 变量SFILES保存工程中所有的.S汇编文件(含绝对路径), 用foreach和wildcard函数挑出所有的.S文件。即 SFILES := project/start.S*/
/* foreach 等同for循环;在变量定义和函数引用的时候,通配符展开会失效,wildcard可以解决这个问题。*/
CFILES := $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.c))
/* 与上一行等同,即 CFILES = project/main.c bsp/clk/bsp_clk.c bsp/led/bsp_led.c bsp/delay/bsp_dealy.c */
SFILENDIR := $(notdir $(SFILES))
CFILENDIR := $(notdir $(CFILES))
/* 使用notdir将 SFILES和CFILES 中的路径去掉,得到文件名集合 */
SOBJS := $(patsubst %, obj/%, $(SFILENDIR:.S=.o))
COBJS := $(patsubst %, obj/%, $(CFILENDIR:.c=.o))
OBJS := $(SOBJS) $(COBJS)
/* 我们将所有的.o文件都放到obj文件夹下,SOBJS = obj/start.o COBJS = obj/main.o obj/bsp_clk.o obj/bsp_led.o obj/bsp_delay.o*/
VPATH := $(SRCDIRS)
/* 指定搜索目录,即SRCDIRS保存的目录 */
.PHONY: clean
$(TARGET).bin : $(OBJS)
$(LD) -Timx6ul.lds -o $(TARGET).elf $^
$(OBJCOPY) -O binary -S $(TARGET).elf $@
$(OBJDUMP) -D -m arm $(TARGET).elf > $(TARGET).dis
$(SOBJS) : obj/%.o : %.S
$(CC) -Wall -nostdlib -c -O2 $(INCLUDE) -o $@ $<
$(COBJS) : obj/%.o : %.c
$(CC) -Wall -nostdlib -c -O2 $(INCLUDE) -o $@ $<
clean:
rm -rf $(TARGET).elf $(TARGET).dis $(TARGET).bin $(COBJS) $(SOBJS)
/* 对应的链接脚本 - imx6ul.lds */
SECTIONS{
. = 0X87800000;
.text :
{
start.o
main.o
*(.text)
}
.rodata ALIGN(4) : {*(.rodata*)}
.data ALIGN(4) : {*(.data)}
__bss_start = .;
.bss ALIGN(4) : {*(.bss) *(COMMON)}
__bss_end = .;
}
/* 蜂鸣器 Makefile - 用通用的Makefile修改, 修改变量TARGET为beep,在变量INCDIRS和SRCDIRS中追加“bsp/beep” */
CROSS_COMILE ?= arm-linux-gnueabihf-
TARGET ?= beep
/* 省略掉其他代码...... */
INCDIRS := imx6ul \
bsp\clk \
bsp\led \
bsp\delay \
bsp\beep
SRCDIRS := project \
bsp/clk \
bsp/led \
bsp/delay \
bsp/beep
/* 省略掉其他代码...... */
clean:
rm -rf $(TARGET).elf $(TARGET).dis $(TARGET).bin $(COBJS) $(SOBJS)
/* 按键 Makefile - 用通用的Makefile修改, 修改变量TARGET为key,在变量INCDIRS和SRCDIRS中追加“bsp/gpio” 和“bsp/key” */
CROSS_COMILE ?= arm-linux-gnueabihf-
TARGET ?= key
/* 省略掉其他代码...... */
INCDIRS := imx6ul \
bsp\clk \
bsp\led \
bsp\delay \
bsp\gpio \
bsp\key
SRCDIRS := project \
bsp/clk \
bsp/led \
bsp/delay \
bsp/gpio \
bsp\key
/* 省略掉其他代码...... */
clean:
rm -rf $(TARGET).elf $(TARGET).dis $(TARGET).bin $(COBJS) $(SOBJS)
== 加入链接库 和 禁用内建函数 ==
== 驱动框架的 Makefile 文件 ==
Makefile 必然配合着 gcc编译器来使用
linaro gcc 使用说明
1. arm-linux-gnueabihf-gcc -g -c led.s -o led.o //将led.s编译为led.o
/* "-g"产生调试信息,GDB能够使用这些调试信息进行调试。
* "-c"编译源文件,但不链接。
* "-o"指定编译产生的文件名字
/**
* 存储地址 == 加载地址 ; 运行地址 == 链接地址
* STM32的加载地址和链接地址是一样的都是0x08000000
* DDR的链接地址是0x8000 0000 开始,为了和uboot保持一致链接地址设为:0x87800000
*/
2. arm-linux-gnueabihf-ld -Ttext 0x87800000 led.o -o led.elf
/* "-Ttext" -> 指定链接地址
* “-o” ->指定链接生成的elf文件名
* 我们需要将led.elf文件转换为.bin文件,就需要用到arm-linux-gnueabihf-objcopy这个工具了
3. arm-linux-gnueabihf-objcopy -O binary -S -g led.elf led.bin
/* "-O"指定什么格式输出,后面的binary即为二进制输出
* "-S"指不要复制源文件中的重定位信息和符号信息
* "-g"表示不复制源文件中的调试信息
/* 可将elf文件反汇编 */
4. arm-linux-gnueabihf-objdump -D led.elf > led.dis
/* "-D"表示反汇编所有的段
链接脚本
/* 链接脚本基本语法 代码别链接到0x10000000 数据被链接到0x30000000 */
SECTIONS{
. = 0X10000000;
.text : {*(.text)}
. = 0x30000000;
.data ALIGN(4) : {*(.data)}
.bss ALIGN(4) : {*(.bss)}
}
// 1. 首先是关键字“SECTIONS”,后面一个大括号
// 2. 对特殊符号"."赋值。"."叫作<定位计数器>,默认值为0。我们要求代码链接地址为0x10000000,所以给"."赋值0x10000000
// 3. ".text"是段名,后面的冒号是语法要求,冒号后面的大括号里面可以填上要链接到".text"这个段里面的所有文件,"*(.text)"中的“*”是通配符,表示所有输入文件的.text段都放到“.text”中。
// 4. 要求数据放到0x30000000开始的地方,重定位定位计数器“.” = 0x30000000。否则“.text”段大小为
//0x10000,接下来.data的地址就是0x10000000+ 0x10000 = 0x10010000
//5. "ALIGN(4)",用来对“.data”的起始地址能被4整除,也就是4字节对齐。
/* 1. 链接的起始地址为0x87800000
* 2. start.o 要被链接到最开始的地方,因为start.o里面包含着第一个要执行的命令。
* 3. 文件名字《imx6ul.lds》
*/
SECTIONS{
. = 0X87800000;
.text :
{
start.o
main.o
*(.text)
}
.rodata ALIGN(4) : {*(.rodata*)}
.data ALIGN(4) : {*(.data)}
__bss_start = .;
.bss ALIGN(4) : {*(.bss) *(COMMON)}
__bss_end = .;
}
/* “__bss_start”和"__bss_end"。是两个符号,对这两个符号赋值,其值为定位符".",这两个符号用来保存.bss
* 段的起始地址和结束地址。
* 由于.bss段是定义了但是没有初始化的变量,我们需要手动对.bss段的变量清零,因此我们需要知道.bss段的起始
* 和结束地址,对此段内存赋0即可。
* .bss段的起始地址和结束地址就保存在了“__bss_start”和"__bss_end"中,我们可以直接在汇编或者C文件里面调用。
*/
/* 使用上面已经写好的链接脚本文件:imx6ul.lds,修改Makefile */
将 arm-linux-gnueabihf-ld -Ttext 0x87800000 -o ledc.elf $^
改为: arm-linux-gnueabihf-ld -Timx6ul.lds -o ledc.elf $^