【问题标题】:Makefile generates and output .o files to a subfolderMakefile 生成 .o 文件并将其输出到子文件夹
【发布时间】:2021-04-02 04:16:13
【问题描述】:

我在使用 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

【问题讨论】:

    标签: c++ makefile


    【解决方案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))
    

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

    【讨论】:

    • 我们在 SO 上一直看到的另一件事是,人们通过将构建结果强制放入特殊的非默认目录中,使事情变得比他们需要的更难,就像在这种情况下一样。我一直不明白这一点。保持源目录清洁的目标最好通过源代码外构建来实现,而且我还没有遇到另一个动机,它不会归结为任意决定以艰难的方式做事。
    • 我认为人们不喜欢源代码外构建,因为您必须从与用于管理源代码不同的目录开始构建,除了通过记住它(“我是否将构建放入 ../obj 或 ../build 或 /tmp/obj 或 ...”)如果您已生成文件,正确编写 makefile 也可能有点棘手,您想写install 规则等。我认为这与源代码外构建本身的概念没有任何冲突。
    • 谢谢!你的建议有效。 addprefix 是为每个单词添加前缀的好选择。谢谢。
    猜你喜欢
    • 1970-01-01
    • 2020-02-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多