动态Makefile变量赋值

发布于 2025-01-03 16:01:27 字数 1078 浏览 1 评论 0原文

我有以下 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

凯凯我们等你回来 2025-01-10 16:01:27

如果您使用 GNU make,您有两个选择(除了递归 make 调用,它存在上述问题)。

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

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

optimal: CPPFLAGS=$(CPPFLAGS_OPTIMAL)
optimal: CFLAGS=$(CFLAGS_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 optimization”,它将使用最佳设置。

然而,这与 make 的递归调用有同样的缺点;如果直接运行“make appfs”,则不会使用任何设置;特定于目标的变量是从导致在 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

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

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

但是,重要的是要注意,这似乎很难做到的原因是您所要求的本质上是有缺陷的。建议基于构建时参数以两种不同方式之一构建目录中的单个派生文件是自找麻烦。您如何知道最后使用的是哪种变体?假设您运行优化的 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:

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

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

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:

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

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

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:

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

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:

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

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.

原谅我要高飞 2025-01-10 16:01:27

一种可怕但中等有效的技术是:

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

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

这意味着 make debug 重新调用 make 并在命令行上设置了调试标志,而 make optimization 重新调用make 并在命令行上设置最佳标志。

这远非完美;这意味着重新调用 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"

这将使用最佳标志构建两个命名目标。最初的命令行并不是非常优雅,但它会带你到达目的地——差不多。仔细选择默认值以及覆盖它们的能力应该可以帮助您到达所需的位置。

One ghastly but moderately effective technique is:

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

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

This means that make debug reinvokes make with the debug flags set on the command line, and make optimal reinvokes make 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:

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

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

This now runs two different build targets for the debug build and the optimal build. Other rules, such as clean or depend don't get the special treatment.

The + notation on the command lines is POSIX's way of saying 'run this rule even under make -n', which is probably what you want. The $(MAKE) notation may also achieve the same effect. If your make does not like the + signs, try removing them.


This doesn't let me do 'make debug appmount' to build the appmount target in debug mode though does it? It only allows for 'make debug' which builds all the targets in debug.

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:

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)

Now when you run make debug, it will rerun and build the all target by default with the debug options. But, you can change that with:

make optimal BUILD_TARGET="appmount totherprog"

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文