【嵌入式】Linux开发工具make及makefile设计

Linux开发工具arm-linux-gcc

make工具及makefile设计

make工具有何价值?

  • 项目源码文件较多时如何编译?

    • 项目目录 /main.c f1.c f2.c …. f100.c
    • 逐条编译不方便
  • 修改部分源码后是否要全部重新编译一遍?

    • 假设修改 f1.c,是否可以仅编译 f1.c,然后连接目标文件成可执行文件即可?
  • make 工具是一个自动的辅助编译的程序,相当于一个 Shell,通过解释Makefile 的中的规则进行工作。

    • Visual C++ 的 nmake
    • Linux 下 GNU 的 make

make是命令行工具, makefile 文件存放一条条规则,make读取某文件夹下的makefile文件,对该文件夹下相应的源码文件进行处理(编译、连接或者其它处理)
在这里插入图片描述


规则:makefile 的基本单位,每一条规则说明一个目标文件(包括所依赖的文件和模块以及生成和更新目标文件的命令)生成的方法。

规则格式:

目标文件 [目标文件属性]: [依赖文件1], [文件2][命令行1;]
	[命令行2;]
	……

规则的执行:
在这里插入图片描述

Makefile 设计示例

例:
目录下只有 hello.c, include, Makefile, max.c, min.c 这几个文件,使用make 编译。

Makefile 的内容:

# hello是目标文件,依赖文件是hello.o,max.o和min.o,规则1
hello:hello.o max.o min.o
		arm-linux-gcc -o hello hello.o max.o min.o
# hello.o是目标文件,依赖文件是hello.c,规则2
hello.o:hello.c
		arm-linux-gcc -c -o hello.o hello.c -I./include
# max.o是目标文件,依赖文件是max.c,规则3
max.o:max.c
		arm-linux-gcc -c -o max.o max.c
# min.o是目标文件,依赖文件是min.c,规则4
min.o:min.c
		arm-linux-gcc -c -o min.o min.c

在这里插入图片描述
这个示例中,一开始目录下只有 hello.c, include, Makefile, max.c, min.c 这几个文件。

⑤执行make max.o ,会去读取 Makefile,其中【规则3】{max.o是目标文件,依赖文件是max.c},由于目录下存在 max.c,因此会调用规则3的命令arm-linux-gcc -c -o max.o max.c,生成目标文件 max.o。

此时目录下有hello.c, include, Makefile, max.c, min.c, max.o (多了max.o)。

⑥执行make hello,读取 Makefile 文件,发现是【规则1】{hello是目标文件,依赖文件是hello.o,max.o和min.o}。由于目录下没有hello.o, min.o,无法执行【规则1】,因此会先去执行【规则2】(生成hello.o)、【规则4】(生成min.o)、最后再执行【规则1】(依赖文件全了)。
执行完以后,目录下有hello.c, include, Makefile, max.c, min.c, max.o, hello.o, min.o, hello(多了min.o, hello.o, hello)。


Makefile 规则–构成

Makefile 规则

  • 显式规则
    Makefile 的书写者明显指出要生成的目标文件,目标文件的依赖文件,生成的命令
  • 隐晦规则
    make 有自动推导的功能,可以简略的书写 Makefile。

Makefile 构成

  • 变量的定义
    在 Makefile 中我们可以定义一系列的变量,变量一般都是字符串,像C语言中的宏,当 Makefile 被执行时,其中的变量都会被扩展到相应的引用位置上。
  • 文件指示
  • 注释
    Makefile 中只有行注释,注释是用#字符

Makefile 变量(宏)

为了简化编辑和维护 Makefile,make允许在 Makefile 中创建和使用变量。
所谓的变量就像是C/C++语言中的宏一样,代表文本字串,在 Makefile 中执行的时候会自动原样地展开在所使用的地方,其与C/C++所不同的是可以在 Makefile 中改变其值。在 Makefile 中,变量可以使用在**“目标”,“依赖目标”,“命令”**或是 Makefile 的其它部分中。

变量的定义格式:

  • 变量名 赋值符号 变量的值
  • 变量的命名字可以包含字符、数字,下划线(可以是数字开头),但不应该含有:#=或是空字符(空格、回车等)
  • 变量名大小写敏感

赋值符号有三种:


  • 直接将后面的字符串赋给变量
  • :=
    后面跟字符串常量,将它的内容赋给变量
  • +=
    变量原来的值+空格+后面的字符串=>新的变量值

变量引用格式:

  • $(变量名)
  • ${变量名}
  • 当变量名为单个字符时,可以省略括号
  • make处理变量时会扫描一遍整个 makefile,确定所有变量的值,因此变量的使用可以在定义之后,而且使用的是最后一次赋予的值。
objects = program.o foo.o utils.o #objects为变量名
#一条规则,目标文件是program,依赖文件是program.o, foo.o, utils.o
program : $(objects) 
   cc -o program $(objects) #规则执行的命令

变量的定义可以出现在三个地方:

  • 在 makefile 中定义
  • make命令行中定义
  • 使用 shell 环境中的定义

优先级:
(1)make命令行中定义
(2)在makefile中定义
(3)使用shell环境中的定义
(4)预定义的变量

GNU make预定义变量
make有许多预定义的变量,这些变量具有特殊的含义,可在规则中直接使用

常用的预定义变量:
在这里插入图片描述
在这里插入图片描述

Makefile 条件判断

条件表达式的语法为:

<conditional-directive> #ifeq,ifneq ,ifdef,ifndef    
	<text-if-true>
	endif

其中<conditional-directive>表示条件关键字,如 ifeq

这个关键字有四个:ifeqifneqifdefifndef

Makefile 中 for 语句

for k in $(DIRS); 
	do ......

k 依次取变量DIRS中的每一个值,执行do后面的语句

Makefile 规则

wildcard 函数(通配符)

wildcard函数

$(wildcard PATTERN)
  • 函数功能
    获取目录下匹配 PATTERN 的所有对象
    返回值:使用空格分割的匹配对象名列表

示例:
目录下有hello.c, include, Makefile, max.c, min.c这些文件。

#匹配目录下的所有.c文件,并返回按空格分隔后的对象名列表
SRCS := $(wildcard *.c) 

该指令匹配到了hello.c, max.c, min.c三个文件,赋值给 SRCS,那么 SRCS 就相当于hello.c max.c min.c
在这里插入图片描述

patsubst 函数(模式字符串替换)

$(patsubst pattern, replacement, text)

函数功能:

  • 查找text字符串中的单词
    如果符合模式pattern,则以replacement替换
  • pattern可以包括通配符%,表示任意长度的字串
  • 返回:函数返回被替换过后的字符串。

例:

OBJS := $(patsubst %.c, %.o, $(SRCS))

即查询SRCS变量对应的字符串中的单词,将所有 .c 文件替换为 .o 文件。

在这里插入图片描述

隐含规则

GNU make 支持两种类型的隐含规则:

  • 后缀规则(Suffix Rule)
    后缀规则是定义隐含规则的老风格方法。后缀规则定义了将一个具有某个后缀的文件(例如.c文件)转换为具有另外一种后缀的文件(例如.o文件)的方法。每个后缀规则以两个成对出现的后缀名定义。

例如,将 .c 文件转换为 .o 文件的后缀规则可定义为:

.c.o:
	$(CC) $(CCFLAGS) $(CPPFLAGS) -c -o $@ $<
  • 模式规则(pattern rules)。
    这种规则更加通用,因为可以利用模式规则定义更加复杂的依赖性规则。模式规则看起来非常类似于正则规则,但在目标名称的前面多了一个%号,同时可用来定义目标和依赖文件之间的关系。

例如,将任意一个.c文件转换为.o文件:

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

伪目标

在 makefile 中,目标分为两类:实目标伪目标

  • 实目标
    会生成实际的文件
main.o:mai.c
	$(CC) $(CCFLAGS) -c -o $@ $<
  • 伪目标
    不会生成实际的文件,大多一些辅助性操作,如打印信息、删除文件。
clean:            
	rm *.o
  • 为了避免和文件重名的这种情况,可以使用一个特殊的标记.PHONY来显式地指明一个目标是“伪目标”,也可不加。
.PHONY: clean
	clean:
		rm *.o hello

标准版 Makefile

# 自动匹配目录下的文件列表
SRCS:=(wildcard *.c)
OBJS:=(patsubst %.c,%.o,$(SRCS))
CFLAGS += -I./include -g

all:hello #第一条目标规则

hello:$(OBJS) # 链接规则
	arm-linux-gcc -o $@ $(OBJS)
%.o:%.c # C转换目标文件编译规则
	arm-linux-gcc -c -o $@ $< $(CFLAGS)
clean:# 清除规则
	rm *.o hello

在这里插入图片描述

makefile文件的命名

缺省情况下,make 按顺序:GNUmakefilemakefileMakefile 寻找 Makefile文件

如果要指定 makefile 文件,通过 makefile -fmakefile --file
例如:makefile -f myMakeFile指定名为myMakeFilemakefile文件

课后作业

(1) 下列文件是可执行程序的为(A、B、D
A、arm-linux-gcc
B、make
C、Makefile
D、gdb

解:
缺省情况下,make 按顺序:GNUmakefilemakefileMakefile 寻找 Makefile文件

(2) 假设文件夹 /opt/exp 下存放C源码文件 f1.c/f2.c/…/f10.c/main.c,其中main.c 是程序主文件,其它文件为函数文件,要求编写 Makefile,要求能使用 make 命令可以生成可执行 exp,运行 make clean 则可以清除该文件夹下目标文件和 exp。

SRCS:=$(wildcard *.c)
OBJS:=$(patsubst %.c,%.o,$(SRCS)) 
# OBJS:=$(patsubst %.c,%.o,$(WILDCARD)) 也可以

all:exp

exp:$(OBJS)
	arm-linux-gcc -o $exp $(OBJS)
	# arm-linux-gcc -o $@ $(OBJS)

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

clean:
	rm *.o exp

解析:

C语言生成可执行文件的步骤:
在这里插入图片描述
预定义变量$@:目标的完整名称。
预定义变量$<:第一个依赖文件的名称。
预定义变量$(CFLAGS):表示用于 C 编译器。

由于存放的文件都是.c文件,因此用wildcard函数获取所有.c文件,赋值给SRCS。

SRCS:=$(wildcard *.c)

由于要求能使用make命令可以生成可执行exp,则需要.o文件来链接,此规则的目标文件是exp,依赖文件是.o
使用patsubst函数将SRCS中所有.c文件替换为.o,赋值给 OBJS。

OBJS:=$(patsubst %.c,%.o,$(SRCS))
exp:$(OBJS)
	arm-linux-gcc -o exp $(OBJS)

.o文件需要通过.c文件编译而来,此规则的目标文件是%.o,依赖文件是%.c

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

要求运行 make clean 则可以清除该文件夹下目标文件和 exp。

clean:
	rm *.o exp
发布了170 篇原创文章 · 获赞 47 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/weixin_43734095/article/details/105090729