多个子目录中源的单个 Makefile

Posted

技术标签:

【中文标题】多个子目录中源的单个 Makefile【英文标题】:Single Makefile for sources in multiple sub directories 【发布时间】:2019-02-20 15:39:00 【问题描述】:

在我的 C++ 项目中,源代码被组织在 src 目录中。在 src 目录里面是子目录,它们都包含头文件和源文件,例如

project
├── Makefile
│
├── MyBinary
│
├── src
│    │
│    ├── main.cpp
│    │
│    ├── Application
│    │      │
│    │      ├── Application.h
│    │      └── Application.cpp
│    │      
│    │
│    └── Tasks
│           ├── BackgroundWorker.h
│           └── BackgroundWorker.cpp
│
└── obj
     ├── Application.o
     └── BackgroungWorker.o

我正在尝试创建一个 Makefile,以便在 obj 目录中创建所有对象文件,并在 src上方创建可执行文件 MyBinary > 与 Makefile 处于同一级别的目录。

它不必太复杂或自动化。我不介意在 Makefile 中手动指定每个 .cpp 和 .h 文件。

但我是 Makefiles 的新手,不幸的是,我正在为这种尝试而苦苦挣扎:

CXX=c++
CXXFLAGS=-Wall -Os -g0

# Name of the output binary
APPNAME=MyBinary

# Source root directory
SRC_ROOT=src

# Object file directory
OBJ_DIR=obj

DEPS=$(SRC_ROOT)/Application/Application.h \
     $(SRC_ROOT)/Tasks/BackgroundWorker.h

_OBJ=$(SRC_ROOT)/Application/Application.o \
    $(SRC_ROOT)/Tasks/BackgroundWorker.o\
    $(SRC_ROOT)/main.o

OBJ=$(patsubst %,$(OBJ_DIR)/%,$(_OBJ))

# This rule says that the .o file depends upon the .c version of the 
# file and the .h files included in the DEPS macro.
$(OBJ_DIR)/%.o: %.cpp $(DEPS)
  $(CXX) -c -o $@ $< $(CXXFLAGS)

# Build the application.
# NOTE: The $@ represents the left side of the colon, here $(APPNAME)
#       The $^ represents the right side of the colon, here $(OBJ)
$(APPNAME): $(OBJ)
  $(CXX) -o $@ $^ $(CXXFLAGS)

clean:
  rm -f $(OBJ_DIR)/*.o $(APPNAME)

调用make时报错:Fatal error: can't create obj/src/Application.o: File or directory not found.

谁能帮忙?

【问题讨论】:

一个可行的解决方案:***.com/a/7321954/412080 【参考方案1】:

OBJ=$(patsubst %,$(OBJ_DIR)/%,$(_OBJ))obj/ 添加到 _OBJ 的单词之前。你想用 obj 替换 src 一些你可以用的东西

OBJ=$(patsubst $(SRC_ROOT)/%,$(OBJ_DIR)/%,$(_OBJ))

请注意,您获得的目录结构需要子目录 ApplicationTasksobj,您要么必须在调用 make 之前手动创建它们,要么更新 Makefile 以创建它们。

在预先创建目录结构时,这是我所期望的行为。

APPNAME=MyBinary
SRC_ROOT=src
OBJ_DIR=obj

DEPS=$(SRC_ROOT)/Application/Application.h \
     $(SRC_ROOT)/Tasks/BackgroundWorker.h

_OBJ=$(SRC_ROOT)/Application/Application.o \
    $(SRC_ROOT)/Tasks/BackgroundWorker.o\
    $(SRC_ROOT)/main.o

OBJ=$(patsubst $(SRC_ROOT)/%,$(OBJ_DIR)/%,$(_OBJ))

$(OBJ_DIR)/%.o: $(SRC_ROOT)/%.cpp $(DEPS)
    echo Making $@ from $<
    touch $@ 

$(APPNAME): $(OBJ)
    echo Making $@ from $^
    touch $@

请注意,在实践中,您必须更好地处理依赖项,并且可能让它们由编译器生成(请参阅-MM 和 g++ 的类似选项),在这里您可以在更改标头时重新编译所有内容。

【讨论】:

您还需要在调用编译器之前将mkdir -p $(@D) 添加到您的编译配方中。编译器不会为您创建目录,您必须在要求编译器在其中创建文件之前确保它们存在。 @AProgrammer 谢谢 - 不幸的是它仍然得到一个错误。 make: *** 没有规则来制作“MyBinary”需要的目标“obj/Application/Application.o”。停止 $(OBJ_DIR)/%.o: %.cpp $(DEPS) 应该是$(OBJ_DIR)/%.o: $(SRC_ROOT)/%.cpp $(DEPS) @AProgrammer - 仍然是相同的错误消息。也许对于这一行,必须以某种方式考虑到某些文件(main.cpp)直接位于 src/ 中,而其他文件(Application.cpp,...)位于 src/ 的子目录中? 感谢@AProgrammer 的扩展示例。它非常具有描述性,并且在用编译器调用替换 touch'es 时可以使用。

以上是关于多个子目录中源的单个 Makefile的主要内容,如果未能解决你的问题,请参考以下文章

Makefile - 从多个目录构建

多个文件目录下Makefile的写法

多个文件目录下Makefile的写法

大型工程多个目录下的Makefile写法

基于 Segue 源的单个按钮的多个操作

在多个管道上创建具有多个输入源的单个管道的意义,每个管道都定义了单独的输入源?