现在我们再对complicated项目做一些更改,增加程序文件间依赖关系的复杂度。

 /×    main.c   ×/
#include"foo.h"
int main(void)
{
foo();
return ;
} /* foo.c */
#include<stdio.h>
#include"foo.h"
void foo(void)
{
printf("%s,This is foo()!\n",HELLO);
} /* foo.h */
#ifndef __FOO_H
#define __FOO_H
#include "define.h"
void foo(void); #endif /*__FOO_H*/ /* define.h */
#ifndef __DEFINE_H
#define __DEFINE_H #define HELLO "hello" #endif/*__DEFINE_H*/

在之前的Makefile不做更改的情况下,我们make一下:

在这次成功编译的基础上,我们再做一些改动,注意在这之前不要执行make clean,否则不能发现新问题。

 /×    define.h    */
#ifndef __DEFINE_H
#define __DEFINE_H #include "other.h" #endif/*__DEFINE_H*/ /* other.h */
#ifndef __OTHER_H
#define __OTHER_H #define HELLO "hello" #endif /*__OTHER_H*/

从结果看,尽管foo.c和main.c都被重新编译了,但依赖关系却没有重新构建。运行complicated结果,其打印结果是我们所希望的“hello”。

现在,我们对other.h文件进行修改把hello改成hi,从下面运行结果来看,项目并没有因为更改了other文件而重新编译。

 #ifndef __OTHER_H
#define __OTHER_H #define HELLO "hi" #endif /*__OTHER_H*/

更改Makefile如下,更改部分红色标出了,其实只增加了一个$@:

 .PHONY: all clean

 MKDIR = mkdir
RM = rm
RMFLAGS = -rf CC=gcc DIR_OBJS=objs
DIR_EXES=exes
DIR_DEPS=deps DIRS =$(DIR_OBJS) $(DIR_EXES) $(DIR_DEPS) EXE=complicated
EXE:=$(addprefix $(DIR_EXES)/,$(EXE))
SRCS=$(wildcard *.c)
OBJS=$(SRCS:.c=.o)
OBJS:=$(addprefix $(DIR_OBJS)/,$(OBJS))
DEPS=$(SRCS:.c=.dep)
DEPS:=$(addprefix $(DIR_DEPS)/,$(DEPS)) ifeq ($(wildcard $(DIR_OBJS)),)
DEP_DIR_OBJS :=$(DIR_OBJS)
endif#dir_objs
ifeq ($(wildcard $(DIR_EXES)),)
DEP_DIR_EXES :=$(DIR_EXES)
endif#dir_exes
ifeq ($(wildcard $(DIR_DEPS)),)
DEP_DIR_DEPS :=$(DIR_DEPS)
endif#dir_deps
all: $(EXE) include $(DEPS) $(DIRS):
$(MKDIR) $@
$(EXE):$(DEP_DIR_EXES) $(OBJS)
$(CC) -o $@ $(filter %.o,$^)
$(DIR_OBJS)/%.o:$(DEP_DIR_OBJS) %.c
$(CC) -o $@ -c $(filter %.c,$^)
$(DIR_DEPS)/%.dep:$(DEP_DIR_DEPS) %.c
@echo "Creating $@ ..."
@set -e;\
$(RM) $(RMFLAGS) $@.tmp;\
$(CC) -E -MM $(filter %.c,$^) > $@.tmp;\
sed 's,\(.*\)\.o[:]*,objs/\1.o $@:,g' <$@.tmp >$@;\
$(RM) $(RMFLAGS) $@.tmp clean:
$(RM) $(RMFLAGS) $(DIRS)

这样之后,Makefile就可以知道other.h的更改了。因为$@表示的是依赖关系的文件名,这个问题(Makefile 6随笔中要把foo.h加在依赖关系中的更改一样)和之前的那个问题解决方案一样,用sed命令可以做到,问题的根本在于,我们应该为依赖文件增加依赖关系,这样才能将整个项目全局联系在一起。

但是,这样之后,连续执行两次make clean:

第一次clean时,没什么问题,也是我们期望的,第二次clean时,make会先构建依赖项,紧接着又把目录删除。为什么第二次clean时,make会重新构建依赖文件?因为我们有一个include指令,他会优先于目标执行!!!

为了解决这个问题,我们再运用条件语法,并且用到我们之前提到的MAKECMDGOALS变量。更改后的Makefile如下:

 .PHONY: all clean

 MKDIR = mkdir
RM = rm
RMFLAGS = -rf CC=gcc DIR_OBJS=objs
DIR_EXES=exes
DIR_DEPS=deps DIRS =$(DIR_OBJS) $(DIR_EXES) $(DIR_DEPS) EXE=complicated
EXE:=$(addprefix $(DIR_EXES)/,$(EXE))
SRCS=$(wildcard *.c)
OBJS=$(SRCS:.c=.o)
OBJS:=$(addprefix $(DIR_OBJS)/,$(OBJS))
DEPS=$(SRCS:.c=.dep)
DEPS:=$(addprefix $(DIR_DEPS)/,$(DEPS)) ifeq ($(wildcard $(DIR_OBJS)),)
DEP_DIR_OBJS :=$(DIR_OBJS)
endif#dir_objs
ifeq ($(wildcard $(DIR_EXES)),)
DEP_DIR_EXES :=$(DIR_EXES)
endif#dir_exes
ifeq ($(wildcard $(DIR_DEPS)),)
DEP_DIR_DEPS :=$(DIR_DEPS)
endif#dir_deps all: $(EXE)
34 ifneq ($(MAKECMDGOALS),clean)
35 include $(DEPS)
36 endif#clean $(DIRS):
$(MKDIR) $@
$(EXE):$(DEP_DIR_EXES) $(OBJS)
$(CC) -o $@ $(filter %.o,$^)
$(DIR_OBJS)/%.o:$(DEP_DIR_OBJS) %.c
$(CC) -o $@ -c $(filter %.c,$^)
$(DIR_DEPS)/%.dep:$(DEP_DIR_DEPS) %.c
@echo "Creating $@ ..."
@set -e;\
$(RM) $(RMFLAGS) $@.tmp;\
$(CC) -E -MM $(filter %.c,$^) > $@.tmp;\
sed 's,\(.*\)\.o[:]*,objs/\1.o $@:,g' <$@.tmp >$@;\
$(RM) $(RMFLAGS) $@.tmp clean:
$(RM) $(RMFLAGS) $(DIRS)

这样就解决了。

再看一个例子:

 all:
@echo "command of rule" all: dep dep:
@echo "prerequisite of rule"

这个make的特性说明了一个问题:在生成的依赖关系文件中,其中的规则只描述了依赖关系,而没有任何的命令,make是怎么知道使用哪些命令进行目标构建的呢?

当一个Makefile中存在构建同一目标的不同规则时,make会将这些规则合在一起,合并的内容包括先决条件和命令。尽管在自动生成的依赖关系文件中只存在目标和先决条件,但是由于Makefile中已经定义了.o 和.dep文件的生成规则,因此make会将这两部分结合在一起,从而形成最终针对一个(类)构建目标的规则。上面的那个例子可以很好地帮助我们理解这个make特性。

Makefile 9——为依赖关系文件建立依赖关系的更多相关文章

  1. linux机器间建立信任关系

    linux机器间建立信任关系 如何建立信任关系 在shell脚本中,需要使用scp命令将本地的文件复制到另一台机器中备份.但通常执行scp命令后都需要输入用户密码,这样在定时自动执行shell脚本中就 ...

  2. Makefile 8——使用依赖关系文件

    Makefile中存在一个include指令,它的作用如同C语言中的#include预处理指令.在Makefile中,可以通过include指令将自动生成的依赖关系文件包含进来,从而使得依赖关系文件中 ...

  3. Makefile中头文件在依赖关系中作用

    摘于:http://bbs.csdn.net/topics/120024677 (1)在makefile的依赖关系中用不用体现.h头文件?(2)如果在依赖关系中要体现.h头文件,应该体现到什么层次?= ...

  4. makefile 自动处理头文件的依赖关系 (zz)

    现在我们的Makefile写成这样: all: main main: main.o stack.o maze.ogcc $^ -o $@ main.o: main.h stack.h maze.hst ...

  5. Makefile目标,伪目标,头文件自动依赖

    目标 即我们最终要生成的文件,make默认生成第一个目标,注意 makefile中tab和空格不是一回事,规则使用tab缩进,编辑器不要设置诸如"将tab替换为空格之类的选项",目 ...

  6. Makefile中自动生成头文件依赖

    为什么需要自动生成头文件依赖? 编译单个源文件时,需要获取文件中包含的头文件的信息,但是一般的Makefile不会在规则中明确写明文件依赖的头文件,所以单独修改头文件后,不会导致包含头文件的源文件重新 ...

  7. UML关系(泛化,实现,依赖,关联(聚合,组合))

    http://www.cnblogs.com/olvo/archive/2012/05/03/2481014.html UML类图关系(泛化 .继承.实现.依赖.关联.聚合.组合) 继承.实现.依赖. ...

  8. 《Entity Framework 6 Recipes》中文翻译系列 (41) ------ 第七章 使用对象服务之标识关系中使用依赖实体与异步查询保存

    翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 7-7  标识关系中使用依赖实体 问题 你想在标识关系中插入,更新和删除一个依赖实体 ...

  9. TestNg依赖详解(三)------灵活的文件配置依赖

    配置型的依赖测试,让依赖测试不局限于测试代码中,在XML文件中进行灵活的依赖配置 原创文章,版权所有,允许转载,标明出处:http://blog.csdn.net/wanghantong Javaco ...

随机推荐

  1. django from表单基础知识点

    今日概要: - 内容拾遗 - 分页 - Form验证 1.内容拾遗 - 新URL -提交时,保留之前的内容? - 对话框 - var data = $('#fmForm表单的ID').serializ ...

  2. jquery使用jsonp进行跨域调用

    关于JSONP的概念和为什么要使用JSONP网上已经有很多教程,这一节主要演示下在JQUERY中的ajax方法怎样通过JSONP进行远程调用 首先介绍下$.ajax的参数 type:请求方式 GET/ ...

  3. grafana-zabbix图形简单配置

    连接zabbix数据库 加入dashboard Home--Add--加入dashboad 设置dashboad 设置名字,和标签tag,tag可在输入后回车加入多个 加入简单的一张图,測试能否获取到 ...

  4. Android -- 启动模式

    Android的启动模式分为四种: standard 模式启动模式,每次激活Activity时都会创建Activity,并放入任务栈中. singleTop 如果在任务的栈顶正好存在该Activity ...

  5. Mongodb 官网驱动2.2.4.26版本 增,删 改,查

    Mongodb是3.2.7版本 最近在学习mongodb数据库在网上找到的都不是2.X版本以下的,因为驱动从2.X以后修改了很多,以前不支持linq现2.X也支持了, Mongodb 启动服务就不说了 ...

  6. (剑指Offer)面试题57:删除链表中的重复结点

    题目: 在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针. 例如,链表1->2->3->3->4->4->5 处理后为 ...

  7. C#应用视频教程3.3 Halcon+C#测试

    接下来我们考虑把Halcon的代码移植到C#程序上,首先找到halcon的dll(.NET类库有1.0,2.0,3.5的,如果你安装了更新版本的halcon则有更新的.NET类库,我们复制最新的dll ...

  8. 广州高清卫星地图 用百度卫星地图server下载 含标签、道路数据叠加 可商用

    广州高清卫星地图的地图展示图片各自是15级别.17级别.19级别的地图.一般来说17级别的地图图片就行用于商用.地图包包括一整张高级别的图片,如要全图浏览请用专业图片处理软件PS等打开. 一般来说互联 ...

  9. nDCG学习笔记

    参考:http://en.wikipedia.org/wiki/Discounted_cumulative_gain Normalized Discounted Cumulative Gain:一种对 ...

  10. FLV视频播放:对未缓冲进度条实现拖动

    FLV视频播放:对未缓冲进度条实现拖动  流媒体开发 Add comments 八282010 一.文件准备 1.转码:ffmpeg 2.添加元数据:yamdi 二.网页播放器:jw player 使 ...