动态Makefile变量赋值

Jun*_*des 2 makefile

我有以下Makefile,我想创建"调试"和"最佳"目标,这些目标会影响CPPFLAGS和CFLAGS中的值,如下所示:

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
Run Code Online (Sandbox Code Playgroud)

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

当然有一种方法来定义CPPFLAGS和CFLAGS取决于你是否想要调试,对吗?

Mad*_*ist 6

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

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

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

optimal: CPPFLAGS=$(CPPFLAGS_OPTIMAL)
optimal: CFLAGS=$(CFLAGS_OPTIMAL)
Run Code Online (Sandbox Code Playgroud)

您缺少的是特定于目标的变量由其先决条件继承.因此,您需要声明"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
Run Code Online (Sandbox Code Playgroud)

现在,如果您运行"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
Run Code Online (Sandbox Code Playgroud)

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

STYLE := $(firstword $(filter optimal,$(MAKECMDGOALS)) debug)
Run Code Online (Sandbox Code Playgroud)

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

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