标签:程序 lin 文件 链表 numa 分享 cal ddp 否则
Makefile中存在一个include指令,它的作用如同C语言中的#include预处理指令。在Makefile中,可以通过include指令将自动生成的依赖关系文件包含进来,从而使得依赖关系文件中的内容成为Makefile的一部分。
在此之前,先介绍一下Makefile中的include的用法。
1 .PHONY:all clean 2 DIR_DEP=dep 3 DEPS=test_deps 4 all: exe 5 6 include $(DEPS) 7 8 dep: 9 mkdir dep 10 exe: 11 @echo "exe" 12 13 test_deps:$(DIR_DEP) 14 @echo "deps"
1. 有多个不同的程序,由不同目录下的几个独立的Makefile来描述其重建规则。它
们需要使用一组通用的变量定义或者模式
规则。通用的做法是将这些共同使用的变量或
者模式规则定义在一个文件中(没有具体的文件命名限制),在需要使用的
Makefile中使用指示符“include”来包含此文件。
2. 当根据源文件自动产生依赖文件时;我们可以将自动产生的依赖关系保存在另
外一个文件中,主Makefile使用指示符“include”包含这些文件。这样的做法
比直接在主Makefile中追加依赖文件的方法要明智的多。其它版本的make已经
使用这种方式来处理。
如 果 指 示 符 “ include ” 指 定 的 文 件 不 是 以 斜 线 开 始 ( 绝 对 路 径 , 如
/usr/src/Makefile...),而且当前目录下也不存在此文件; make将根据文件名试图在以下
几个目录下查找:首先,查找使用命令行选项“-I”或者“--include-dir”
指定的目录,如果找到指定的文件,则使用这个文件;否则继续
依此搜索以下几个目录(如果其存在):“/usr/gnu/include”、“/usr/local/include”和
“/usr/include”。
当在这些目录下都没有找到“include”指定的文件时,make将会提示一个包含文
件未找到的告警提示,但是不会立刻退出。而是继续处理Makefile的后续内容。当完成
读取整个Makefile后,make将试图使用规则来创建通过指示符“include”指定的但未
找到的文件(参考 3.7 makefile文件的重建 一节),当不能创建它时(没有创建这个文
件的规则),make将提示致命错误并退出。
通常我们在 Makefile 中可使用“-include”来代替“include”,来忽略由于包含文
件不存在或者无法创建时的错误提示(“-”的意思是告诉 make,忽略此操作的错误。
make 继续执行)。
我们改成-include之后:
这样就没有提示找不到那个目录或文件了,但是我们必须确保有规则去创建include指定的内容,否则最后将出错。
make的执行过程如下:
1. 依次读取变量“MAKEFILES”定义的makefile文件列表
2. 读取工作目录下的makefile文件(根据命名的查找顺序“GNUmakefile”,“makefile”,“Makefile”,首先找到那个就读取那个)
3. 依次读取工作目录makefile文件中使用指示符“include”包含的文件
4. 查找重建所有已读取的makefile文件的规则(如果存在一个目标是当前读取的某一个makefile文件,则执行此规则重建此makefile文件,完成以后从第一步开始重新执行)
5. 初始化变量值并展开那些需要立即展开的变量和函数并根据预设条件确定执行分支
6. 根据“终极目标”以及其他目标的依赖关系建立依赖关系链表
7. 执行除“终极目标”以外的所有的目标的规则(规则中如果依赖文件中任一个文件的时间戳比目标文件新,则使用规则所定义的命令重建目标文件)
8. 执行“终极目标”所在的规则
知道了include优先于本Makefile的目标运行之后,来看我们的complicated项目:
1 .PHONY: all clean 2 3 MKDIR = mkdir 4 RM = rm 5 RMFLAGS = -rf 6 7 CC=gcc 8 9 DIR_OBJS=objs 10 DIR_EXES=exes 11 DIR_DEPS=deps 12 13 DIRS =$(DIR_OBJS) $(DIR_EXES) $(DIR_DEPS) 14 15 EXE=complicated 16 EXE:=$(addprefix $(DIR_EXES)/,$(EXE)) 17 SRCS=$(wildcard *.c) 18 OBJS=$(SRCS:.c=.o) 19 OBJS:=$(addprefix $(DIR_OBJS)/,$(OBJS)) 20 DEPS=$(SRCS:.c=.dep) 21 DEPS:=$(addprefix $(DIR_DEPS)/,$(DEPS)) 22 23 all: $(EXE) 24 25 include $(DEPS) 26 27 $(DIRS): 28 $(MKDIR) $@ 29 $(EXE):$(DIR_EXES) $(OBJS) 30 $(CC) -o $@ $(filter %.o,$^) 31 $(DIR_OBJS)/%.o:$(DIR_OBJS) %.c 32 $(CC) -o $@ -c $(filter %.o,$^) 33 $(DIR_DEPS)/%.dep:$(DIR_DEPS) %.c 34 @echo "Creating $@ ..." 35 @set -e;36 $(RM) $(RMFLAGS) $@.tmp;37 $(CC) -E -MM $(filter %.c,$^) > $@.tmp;38 sed ‘s,\(.*\)\.o[:]*,objs/\1.o:,g‘ <$@.tmp >$@;39 $(RM) $(RMFLAGS) $@.tmp 40 clean: 41 $(RM) $(RMFLAGS) $(DIRS)
这里增加了filter函数,具体可以看前面函数那一篇随笔。正如前面所提及的,当make看到include指令时会师徒去构建所需包含进来的依赖文件,这样就不必在显式地让all目标依赖它了。这也是我举第一个例子的原因,有了include,make会自动去 构建 依赖。所以,在complicated项目中,我们在每一个依赖项之前都添加了一个先决条件,这个先决条件就是每一个依赖的目录。
需要指出地是,上面的代码可能会无限循环。
如果你的编译器安装在FAT32文件系统上,将可以运行不会无限循环,但是如果是在NTFS文件系统上,会死循环。笔者的Linux上是无限循环了。
出现无限循环的原因和文件系统有关,有的文件系统当目录中的文件被更改时,目录时间戳随之更改,由于在Makefile中创建依赖关系时,制定了deps目录是其第一个先决条件,于是,deps目录时间戳地改变使得make又一次使用规则再次创建main.dep 和foo.dep,这样造成了无限循环。
既然发现了问题,证明我们这个Makefile存在bug,需要更改,基本思路是:
如果deps目录不存在,则让deps目录成为规则的第一个先决条件;
如果deps目录已经存在,则不让deps目录出现在规则的先决条件中。
沿着这个思想走下去,需要用到Makefile中的条件语法。
标签:程序 lin 文件 链表 numa 分享 cal ddp 否则
原文地址:http://www.cnblogs.com/yangguang-it/p/6828058.html