动态Makefile变量赋值

时间:2012-02-08 02:25:07

标签: makefile

我有以下Makefile,我想创建影响CPPFLAGS和CFLAGS中值的“debug”和“optimal”目标,如下所示:

include Makefile.inc

DIRS    = applib
EXE_APPFS       = appfs
EXE_APPMOUNT    = appmount
EXE_APPINSPECT  = appinspect
EXE_APPCREATE   = appcreate
BUILD_APPFS     =
BUILD_APPMOUNT  = -DAPPMOUNT
OBJS_APPFS      = main.o appfs.o
OBJS_APPMOUNT   = main.o appmount.o
OBJS_APPINSPECT = appinspect.o
OBJS_APPCREATE  = appcreate.o
OBJLIBS = libapp.a
LIBS    = -L. -lpthread -lstdc++ -ldl -lrt -largtable2 -lm ./libapp.a     /usr/lib64/libfuse.a

# Optimization settings.
debug: CPPFLAGS=$(CPPFLAGS_DEBUG)
debug: CFLAGS=$(CFLAGS_DEBUG)
debug:
    @true

optimal: CPPFLAGS=$(CPPFLAGS_OPTIMAL)
optimal: CFLAGS=$(CFLAGS_OPTIMAL)
optimal:
    @true

appfs: appfs.o $(OBJLIBS)
    @echo "stuff is done here"

appmount: appmount.o $(OBJLIBS)
    @echo "stuff is done here"

appmount_optimal: optimal appmount

我遇到的问题是“debug”和“optimal”中的变量赋值不会转移到其他目标(尽管如果我将@echo $(CPPFLAGS)置于最佳工作范围内)。无论是“制作最佳appmount”还是“make appmount_optimal”都不能得到我期待的结果。

当然有一种方法可以根据你是否要调试来定义CPPFLAGS和CFLAGS,对吗?

2 个答案:

答案 0 :(得分:6)

如果您使用的是GNU make,则有两个选项(除了递归make调用之外,还有上面列出的问题)。

第一种选择是使用特定于目标的变量。您在原始示例中使用它们:

debug: CPPFLAGS=$(CPPFLAGS_DEBUG)
debug: CFLAGS=$(CFLAGS_DEBUG)

optimal: CPPFLAGS=$(CPPFLAGS_OPTIMAL)
optimal: CFLAGS=$(CFLAGS_OPTIMAL)

您缺少的是,特定于目标的变量是由先决条件继承的。因此,您需要声明“debug”和“optimal”的先决条件(它们本身不必具有配方;实际上,它们可以声明为.PHONY)。例如:

debug: CPPFLAGS=$(CPPFLAGS_DEBUG)
debug: CFLAGS=$(CFLAGS_DEBUG)
debug: appfs appmount

optimal: CPPFLAGS=$(CPPFLAGS_OPTIMAL)
optimal: CFLAGS=$(CFLAGS_OPTIMAL)
optimal: appfs appmount

现在,如果您运行“make debug”,它将使用CPPFLAGS和CFLAGS的调试设置构建appfs和appmount;如果你运行“make optimal”,它将使用最佳设置。

然而,这与make的递归调用具有相同的缺点;如果你直接运行“make appfs”,那么将使用NEITHER设置;特定于目标的变量继承自导致在此make调用中构建目标的父项。如果这些目标都不在父目标列表中,则不会使用它们的目标特定变量。

第二个选项,它提供了您正在寻找的接口,它是使用MAKECMDGOALS变量来决定用户是否要求最佳构建或调试构建。例如:

CPPFLAGS_debug = <debug CPPFLAGS>
CFLAGS_debug = <debug CFLAGS>

CPPFLAGS_optimal = <optimal CPPFLAGS>
CFLAGS_optimal = <optimal CFLAGS>

STYLE := $(firstword $(filter debug optimal,$(MAKECMDGOALS)))
$(if $(STYLE),,$(error No style "debug" or "optimal" set))

CPPFLAGS = $(CPPFLAGS_$(STYLE))
CFLAGS = $(CFLAGS_$(STYLE))

debug optimal:
.PHONY: debug optimal

或者,如果您愿意,可以选择默认行为(如果没有给出),而不是抛出错误;这默认选择“debug”,例如:

STYLE := $(firstword $(filter optimal,$(MAKECMDGOALS)) debug)

但是,重要的是要注意这个看起来很棘手的原因是你所要求的是天生就有缺陷的。建议目录中的单个派生文件应该基于构建时参数以两种不同的方式之一构建,这就是要求麻烦。您如何知道最后使用的变体?假设您运行make with optimization,然后修改一些文件,然后这次使用debug再次运行make ...现在您的一些文件已经过优化,一些文件已经过调试。

处理代码的不同构建变体的正确方法是确保派生文件是唯一的。这意味着将调试目标写入一个目录,并将优化的目标写入另一个目录。一旦你做出这种区分,剩下的就很容易了:你在编写调试目标的规则时使用调试标志,在为优化目标编写规则时使用最佳标志。

答案 1 :(得分:2)

一种可怕但适度有效的技术是:

# Optimization settings.
debug:
    +$(MAKE) CPPFLAGS="$(CPPFLAGS_DEBUG)" CFLAGS="$(CFLAGS_DEBUG)"

optimal:
    +$(MAKE) CPPFLAGS="$(CPPFLAGS_OPTIMAL)" CFLAGS="$(CFLAGS_OPTIMAL)"

这意味着make debug使用在命令行上设置的调试标志重新调用make,并make optimal重新调用make并在命令行上设置最佳标志。< / p>

这远非完美;这意味着当重新调用make时将运行默认规则。

您可以通过以下方式改变:

# Optimization settings.
debug:
    +$(MAKE) CPPFLAGS="$(CPPFLAGS_DEBUG)" CFLAGS="$(CFLAGS_DEBUG)" debug_build

optimal:
    +$(MAKE) CPPFLAGS="$(CPPFLAGS_OPTIMAL)" CFLAGS="$(CFLAGS_OPTIMAL)" optimal_build

现在,它为调试版本和最佳版本运行两个不同的构建目标。其他规则(例如cleandepend)未获得特殊处理。

命令行上的+符号是POSIX的说法'即使在make -n'下运行此规则,这可能就是你想要的。 $(MAKE)符号也可以达到同样的效果。如果您的make不喜欢+标志,请尝试将其删除。


  

这不允许我在调试模式下“make debug appmount”来构建appmount目标吗?它只允许在调试中构建所有目标的“make debug”。

你是对的;这就是为什么它不完美的原因。如果你很幸运,其他人会想出更好的解决方案。有一种略微狡猾的方式来或多或少地实现你想要的东西:

BUILD_TARGET = all

# Optimization settings.
debug:
    +$(MAKE) CPPFLAGS="$(CPPFLAGS_DEBUG)" CFLAGS="$(CFLAGS_DEBUG)" $(BUILD_TARGET)

optimal:
    +$(MAKE) CPPFLAGS="$(CPPFLAGS_OPTIMAL)" CFLAGS="$(CFLAGS_OPTIMAL)" $(BUILD_TARGET)

现在,当您运行make debug时,默认情况下会使用调试选项重新运行并构建all目标。但是,您可以通过以下方式进行更改:

make optimal BUILD_TARGET="appmount totherprog"

这将使用最佳标志构建两个命名目标。初始命令行不是很优雅,但它会让你到达你的目的地 - 几乎。仔细选择默认值以及覆盖它们的能力应该可以让您到达目的地。