Makefile脚本实例

1.makefile脚本

  • makefile脚本帮助我们快速完成编译、链接、清空、反汇编等步骤,是快速开发的必备方法。
//定义变量
CROSS_COMPILE ?= arm-linux-gnueabihf-	
NAME		  ?= ledc  //只需要改这里就可以,其他全都一样

// $(),引用变量
CC 		:= $(CROSS_COMPILE)gcc
LD		:= $(CROSS_COMPILE)ld  //链接脚本文件
OBJCOPY := $(CROSS_COMPILE)objcopy	//elf转为bin
OBJDUMP := $(CROSS_COMPILE)objdump	//反汇编

OBJS 	:= start.o main.o
//定义变量 OBJS, OBJS 包含着要生成 ledc.bin 所需的材料: start.o 和 main.o,
//就是当前工程下的 start.s 和 main.c 这两个文件编译后的.o 文件。
//注意 start.o 一定要放到最前面!因为在后面链接的时候 start.o 要在最前面,因为 start.o 是最先要执行的文件!

$(NAME).bin:$(OBJS)
//默认目标,目的是生成最终的可执行文件 ledc.bin, ledc.bin 依赖 start.o 和 main.o
//如果当前工程没有 start.o 和 main.o 的时候就会找到相应的规则去生成 
//比如start.o 是 start.s 文件编译生成的,因此会执行%.o:%.s规则

	$(LD) -Timx6ul.lds -o $(NAME).elf $^
//调用链接脚本imx6ul.lds生成ledc.elf文件
//“$^”这一自动变量的意思是所有依赖文件的集合,相当于生成ledc.elf需要用start.o main.o

	$(OBJCOPY) -O binary -S $(NAME).elf $@
//将 ledc.elf 文件转为 ledc.bin
//“$@”的意思是目标集合,即ledc.bin

	$(OBJDUMP) -D -m arm $(NAME).elf > $(NAME).dis
//反汇编,生成 ledc.dis 文件。

//下面三种针对不同的文件类型将其编译成对应的.o 文件
//其实就是汇编.s(.S)和.c 文件,比如 start.s 就会使用第 8 行的规则来生成对应的 start.o 文件。
%.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

2.链接脚本

  • 链接脚本注解
    • imx6ul.lds是链接脚本文件,-T后跟imx6ul.lds是使用该链接脚本;也可以直接跟地址如-Ttext 0X87800000,表示所有文件链接到此地址之后。
    • 有时候我们很多文件需要链接到指定的区域,或者叫做段里面,比如在 Linux 里面初始化函数就会放到 init 段里面。因此我们需要能够自定义一些段,这些段的起始地址我们可以自由指定,同样的我们也可以指定一个文件或者函数应该存放到哪个段里面去。
    • 链接脚本:用于描述文件应该如何被链接在一起形成最终的可执行文件。目的是描述输入文件中的段如何被映射到输出文件中,并且控制输出文件中的内存排布。
    • 最简单的链接脚本可以只包含一个命令“SECTIONS”,我们可以在这一个“SECTIONS”里面来描述输出文件的内存布局。
    • 我们一般编译出来的代码都包含在 text、 data、 bss 和 rodata 这四个段内
// imx6ul.lds 链接脚本代码
SECTIONS{
	. = 0X87800000; 
	// . 是定位计数器值,代表链接地址,表示所有文件链接到此地址之后
	.text : //段名
	//{}填上要链接到“.text”这个段里面的所有文件
	{
		start.o //若是下面的makefile需要在前面加 obj/
		//链接到开始位置的文件为start.o
		//因为 start.o 里面包含着第一个要执行的指令,所以一定要链接到最开始的地方。
		main.o 
		*(.text)
		//“*(.text)”中的“*”是通配符,表示所有输入文件的.text段都放到“.text”中。
	}
	.rodata ALIGN(4) : {*(.rodata*)}     

//定义了一个名为“.data”的段,然后所有文件的“.data”段都放到这里面
//ALIGN(4) 用来对“.data”这个段的起始地址做字节对齐的, 表示 4 字节对齐。
//也就是说段“.data”的起始地址要能被 4 整除,常见 ALIGN(4/8), 4 /8字节对齐。

	.data ALIGN(4)   : { *(.data) }    

	//__bss_start/__bss_end是符号,这两个符号用来保存.bss 段的起始地址和结束地址。
	//.bss 段是定义了但是没有被初始化的变量,我们需要手动对.bss 段的变量清零的,		//因此我们需要知道.bss 段的起始和结束地址,这样我们直接对这段内存赋 0 即可完成清零。
	__bss_start = .;    //对该符号赋值为定位计数器值
	.bss ALIGN(4)  : { *(.bss)  *(COMMON) }    
	//“.bss”段,所有文件中的“.bss”数据都会被放到这个里面,
	//“.bss”数据就是那些定义了但是没有被初始化的变量。
	__bss_end = .;  //对该符号赋值为定位计数器值

//地址就保存在了“__bss_start”和“__bss_end”中,
//我们就可以直接在汇编或者 C 文件里面使用这两个符号。
}

3. 文件烧写

.bin文件烧写的时候缺乏权限会提示premission denid
此时运行:
chmod 777 imxdownload
 //给予 imxdownoad 可执行权限,一次即可
 ls /dev/sd*
 //检测sd卡是否存在
./imxdownload ledc.bin /dev/sdb 
//下载到 SD 卡中sd(x)还是sdb需要看自己电脑

4.链接头文件设置

  • CTRL+shift+p ->c/c++:Edit Configurations
  • 在当前工作区创建.vscode文件夹,上面文件会自动存在其中
  • 在终端中默认不显示以.开头的文件,可以通过ls -a来使其显示
  • 在上述文件中的"includePath":{}中添加工程中有.h文件的文件夹

5. bsp下的通用makefile

CROSS_COMPILE 	?= arm-linux-gnueabihf-
TARGET		  	?= bsp //文件名,改1(共3)

CC 				:= $(CROSS_COMPILE)gcc
LD				:= $(CROSS_COMPILE)ld
OBJCOPY 		:= $(CROSS_COMPILE)objcopy
OBJDUMP 		:= $(CROSS_COMPILE)objdump

//头文件路径  改 2
INCDIRS 		:= imx6ul \      //"\"表示下行继续
				   bsp/clk \
				   bsp/led \
				   bsp/delay 
				   			   
//源码路径 改3
SRCDIRS			:= project \
				   bsp/clk \
				   bsp/led \
				   bsp/delay 
				   
//$(函数名)返回函数执行结果。			
//需要在所有文件夹之前加 -I
//$(patsubst <pattern>,<replacement>,<text>)	   
//patsubst 模式字符串替换函数,查找<text>中的单词(单词以“空格”、“Tab”或“回车”“换行”分隔)是否符合模式<pattern>,如果匹配的话,则以<replacement>替换。
INCLUDE			:= $(patsubst %, -I %, $(INCDIRS))
//print
	@echo INCLUDE =$(INCLUDE)
	执行 make print
	返回 -I imx6u -I bsp/clk -i bsp/led -I bsp/delay

//获取工程中所有.S/.c文件
//$(wildcard)展开通配符, $(wildcard $(dir)/*.S))意为展开dir目录下的所有.S文件
//$(foreach <var>,<list>,<text>)。把参数<list>中的单词逐一取出放到参数<var>所指定的变量中,然后再执行<text>所包含的表达式。
SFILES			:= $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.S))	//保存工程下所有.S文件
CFILES			:= $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.c))

//notdir会去除所有路径而只保留文件名
SFILENDIR		:= $(notdir  $(SFILES))
CFILENDIR		:= $(notdir  $(CFILES))

//将文件名的.s/.c变为.o,文件属性没变
SOBJS			:= $(patsubst %, obj/%, $(SFILENDIR:.S=.o))
COBJS			:= $(patsubst %, obj/%, $(CFILENDIR:.c=.o))
OBJS			:= $(SOBJS) $(COBJS)
//现在OBJS是所有.o文件的集合
//通过以上变量操作,准备好编译的原材料

//默认只会在当前路径下找源码或者头文件,通过VPATH添加新的搜寻路径
VPATH			:= $(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

//将所有的.S文件编译成.o并存其在SOBJ目录下 
//静态模式
$(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)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Arist9612

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值