动态Makefile变量赋值
我有以下Makefile,我想创建“debug”和“optimal”目标,它们会影响CPPFLAGS和CFLAGS中的值,如下所示:动态Makefile变量赋值,makefile,Makefile,我有以下Makefile,我想创建“debug”和“optimal”目标,它们会影响CPPFLAGS和CFLAGS中的值,如下所示: include Makefile.inc DIRS = applib EXE_APPFS = appfs EXE_APPMOUNT = appmount EXE_APPINSPECT = appinspect EXE_APPCREATE = appcreate BUILD_APPFS = BUILD_APPMOUNT =
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)放在optimal中,它就可以工作)。无论是“使appmount最优”还是“使appmount_最优”,都不能得到我期望的结果
当然有一种方法可以根据您是否需要调试来定义CPPFLAGS和CFLAG,对吗?一种可怕但中等有效的技术是:
# Optimization settings.
debug:
+$(MAKE) CPPFLAGS="$(CPPFLAGS_DEBUG)" CFLAGS="$(CFLAGS_DEBUG)"
optimal:
+$(MAKE) CPPFLAGS="$(CPPFLAGS_OPTIMAL)" CFLAGS="$(CFLAGS_OPTIMAL)"
这意味着make debug
reinvokesmake
使用在命令行上设置的调试标志,以及make optimal
reinvokesmake
使用在命令行上设置的最佳标志
这远非完美;这意味着当重新调用make
时,将运行默认规则
您可以根据以下情况进行更改:
# Optimization settings.
debug:
+$(MAKE) CPPFLAGS="$(CPPFLAGS_DEBUG)" CFLAGS="$(CFLAGS_DEBUG)" debug_build
optimal:
+$(MAKE) CPPFLAGS="$(CPPFLAGS_OPTIMAL)" CFLAGS="$(CFLAGS_OPTIMAL)" optimal_build
现在,它为调试构建和优化构建运行两个不同的构建目标。其他规则,如clean
或dependent
没有得到特殊处理
命令行上的+
符号是POSIX表示“即使在make-n
下运行此规则”的方式,这可能是您想要的。$(MAKE)
符号也可以达到相同的效果。如果您的make
不喜欢+
符号,请尝试删除它们
这不允许我在调试模式下执行“
make debug appmount
”来构建appmount目标,尽管这样做了吗?它只允许“makedebug
”生成调试中的所有目标
你是对的;这就是为什么它不完美的原因。如果你幸运的话,其他人会想出更好的解决方案。有一种稍微迂回的方法可以或多或少地实现你想要的:
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)
现在,当您运行makedebug
时,默认情况下,它将使用debug选项重新运行并构建all
目标。但是,您可以通过以下方式改变这一点:
make optimal BUILD_TARGET="appmount totherprog"
这将使用最佳标志构建两个命名目标。最初的命令行并不是非常优雅,但它可以让您到达目的地——差不多。仔细选择默认值和覆盖默认值的能力应该可以帮助您找到需要的地方。如果您使用的是GNU make,那么您有两个选项(除了递归make调用之外,递归make调用存在上述问题) 第一种选择是使用特定于目标的变量。您正在原始示例中使用它们:
debug: CPPFLAGS=$(CPPFLAGS_DEBUG)
debug: CFLAGS=$(CFLAGS_DEBUG)
optimal: CPPFLAGS=$(CPPFLAGS_OPTIMAL)
optimal: CFLAGS=$(CFLAGS_OPTIMAL)
您缺少的是特定于目标的变量由其先决条件继承。因此,您需要声明“调试”和“优化”的先决条件(它们本身不必有配方;事实上,它们可以被声明为假的)。例如:
debug: CPPFLAGS=$(CPPFLAGS_DEBUG)
debug: CFLAGS=$(CFLAGS_DEBUG)
debug: appfs appmount
optimal: CPPFLAGS=$(CPPFLAGS_OPTIMAL)
optimal: CFLAGS=$(CFLAGS_OPTIMAL)
optimal: appfs appmount
STYLE := $(firstword $(filter optimal,$(MAKECMDGOALS)) debug)
现在,若您运行“makedebug”,它将使用cppfags和CFLAGS的调试设置构建appfs和appmount;如果您运行“makeoptimal”,它将使用最佳设置
然而,这与make的递归调用具有相同的缺点;如果直接运行“makeappfs”,则两种设置都不会使用;特定于目标的变量是从父级继承的,该父级导致在此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
然而,重要的是要注意,这样做似乎很棘手的原因是,你所要求的是内在的缺陷。建议目录中的单个派生文件应基于构建时参数以两种不同方式之一构建,这是自找麻烦。你怎么知道上次使用的是哪种变体?假设您使用优化运行make,然后修改一些文件,然后再次使用调试运行make。。。现在,您的一些文件已优化,一些已调试
处理不同版本代码的正确方法是确保派生文件是唯一的。这意味着调试目标将写入一个目录,而优化目标将写入另一个目录。一旦你做了这个区分,剩下的部分就很容易被忽略了:当你为调试目标编写规则时,你只需使用调试标志,当你为优化目标编写规则时,你只需使用优化标志。这不允许我在调试模式下使用“make debug appmount”来构建appmount目标,是吗?它只允许“make debug”在debug中构建所有目标。好吧,我将把它标记为答案,因为这是我正在使用的(因为make中实际上不可能有原始请求)。可能有更好的方法来实现它,特别是如果您对GNU make的特殊功能了解足够多,并且可以接受使用它。显然,您正在使用GNU make。我没有研究过GNU make的高级功能,因为它们在我需要我的make文件的任何地方都不可用。必须有一种更好的方法,“先决条件继承”是我不知道的一点。好吧,我现在正在使用这个解决方案(尽管它更具体到GNU make)。我还在样式检查之后添加了“$(if$(filter 1,$(words$(MAKECMDGOALS)),$(error$(error\u NOTARGET)),)”,以确保用户提供构建目标(例如“all”)。