如何在GNU make中将目标设为"私有"仅供内部使用?或者:如何最好地执行特定于目标的变量值?

 jack_wangzhu 发布于 2022-12-19 15:29

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

我希望有一个特殊目标.HIDDEN或者.PRIVATE其他东西可以做到这一点,类似于.PHONY非文件目标,但我认为这不存在.该private关键字仅用于变量.

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

我能想出的最好的解决方法是检查$(MAKECMDGOALS)"不可接受的"目标,然后指出错误输出; 这似乎不优雅.我确信makefile可以被重写以避免这种情况 - 也许是一个更好的解决方案 - 但这在这里不实用.


在切割线下面......这是一个人为的例子.

虽然我正在寻找一般解决方案,但作为个人/主要目标有害的目标的一个示例是继承特定于目标的变量值:

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

隐含规则重复(不必要)用于说明.随着目标debug或者release,foo.o和其他人将继承各自CFLAGSCPPFLAGS-如果一个人make clean debug的所有对象将是一致的.但是,例如,如果有人foo.o单独构建,它将无法继承适当的标志; 例如,make clean foo.o debug你将foo.o使用默认构建CFLAGS; 然后在构建时不需要更新debug它,因此它将与具有不同优化或不同宏设置的其他对象链接.它可能适用于这种情况,但它不是预期的.将标记foo.o等标记为非法目标会阻止这种情况.


编辑:

很明显,我的例子(上图)对于我更普遍的问题来说不是一个好的选择:隐藏目标并不是解决我的例子问题的最佳方法.这是一个修改过的示例,说明了修改后的问题"如何强制执行特定于目标的值?" - 它建立在@Michael,@ Bed,@ Ross下面的评论的基础上,并允许冒充和回答这个更有限的场景.

如下面的前面的响应中所述,在这种情况下,更好的想法是创建在不同位置具有不同构建标志的对象.例如,

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所有目标都在一次建有一个配方,看到那么问题这个和这个).

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

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

但这仍然受到影响:

make bin_debug/foo.o

不会得到CPPFLAGSdebug.我已经接受了@ Michael的答案,因为它让我以更有帮助的方式思考问题,但也回答了我自己的一些修辞问题.

2 个回答
  • 你试图解决的问题是合法的,但你正朝着解决它的更糟糕的道路前进.

    宣布私人目标没有任何意义

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

    make clean
    make foo.o
    make debug
    

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

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

    因为在使用不同的标志编译后续单元时make,foo.o它会恢复其所在的任务并保持foo.o不变,使构建目录与第一个场景中的状态相同.

    因此,如果我们可以在Makefile中实现私有目标,那么这将是无效的并且可能传达错误的安全感,这甚至比不安全感本身更糟糕.您想象的解决方案也消除了使用Makefiles而不是shell脚本的最重要优势之一:Make可以轻松地继续执行中断任务.

    我在回答"在Makefile中单独链接目标文件的目的是什么?"这一问题的答案中,记录了使用Makefiles的一些其他方面.

    解决问题的另一种方法

    为了解决编译标志不一致的问题,我们可以安排将构建的目标存储到特殊目录中,具体取决于使用的编译标志.实现这一点可以解决问题,而不会迫使我们在恢复中断的编译工作时轻松辞职.

    以下是实施路线图:

      确定构建配置文件,这里有你releasebuild.

      选择要用于每个构建配置文件的编译.

      选择存储每个构建配置文件的构建目标的目录.

      编写Makefile,以便将构建的目标存储在您选择的目录中.请参考Gnu make - 如何在单独的子目录中获取目标文件.

    注意.在我看来,的BSD变体make很多在一个特殊的目录写入目标更好的支持,请参阅我的回答这个问题:"如何编写使用目标和来源不同的目录中生成文件".一般来说,我喜欢的BSD变体make,因为它的文档很短,以点,它享有了很多有用的先进典型,因为操作系统的建立和港口在BSD世界建立该程序的编排.

    2022-12-19 15:31 回答
  • 您可以通过使用两个连字符开始其名称来定义私有目标.

    --private-target:
        @echo private
    
    public-target: --private-target
        @echo public
    

    你可以打电话,make public-targetmake --private-target会抱怨一个未知的选项:

    $ make public-target
    private
    public
    
    $ make --private-target
    /Library/Developer/CommandLineTools/usr/bin/make: unrecognized option `--private-target'
    

    $ make --version
    GNU Make 3.81
    Copyright (C) 2006  Free Software Foundation, Inc.
    This is free software; see the source for copying conditions.
    There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
    PARTICULAR PURPOSE.
    
    This program built for i386-apple-darwin11.3.0
    

    2022-12-19 15:31 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有