Makefile 为什么为-C选项指定绝对路径和本地路径时,make的行为会有所不同?
我正在编写一个make文件来编译源代码树中的代码。在我的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 =
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
.o
文件!),如果一个隐式规则不匹配,make只需寻找另一个。只有当没有匹配项时,才会出现错误。对于显式规则,如果不能创建所有先决条件,make将立即失败。make的工作方式是在尝试构建任何目标之前,它将确保所有先决条件都是最新的。如果其中一个或多个无法更新(不存在/无法创建),则该隐式规则不匹配(或显式规则失败)。顺便说一句PWD
不需要,因为make已经有CURDIR
(而且CURDIR
也很少需要,因为默认情况下,所有路径都是相对于当前目录的)。
%: %.cc foo.o
$(CC) $(CFLAGS) $(IFLAGS) $(LFLAGS) -o $@ $^