Linux-makefile学习-答疑汇总

‘=’‘:=’‘?=’‘+=’四种赋值方式的区别

‘=’:基本赋值。是整个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 $^


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值