动态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
我遇到的问题是“调试”和“最佳”内部的变量分配不正确不会转移到其他目标(尽管如果我将 @echo $(CPPFLAGS) 放在最有效的范围内)。 “make best appmount”和“make appmount_optimal”都没有得到我期望的结果。
当然有一种方法可以根据您是否想要调试来定义 CPPFLAGS 和 CFLAGS,对吗?
I have the following Makefile and I want to create "debug" and "optimal" targets which affect the values in CPPFLAGS and CFLAGS, like so:
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
The problem I'm having is that the variable assignments inside "debug" and "optimal" don't carry over to other targets (though if I put @echo $(CPPFLAGS) inside optimal that works). Neither doing "make optimal appmount" nor "make appmount_optimal" gets me the results I'm expecting.
Surely there is a way to define CPPFLAGS and CFLAGS depending on whether you want debugging or not, right?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
如果您使用 GNU make,您有两个选择(除了递归 make 调用,它存在上述问题)。
第一个选项是使用特定于目标的变量。您在原始示例中使用了它们:
您缺少的是特定于目标的变量继承其先决条件。因此,您需要声明“调试”和“最佳”的先决条件(它们本身不必有配方;事实上,它们可以声明为 .PHONY)。例如:
现在,如果您运行“make debug”,它将使用 CPPFLAGS 和 CFLAGS 的调试设置构建 appfs 和 appmount;如果您运行“make optimization”,它将使用最佳设置。
然而,这与 make 的递归调用有同样的缺点;如果直接运行“make appfs”,则不会使用任何设置;特定于目标的变量是从导致在 make 调用中构建目标的父级继承的。如果这些目标都不在父目标列表中,则不会使用它们的特定于目标的变量。
第二个选项为您提供了几乎完全相同的界面,即使用 MAKECMDGOALS 变量来决定用户是否要求最佳版本或调试版本。例如这样的事情:
或者,如果您愿意,您可以选择默认行为(如果没有给出),而不是抛出错误;例如,默认情况下选择“调试”:
但是,重要的是要注意,这似乎很难做到的原因是您所要求的本质上是有缺陷的。建议基于构建时参数以两种不同方式之一构建目录中的单个派生文件是自找麻烦。您如何知道最后使用的是哪种变体?假设您运行优化的 make,然后修改一些文件,然后这次再次运行调试的 make...现在您的一些文件已优化,有些文件正在调试。
处理代码的不同构建变体的正确方法是确保派生文件是唯一的。这意味着调试目标将写入一个目录,而优化目标将写入另一目录。一旦你做出了这种区分,其余的事情就很容易消失了:当你为调试目标编写规则时,你只需使用调试标志,而当你为优化目标编写规则时,你只需使用最佳标志。
If you are using GNU make, you have two options (in addition to the recursive make invocation, which has the problems outlined above).
The first option is to use target-specific variables. You are using them in your original example:
The thing you're missing is that target-specific variables are inherited by their prerequisites. So you need to declare prerequisites of "debug" and "optimal" (they don't have to have recipes themselves; in fact, they can be declared .PHONY). So for example:
Now if you run "make debug" it will build both appfs and appmount with the debug settings for CPPFLAGS and CFLAGS; if you run "make optimal" it will use the optimal settings.
However this has the same downside as the recursive invocation of make; if you run "make appfs" directly then NEITHER of the settings will be used; target-specific variables are inherited from the parent(s) that led to the target being built in this invocation of make. If neither of those targets are in the parent target list then their target-specific variables won't be used.
The second option, which gives you pretty much exactly the interface you were looking for, is to use the MAKECMDGOALS variable to decide whether the user asked for optimal or debug builds. For example something like this:
Or if you prefer you can choose a default behavior if one isn't given, instead of throwing an error; this chooses "debug" by default for example:
However, it's important to note that the reason this seems tricky to do is that what you're asking for is inherently flawed. Suggesting that a single derived file in a directory should be built in one of two different ways based on a build-time parameter is asking for trouble. How do you know which variation was used last? Suppose you run make with optimization, then you modify some files, then you run make again this time with debug... now some of your files are optimized and some are debug.
The right way to handle different build variations of code is to ensure that the derived files are unique. This means that the debug targets are written to one directory, and the optimized targets are written to a different directory. Once you make this distinction the rest of it falls out easily: you simply use the debug flags when you write the rules for the debug targets and the optimal flags when you write the rules for the optimized targets.
一种可怕但中等有效的技术是:
这意味着
make debug
重新调用make
并在命令行上设置了调试标志,而make optimization
重新调用make
并在命令行上设置最佳标志。这远非完美;这意味着重新调用
make
时将运行默认规则。您可以通过以下方式改变这一点:
现在为调试构建和最佳构建运行两个不同的构建目标。其他规则,例如
clean
或depend
不会得到特殊待遇。命令行上的
+
表示法是 POSIX 表达“即使在make -n
下也运行此规则”的方式,这可能就是您想要的。$(MAKE)
符号也可以达到相同的效果。如果您的make
不喜欢+
符号,请尝试删除它们。你是对的;这就是它不完美的原因。如果你幸运的话,其他人会想出更好的解决方案。有一种稍微狡猾的方法可以或多或少地实现您想要的:
现在,当您运行
make debug
时,它将重新运行并默认使用调试选项构建all
目标。但是,您可以通过以下方式更改:这将使用最佳标志构建两个命名目标。最初的命令行并不是非常优雅,但它会带你到达目的地——差不多。仔细选择默认值以及覆盖它们的能力应该可以帮助您到达所需的位置。
One ghastly but moderately effective technique is:
This means that
make debug
reinvokesmake
with the debug flags set on the command line, andmake optimal
reinvokesmake
with the optimal flags set on the command line.This is far from perfect; it means the default rule will be run when
make
is reinvoked.You could vary this with:
This now runs two different build targets for the debug build and the optimal build. Other rules, such as
clean
ordepend
don't get the special treatment.The
+
notation on the command lines is POSIX's way of saying 'run this rule even undermake -n
', which is probably what you want. The$(MAKE)
notation may also achieve the same effect. If yourmake
does not like the+
signs, try removing them.You're correct; that's the sort of reason why it is not perfect. If you're lucky, someone else will come up with a better solution. There is a slightly devious way to more or less achieve what you want:
Now when you run
make debug
, it will rerun and build theall
target by default with the debug options. But, you can change that with:This will build the two named targets with the optimal flags. The initial command line is not dreadfully elegant, but it would get you to your destination - just about. Careful choice of defaults and the ability to override them should get you where you need to go.