嵌入式之Makefile的学习

本文章适用于从事嵌入式uboot移植,和驱动开发的工程师阅读,涉及到的知识点比较基础,涉及内容不是那么深入。

首先Makefile是管理一个大型项目必须的文件,当一个项目中涉及到多个C语言程序和.h头文件的时候,这种情况下就必须使用到Makefile进行项目的编译和链接。

Makefile文件的格式:

目标:依赖
TAB命令

命令前面是一个Tab键,当且仅当是Tab按键,不能是空格,必须是一个Tab按键。然后书写命令。

一、一个简单的Makefile文件的编写与执行

1、Makefile文件的编写

编译一个.c文件,生成hello的输出文件。

  1 hello:hello.c
  2     gcc hello.c -o hello 
  3 
  4 clean:
  5     rm hello
                 

在Linux的命令行中使用make hello命令,就可以直接执行gcc hello.c -o hello这句代码;当在Linux命令行中键入make clean命令,就会执行rm hello这句代码,将生成的hello可执行文件删除。其中使用make命令等同于make hello。默认make执行第一个目标所对应的命令。

二、裸机程序的Makefile分析

led.bin: start.o 
	arm-linux-ld -Ttext 0x0 -o led.elf $^	//生成可执行文件led.elf,这个文件不可用来烧录;$^依赖文件集合
	arm-linux-objcopy -O binary led.elf led.bin  ;用来生成可烧写的镜像文件的。
	arm-linux-objdump -D led.elf > led_elf.dis	;用来反汇编的。就是把编译好的elf格式的可执行程序,反过来,得到汇编源代码
	gcc mkv210_image.c -o mkx210	;gcc是用来生成可执行程序,在Ubuntu中执行的
	./mkx210 led.bin 210.bin		;制作SD卡启动的镜像,目的就是为了加上校验头
	
%.o : %.S    ;%是makefile中的通配符,%.o代表所有.o的文件,自动推导规则
	arm-linux-gcc -o $@ $< -c	;$@代表目标文件的名称,$<代表依赖文件的名称;-c是只编译不链接的意思

%.o : %.c
	arm-linux-gcc -o $@ $< -c 

.PHONY clean
clean:
	rm *.o *.elf *.bin *.dis mkx210 -f

这是编译一个裸机程序所使用到的Makefile文件,其中涉及到几个知识点:

1、Makefile自动推导规则

比如我们使用make的时候,此时就需要执行led.bin对应的命令,但是在执行该命令之前,程序会自动检测依赖文件start.o的来源,首先我们找不到这个start.o文件在哪里,这时候程序就会从下面的目标中寻找,首先判断该.o文件是不是由.S文件生成的,如果是就会执行对应目标下的命令,来生成该.o文件;如果不是,程序就会检测是不是对应的.c文件生成的,如果是,就会执行对应的命令生成.o的文件。这就是Makefile的自动推导规则。

2、Makefile的伪目标

伪目标就是没有依赖的目标,这段程序的目的就是为了执行伪目标对应的命令,不生成任何的文件,所以叫做伪目标。表示方式就是在.PHONY,例如上面clean目标就是一个伪目标。就是为了执行删除的目的。

3、Makefile中一些自动变量

Makefile中预定义的具有特殊意义的符号,也就是命令中对于目标和依赖文件的简写:

$@:规则中目标文件名;

$<:规则中所有依赖文件中的第一个依赖文件;

$^:所有依赖文件的集合。

4、Makefile中的通配符

(1) * : 若干个任意字符。

(2) ? : 1个任意字符。

(3) [ ] : 将[]中字符一次与外面的匹配结合。

(4) % : 表示任意字符,但是只用于规则描述中,又叫做规则通配符。

例如项目中有1.c、2.c、12.c、test.c几个文件,使用下面通配符进行输出的结果:

  1 all:1.c 2.c 12.c test.c
  2     echo *.c #会输出所有的文件
  3     echo ?.c   #输出1.c和2.c,长度为1的
  4     echo [12].c    #输出1.c和2.c
  5 

5、其他几点注意事项

(1)Makefile中注释和shell中相同的,都是用#进行注释

(2)在命令前面加上@符号,表示静默执行,makefile在执行的时候就不会输出该命令。而是直接输出结果。

(3)变量的赋值运算符号:

"?=":表示如果前面定义过变量,就不给该变量赋值,如果前面没有该变量的定义,就给该变量赋值。

"+=":可以将Makefile中的变量,看成字符串,该赋值运算符,就相当于字符串的strcat函数的作用,将字符串连接起来。

"="   : 变量的赋值,需要前后考虑,不仅是前面变量的值,如果在后面变量的值发生改变,也是会对这个产生作用的。

":=" :变量的赋值,只考虑前面的代码。下面使用代码进行讲解。

  1 
  2 
  3 A=abc
  4 B=$(A)def
  5 A=ght
  6 
  7 all:
  8     echo $B    
#这段代码的输出为ghtdef 

  1 
  2 
  3 A=abc
  4 B:=$(A)def
  5 A=ght
  6 
  7 target1:
  8     echo $B
#这段代码的输出为abcdef

三、子Makefile和主Makefile如何关联

当一个项目中涉及到多个Makefile时,该如何去管理这些Makefile了,我们将项目中涉及到的多个Makefile分为两个大类:主Makefile和子Makefile。我们如何让这里Makefile能够很好的合作,而不出问题了,怎么通过主Makefile来编译所有的子Makefile对应的文件呢?

例如这里的两个Makefile文件。

 

#子Makefile文件
objs := div64.o lib1funcs.o ctype.o muldi3.o printf.o string.o vsprintf.o

libc.a: $(objs)
	${AR} -r -o $@ $^   #使用AR,这个命令是主Makefile文件传递过来的,用来生成库文件的
	
%.o:%.c
	${CC} $(CPPFLAGS) $(CFLAGS) -c -o $@ $<

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

clean:
	rm -f libc.a *.o		

 

 

#主Makefile文件
CC		= arm-linux-gcc
LD 		= arm-linux-ld
OBJCOPY	= arm-linux-objcopy
OBJDUMP	= arm-linux-objdump
AR		= arm-linux-ar

INCDIR	:= $(shell pwd)
# C预处理器的flag,flag就是编译器可选的选项
CPPFLAGS	:= -nostdlib -nostdinc -I$(INCDIR)/include
# C编译器的flag,-O2优化等级,-fno-builtin在编译链接的时候使用本地的文件和头文件
CFLAGS		:= -Wall -O2 -fno-builtin

#导出这些变量到全局,其实就是给子文件夹下面的Makefile使用
export CC LD OBJCOPY OBJDUMP AR CPPFLAGS CFLAGS


objs := start.o sdram_init.o led.o uart.o main.o
#objs += clock.o
objs += lib/libc.a 

uart.bin: $(objs)
	$(LD) -Tlink.lds -o uart.elf $^
	$(OBJCOPY) -O binary uart.elf uart.bin
	$(OBJDUMP) -D uart.elf > uart_elf.dis
	gcc mkv210_image.c -o mkx210
	./mkx210 uart.bin 210.bin

lib/libc.a:
	cd lib;	make;	cd ..
	
%.o : %.S
	$(CC) $(CPPFLAGS) $(CFLAGS) -o $@ $< -c

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

clean:
	rm *.o *.elf *.bin *.dis mkx210 -f
	cd lib; make clean; cd ..

	
	

1、objs += lib/libc.a 这句代码,就是将主Makefile和子Makefile关联起来的代码,当执行目标的时候,主Makefile就会判断依赖文件的来源,这时候就会检测到libc.a文件的对应的目标,就会执行

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

对应的命令,注意这几句代码,需要放在一行书写。然后进入lib文件夹,使用make命令执行子Makefile中命令,然后退出子目录,回到主Makefile中。

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值