【问题标题】:Makefile - Dependency file in a folder "No such file or directory"Makefile - 文件夹中的依赖文件“没有这样的文件或目录”
【发布时间】:2013-07-27 15:12:20
【问题描述】:

到目前为止,我有一个运行良好的 Makefile。虽然,随着它开始增长,每次重新编译所有源代码开始花费太长时间。这是工作版本的 sn-p:

CC=$(CROSS_COMPILE)g++
CFLAGS=-Wall -I./include -pg -O2
VPATH=./src:./include

all: dotgazer.cpp dotgazer/Dot.cpp
    $(CC) $(CFLAGS) $^ -o dotgazer.out `pkg-config --libs opencv`

还有很多依赖,但这两个足以说明问题所在。我正在尝试将每个 cpp 文件的编译阶段移动到单独的目标。对于顶级文件 (dotgazer.cpp),这不是问题,一般规则 %.o: %.cpp 可以正常工作。但我无法让第二个依赖项工作。这是它现在的样子:

CC=$(CROSS_COMPILE)g++
CFLAGS=-Wall -I./include -pg -O2
VPATH=./src:./include

all: dotgazer.o dotgazer/Dot.o
    $(CC) $(CFLAGS) $^ -o dotgazer.out `pkg-config --libs opencv`

%.o: %.cpp
    $(CC) -c $(CFLAGS) $^ -o $@

dotgazer/Dot.o: dotgazer/Dot.cpp
    $(CC) -c $(CFLAGS) $^ -o $@

我尝试了Dot.o 规则的不同变体,但它们似乎都不起作用。我得到的错误是:

Fatal error: can't create dotgazer/Dot.o: No such file or directory

我该怎么做?我最希望将.o 文件与它们的源放在相同的文件夹中。另外,我会感谢一般规则(如%.o: %.cpp),因为有很多源文件,我不希望 Makefile 变得过于臃肿。谢谢!

【问题讨论】:

  • 我可能很笨,但%.o: %.cppdotgazer/Dot.o: dotgazer/Dot.cpp 规则不是加倍吗?比如,后者的目标不是已经被前者处理了吗?
  • @AdamGoodwin 我认为它会以这种方式工作(只需要%.o: %.cpp 规则)。但事实证明 - 不。所以我添加了第二条规则,特别是对于第二个依赖项,它仍然不起作用。仅使用%.o: %.cpp 规则,消息是相同的:can't create dotgazer/Dot.o: No such file or directory
  • 嗯,我刚刚尝试了您的 makefile,它对我来说效果很好。即使只使用%.o 目标而没有dotgazer/Dot.o 目标,它也可以工作。你没有弄错文件名或目录吧?或者你是在做一些事情,比如从它自己的目录以外的地方运行 makefile?
  • 我很确定没有拼写错误或任何东西。我是从 Netbeans 运行它的,所以我认为它在 Makefile 的文件夹中运行 make。无论如何,接受的答案解决方案比我预期的要好得多。

标签: build makefile dependencies


【解决方案1】:

我认为您的Makefile 有点具体,因此容易出错。我建议看一下我的以下示例,它比您的更通用。

我的示例利用了make 的隐含规则目录。对于cpp-files 已经存在一个通用的隐式规则。那么为什么不应该使用它呢!?

参考手册描述如下:

编译 C++ 程序

n.o 由 n.cc、n.cpp 或 n.C 自动生成,配方形式为 $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c

因此,如果您将 %.o 文件作为先决条件,如规则 dotgazer.out: $(OBJS) make 自动将上述隐式规则应用于所有这些文件。假设您为CXXCPPFLAGS 和/或CXXFLAGS 设置了有效值。

此外,您通常不需要手动将源添加到变量中。大多数时候,构建可执行文件需要项目目录树中的所有源代码。如果不是这种情况,您应该考虑构建一个反映这一点的适当树。

由于find 负责将源分配给CPPFILES,我们也不需要设置VPATH。由于我们使用了findpatsubst,我们在Makefile 中只有一个明确的文件名。这使得处理具有大量不同来源的真实项目更加顺畅。

当然,您不需要allclean 规则。为了方便起见,我只是添加了这些。

CXX=$(CROSS_COMPILE)g++
CPPFLAGS=-I./include
CXXFLAGS=-Wall -pg -O2
LDLIBS=`pkg-config --libs opencv`

CPPFILES=$(shell find . -name "*.cpp")
OBJS=$(patsubst %.cpp, %.o, $(CPPFILES))

all: dotgazer.out
    @echo $(CPPFILES)
    @echo $(OBJS)

dotgazer.out: $(OBJS)
    $(CXX) $(CXXFLAGS) -o $@ $^ $(LDLIBS)

clean: 
    rm -f $(OBJS)

【讨论】:

  • 很棒的答案,谢谢!它有我需要的一切,所有文件单独编译,.o 文件在各自的文件夹中。但是有一个问题,尽管有LDLIBS 设置,但仍无法识别 OpenCV 函数。以下是输出:pastebin.com/zV9btgqN dotgazer.out 规则应如下所示:$(CXX) $^ -o $@ $(LDLIBS)。但是,这是一个很好的答案!
  • 你说得对,我应该把$(CXX) $(LDLIBS) $^ -o $@改成$(CXX) $(LDLIBS) -o $@ $^g++ --help 说输入文件应该在选项之后。最好的问候
  • 这不是问题。 -o 可以随时来。问题是库必须排在最后(而且库的列出顺序也很重要)。 CPPFLAGS 也用于 C 预处理器标志 (-I / -D);像-Wall -pg -O2 这样的编译器标志属于CXXFLAGS(对于C++)。要链接,请使用$(CXX) $(CXXFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS)
  • @MadScientist:感谢您的评论。特别是你指出了btw的区别。 CXXFLAGSCPPFLAGS(我将相应地编辑我的答案)。直到现在我才意识到这一点。您的声明...the libraries must come last 有任何参考。直到今天,我的方法从未遇到过任何问题,但感谢您在未来为我省去了麻烦......
猜你喜欢
  • 1970-01-01
  • 2016-01-10
  • 1970-01-01
  • 2014-12-09
  • 1970-01-01
  • 1970-01-01
  • 2020-03-01
  • 1970-01-01
  • 2021-09-30
相关资源
最近更新 更多