我有一个(相当简单的)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
创建目标文件。
您应该看到您的INC
和CFLAGS
编译行上的值(但您正在获取链接输出,因此显然没有看到它们)。
这就是为什么你的标题找不到的原因,你的链接行没有 -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/