gnu make中rule的顺序问题

gnu make中rule的顺序问题

假设在makefile里有:

A : B C
    xxx  a command which update A
D : E F
    xxx  a commnad which update D
B : D H
    xxx
C : w t
    xxx

如果我更新了E,A最后会被更新吗?      
应该会      
条件都是从头开始找的吗,也就是说跟所放的位置没有关系?如果我make B 呢?      
make B, B不会被更新,因为B的更新仅依赖于D或H的更新,除非D或H被更新才会导致B被处理,与B的定义次序无关;
make的工作原理是你定义好编译文件的依赖关系后,目标文件的更新仅仅取决于所有层次的被依赖文件的更新。比如
a: b c
... Update a
b: e
... Update b
e: f
... Update e

如果你touch f,make a会导致a被Update      
> A : B C
>     update A
> D : E F
>     update D
> B : D H
>     update B
> C : w t
>     update C

你举的例子是最好理解的,我没讲清楚的是我说 make B 的前提是比如我改了E,D的rule是在B的rule前面。我所关心的是当make决定各文件的依存关系的时候是否都是从头扫描。如果不是的话,我上面的设计就很有问题了。我看了一下gnu make的手册,没有看到对这方面的叙述。ok,谢谢你的指点。

我在另一个贴子里提到directory的问题,请再指教:target一开始不存在的话,会在current directory(即运行make的dir)生成吗?如果target已在某个make能搜寻到的dir(如vpath,VPATH, GPATH,及其他缺省的搜索dir)中已有,是会在其所在的dir进行更新吗?

make menual中有一段4.3.3 How Directory Searches are Performed,没看明白。还请兄台指点。      
也许我比较笨,看了五遍第4章 (4. Writing Rules),总算“自以为”看懂了它在讲的意思。以下是我的理解,如有不对,请大侠们指正:

1)make按依存关系排好处理的先后次序(具体怎么实现我没读源码,可能会是用堆栈,我猜),最先处理的是关系中的最底(基本)层。此时应该还没有决定文件所在的dir。
2)一层一层的对rule进行处理:按makefile中定义好的顺序(current,vpath,VPATH),分别去找target,prerequisite list中的文件,决定他们各自的dir。
3)决定是否需要update target。如果不需要,这个target所在的dir就是上一层以这个target为prerequisite的文件的dir;如果要update,这个target原来所在的dir会被”thrown away“,而在本地(current dir,make执行所在的dir?)生成新的target,上一层的引用到这个target的prerequisite自然就用这个新的target。
4)重复2)3)直至全部处理完。

以上3)中dir的确定是gnu make的方式,如果希望target在它被发现的dir里被更新,则要用到GPATH的功能,即那个dir要在GPATH中也出现。

以上理解如有错误,请各位一定给我指出。      
Sorry, 没看清楚,我在上面的回答有误,因为:B依赖于D和H, D依赖于E和F, 所以E更新的话会导致D被更新,从而导致B被更新.

实际上make在执行过程中会根据所定义的依赖关系和算法在内存空间自动形成一个类似树形结构的依赖关系,它与Makefile定义次序无关。所以也不用每次都去扫描Makefile.
target一开始不存在, 会在VPATH中找,如果是最新的,不会更新,会不会其所在的dir进行更新,取决于command中target的输出如何定义。如果target的输出目录在VPATH的list中,会更新该目录的target, 如果command中target的输出目录即不是当前目录,也不在VPATH的list中,或者干脆没有target的输出,会导致make target始终被执行      
》如果target的输出目录在VPATH的list中,会更新该目录的target

你的理解好象跟我的理解(见上一贴)好象有点出入,也许我的理解有误。我看的是

  4.3.3 How Directory Searches are Performed

它里面好象讲如果需要更新的话,会仍掉那个path,而在本地生成,如果想在原地更新,要放在GPATH

谢谢。

附:

4.3.3 How Directory Searches are Performed

When a prerequisite is found through directory search, regardless of type (general or selective), the pathname located may not be the one that make actually provides you in the prerequisite list. Sometimes the path discovered through directory search is thrown away.

The algorithm make uses to decide whether to keep or abandon a path found via directory search is as follows:

If a target file does not exist at the path specified in the makefile, directory search is performed.
If the directory search is successful, that path is kept and this file is tentatively stored as the target.
All prerequisites of this target are examined using this same method.
After processing the prerequisites, the target may or may not need to be rebuilt:
If the target does not need to be rebuilt, the path to the file found during directory search is used for any prerequisite lists which contain this target. In short, if make doesn't need to rebuild the target then you use the path found via directory search.
If the target does need to be rebuilt (is out-of-date), the pathname found during directory search is thrown away, and the target is rebuilt using the file name specified in the makefile. In short, if make must rebuild, then the target is rebuilt locally, not in the directory found via directory search.
This algorithm may seem complex, but in practice it is quite often exactly what you want.

Other versions of make use a simpler algorithm: if the file does not exist, and it is found via directory search, then that pathname is always used whether or not the target needs to be built. Thus, if the target is rebuilt it is created at the pathname discovered during directory search.

If, in fact, this is the behavior you want for some or all of your directories, you can use the GPATH variable to indicate this to make.

GPATH has the same syntax and format as VPATH (that is, a space- or colon-delimited list of pathnames). If an out-of-date target is found by directory search in a directory that also appears in GPATH, then that pathname is not thrown away. The target is rebuilt using the expanded path.      
我的意思可能没说清楚。
比如以下几个例子:
VPATH=test
a: x y
    touch /pathto/a
x: j
    touch $@
j:
    touch $@
y:
    touch $@

这里无论是否指定GPATH及是否包含/pathto目录, a的rebuild只会导致a被放入/pathto目录,并且因为在当前路径和test路径下均找不到a, 所以make a始终导致a 被rebuild, 我说的是这种情况.
如果将touch /pathto/a 该为touch $@,
那么如果当前没有a会去VPATH中找,如果没找到会在当前目录生成a,如果在当前目录没有在VPATH中找到,但没有GPATH, 且a需要rebuild, 那么a会放到当前目录,有GPATH包含该目录, 就会放到原来的目录;如果当前目录有,VPATH也有,将处理当前目录.      
我明白你讲的意思了。谢谢。
我觉得手册里讲得很晦涩,看得我晕晕呼呼的。网上对这个问题的讨论也非常少,都是在引一个叫”哈少“的人的文章,浅尝即止,解不了我的问题。

还有一种情况(只是假设,就当我是在专牛角尖好了),如果:

VPATH=dir1:dir2
a : b c
   update $@
b : d e
   update $@

假设a 在dir1中有,当前的目录是dir2(在dir2中执行make),则a会在dir2中生成,对不对?如果对的话,以后每次make,不管prerequisite的情况如何,dir2中的a都会重新update一次,因为dir1里有一个旧版的a ?如果上述讲法是对的话,以后真要很小心,在真正使用的时候要记住dir2的比dir1的新。

gnu make的这种算法真的很特别。