Makefile小结

优快云仅用于增加百度收录权重,排版未优化,日常不维护。请访问:www.hceng.cn 查看、评论。
本博文对应地址: https://hceng.cn/2017/03/11/Makefile小结/#more
本文主要是记录一些遇到的Makefile知识。

Makefile以韦东山老师第一期裸板视频中的 第8课LCD实验的配套代码lcd_3.5_4.3 中的Makefile为例,该工程有两个Makefile,分别位于根目录和lib目录中:
{% codeblock lang:makefile [根目录Makefile]%}
CC = arm-linux-gcc
LD = arm-linux-ld
AR = arm-linux-ar
OBJCOPY = arm-linux-objcopy
OBJDUMP = arm-linux-objdump

INCLUDEDIR := ( s h e l l p w d ) / i n c l u d e C F L A G S : = − W a l l − O 2 C P P F L A G S : = − n o s t d i n c − I (shell pwd)/include CFLAGS := -Wall -O2 CPPFLAGS := -nostdinc -I (shellpwd)/includeCFLAGS:=WallO2CPPFLAGS:=nostdincI(INCLUDEDIR)

export CC LD AR OBJCOPY OBJDUMP INCLUDEDIR CFLAGS CPPFLAGS

objs := head.o init.o nand.o interrupt.o serial.o lcddrv.o/
framebuffer.o lcdlib.o main.o lib libc.a

lcd.bin: $(objs)
${LD} -Tlcd.lds -o lcd_elf $^
${OBJCOPY} -O binary -S lcd_elf $@
${OBJDUMP} -D -m arm lcd_elf > lcd.dis

.PHONY : lib/libc.a
lib/libc.a:
cd lib; make; cd …

%.o:%.c
${CC} $(CPPFLAGS) $(CFLAGS) -c -o $@ $<

%.o:%.S
${CC} $(CPPFLAGS) $(CFLAGS) -c -o $@ $<

clean:
make clean -C lib
rm -f lcd.bin lcd_elf lcd.dis *.o
{% endcodeblock %}


主Makefile总领全局的就这句:
{% codeblock lang:makefile %}
lcd.bin: $(objs)
{% endcodeblock %}
要生成lcd.bin,依赖于objs列举的一堆文件:head.o init.o nand.o interrupt.o serial.o lcddrv.o framebuffer.o lcdlib.o main.o lib libc.a,所以要先找到这些文件,几个.o,还有一个.a。

  • .o目标文件怎么生成?
    %.o:%.c和%.o:%.S是生成规则,就是依赖于.c或.S文件,使用交叉编译命令生成。
  • .a目标文件怎么生成?
    .a是库文件,到lib子目录里去找,在子目录里用make命令生成。

注:
**链接:**将多.o文件,或者.o文件和库文件链接成为可被操作系统执行的可执行程序(Linux环境下,可执行文件的格式为“ELF”格式)。链接器不检查函数所在的源文件,只检查所有.o文件中的定义的符号。将.o文件中使用的函数和其它.o或者库文件中的相关符号进行合并,对所有文件中的符号进行重新安排(重定位),并链接系统相关文件(程序启动文件等)最终生成可执行程序。链接过程使用GNU 的“ld”工具。
**静态库:**又称为文档文件(Archive File)。它是多个.o文件的集合。Linux中静态库文件的后缀为“.a”。静态库中的各个成员(.o文件)没有特殊的存在格式,仅仅是一个.o文件的集合。使用“ar”工具维护和管理静态库。
**共享库:**也是多个.o文件的集合,但是这些.o文件时有编译器按照一种特殊的方式生成(Linux中,共享库文件格式通常为“ELF”格式。共享库已经具备了可执行条件)。模块中各个成员的地址(变量引用和函数调用)都是相对地址。使用此共享库的程序在运行时,共享库被动态加载到内存并和主程序在内存中进行连接。多个可执行程序可共享库文件的代码段(多个程序可以共享的使用库中的某一个模块,共享代码,不共享数据)。另外共享库的成员对象可被执行(由libdl.so提供支持)。


下面进行分析:

第一至五行:
{% codeblock lang:makefile %}
CC = arm-linux-gcc
LD = arm-linux-ld
AR = arm-linux-ar
OBJCOPY = arm-linux-objcopy
OBJDUMP = arm-linux-objdump
{% endcodeblock %}

  • 作用:将右边工具链名赋值给左边变量,为了简化书写;
  • 分析:
    1. arm-linux-gcc:编译.c或.s头的C文件或汇编程序;
    2. arm-linux-ld:连接器,把多个.o文件或库文件连接成一个可执行文件;
    3. arm-linux-ar:库管理器,把多个.o文件合并成一个.o文件或静态库文件(.a文件);
    4. arm-linux-objcopy:转换可执行文件的格式;
    5. arm-linux-objdump:生成反汇编;

第七行:
{% codeblock lang:makefile %}
INCLUDEDIR := $(shell pwd)/include
{% endcodeblock %}

  • 作用:将shell命令和include组成的路径立即赋值给左边变量,为了简化书写;
  • 分析:Makefile中调用shell命令:$(shell 命令);

‘ = ’与‘ := ’的区别注: - “ = ”:make会将整个Makefile展开后,再决定变量的值。也就是说,变量的值将会是整个,Makefile中最后被指定的值。看例子:
{% codeblock lang:makefile %}
x = foo
y = $(x) bar
x = xyz
{% endcodeblock %}
在上例中,y的值将会是 xyz bar ,而不是 foo bar 。- “ := ”表示变量的值决定于它在makefile中的位置,而不是整个makefile展开后的最终值。
{% codeblock lang:makefile %}
x := foo
y := $(x) bar
x := xyz
{% endcodeblock %}
在上例中,y的值将会是 foo bar ,而不是 xyz bar 了。


第八行:
{% codeblock lang:makefile %}
CFLAGS := -Wall -O2
{% endcodeblock %}

  • 作用:将gcc的编译参数赋值给左边变量,为了简化书写;
  • 分析:-Wall显示所有编译错误或警告;-O2优化选项,编译时使用2级优化

第九行:
{% codeblock lang:makefile %}
CPPFLAGS := -nostdinc -I$(INCLUDEDIR)
{% endcodeblock %}

  • 作用:将gcc编译路径参数赋值给左边变量,为了简化书写;
  • 分析:-nostdinc忽略系统库目录(这里我们自定义了printf等系统函数,不能再包含系统文件里的相关函数);-I指定搜索路径;

第十一行:
{% codeblock lang:makefile %}
export CC LD AR OBJCOPY OBJDUMP INCLUDEDIR CFLAGS CPPFLAGS
{% endcodeblock %}

  • 作用:将变量传递到下级Makefile,类似于宏;
  • 分析:本文件中指的是生成lib/libc.a库文件时的Makefile;

第十三行:
{% codeblock lang:makefile %}
objs := head.o init.o nand.o interrupt.o serial.o lcddrv.o/
framebuffer.o lcdlib.o main.o lib libc.a
{% endcodeblock %}

  • 作用:定义变量objs,包含了生成目标文件所需的文件,为了简化书写;
  • 分析:一行代码写不完,使用/符号可继续在下行写;

第十六行:
{% codeblock lang:makefile %}
lcd.bin: $(objs)
{% endcodeblock %}

  • 作用:定义生成目标lcd.bin,依赖于objs对象;
  • 分析:执行这条命令时,先生成所有依赖文件,然后依次执行后面三条命令;

第十七行:
{% codeblock lang:makefile %}
${LD} -Tlcd.lds -o lcd_elf $^
{% endcodeblock %}

  • 作用:根据链接脚本lcd.lds链接,输出目的文件lcd_elf,依赖全部文件;
  • 分析:-T指定链接脚本;$^表示全部依赖文件;

第十八行:
{% codeblock lang:makefile %}
${OBJCOPY} -O binary -S lcd_elf $@
{% endcodeblock %}

  • 作用:将lcd_elf文件转换成二进制文件;
  • 分析:-O表示输出格式;-S表示不从源文件中复制重定位信息和符号信息到目标文件中;$@表示全部目标文件;

第十九行:
{% codeblock lang:makefile %}
${OBJDUMP} -D -m arm lcd_elf > lcd.dis
{% endcodeblock %}

  • 作用:将lcd_elf文件反汇编为lcd.dis文件;
  • 分析:-m后面跟的是cpu构架;>表示将这个程序的反汇编程序写入到led.dis这个文件中,在终端中不显示出来;

第二十一行:
{% codeblock lang:makefile %}
.PHONY : lib/libc.a
{% endcodeblock %}

  • 作用:.PHONY伪目标,不要管lib/libc.a文件是否存在,都执行后面的指令;
  • 分析:通常为了避免伪目标和文件重名的这种情况,使用特殊的记“.PHONY”来显示地指明一个目标是“伪目标”;

第二十二、二十三行:
{% codeblock lang:makefile %}
lib/libc.a:
cd lib; make; cd …
{% endcodeblock %}

  • 作用:执行lib文件夹的Makefile,从而生成libc.a;
  • 分析:执行shell指令,进入lib目录,make,退出;

第二十五至二十九行:
{% codeblock lang:makefile %}
%.o:%.c
${CC} $(CPPFLAGS) $(CFLAGS) -c -o $@ $<
%.o:%.S
${CC} $(CPPFLAGS) $(CFLAGS) -c -o $@ $<
{% endcodeblock %}

  • 作用:依赖所有的.c和.S文件,生成所有的.o文件;
  • 分析:%通配符;-c编译不链接; @ 表 示 目 标 文 件 ; @表示目标文件; @;<表示第一个依赖文件;

第三十一至三十三行:
{% codeblock lang:makefile %}
%.o:%.S
clean:
make clean -C lib
rm -f lcd.bin lcd_elf lcd.dis *.o
{% endcodeblock %}

  • 作用:清理所有生成文件;
  • 分析:-C lib即清理包括lib文件夹下生成的文件;

下面是lib目录Makefile:

{% codeblock lang:makefile [lib目录Makefile]%}
objs := div64.o lib1funcs.o ctype.o muldi3.o printf.o string.o/
vsprintf.o

libc.a: $(objs)
${AR} -r -o $@ $^

%.o:%.c
${CC} $(CPPFLAGS) $(CFLAGS) -c -o $@ $<

%.o:%.S
${CC} $(CPPFLAGS) $(CFLAGS) -c -o $@ $<

clean:
rm -f libc.a *.o

{% endcodeblock %}


第一、二行:
{% codeblock lang:makefile %}
objs := div64.o lib1funcs.o ctype.o muldi3.o printf.o string.o/
vsprintf.o
{% endcodeblock %}

  • 作用:定义变量objs,包含了生成目标文件所需的文件,为了简化书写;
  • 分析:一行代码写不完,使用/符号可继续在下行写;

第四、五行:
{% codeblock lang:makefile %}
libc.a: $(objs)
${AR} -r -o $@ $^
{% endcodeblock %}

  • 作用:使用库管理器生成lib.a;
  • 分析: @ 表 示 目 标 文 件 ; @表示目标文件; @;^所有依赖文件;

第七至十一行:
{% codeblock lang:makefile %}
%.o:%.c
${CC} $(CPPFLAGS) $(CFLAGS) -c -o $@ $<
%.o:%.S
${CC} $(CPPFLAGS) $(CFLAGS) -c -o $@ $<
{% endcodeblock %}

  • 作用:依赖所有的.c和.S文件,生成所有的.o文件;
  • 分析:%通配符;-c编译不链接; @ 表 示 目 标 文 件 ; @表示目标文件; @;<表示第一个依赖文件;

第十三、十四行:
{% codeblock lang:makefile %}
%.o:%.S
clean:
rm -f libc.a *.o
{% endcodeblock %}

  • 作用:清理所有生成文件;
  • 分析:-f强制删除;

参考博文:sekon LCD实验学习笔记(一):Makefile

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值