c++ - 无法使用 make 找到 header

标签 c++ makefile

我有一个(相当简单的)makefile,改编自 here我正在尝试用它在 Ubuntu 上构建一个项目。项目树相当简单:Makefile位于项目根目录中,有src/include/build/bin/,分别存储源代码、头文件、目标文件和可执行文件。

当我从项目的根目录运行 make 时,收到以下错误消息:

Linking...
g++                  src/Main.cpp src/Foo.cpp -o bin/runner     
src/Main.cpp:1:19: fatal error: Foo.hpp: No such file or directory 
#include "Foo.hpp"
               ^
compilation terminated.
src/Foo.cpp:1:19: fatal error: Foo.hpp: No such file or directory
 #include "Foo.hpp"
               ^
compilation terminated.
make: *** [bin/runner] Error 1

项目中当前的所有内容是Main.cpp。它从 Foo.cpp 调用两个测试函数 Foo()Bar(),它引用头文件 Foo.hpp。这是生成文件:

CC := g++               # This is the main compiler
SRCDIR := src           # Directory for source code
BUILDDIR := build       # Directory containing all object files, which are removed on "make clean"
TARGET := bin/runner    # bin/runner contains the main executable for project
                        # bin/ contains all other executables in the project (such as tests)

SRCEXT := cpp           # File extension of source code

# Look for all the source files in SRCDIR with the file extension specified above
SOURCES := $(shell find $(SRCDIR) -type f -name *.$(SRCEXT))

# Name all object files the same root name as the source files from which they came, but add a .o extension to the end
OBJECTS := $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%,$(SOURCES:.$(SRCEXT)=.o))

# The -g flag specifies that debugging information should be produced in the native format of the OS
CFLAGS := -g -Wall

# Various flags for libraries that might need to be linked
INC := -I include       # Ensures that all header files (in the include/ folder) are accessible for build

# Show the components that are currently being compiled/linked
# Also, this is the main procedure for make: The TARGET is built from the objects, and
# object files are built from source
$(TARGET): $(OBJECTS)
    @echo " Linking..."
    @echo " $(CC) $^ -o $(TARGET)"; $(CC) $^ -o $(TARGET)

$(BUILDDIR)/%.o: $(SRCDIR)/%.$(SRCEXT)
    @mkdir -p $(BUILDDIR)
    @echo " $(CC) $(CFLAGS) $(INC) -c -o $@ $<"; $(CC) $(CFLAGS) $(INC) -c -o $@ $<

# Directives for "make clean" which cleans all object files out of the build/ folder
clean:
    @echo " Cleaning..."; 
    @echo " $(RM) -r $(BUILDDIR) $(TARGET)"; $(RM) -r $(BUILDDIR) $(TARGET)

# Destroys everything in the build/ and bin/runner/ folders. Does not clean test executables.
.PHONY: clean

为了正确链接头文件,我在这里缺少什么?

编辑:这是新的 makefile 和当前输出:

# This is the main compiler
CC := g++

# Directory for source code
SRCDIR := src

# Directory containing all object files, which are removed on "make clean"
BUILDDIR := build

# bin/runner contains the main executable for project
# bin/ contains all other executables in the project (such as tests)
TARGET := bin/runner

# File extension of source code
SRCEXT := cpp

# Ensures that all header files (in the include/ folder) are accessible for build
INC := -I/include

# Look for all the source files in SRCDIR with the file extension specified above
# SOURCES := $(shell find $(SRCDIR) -type f -name *.$(SRCEXT))
SOURCES := $(wildcard $(SRCDIR)/*.$(SRCEXT))

# Name all object files the same root name as the source files from which they came, but add a .o extension to the end
# OBJECTS := $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%,$(SOURCES:.$(SRCEXT)=.o))
OBJECTS := $(addprefix $(TARGET)/, $(notdir $(SOURCES:.cpp=.o)))

# The -g flag specifies that debugging information should be produced in the native format of the OS
CFLAGS := -g -Wall

# Various flags for libraries that might need to be linked
LIB := #-pthread -lmongoclient -L lib -lboost_thread-mt -lboost_filesystem-mt -lboost_system-mt

# Show the components that are currently being compiled/linked
# Also, this is the main procedure for make: The TARGET is built from the objects, and
# object files are built from source
$(TARGET): $(OBJECTS)
    @echo " Linking..."
    $(CC) $^ -o $(TARGET)
    # @echo " $(CC) $^ -o $(TARGET) $(LIB)"; $(CC) $^ -o $(TARGET) $(LIB)

$(BUILDDIR)/%.o: $(SRCDIR)/%.$(SRCEXT)
    @mkdir -p $(BUILDDIR)
    $(CC) $(CFLAGS) $(INC) -c -o $@ $<

# Directives for "make clean" which cleans all object files out of the build/ folder
clean:
    @echo " Cleaning..."; 
    @echo " $(RM) -r $(BUILDDIR) $(TARGET)"; $(RM) -r $(BUILDDIR) $(TARGET)

# Tests
# tester:
    # $(CC) $(CFLAGS) test/tester.cpp $(INC) $(LIB) -o bin/tester

# Spikes
# ticket:
    # $(CC) $(CFLAGS) spikes/ticket.cpp $(INC) $(LIB) -o bin/ticket

# Destroys everything in the build/ and bin/runner/ folders. Does not clean test executables.
.PHONY: clean

输出:

[scott]> make
make: *** No rule to make target `bin/runner/Foo.o', needed by `bin/runner'.  Stop.

最佳答案

tl;博士

不要在 make 中的变量赋值上添加行尾注释。它不会按照您期望的方式工作。


说明

您的 makefile 没有按照您期望的步骤运行。

您不应该看到 Linking...用于编译步骤。

make 不应尝试从源 .cpp 创建目标文件。

应该看到您的INCCFLAGS编译行上的值(但您正在获取链接输出,因此显然没有看到它们)。

这就是为什么你的标题找不到的原因,你的链接行没有 -I在任何地方。

发生这种情况的原因是 make 应用了错误的规则。

make 应用了错误的规则,因为您的变量设置不正确。

您的变量设置不正确,因为您的变量具有您不期望的值。

您启动的 makefile 存在作者没有意识到的错误。

make 并不总是很聪明。

当你写的时候

FOO := some value     # comment

你期望FOO具有值 some value但 make 的看法不同。

make 赋予它值 some value因为它无法区分 some 之间的空格和value以及 value 之后的空格以及在评论之前。

因此,当您运行 shell 命令时(*.$(SRCEXT) 不带引号),shell 只是忽略尾随空格)。 (尝试引用 *.'$(SRCEXT)' 并看看您会得到什么。)

但是,当您尝试$(SOURCES:=.$(SRCEXT)=.o)时make 不会删除空格,而您实际上已经写了 $(src/Main.cpp src/Foo.cpp:=cpp =.o)您可能会注意到,这是一个实际上不匹配的模式。

结果$(OBJECTS)获取未修改的值$(SOURCES)并“混淆”$(TARGET): $(OBJECTS)稍后的行会导致 make 跳过您的编译目标。

(哦,这也是为什么你的链接行在 g++ 和第一个源文件之间有一百万个空格。)

哦,还有,你不需要花钱在那里找到,除非你的 src/目录有自己的子目录(即使如此,也没有使用一些 make magic),因为 $(wildcard $(SRCDIR)/*.$(SRCEXT))会工作得很好(而且我相信考虑到这个问题,早些时候也会失败)。

关于c++ - 无法使用 make 找到 header ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26111332/

相关文章:

c++ - 如何在编译时检测 C++ 中的 std::reference_wrapper

c++ - "polymorphic base class"是 C++ 标准的一部分吗?

c - 通过 "make"合并 C 程序和 VHDL 比特流(即使用 Makefile)

c++ - ros出现 'undefined reference to libusb'错误怎么解决?

c++ - 如何重载 << 运算符以在 C++ 中打印数组的内容?

c++ - 为什么这个循环不加载正确的事件?

makefile - 读取 JSON 并分配给 make 变量列表

c - 依赖树中的 Makefile 循环

c++ - 如何在 Visual Studio 2019 中使用 cmake 项目进行 "Edit and Continue"构建?

c - 制定排除目标?