提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
这里主要是对前面的工程进行优化,将各个不同的文件进行分类,学习如何整理工程、就和学习STM32一样创建工程的各个文件夹分类,实现工程文件 的分类化和模块化,便于管理
深入学习Makefile,学习Makefile的高级技巧,学习编写通用Makefile
提示:以下是本篇文章正文内容,下面案例可供参考
一、工程优化
将不同功能的源码文件放到不同的目录中。另外我们也需要将源码文件中,所有完成同一个功能的代码提取出来放到一个单独的文件中,也就是对程序分功能管理
新建一个工程,在工程里面建立 bsp、 imx6ul、 obj 和 project 这 4 个文件夹
bsp:存放驱动文件
imx6ul:存放跟芯片有关的文件,如SDK库文件
obj:存放编译生成的.o 文件
project:应用文件,也就是start.S 和 main.c 文件
在驱动bsp 文件夹下创建三个子文件夹: clk、 delay 和 led,分别用来存放时钟驱动文件、延时驱动文件和 LED 驱动文件
大致如下图:
二、路径添加
设置VSCODE头文件路径, 先创建.vscode目录,然后打开c/c++配置器,会在.vscode目录下生成一个叫做c_cpp_properties.json的文件,然后在includePath下按如下方式添加路径
三、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
INCLUDE := $(patsubst %, -I %, $(INCDIRS))
SFILES := $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.S))
CFILES := $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.c))
SFILENDIR := $(notdir $(SFILES))
CFILENDIR := $(notdir $(CFILES))
SOBJS := $(patsubst %, obj/%, $(SFILENDIR:.S=.o))
COBJS := $(patsubst %, obj/%, $(CFILENDIR:.c=.o))
OBJS := $(SOBJS) $(COBJS)
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
$(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)
注:Makefile实在写着有点难受,报错了都不知道是啥子意思,这里报错要么是makefile写错了,要么是链接脚本那里写错了。
1.前面几行都是定义了一些变量,INCDIRS包含了整个工程的.h文件的目录,所有的头文件目录都要添加到INCDIRS中;’'是换行符:表示本行和下一行属于同一行;=SRCDIRS包含了整个工程文件所以的.c和.s文件目录;
2.patsubst(模式字符串替换)是Makefile函数
函数原型
$(patsubst < pattern>,< replacement>,< text>)
查找< text >中的单词(单词以“空格”、“Tab”或“回车”“换行”分隔)是否
符合模式< pattern>,如果匹配的话,则以< replacement>替换。这里, < pattern>可以包括通配符“ %”,表示任意长度的字串。
INCLUDE := $(patsubst %, -I %, $(INCDIRS))
通过函数 patsubst 给变量 INCDIRS 添加一个“-I”,因为Makefile指定头文件路径,需要-I
原来的路径就变为
INCLUDE := -I imx6ul -I bsp/clk -I bsp/led -I bsp/delay
3.变量 SFILES 保存工程中所有的.s 汇编文件(包含绝对路径),变量 SRCDIRS 已经存放了工程中所有的.c 和.S 文件,所以只需要从里面挑出所有的.S 汇编文件即可
foreach函数,作用:用来做循环用的
函数原型:
$(foreach < var>,< list>,< text>)
把参数中的单词逐一取出放到参数所指定的变量中,然后再执行
wildcard函数, 用来明确表示通配符,在Makefile规则中,通配符会被自动展开,但在变量的定义和函数引用时,通配符将失效。这种情况下如果需要通配符有效,就需要使用函数wildcard
比如,$(wildcard *.c)”来获取工作目录下的所有的.c文件列表
SFILES := $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.S))
CFILES := $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.c))
这里SFILES将会被展开为:
SFILES = project/start.S
CFILES = project/main.c bsp/clk/bsp_clk.c bsp/led/bsp_led.c bsp/delay/bsp_delay.c
4.变量 SFILENDIR 和 CFILENDIR 包含所有的.S 汇编文件和.c 文件,相比变量 SFILES 和 CFILES, SFILENDIR 和 CFILNDIR 只是文件名,不包含文件的绝对路径,使用函数 notdir 将 SFILES 和 CFILES 中的路径去掉即可
函数原型
$(notdir < names…>)
从文件名序列< names>中取出目录部分。目录部分是指最后一个反斜杠(“/”)之前的部分,也就是提前目录下的函数
SFILENDIR := $(notdir $(SFILES))
CFILENDIR := $(notdir $(CFILES))
变成了如下
SFILENDIR = start.S
CFILENDIR = main.c bsp_clk.c bsp_led.c bsp_delay.c
5.变量SOBJS 和 COBJS 是.S 和.c 文件编译以后对应的.o 文件目录,默认所有的文件编译出来的.o 文件和源文件在同一个目录中,这里我们将所有的.o 文件都放到 obj 文件夹下,变量 OBJS 是变量 SOBJS 和 COBJS 的集合
内容如下
SOBJS = obj/start.o
COBJS = obj/main.o obj/bsp_clk.o obj/bsp_led.o obj/bsp_delay.o
OBJS = obj/start.o obj/main.o obj/bsp_clk.o obj/bsp_led.o obj/bsp_delay.o
==6.VPATH作用:指定搜索目录 ==
VPATH := $(SRCDIRS)
这里指定的搜素目录就是变量SRCDIRS 所保存的目录,当编译的时候所需的.S 和.c 文件就会在 SRCDIRS 中指定的目录中查找
7.(.PHONY)用来指明该目标是一个伪目标
这里提供一个清除它们的“目标”以备完整地重编译而用,但是不生成clean这个文件,这就是一个伪目标
“伪目标”并不是一个文件,只是一个标签,由于“伪目标”不是文件,所以 make 无法生成它的依赖关系和决定它是否要执行。只有通过显示地指明这个“目标”才能让其生效,“伪目标”的取名不能和文件名重名
为了避免和文件重名的这种情况,我们可以使用一个特殊的标记“.PHONY”来显示地指明一个目标是“伪目标”,向 make 说明,不管是否有这个文件,这个目标就是“伪目标”
8.Makefile静态模式 ,静态模式可以更加容易地定义多目标的规则,可以让我们的规则变得更加的有弹性和灵活
< targets …>: < target-pattern>: < prereq-patterns …>
targets :定义了一系列的目标文件,可以有通配符,是目标的一个集合
target-parrtern :指明了 targets 的模式,也就是的目标集模式
prereq-parrterns :目标的依赖模式,它对 target-parrtern 形成的模式再进行一次依赖目标的定义
$(OBJS): obj/%.o : %.S
表示将所有的.S文件编译为.o并且存放到obj目录下去
后面的都很熟悉,编译,链接,反汇编
四、链接脚本和下载
SECTIONS{
. = 0X87800000;
.text :
{
obj/start.o
*(.text)
}
.rodata ALIGN(4) : {*(.rodata*)}
.data ALIGN(4) : { *(.data) }
__bss_start = .;
.bss ALIGN(4) : { *(.bss) *(COMMON) }
__bss_end = .;
}
这里主要是添加 start.o 文件路径
最后就可以下载程序了…
总结
提示:这里对文章进行总结: