【问题标题】:Recursive Make issue递归 Make 问题
【发布时间】:2011-06-08 11:01:49
【问题描述】:

我正在尝试使用递归 make 来消除诸如拥有多个 CFLAGS 变量之类的东西,每个目标一个变量。只有一级递归,这里没有发生疯狂的目录树遍历。我只想将我的目标文件转储到他们的目标特定文件夹中。

到目前为止,我已经想出了一些非常优雅的东西(编辑:好吧,它比我以前使用的单一 makefile 解决方案更优雅。重复太多了!)但不幸的是不起作用。

我认为通过在此处发布格式,很明显我正在尝试做什么。

# ./makefile
.PHONY: all clean

export CC = g++
export INCLUDE = -I ../include/
export SRC = Main.cpp Graphics.cpp Thread.cpp Net.cpp Otherstuff.cpp 
export LINKEROPT = -lglew32 -lopengl32 -lsdl -lws2_32 -lglu32 -lmorelibraries

test: 
    $(MAKE) -f make.unittest

all: 
    $(MAKE) -f make.unittest
    $(MAKE) -f make.debug
    $(MAKE) -f make.release

clean: 
    -rm -rf build_* *.exe 
# I am on windows so the targets are .exe's

这里是 make.debug 文件:

### sub-makefile for the debug build target. Contains target specific build settings.
DIRNAME = build_debug
TARGETNAME = program_debug
TARGETDESCR = DEBUG
CFLAGS = -Wextra -Wall -O0 -g3 -DDEBUG

### EVERYTHING AFTER THIS POINT IS A TEMPLATE
# my goal is to have as much of my makefile code being "reusable" as possible
# so that I can easily add targets. 

OBJ = $(patsubst %.cpp,$(DIRNAME)/%.o,$(SRC))
DEPS = $(patsubst %.cpp,$(DIRNAME)/%.d,$(SRC))
-include $(DEPS)

# default behavior. Set up the build directory. Then build the debug target. 
all: $(DIRNAME) $(TARGETNAME)

# this is the build dir
$(DIRNAME): 
    mkdir $(DIRNAME)

$(DIRNAME)/%.o: %.cpp 
    @echo -e "Compiling for $(TARGETDESCR): $< --> $@"
    $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@ 
    @echo -e "Generating dependencies: $< --> $(patsubst %.o,%.d,$@)"
    $(CC) $(CFLAGS) $(INCLUDE) -MM -MT $@ -MF $(patsubst %.o,%.d,$@) $<
    # I realize there is a way to generate the deps while compiling in one pass 
    # but I'll figure it out later

$(TARGETNAME): $(OBJ)
    @echo -e "Linking $(TARGETDESCR): $@.exe"
    $(CC) -L ../lib/win32/ -o $@ $(OBJ) $(LINKEROPT)

如您所见,我可以通过复制子 makefile 并稍微修改它,然后在主 makefile 中添加一些条目,非常快速地添加一个具有自己的 CFLAGS 集的新构建目标。

所以这里的问题是它无法识别文件中的更改。只有当我编辑 Main.cpp 时,它才会重新编译 build_debug/Main.o。我真的不确定我可以从哪里开始找出不正确的地方。

【问题讨论】:

  • main.d 是否按预期包含在内?修改该文件并将$(info Including main.d...) 添加到文件末尾,并确保在尝试重新构建时看到该消息。此外,请验证 .d 文件是否包含您希望它包含的所有内容以及所有路径是否正确。
  • 要生成依赖项并一次性编译,请添加-MD 选项(gnu.org/software/gcc/news/dependencies.html)。

标签: recursion makefile


【解决方案1】:

我创造了一个怪物。

当我在 that other post 中建议递归 make 时,它​​是为了处理一个特定的 - 并且非常奇怪的 - 包含问题。我不赞同递归生成是纯粹的邪恶的教条,但它确实有缺点,不应该被用作万灵药。

首先,让我们消除不良(且持续存在的)冗余来源。在你的主生成文件中,而不是

$(MAKE) -f make.debug

使用

$(MAKE) -f makefile.sub DIRNAME = build_debug TARGETNAME = program_debug TARGETDESCR = DEBUG CFLAGS = -Wextra -Wall -O0 -g3 -DDEBUG

其中makefile.sub 是各种子makefile 的“模板”部分。我知道这看起来不像是一种改进,但是这样你只有一个子 makefile,而不是 N。(我也认为你使用了太多特定于目标的变量,但我们可以稍后讨论。)

一旦您对此感到满意,您就可以在makefile.sub 中使用target-specific variables,这样您就可以在主makefile 中替换

all: 
    $(MAKE) -f makefile.sub DIRNAME=build_unittest ...
    $(MAKE) -f makefile.sub DIRNAME=build_debug ...
    $(MAKE) -f makefile.sub DIRNAME=build_release ...

all: 
    $(MAKE) -f makefile.sub unittest debug release

我不清楚您在识别文件更改时遇到了什么问题(如果 Main.cc 没有更改,什么时候应该 Make 重建 build_debug/Main.o?),但这可能是递归使用 make 的直接后果(请参阅上面的“缺点”),我们可能可以在没有太多悲伤的情况下解决它。

编辑:

在您的子makefile 中,将all 规则放在-include 行之前,使其成为默认规则。当您调用$(MAKE) 时,您没有指定目标,因此 Make 选择默认目标,即(通常)先出现的目标。 %.d文件的内容有规则的形式,所以如果你先include他们,其中一个(即build_debug/Main.o: Main.cpp)将获胜。

【讨论】:

  • 好吧,它似乎无法识别何时发生变化。如果我删除构建目录中的每个目标文件,它们都会被重建。但是如果我删除其中的一半,它不会认为有什么问题。直到我删除 Main.o (我怀疑这是因为它是列表中的第一个元素)。此时 Main.o 被编译。其余的仍然丢失。不发生链接。这根本没有意义,真的。
猜你喜欢
  • 2016-02-01
  • 2010-12-19
  • 2017-01-31
  • 2011-12-10
  • 2011-08-01
  • 2023-04-10
  • 1970-01-01
相关资源
最近更新 更多