【linux】上手makefile

  本文首先介绍makefile的语法,之后举一个makefile示例。

一、make介绍

  由代码生成可执行文件,叫做编译(compile);对编译顺序进行安排,叫做构建(build)。Make是最常用的构建工具,诞生于1977年,主要用于C语言的项目。详细参考《GNU Make手册》跟我一起写makefilemake命令教程

二、makefile语法

2.1 通配符

通配符(wildcard)用来指定一组符合条件的文件名。Makefile 的通配符与 Bash 一致,主要有星号(*)、问号(?)和 […] 。比如, *.o 表示所有后缀名为o的文件。

clean:
        rm -f *.o

2.2 模式匹配

Make命令允许对文件名,进行类似正则运算的匹配,主要用到的匹配符是%。比如,假定当前目录下有 f1.c 和 f2.c 两个源码文件,需要将它们编译为对应的对象文件。

%.o: %.c
等同于 
f1.o: f1.c
f2.o: f2.c

2.3 变量和赋值

2.3.1 变量

要调用变量,需将变量放在 $( ) 之中。

txt = Hello World
test:
	@echo $(txt)

2.3.2 赋值

VARIABLE = value #在执行时扩展,允许递归扩展。
VARIABLE := value #在定义时扩展。
VARIABLE ?= value #只有在该变量为空时才设置值。
VARIABLE += value #将值追加到变量的尾端。

2.4 自动变量

$@:指代当前目标。

  • $<:指代第一个前置条件。
  • $?:指代比目标更新的所有前置条件。
  • $^:指代所有前置条件。
  • $*:指代匹配符 % 匹配的部分。
  • $(@D) 和 ( @ F ) : (@F): (@F)(@D) 和 $(@F) 分别指向 @ 的 目 录 名 和 文 件 名 。 比 如 , @ 的目录名和文件名。比如, @@是 src/input.c,那么 ( @ D ) 的 值 为 s r c , (@D) 的值为 src , (@D)src(@F) 的值为 input.c。
  • $(<D) 和 ( < F ) : (<F): (<F)(<D) 和 $(<F) 分别指向 $< 的目录名和文件名。

2.5 函数

2.5.1 patsubst函数

$(patsubst <pattern>,<replacement>,<text>)
  • 名称:模式字符串替换函数。
  • 功能:查找 中的单词(单词以“空格”、“Tab”或“回车”“换行”分隔)是否符合模式 ,如果匹配的话,则以 替换。这里, 可以包括通配符 % ,表示任意长度的字串。如果 中也包含 % ,那么, 中的这个 % 将是 中的那个 % 所代表的字串。(可以用 \ 来转义,以 % 来表示真实含义的 % 字符)
  • 返回:函数返回被替换过后的字符串。
  • 示例:
$(patsubst %.c,%.o,x.c.c bar.c)
把字串 x.c.c bar.c 符合模式 %.c 的单词替换成 %.o ,返回结果是 x.c.o bar.o

2.5.2 foreach函数

names := a b c d
$(foreach <var>,<list>,<text>)

上面的例子中, $(name) 中的单词会被挨个取出,并存到变量 n 中, $(n).o 每次根据 $(n) 计算出一个值,这些值以空格分隔,最后作为foreach函数的返回,所以, $(files) 的值是 a.o b.o c.o d.o 。

注意,foreach中的 参数是一个临时的局部变量,foreach函数执行完后,参数 的变量将不在作用,其作用域只在foreach函数当中。

2.5.3 notdir函数

$(notdir <names...>)
  • 名称:取文件函数——notdir。
  • 功能:从文件名序列 中取出非目录部分。非目录部分是指最後一个反斜杠( / )之后的部分。
  • 返回:返回文件名序列 的非目录部分。
  • 示例: $(notdir src/foo.c hacks) 返回值是 foo.c hacks 。

三、示例

根据上面的内容理解以下的makefile文件:

  • 定义了编译器变量CC、LD、OBJCOPY、OBJDUMP ,这有利于跨平台。
  • 上面定义了很多变量,方便后面的修改,类似于写C语言程序的宏。
  • 变量定义之后的就是编译规则了:有4个目标:从上往下为.bin,.S文件编译出的.o,.c文件编译出的.o,最后一个伪目标clean。
CROSS_COMPILE 	?= arm-linux-gnueabihf-
TARGET		  	?= ap3216c

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

LIBPATH			:= -lgcc -L /usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/lib/gcc/arm-linux-gnueabihf/4.9.4


INCDIRS 		:= imx6ul \
				   stdio/include \
				   bsp/clk \
				   bsp/led \
				   bsp/delay  \
				   bsp/beep \
				   bsp/gpio \
				   bsp/key \
				   bsp/exit \
				   bsp/int \
				   bsp/epittimer \
				   bsp/keyfilter \
				   bsp/uart \
				   bsp/lcd \
				   bsp/rtc \
				   bsp/i2c \
				   bsp/ap3216c
				   			   
SRCDIRS			:= project \
				   stdio/lib \
				   bsp/clk \
				   bsp/led \
				   bsp/delay \
				   bsp/beep \
				   bsp/gpio \
				   bsp/key \
				   bsp/exit \
				   bsp/int \
				   bsp/epittimer \
				   bsp/keyfilter \
				   bsp/uart \
				   bsp/lcd \
				   bsp/rtc \
				   bsp/i2c \
				   bsp/ap3216c
				   
				   
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 $^ $(LIBPATH)
	$(OBJCOPY) -O binary -S $(TARGET).elf $@
	$(OBJDUMP) -D -m arm $(TARGET).elf > $(TARGET).dis

$(SOBJS) : obj/%.o : %.S
	$(CC) -Wall -nostdlib -fno-builtin -c -O2  $(INCLUDE) -o $@ $<

$(COBJS) : obj/%.o : %.c
	$(CC) -Wall -Wa,-mimplicit-it=thumb -nostdlib -fno-builtin -c -O2  $(INCLUDE) -o $@ $<
	
clean:
	rm -rf $(TARGET).elf $(TARGET).dis $(TARGET).bin $(COBJS) $(SOBJS)

四、难点

4.1 对$(CFILENDIR:.c=.o))的理解

把变量CFILENDIR中.c替换成.o。

我们可以替换变量中的共有的部分,其格式是 $(var:a=b) 或是 ${var:a=b} ,其意思是,把变量“var”中所有以“a”字串“结尾”的“a”替换成“b”字串。这里的“结尾”意思是“空格”或是“结束符”。
–举例:
foo := a.o b.o c.o
bar := $(foo:%.o=%.c)
这依赖于被替换字串中的有相同的模式,模式中必须包含一个 % 字符,这个例子同样让 $(bar) 变量的值为“a.c b.c c.c”。

4.x 后面遇到再补充

Guess you like

Origin blog.csdn.net/weixin_43810563/article/details/115983966