make--变量与函数的综合示例 自动生成依赖关系

一.变量与函数的示例

示例的要求
1.自动生成target文件夹存放可执行文件
2.自动生成objs文件夹存放编译生成的目标文件
3.支持调试版本的编译选项
4.考虑代码的扩展性
完成该示例所需的
1.$(wildcardpattern)获取当前工作目录中满足pattern的文件或目录列表
2.$(addprefix,_name)给名字列表name的每一个名字增加前缀_prefix
关键技巧
1.自动获取当前目录下的源文件列表(函数调用)

SRC : = $(wildcard *.c)

2.根据源文件列表生成目标目标文件列表(变量的值替换)

OBJS := $(SRCS:.c=.o)

3.对每一个目标文件列表加上路径前缀(函数调用)

OBJS := $(addprefix path/,$(OBJS))

规则中的模式替换(目录结构)

编译规则的依赖

编译的示例代码及运行结果

CC := gcc
MKDIR := mkdir
RM := rm -fr

DIR_OBJS := objs
DIR_TARGET := target

DIRS := $(DIR_OBJS) $(DIR_TARGET)

TARGET := $(DIR_TARGET)/hello-makefile.out
# main.c const.c func.c
SRCS := $(wildcard *.c)
# main.o const.o func.o
OBJS := $(SRCS:.c=.o)
# objs/main.o objs/const.o objs/func.o
OBJS := $(addprefix $(DIR_OBJS)/, $(OBJS))

.PHONY : rebuild clean all

$(TARGET) : $(DIRS) $(OBJS)
    $(CC) -o [email protected] $(OBJS)
    @echo "Target File ==> [email protected]"

$(DIRS) :
    $(MKDIR) [email protected]

$(DIR_OBJS)/%.o : %.c
    ifeq ($(DEBUG),true)
        $(CC) -o [email protected] -g -c $^
    else
        $(CC) -o [email protected] -c $^
    endif

rebuild : clean all

all : $(TARGET)

clean :
    $(RM) $(DIRS)

运行结果

小结:
1.目录可以成为目标的依赖,在规则中创建目录
2.预定义函数是makefile不可或缺的部分
3.规则这的模式匹配可以直接针对目录中的文件
4.可以使用命令行变量编译特殊的目标版本

二.自动生成依赖关系

一.编译行为带来的缺陷
1.预处理器将头文件中的代码直接插入源文件
2.编译器只能通过预处理后的源文件产生目标文件‘
所以,规则中以源文件为依赖,命令可能无法执行
示例

在第一张图可以看出main.c与func.c是依赖于func.h的,此时将func.h中的打印信息改了之后运行的结果如下图所示


由运行的结果可以看到把打印的信息改变了,但是make之后的结果并没有改变,这是因为并没有把func.h算子啊依赖上去,所以在它的打印信息改变之后,结果还是一样的 ,需要进行以下修改才能实现修改打印信息,运行结果也改变(如图所示)

由上面的解决方法可以得出
1.头文件作为依赖条出现于每个目标对应的规则中
2.当头文件改动,任何源文件都将被重新编译
3.当项目中头文件数量巨大时,makefile将很难维护

二.改进的方法
1.通过命令自动生成对头文件的依赖
2.将生成的依赖自动包含进makefile中
3.当头文件改动后,自动确认需要重新编译的文件
所需条件
1.Linux命令sed
2.编译器依赖生成选项gcc -MM(gcc -M)
A.Linux中的sed命令
1.sed是一个流编辑器,用于流文本的修改(增/删/查/改)
2.sed可用于流文本的中的字符串替换
3.sed的字符串替换方式为 :sed ‘s:src:des:g‘

B.sed的正则表达式支持
1.在sed中可以用正在表达式匹配替换目标
2.并且可以使用匹配的目标生成替换结果

C.gcc关键编译选项(生成依赖关系)
1.获取目标的完整依赖关系(gcc -M test.c)
2.获取目标的部分依赖关系(gcc -MM test.c)
D.makefile中的include关键字
1.类似C语言中的include
2.将其它文件的内容原封不动的搬入当前文件


make对include关键字的处理方式
a.在当前目录搜索或指定目录搜索目标文件
1.搜索成功:将文件搬入当前makefile中
2.搜索失败:产生警告
a.以文件名作为目标查找并执行对应规则
b.当前文件名对应的规则不存在时,最终产生错误
代码示例及运行结果

makefile中命令的执行机制
1.规则中的每个命令默认是在一个新的进程中执行
2.可以通过连续符(;)将多个命令组成一个命令
3.组合的命令依次在同一个进程中被执行
4.set -e指定发生错误后立即退出执行

示例:


该代码主要的目的是想在当前文件夹下新建test文件夹,然后进入test文件夹,创建subtest文件夹,但是make之后的结果如图所示,可以看到subtest与test文件夹在同一级目录,不是我们要的结果
经过修改之后的代码及运行结果

三.综合示例

思路:通过gcc -MM 和sed得到.dep依赖文件,通过inclue指令包含所有的.dep依赖文件

运行的结果:

该示例可能会出现的问题是如何在makefile在组织.dep文件到指定目录
解决的思路:
当include发现.dep文件不存在:
1.通过规则和命令创建deps文件
2.将所有.dep文件创建到deps文件夹
3..dep文件记录目标文件的依赖关系
代码实现

总结:
a.使用减号(-)不但关闭了include发出的警告,同时关闭了错误,当错误发生时make将忽略这些错误
b.当目标文件不存在(以文件名查找规则,并执行)
c.当目标文件不存在,且查找到的规则在创建了目标文件(将创建成功的目标文件包含进当前makefile)
d.当目标文件存在(将目标文件包含进当前makefile,以目标文件名查找是否有相应的规则)
e.当目标文件存在,且目标名对应的规则被执行(规则中的命令更新了目标文件,make重新包含目标文件,替换之前包含的内容),目标文件未被更新(无操作)

原文地址:http://blog.51cto.com/13475106/2348754

时间: 2024-09-30 03:55:58

make--变量与函数的综合示例 自动生成依赖关系的相关文章

第10课 - 变量与函数的综合示例

第10课 - 变量与函数的综合示例 1. 实战需求 (1)自动生成 target 文件夹存放可执行文件 (2)自动生成 objs 文件夹存放编译生成的目标文件(*.o) (3)支持调试版本的编译选项 (4)考虑代码的扩展性  --> 使用变量 2. 工具原料 - $(wildcard _pattern) 获取当前工作目录中满足_pattern的文件或目录列表 - $(addprefix _prefix, _names) 给名字列表_names中的每一个名字增加前缀_prefix 3. 关键技巧

自动生成依赖关系(十)

我们在之前的 makefile 学习中,其目标文件(.o)只依赖于源文件(.c).那么如果在源文件中还包含有头文件,此时编译器如何编译源文件和头文件呢?我们来看看编译行为带来的缺陷:1.预处理器将头文件中的代码直接插入源文件:2.编译器只通过预处理后的源文件产生目标文件:3.规则中以源文件为依赖,命令就可能无法执行. 我们来看看下面的 makefile 有没有问题 makefile 源码 OBJS := func.o main.o hello.out : $(OBJS)     @gcc -o 

Makefile学习7————自动生成依赖关系 三颗星

后面会介绍gcc获得源文件依赖的方法,gcc这个功能就是为make而存在的.我们采用gcc的-MM选项结合sed命令.使用sed进行替换的目的是为了在目标名前加上"objs/"前缀.gcc的-E选项,预处理.在生成依赖关系时,其实并不需要gcc编译源文件,只要预处理就可以获得依赖关系了.通过-E选项,可以避免生成依赖关系时gcc发出警告,以及提高依赖关系的生成效率. 现在,已经找到自动生成依赖关系的方法了,那么如何将其整合到我们complicated项目的Makefile中呢?自动生成

Makefile 7——自动生成依赖关系 三颗星

后面会介绍gcc获得源文件依赖的方法,gcc这个功能就是为make而存在的.我们采用gcc的-MM选项结合sed命令.使用sed进行替换的目的是为了在目标名前加上"objs/"前缀.gcc的-E选项,预处理.在生成依赖关系时,其实并不需要gcc编译源文件,只要预处理就可以获得依赖关系了.通过-E选项,可以避免生成依赖关系时gcc发出警告,以及提高依赖关系的生成效率. 现在,已经找到自动生成依赖关系的方法了,那么如何将其整合到我们complicated项目的Makefile中呢?自动生成

变量与函数的综合示例(九)

之前我们学习了 makefile 中的变量及函数的相关语法知识,那么我们今天就来以实际需求为例来进行实际编写.实战需求:1.自动生成 target 文件夹存放可执行文件:2.自动生成 objs 文件夹存放编译生成的目标文件(*.o):3.支持调试版本的编译选项:4.考虑代码的扩展性. 那么在进行今天的 makefile 编写之前,我们还需要了解下几个知识点:a> $(wildcard _pattern),它的作用是获取当前工作目录中满足 _pattern 的文件或目录列表:b> $(addpr

makefile自动生成依赖关系 可自动检测头文件变化

DEBUG=1 CC = gcc CXX=g++ ifeq ($(DEBUG), 1) OPTS=-O0 -g -DDEBUG endif CFLAGS = -fPIC   -I$(COMPILE_DIR) -I$(vesdkdev)  -I$(es_common) -I$(vesdk) -I$(vesdk)/boost-153/include -I$(vesdkproject) CXXFLAGS=$(CFLAGS) Target = libServerCfg.so VPATH = src OB

Makeflie自动生成依赖,自动化编译

在netbeans里开发,有一个重要文件makefile,是用来编译所有的文件. 项目的目录结构如下,扁平的目录结构,如何实现自动化编译,写makefile呢? 第一版 基础版: CC = g++ CFLAGS = -O3 -DNDEBUG SOURCE =AdaBoost.cpp aodeselect.cpp sample.cpp vfan.cpp kdbext2.cpp tan_gen.cpp petal: ${SOURCE} $(CC) -o [email protected] ${SOU

make自动生成依赖文件的两种形式

最近编译源文件发现当修改头文件后,make并不会自动把包含此头文件的所有源文件重新编译,而每次都是需要把对应的中间文件清除才能重新编译,非常的麻烦.因此需要make自动对源文件所依赖的头文件进行管理,即make自动生成依赖文件.鉴于本人的刚开始写的博客,很多方面经验不足,比如如何介绍我所用到的知识等,现在只是对我在过程中遇到的问题进行记录,相关的知识可以查看gnu make中文文档,上网等等. 遇到的问题记录如下:1.make在生成依赖文件后并不正确:原因是生成的依赖文件中的目标文件(.d与.o

第19课 - 路径搜索的综合示例

第19课 - 路径搜索的综合示例 1. 需求分析 (1)工程项目中不希望源码文件夹在编译时被改动(只读文件夹) (2)在编译时自动创建文件夹(build)用于存放编译结果 (3)编译过程中能够自动搜索需要的文件 (4)makefile 易于扩展,能够复用于相同类型的项目 (5)支持调试版本的编译选项 2. 项目类型分析 3. 工具原料 4. 关键技巧 5. 编译规则的依赖 值得斟酌的问题? 对于规模较小的项目,makefile 中是否也需要使用自动生成依赖关系的解决方案呢? 模式规则的灵活运用使