我在makefile中有一些辅助目标,我想在makefile中限制内部或"私人"使用(仅限).也就是说,我希望能够在makefile中将这些目标指定为依赖项,但我想阻止将目标从命令行指定为构建目标.有点类似于private
OOP中的函数:目标是单独构建的有害(或根本没有意义).
我希望有一个特殊目标.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
和其他人将继承各自CFLAGS
和CPPFLAGS
-如果一个人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
不会得到CPPFLAGS
从debug
.我已经接受了@ Michael的答案,因为它让我以更有帮助的方式思考问题,但也回答了我自己的一些修辞问题.
你试图解决的问题是合法的,但你正朝着解决它的更糟糕的道路前进.
当我们编写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的一些其他方面.
为了解决编译标志不一致的问题,我们可以安排将构建的目标存储到特殊目录中,具体取决于使用的编译标志.实现这一点可以解决问题,而不会迫使我们在恢复中断的编译工作时轻松辞职.
以下是实施路线图:
确定构建配置文件,这里有你release
和build
.
选择要用于每个构建配置文件的编译.
选择存储每个构建配置文件的构建目标的目录.
编写Makefile,以便将构建的目标存储在您选择的目录中.请参考Gnu make - 如何在单独的子目录中获取目标文件.
注意.在我看来,的BSD变体make
有很多在一个特殊的目录写入目标更好的支持,请参阅我的回答这个问题:"如何编写使用目标和来源不同的目录中生成文件".一般来说,我喜欢的BSD变体make
,因为它的文档很短,以点,它享有了很多有用的先进典型,因为操作系统的建立和港口在BSD世界建立该程序的编排.
您可以通过使用两个连字符开始其名称来定义私有目标.
--private-target: @echo private public-target: --private-target @echo public
你可以打电话,make public-target
但make --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