如何使目标“私有"?在GNU中仅供内部使用?或者:如何最好地实施特定于目标的变量值? [英] How can I make a target "private" in GNU make for internal use only? OR: how to best enforce target-specific variable-values?

查看:60
本文介绍了如何使目标“私有"?在GNU中仅供内部使用?或者:如何最好地实施特定于目标的变量值?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在makefile中有一些辅助目标,我希望限制该目标用于makefile中的内部或专用"使用(仅).也就是说,我希望能够从makefile中将这些目标指定为依赖项,但是我想防止从命令行将目标指定为构建目标.类似于OOP中的private函数:单独构建目标是有害的(或者根本没有意义).

I have some ancillary targets in a makefile that I want to restrict for internal or "private" use (only) inside the makefile. That is, I want to be able to specify these targets as dependencies from within the makefile, but I want to prevent the target from being specified as a build goal from the command line. Somewhat analogous to a private function from OOP: the target is harmful (or simply doesn't make sense) to build separately.

我希望有一个特殊目标.HIDDEN.PRIVATE或类似的东西,类似于.PHONY对非文件目标的作用,但是我不认为这是存在的. private关键字仅用于变量.

I wish there were a special-target .HIDDEN or .PRIVATE or something that did this, akin to what .PHONY does for non-file targets, but I don't think this exists. The private keyword is only for variables.

什么是保护目标仅供内部/私人使用的好/一般/优雅的方式?

我能想到的最好的解决方法是检查$(MAKECMDGOALS)中是否存在不可接受的"目标,如果指定了错误,然后进行检查;这似乎很不礼貌.我确信可以重写makefile以避免这种情况-也许是一个更好的解决方案-但这在这里不切实际.

The best workaround that I could come up with is to check $(MAKECMDGOALS) for "unacceptable" targets, then error-out if specified; this seems inelegant. I'm sure the makefile could be rewritten to avoid this situation -- perhaps a superior solution -- but that's not practical here.

在切割线下方...这是一个精心设计的示例.

Below the cut-line... here's a contrived example for illustration.

尽管我正在寻找一种通用的解决方案,但作为个体/主要目标有害的目标的一个示例是继承特定于目标的变量值:

Though I'm looking for a general solution, one example of targets that are harmful as individual/primary goal is with inheriting of target-specific variable values:

override CFLAGS += -Wall
all : debug
%.o : %.c
    $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
debug   : CFLAGS += -g3 -O0
release : CFLAGS +=     -O3
debug   : CPPFLAGS += -DDEBUG
release : CPPFLAGS += -DRELEASE
debug release : foo.o bar.o main.o
    $(CC) -o $@ $^ $(LDFLAGS) $(LDLIBS)
clean:
    -rm -f *.o debug release
.PHONY: all clean

重复(不必要)的隐含规则以进行说明.出于debugrelease的目标,foo.o和其他对象将分别继承CFLAGSCPPFLAGS-如果一个对象做到make clean debug,则所有对象将保持一致.但是,例如,如果有人单独构建foo.o,它将无法继承适当的标志;例如,例如make clean foo.o debug,您将获得使用默认CFLAGS构建的foo.o;那么在构建debug时无需更新它,因此它将与具有不同优化或宏设置的其他对象链接.在这种情况下,它可能会起作用,但这不是预期的.将foo.o等标记为非法目标可以防止这种情况.

Implicit rule duplicated (unnecessary) for illustration. With the goal of debug or release, foo.o and others will inherit respective CFLAGS and CPPFLAGS -- If one does make clean debug all objects will be consistent. But for example if someone builds foo.o separately, it will fail to inherit the appropriate flags; e.g., make clean foo.o debug you'll get foo.o built with default CFLAGS; then it doesn't need to be updated when building debug, so it will be linked with other objects with different optimizations or different macro settings. It will probably work in this case, but it's not what was intended. Marking foo.o, etc. as illegal goals would prevent this.

很明显,我的示例(以上)对于我更笼统的问题不是一个好的选择:隐藏目标并不是解决示例中的问题的最佳方法.这是一个修改后的示例,它说明了修改后的问题如何强制执行特定于目标的值?". -它以下面的@ Michael,@ Beta,@ Ross的评论为基础,并允许摆出和回答这种更为有限的情况.

It's very clear that my example (above) was not a good choice for my more-general question: hiding targets was not the best way to fix an issue with my example. Here's a modified example that illustrates the modified question "How to enforce target-specific values?" -- it builds on commentary from @Michael, @Beta, @Ross below, and allows posing and answering this more limited scenario.

如下面的先前响应中所述,在这种情况下,最好在不同的位置创建具有不同构建标记的对象.例如

As described in previous responses below, it's a much better idea in this case to create objects that have different build flags in separate locations. e.g.,

bin_debug/%.o   : %.c
    $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
bin_release/%.o : %.c
    $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
OBJS = foo.o bar.o main.o # or $(SRCS:.o=.c)
DEBUG_OBJS   = $(addprefix bin_debug/,$OBJS)
RELEASE_OBJS = $(addprefix bin_release/,$OBJS)
debug   : $(DEBUG_OBJS)
release : $(RELEASE_OBJS)
debug release :
    $(CC) -o $@ $^ $(LDFLAGS) $(LDLIBS)

模式规则重复,因为我认为它必须(多个模式目标"(%))说服make所有目标都是用一个配方一次建立的;请参阅这样的问题).

Pattern rule duplicated because I think it has to be (multiple "pattern targets" (%) convince make all targets are built at once with one recipe; see SO questions this and this).

现在,添加目标特定的标志:

So now, add in target-specific flags:

debug   : CPPFLAGS += -DDEBUG
release : CPPFLAGS += -DRELEASE

但这仍然遭受:

make bin_debug/foo.o

不会从debug获取CPPFLAGS.我接受了@Michael的以下回答,因为它使我以更有帮助的方式思考问题,同时还回答了下面我自己的一些修辞问题.

will not get the CPPFLAGS from debug. I've accepted @Michael's answer below as it got me thinking about the problem in a more helpful way, but also answered some of my own rhetorical questions below.

推荐答案

您尝试解决的问题是合理的,但您正在朝着更糟糕的解决之路前进.

The problem you are trying to solve is legitimate but you are heading on the worse possible path to solve it.

当我们编写Makefile时,我们将根据目标,源代码和配方来描述编译工作.这项工作的进展由已经建立的一组目标来描述.现在,您可以准确地观察到该序列了

When we write a Makefile, we are describing a compilation job in terms of targets, sources and recipes. The advancement of this job is described by the set of targets which are already built. Now you are accurately observing that the sequence

make clean
make foo.o
make debug

会生成其格式与foo.o不一致的对象,从而使您的构建目录处于不一致状态.但是,推断用户不应该能够显式构造foo.o是非常错误的.请考虑以下顺序:

will produce objects whose format is inconsistent with foo.o thus leaving your build directory in an inconsistent state. But it is very wrong to deduce that the user should not be able to construct foo.o explicitly. Consider the following sequence:

make clean
# Wait for foo.o being compiles and
#  interrupt the build job with a signal
make debug

由于make看到foo.o它将继续执行其原处的任务,并保留foo.o不变,同时用不同的标志编译后续单元,使生成目录的状态与第一种情况相同.

Since make sees that foo.o it will resume its task where it was at and left foo.o untouched while compiling subsequent units with different flags, leaving the build directory the same inconsistent state as in the first scenario.

因此,如果我们可以在Makefile中实现私有目标,那么这将是无效的,并且可能传达一种错误的安全感,甚至比不安全本身更糟.同样,您想象中的解决方案消除了在外壳程序脚本上使用Makefile的最重要优点之一: Make使在原处轻松执行中断的任务变得很容易.

Hence, if we could implement private targets in Makefiles, this would be ineffective and could convey a false sense of security, which is even worse than insecurity by itself. Also the solution you imagined annihilates one of the most important advantages of using Makefiles over shell scripts: Make makes it easy to continue an interrupted task where it was at.

我记录了有关Makefile与使用.

I documented some other aspects of using Makefiles in relation to the set of targets already built in my answer to the question "What is the purpose of linking object files separately in a Makefile?".

要解决编译标志不一致的问题,我们可以根据所使用的编译标志来安排将构建的目标存储到特殊目录中.实施此操作将解决该问题,而不会迫使我们辞职,因为恢复中断的编译作业很容易.

To address the issue of compilation flags inconsistency, we can arrange to store built targets into a special directory, depending on the compilation flags used. Implementing this would fix the issue without forcing us to resign upon the ease of resuming an interrupted compilation job.

以下是实施路线图:

  1. 标识构建配置文件,这里有releasebuild.
  2. 选择用于每个构建配置文件的编译.
  3. 为每个构建配置文件选择在哪个目录中存储构建目标.
  4. 编写Makefile,以便将构建的目标存储在您选择的目录中.请参考 Gnu make-如何在单独的子目录中获取目标文件.
  1. Identify build profiles, here you have release and build.
  2. Choose which compilation to use for each build profile.
  3. Choose in which directory to store built targets for each build profile.
  4. Write your Makefile so that built targets are stored in the directories you choosed. Please refer Gnu make - how to get object files in separate subdirectory.

注意.在我看来,make的BSD变体对在特殊目录中编写目标提供了更好的支持,请参见.通常,我更喜欢make的BSD变体,因为它的文档简明扼要,并且拥有许多有用的高级示例,因为BSD世界中的操作系统构建和端口构建是由该程序编排的.

Note. In my opinion, the BSD variant of make has a much nicer support for writing targets in a special directory, see my answer to the question "How to write a Makefile using different directories for targets and sources". Generally I prefer the BSD variant of make because its documentation is short and to the point and it enjoys a lot of useful advanced examples, since operating system build and ports build in the BSD world are orchestrated by this program.

这篇关于如何使目标“私有"?在GNU中仅供内部使用?或者:如何最好地实施特定于目标的变量值?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆