【问题标题】:How can my makefile include subdirectories?我的 makefile 如何包含子目录?
【发布时间】:2021-06-19 07:59:46
【问题描述】:

(为清楚起见已更新)(在底部添加了解决方案)

我在网上找到了一个makefile,它在该目录中构建所有cpp文件并编译它们。

但我不知道如何在子目录中包含文件。

以下是所发生情况的细分:

  • 我创建文件 test.cpp 和 test.hpp 并将它们放在我的工作目录中包含的子目录“/gui”中,它们包含函数 testFunction()。
  • 在不包含 test.hpp 的情况下,我在终端中输入“make”,我收到错误:

g++    -c -o main.o main.cpp
main.cpp: In function 'int main(int, char**)':
main.cpp:6:2: error: 'testFunction' was not declared in this scope
  testFunction();
  ^~~~~~~~~~~~
make: *** [<builtin>: main.o] Error 1
  • 如果我包含 (#include "gui/test.hpp"),则会收到不同的错误:

g++    -c -o main.o main.cpp
g++  main.o -Wall  -o testfile
/usr/bin/ld: main.o: in function `main':
main.cpp:(.text+0x14): undefined reference to `testFunction()'
collect2: error: ld returned 1 exit status
make: *** [makefile:34: testfile] Error 1
  • 但是,如果我随后将“-I/gui”或(猜测)“-I./gui”添加到 CFLAGS,我会收到完全相同的错误消息。

这是供参考的makefile:

TARGET = testfile
LIBS = 
CC = g++
CFLAGS = -g -Wall

.PHONY: default all clean

default: $(TARGET)
all: default

OBJECTS = $(patsubst %.cpp, %.o, $(wildcard *.cpp))
HEADERS = $(wildcard *.hpp)

%.o: %.c $(HEADERS)
    $(CC) $(CFLAGS) -c $< -o $@

.PRECIOUS: $(TARGET) $(OBJECTS)

$(TARGET): $(OBJECTS)
    $(CC) $(OBJECTS) -Wall $(LIBS) -o $@

clean:
    -rm -f *.o
    -rm -f $(TARGET)

提前致谢!


自接受答案后更新生成文件:

(更改包括目录,CC 替换为 CXX,%.c 替换为 %.cpp)

TARGET = testfile
DIRS =
LDLIBS =

CXX = g++

CXXFLAGS= -g -Wall

# this ensures that if there is a file called default, all or clean, it will still be compiled
.PHONY: default all clean

default: $(TARGET)
all: default

# substitute '.cpp' with '.o' in any *.cpp 
OBJECTS = $(patsubst %.cpp, %.o, $(wildcard *.cpp $(addsuffix /*.cpp, $(DIRS))))
HEADERS = $(wildcard *.h)

# build the executable
%.o: %.cpp $(HEADERS)
    $(CXX) $(CXXFLAGS) -c $< -o $@
    
# if make is interupted, dont delete any object file
.PRECIOUS: $(TARGET) $(OBJECTS)

# build the objects
$(TARGET): $(OBJECTS)
    $(CXX) $(OBJECTS) -Wall $(LDLIBS) -o $@ 

clean:
    -rm -f *.o $(addsuffix /*.o, $(DIRS))
    -rm -f $(TARGET)

【问题讨论】:

  • “不走运”不是我们可以帮助解决的问题。请编辑您的问题并添加(a)您调用的 make 命令,(b)make 打印的编译行,以及(c)您收到的错误消息; (d) 源代码中与错误相关的实际#include 行也很有用。请按照格式正确剪切和粘贴它们(没有屏幕截图或速记参考)。然后我们可以提供帮助。顺便说一句,-I/gui 不太可能是正确的,除非你的系统上有一个目录/gui(你可以运行ls /gui 并查看你想要的文件)。
  • 你说的是源文件还是头文件?
  • @MadScientist 感谢您的回复,我已经更新了这个问题,希望现在更清楚一点吗?如果没有,请告诉我:)
  • @Beta 因为包含头文件时错误发生了变化,我认为它是找不到源?

标签: makefile subdirectory


【解决方案1】:

要了解这里发生的情况,您必须查看 C++(和其他语言)中 declarationdefinition 的定义。你绝对应该这样做。

声明(通常放在头文件中)就像你家的地址。如果有人想给你寄信,他们需要你的地址。如果你的主函数要调用另一个函数,比如testFunction(),它需要函数的声明。

第一个错误是因为你没有包含头文件,所以编译器没有你要调用的函数的声明,这意味着它不会编译你的调用函数。

但要让信真正送达,您需要真正的房子。地址是声明,你的房子是定义......在这种情况下是实际的功能实现。它位于test.cpp 文件中。当您将代码链接在一起时,链接器(在这种情况下,我猜链接器就像邮政服务 :p :))将尝试链接对定义的调用。

但是,您可以看到您没有编译 test.cpp 文件,也没有链接目标文件:

g++  main.o -Wall  -o testfile

在这里我们看到main.o,但不是gui/test.o

为什么不呢?这一行:

OBJECTS = $(patsubst %.cpp, %.o, $(wildcard *.cpp))

匹配所有*.cpp 文件并将它们转换为.o 文件。但是*.cpp 只匹配当前目录中的文件,例如main.cpp。如果你想把文件放在不同的目录中,你必须告诉 make 它们在哪里;例如:

OBJECTS = $(patsubst %.cpp, %.o, $(wildcard *.cpp gui/*.cpp))

【讨论】:

  • 感谢您的回复,这似乎已经解决了问题。我很确定它根本没有看到它,但我认为这是我的 makefile 知识阻碍了我在这里......它不是一种非常直观的语言。有什么办法可以在我的make文件中创建一个变量,让我可以干净地添加多个目录?例如 DIRS = gui otherdir otherdir2?并有类似 OBJECTS = $(patsubst %.cpp, %.o, $(wildcard .cpp $(DIRS)/.cpp)) 的行
  • 它不是程序语言。它是一种声明性语言。它非常适合它的任务,但是如果您从未使用过声明性语言,那么它可能会令人困惑。此外,与大多数编程事物一样,从某个地方从网上抓取一些随机文件并不是最好的学习方式:)。最好是编写自己的makefile,使用gnu.org/software/make/manual/html_node/Introduction.html
  • 抱歉,我编辑了最后一条消息,所以您可能没有看到:有什么方法可以在我的 make 文件中创建一个变量,让我可以干净地添加多个目录?例如 DIRS = gui otherdir otherdir2?并有类似 OBJECTS = $(patsubst %.cpp, %.o, $(wildcard .cpp $(DIRS)/.cpp))
  • 当然:OBJECTS = $(patsubst %.cpp,%.o,$(wildcard *.cpp $(addsuffix /*.cpp,$(DIRS))))
  • 绝对传奇!这将大大清理我的项目!谢谢! :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-16
相关资源
最近更新 更多