首页 > 解决方案 > 为什么在给定绝对路径与 -C 选项的本地路径时,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's 目录中是另一个 makefile:

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++ 命令与我在 make 文件中的模板不匹配。现在,如果我$(PWD)/从变量中删除SRCDIRTSTDIR得到这个...

make  -C tests
find: ‘src’: No such file or directory
make[1]: Entering directory `<pwd>/tests'
g++ -std=c++11 -g -Wall -Isrc  -o ts_tst ts_tst.cc 
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++ 命令现在与我的模板匹配......有谁知道为什么会发生这种情况以及我该如何解决?

标签: makefile

解决方案


考虑一下:

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

%: %.cc $(OBJS)
        $(CC) $(CFLAGS) $(IFLAGS) $(LFLAGS) -o $@ $^

SRCDIR设置它可能会找到一些目标文件(顺便说一下,我不知道你为什么在grep这里使用而不是仅仅添加-name \*.ofind命令:这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)or显式使用,而从不使用或其他一些变量。${MAKE}make
  • 一般来说,您应该:=在调用shell或其他较慢的功能时使用。
  • 如果您使用显式规则而不是模式规则来构建测试程序,则可能更容易理解正在发生的事情:然后您会收到一个错误,例如no rule to build foo.o

推荐阅读