即使指定了Makefile,也没有选择正确的文件夹来构建

问题描述 投票:0回答:1

我是 C++ 新手,很难理解为什么我的 Makefile 没有达到预期效果。

这是我的项目的(所需的)结构:

MyProject
 ├── build
 │   ├── debug
 │   │   ├── main
 │   │   └── src
 │   │       └── call .o and .d files compiled with debug flag
 │   └── release
 │       ├── main
 │       └── src
 │           └── all .o and .d files compiled without additional flags
 ├── include
 │   └── all .hpp files
 ├── lib
 │   └── currently empty
 ├── src
 │   └── all .cpp files
 └── Makefile 

构建文件夹中的文件夹结构是所需的部分 - 这是不起作用的部分。 我的意图是:每当我调用

make
时,它都会按照 src 文件夹结构将
.o
.d
文件构建到
release
文件夹中,并且主要可执行文件直接放在
/release
中。 同样,每当我调用
make debug
时,它都会构建到
debug
文件夹中(并传递附加调试标志)。

ATM 调用

make
会产生以下结构:

MyProject
 ├── build
 │   ├── main
 │   └── src
 │       └── all .o and .d files compiled without additional flags
...

因此,即使

make
应该是默认目标,
release
也不会导致使用
release
文件夹。

调用

make debug
(如果相应替换,则调用
make release
)会产生以下结构:

MyProject
 ├── build
 │   ├── debug
 │   │   └── main
 │   └── src
 │       └── all .o and .d files (not compiled anew! And hence without the debug flags)
...

只有

main
可执行文件位于
debug
文件夹中。其余部分位于
/build
下,如果我之前调用过
make
,则不会再次编译。因此,调试标志丢失,我没有得到调试输出。 所以构建总体上是有效的,文件只是不是我想要的位置,在调试的情况下,我必须每次运行
make clean
才能获得正确的编译和调试输出。

我知道这些块称为配方,并且用制表符缩进的所有内容都会传递到 shell。不过,我认为我不理解 Makefile 的一般执行流程。 这部分

$(BUILD)/%.o: %.cpp
    $(MD) $(@D)
    $(CXX) $(CXXFLAGS) $(INCLUDES) -c $< -MMD -o $@

似乎是在其他事情之前执行的。我什至看不出它在哪里被称为。尤其是这是失败的部分,因为它没有更新的

BUILD
路径。

这是我的完整 Makefile:

CXX         = g++
CXXFLAGS    = -std=c++17 -Wall -Wextra -g
debug: CXXFLAGS += -DDEBUG -g
LFLAGS      =

SRC     := src
BUILD       = build
release: BUILD  := $(BUILD)/release
debug: BUILD    := $(BUILD)/debug
INCLUDE     := include
LIB     := lib

ifeq ($(OS),Windows_NT)
  MAIN      := main.exe
  SOURCEDIRS    := $(SRC)
  INCLUDEDIRS   := $(INCLUDE)
  LIBDIRS   := $(LIB)
  FIXPATH   = $(subst /,\,$1)
  RM        := del /q /f
  MD        := mkdir
else
  MAIN      := main
  SOURCEDIRS    := $(shell find $(SRC) -type d)
  INCLUDEDIRS   := $(shell find $(INCLUDE) -type d)
  LIBDIRS   := $(shell find $(LIB) -type d)
  FIXPATH   = $1
  RM        := rm -f
  MD        := mkdir -p
endif

INCLUDES        := $(patsubst %,-I%, $(INCLUDEDIRS:%/=%))
LIBS            := $(patsubst %,-L%, $(LIBDIRS:%/=%))
SOURCES         := $(wildcard $(patsubst %,%/*.cpp, $(SOURCEDIRS)))
OBJECTS         := $(SOURCES:%.cpp=$(BUILD)/%.o)
DEPS            := $(OBJECTS:.o=.d)


all: $(OBJECTS)
    $(MD) $(BUILD)
    $(CXX) $(CXXFLAGS) $(INCLUDES) -o $(BUILD)/$(MAIN) $(OBJECTS) $(LDFLAGS) $(LIBS)

# this seems to be executed whenever calling any "make" command
# this command does not have the updated BUILD path (aka build/release or build/debug)
# Is this a recipe as well? When is it called?
$(BUILD)/%.o: %.cpp
    $(MD) $(@D)
    $(CXX) $(CXXFLAGS) $(INCLUDES) -c $< -MMD -o $@

-include $(DEPS)

# I would like for release to be called when simply calling "make" (doesn't happen)
.PHONY: default_target
default_target: release

.PHONY: clean
clean:
    $(RM) $(call FIXPATH,$(BUILD)/$(MAIN))
    $(RM) $(call FIXPATH,$(OBJECTS))
    $(RM) $(call FIXPATH,$(DEPS))
    @echo Cleanup complete!

.PHONY: debug
debug: all

.PHONY: release
release: all

.PHONY: debugrun
debugrun: all
    ./$(call FIXPATH,$(BUILD)/$(MAIN))

.PHONY: run
run: all
    ./$(call FIXPATH,$(BUILD)/$(MAIN))

当然这个Makefile不是我自己想出来的。我从两个模板复制。我的第一个模板将所有

.o
.d
文件构建到
src
目录中。 :/ 并查阅了其他各种 stackoverflow 帖子,但无法破解最后一点。这个 Makefile 经历了更糟糕的阶段。

c++ makefile
1个回答
0
投票

这不能按你想要的方式工作:

release: BUILD  := $(BUILD)/release
debug: BUILD    := $(BUILD)/debug

$(BUILD)/%.o: %.cpp

GNU Make手册你会看到:

与自动变量一样,这些值仅在目标配方的上下文中可用(以及其他特定于目标的分配)

这意味着特定于目标的变量不能在规则的目标或先决条件中使用,因为它们仅在配方中设置。

© www.soinside.com 2019 - 2024. All rights reserved.