Makefile 为什么为-C选项指定绝对路径和本地路径时,make的行为会有所不同?

Makefile 为什么为-C选项指定绝对路径和本地路径时,make的行为会有所不同?,makefile,Makefile,我正在编写一个make文件来编译源代码树中的代码。在我的make文件中,我有以下内容: MK = make CC = g++ PWD = $(shell pwd) CFLAGS = -std=c++11 -g -Wall SRCDIR = $(PWD)/src TSTDIR = $(PWD)/tests export MK CC SRCDIR TSTDIR CFLAGS tests: $(MK) -C $(TSTDIR) 然后在TSTDIR的目录中有另一个生成文件: OBJS =

我正在编写一个make文件来编译源代码树中的代码。在我的make文件中,我有以下内容:

MK = make
CC = g++
PWD = $(shell pwd)
CFLAGS = -std=c++11 -g -Wall
SRCDIR = $(PWD)/src
TSTDIR = $(PWD)/tests


export MK CC SRCDIR TSTDIR CFLAGS

tests:
    $(MK) -C $(TSTDIR)
然后在
TSTDIR
的目录中有另一个生成文件:

OBJS = $(notdir $(shell find $(SRCDIR) | grep .o))
IFLAGS = -I$(SRCDIR)

all: ts_tst

%: %.cc $(OBJS)
    $(CC) $(CFLAGS) $(IFLAGS) $(LFLAGS) -o $@ $^
通过运行此命令,我得到的输出是:

make  -C <pwd>/tests
make[1]: Entering directory `<pwd>/tests'
g++     ts_tst.cc   -o ts_tst
ts_tst.cc:8:31: fatal error: packets/ts_packet.h: No such file or directory
 #include "packets/ts_packet.h"
                               ^
compilation terminated.
make[1]: *** [ts_tst] Error 1
make[1]: Leaving directory `<pwd>/tests'
make: *** [tests] Error 2
如您所见,搜索源目录显然失败,因为路径现在是本地的,因此它不存在,但是g++命令现在与我的模板匹配。。。有人知道为什么会发生这种情况,以及我如何解决它吗?

考虑一下:

OBJS = $(notdir $(shell find $(SRCDIR) | grep .o))

%: %.cc $(OBJS)
        $(CC) $(CFLAGS) $(IFLAGS) $(LFLAGS) -o $@ $^
当设置
SRCDIR
时,它可能会找到一些目标文件(顺便说一句,我不知道你为什么在这里使用
grep
,而不是仅仅在
find
命令中添加
-name\*.o
:grep有缺陷,因为它也会匹配
foo.ohno
等文件)

假设它找到了对象文件
/my/path/to/src/foo.o
notdir
在其上运行,
OBJS
设置为
foo.o

这意味着模式变成:

%: %.cc foo.o
        $(CC) $(CFLAGS) $(IFLAGS) $(LFLAGS) -o $@ $^
现在make希望搜索匹配的模式规则。它将不匹配此规则,因为尽管模式
%
%.cc
匹配,但另一个先决条件
foo.o
不存在(它不在本地目录中)。因此,此模式被忽略,make将继续寻找其他模式。它将找到与之匹配的内置模式,这就是您获得输出的原因

如果未找到任何对象文件(错误的
find
命令),
OBJS
变量为空,因此模式规则匹配

如果您删除了
notdir
,它应该可以工作,但我不知道您为什么要添加它,所以可能还有其他问题

其他说明:

  • 调用递归MAKE时,应始终显式使用
    $(MAKE)
    ${MAKE}
    ,而决不能使用
    MAKE
    或其他变量
  • 通常,在调用
    shell
    或其他较慢的函数时,应该使用
    :=
  • 如果您使用显式规则而不是模式规则来构建测试程序,那么理解正在发生的事情可能会更简单:然后您会得到一个错误,比如没有规则来构建foo.o

谢谢,我不知道如果目标存在问题,依赖关系可能会导致目标不匹配。一旦我意识到这一点,我就得出了完全相同的结论。解决方案实际上是删除notdir。要清楚,除非所有先决条件(包括非模式)都匹配,否则隐式规则(如模式规则)将不匹配。由于可以存在许多不同的隐式规则来构建同一个目标(考虑有多少种方法可以构建
.o
文件!),如果一个隐式规则不匹配,make只需寻找另一个。只有当没有匹配项时,才会出现错误。对于显式规则,如果不能创建所有先决条件,make将立即失败。make的工作方式是在尝试构建任何目标之前,它将确保所有先决条件都是最新的。如果其中一个或多个无法更新(不存在/无法创建),则该隐式规则不匹配(或显式规则失败)。顺便说一句
PWD
不需要,因为make已经有
CURDIR
(而且
CURDIR
也很少需要,因为默认情况下,所有路径都是相对于当前目录的)。
%: %.cc foo.o
        $(CC) $(CFLAGS) $(IFLAGS) $(LFLAGS) -o $@ $^