Makefile基础知识(3)

文章目录

  • I 程序编译的过程
  • II MakeFile的规则
    • 1 格式
    • 2 规则
    • 3 符号
    • 4 函数与关键字
    • 5 文件搜寻
    • 6 伪目标
    • 7 静态模式
  • III 栗子

-在学习的过程中,逐渐补充,当前只写入了目前用到的函数、语法等。

I 程序编译的过程

源文件->编译(compile)->形成中间代码文件(.o/.obj)
中间代码文件->链接(link)->可执行文件

在编译时,编译器只检测程序语法,和函数、变量是否被声明。如果函数未被声明,编译器会给出
一个警告,但可以生成 Object File。而在链接程序时,链接器会在所有的 Object File 中
找寻函数的实现,如果找不到,那到就会报链接错误码(Linker Error)

II MakeFile的规则

1 格式

target ... : prerequisites ...
command

->
target 是目标文件,可以是 .o文件,也可以是执行文件。还可以是一个标签(Label)
->
prerequisites 是,要生成那个 target 所需要的文件或是目标(也可以叫成是"依赖")。
->
command 也就是 make 需要执行的命令。(可用任意的 Shell 命令)

2 规则

在对应目录下执行make命令,就会追踪到当前目录下的Makefile文件。
查看“prerequisites”的修改时间是否“新”于“target”
如果是,就执行下面的command

3 符号

 = 是最基本的赋值
:= 是覆盖之前的值
?= 是如果没有被赋值过就赋予等号后面的值
+= 是添加等号后面的值
$@ 是当前目标文件(target)
$^ 是所有的依赖文件
$< 是第一个依赖文件
$(xxx) 相当于宏替换。
$  是通佩符
*  是通佩符

4 函数与关键字

patsubst
$(patsubst 参数1, 参数2, 参数3)
功能:查找参数3中的字符串(字符串需要以“空格”、“TAB”、“回车” 或 “换行”分隔)
如果当前字符串符合参数1的格式,那么将会替换为参数2的格式。(可以使用通佩符)

我为什么要使用这个函数?
因为我们在编译源码的时候需要指定"头文件的路径"。而Makefile在制定头文件路径的时候需要 “-i”
这个函数就是能将:我们写入的路径上面 批量的加入 “-i”

wildcard
$(wildcard 参数1)
$(wildcard 参数1)可以在函数的参数/变量中使用,而参数1中可以带通佩符。调用函数的时候会将通佩符所代表的所有值都带入函数。
功能:在变量中使用通佩符,将其展开使用。
$(foreach 参数1,参数2,参数3)、
注:参数3是一个含参数1的表达式
功能:将参数2中的字串取出,放入参数1中,再带入到参数3这个表达式中遍历并逐一返回。
$(notdir 参数1)
注:参数1是一串路径
功能:将参数1字串中非目录部分取出。非目录部分是指最后一个反斜杠“/”后的字串
例:obj/bsp_led.o -> bsp_led.o

5 文件搜寻

VPATH:
Makefile 文件中的特殊变量“VPATH”就是完成不同目录下文件搜寻功能的,如果没有指明这个变量,
make 只会在当前的目录中去找寻依赖文件和目标文件。如果定义了这个变量,那么,make
就会在当当前目录找不到的情况下,到所指定的目录中去找寻文件了。

6 伪目标

无依赖文件,make xxx直接执行命令

clean:
rm *.o temp

–我们并不生成“clean”这个文件。“伪目标”并不是一个文件,只是一个标签,
由于“伪目标”不是文件,所以 make 无法生成它的依赖关系和决定它是否要执行。我们只
有通过显示地指明这个“目标”才能让其生效。当然,“伪目标”的取名不能和文件名重名,
不然其就失去了“伪目标”的意义了。
–当然,为了避免和文件重名的这种情况,我们可以使用一个特殊的标记“.PHONY”来显
示地指明一个目标是“伪目标”,向 make 说明,不管是否有这个文件,这个目标就是“伪
目标”。

.PHONY : clean

7 静态模式

Makefile的格式是这样的:
目标 : 依赖
命令

静态模式则:
: : 

我也没看懂,暂时用过下面这种

据个例子:
OBJS = obj/start.o obj/main.o obj/bsp_clk.o obj/bsp_led.o obj/bsp_delay.o
$(SOBJS) : obj/%.o : %.S 
...
将所有的.S文件编译成.o,并存放到obj目录下

III 栗子

用程序模块化的思想建立了bsp工程

#  工程文件夹路径分配:
#  bsp:imx6ul :包含寄存器定义结构体
#     :bsp    :包含自定义的.c.h文件
#     :obj    :编译后生成的中间文件.o
#     :project:main.c和 start.s

CROSS_COMPILE 	?= arm-linux-gnueabihf-
#交叉编译工具    注 ?= 是如果没有被赋值过就赋予等号后面的值

TARGET		  	?= bsp
#bin文件(可执行文件)的文件名

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                #源文件目录路径
				   
#抓取工程中的.h文件的路径				   
INCLUDE			:= $(patsubst %, -I %, $(INCDIRS))  #patsubst:批量格式替换,将$(INCDIRS)中的字符串都加入"-I"为前缀。
													#为什么要加“-I”,这是makefile对指定头文件路径的要求
#抓取工程中的.s文件 和 .c文件路径
SFILES			:= $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.S)) #wildcard关键字:在变量中可以使用通佩符$*
CFILES			:= $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.c)) #foreach函数:将参数2中的字串,放入参数1中,再带入到参数3这个表达式中遍历并逐一返回。

#一个.S/c 对应1个.o文件,把文件名抓出来
SFILENDIR		:= $(notdir  $(SFILES))
CFILENDIR		:= $(notdir  $(CFILES)) #notdir:将.s文件 和 .c文件的路径去掉只留文件名:xxx.S xxx.C

#抓取工程中的.o文件的路径
SOBJS			:= $(patsubst %, obj/%, $(SFILENDIR:.S=.o)) #patsubst:批量格式替换,将$(SFILENDIR:.S=.o)中的字符串都加入"obj/"为前缀。
COBJS			:= $(patsubst %, obj/%, $(CFILENDIR:.c=.o)) #$(SFILENDIR:.S=.o),将SFILENDIR中的.替换为.o
OBJS			:= $(SOBJS) $(COBJS)

VPATH			:= $(SRCDIRS)
#VPATH特殊变量的作用:指定搜索依赖的路径。如果不定义,就只会再mikefile文件的同一目录下寻找

.PHONY: clean #声明伪目标,为防止与文件重名。


#链接
$(TARGET).bin : $(OBJS)
	$(LD) -T imx6ul.lds -o $(TARGET).elf $^
	$(OBJCOPY) -O binary -S $(TARGET).elf $@
	$(OBJDUMP) -D -m arm $(TARGET).elf > $(TARGET).dis

#编译
$(SOBJS) : obj/%.o : %.S  #这个写法叫静态模式:将所有的.S文件编译成.o,并存放到obj目录下
	$(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)

print1:#测试1-抓取.h路径
	@echo INCLUDE = $(INCLUDE)
print2:#测试2-抓取.s路径
	@echo SFILES = $(SFILES)
print3:#测试3-抓取.c路径
	@echo CFILES = $(CFILES)	
print4:#测试3-抓取.o路径
	@echo OBJS = $(OBJS)	

Makefile基础知识(3)_第1张图片

你可能感兴趣的:(嵌入式从入门到摔开发板,makefile,编译器)