Makefile 生成 .o 文件并将其输出到子文件夹

时间:2021-04-02 04:16:13

标签: c++ makefile

我在使用 Makefile 生成 .o 到“src/build”时遇到了一些困难。下面是我的结构。

Project
├── include
│   └── Solution.hpp
└── src
    ├── bin
    │   └──
    ├── build
    │   └── 
    ├── Makefile
    ├── Solution.cpp
    └── main.cpp

我想要做的是在src/build文件夹下生成main.o和Solution.o,然后在src/bin下生成可执行文件'test'。运行我的 Makefile 后,我在 src/build 中得到了 main.o,但在 src 中得到了 Solution.o。我不知道为什么?变量 OBJDIR 和 BINDIR 应该设置目标在哪里,对吗?如果我删除 $(OBJECTS),一切正常。为什么我不能将所有 .o 文件输出到 src/build 有什么帮助吗?

ROOTDIR       ?= ..

BINDIR        := bin
OBJDIR        := build
INCLUDEDIR    := $(ROOTDIR)/src $(ROOTDIR)/include 

CXX           := g++
CCFLAGS       := -c -g -O2 -Wall -std=c++17
LINKFLAGS     := 

SOURCES       := main.cpp Solution.cpp
OBJECTS       := $(SOURCES:.cpp=.o)
EXECUTABLE    := test

OBJSUFFIX     := .o

all : $(BINDIR)/$(EXECUTABLE)

makedirs :
    @if test ! -d $(BINDIR); then mkdir $(BINDIR); fi
    @if test ! -d $(OBJDIR); then mkdir $(OBJDIR); fi

## Link ##
$(BINDIR)/$(EXECUTABLE) : $(OBJDIR)/$(OBJECTS)
    $(CXX) $(LINKFLAGS) -o $@ $^

## Compile ##
$(OBJDIR)/%.o : %.cpp makedirs
    $(CXX) $(CCFLAGS) $< -o $@

clean :
    rm -rf $(BINDIR) $(OBJDIR) *.o

1 个答案:

答案 0 :(得分:1)

这是错误的:

$(BINDIR)/$(EXECUTABLE) : $(OBJDIR)/$(OBJECTS)

我看到人们一直在 SO 上这样做,我不知道为什么它如此诱人,但仔细想想它显然行不通。

你有这个:

SOURCES       := main.cpp Solution.cpp
OBJECTS       := $(SOURCES:.cpp=.o)

所以 OBJECTSmain.o Solution.oOBJDIRbuild

那么 $(OBJDIR)/$(OBJECTS) 扩展成什么?这里有一个提示:make 不会以某种方式发现 $(OBJECTS) 有多个单词并推断出您想将前缀应用于每个单词。它只是按照写入的方式扩展变量。所以这个扩展的结果是build/main.o Solution.o。这就是为什么你会得到你所做的行为。

你想写这个:

OBJECTS       := $(patsubst %.cpp,$(OBJDIR)/%.o,$(SOURCES))

或者这个:

OBJECTS       := $(addprefix $(OBJDIR)/,$(SOURCES:.cpp=.o))

确保目录单独应用于每个单词,而不只是粘贴到第一个单词的前面。