当有人运行 `make` 时检测(非)GNU Make
我有一个项目,其 makefile 使用 GNU Make 独有的功能。遗憾的是,有些平台我们必须支持,但在运行 make
时,GNU make 仍然不是默认的。
当非 GNU make 实现默默地未能正确构建我们的代码(它将自动变量扩展为空字符串)时,我的一位同事对此感到很困惑。我想通过生成明确的错误消息来防止这种情况再次发生。
我可以在 Makefile
中编写什么来区分 GNU make 和非 GNU make,打印明确的错误,然后退出?
我已经找到了重命名我的文件的解决方法真正的 makefile 到 GNUmakefile
,并在 Makefile
中放置一个小存根,但我宁愿更直接的东西。
Beta 和 Dan Molding 的答案看起来非常好且简单,但是在 AIX 6.1 上,make 实现无法处理其中任何一个:
$ cat testmake
foo:
touch foo
ifeq ($(shell $(MAKE) -v | grep GNU),)
$(error this is not GNU Make)
endif
ifeq "${MAKE_VERSION}" ""
$(info GNU Make not detected)
$(error ${MIN_MAKE_VER_MSG})
endif
$ /usr/bin/make -f testmake
"testmake", line 5: make: 1254-055 Dependency line needs colon or double colon operator.
"testmake", line 6: make: 1254-055 Dependency line needs colon or double colon operator.
"testmake", line 7: make: 1254-055 Dependency line needs colon or double colon operator.
"testmake", line 8: make: 1254-055 Dependency line needs colon or double colon operator.
"testmake", line 11: make: 1254-055 Dependency line needs colon or double colon operator.
"testmake", line 12: make: 1254-055 Dependency line needs colon or double colon operator.
"testmake", line 13: make: 1254-055 Dependency line needs colon or double colon operator.
make: 1254-058 Fatal errors encountered -- cannot continue.
我在 Sun 的 make 的古老版本和现代版本(Solaris 8 和 10)上都遇到了类似的问题。这个不太重要,但很容易管理。
I have a project whose makefile uses features exclusive to GNU Make. Sadly, there are platforms we must support where GNU make is still not the default when running make
.
One of my colleagues was bitten by this, when a non-GNU make implementation silently failed to build our code correctly (it expanded an automatic variable to an empty string). I want to prevent that from happening again, by generating an explicit error message instead.
What can I write in a Makefile
to distinguish GNU make from non-GNU make, print a clear error, and exit?
I've already figured out a workaround in renaming my real makefile to GNUmakefile
, and putting a small stub in Makefile
, but I'd rather something more direct.
The answers by Beta and Dan Moulding look really nice and simple, but on AIX 6.1, the make implementation can't handle either of them:
$ cat testmake
foo:
touch foo
ifeq ($(shell $(MAKE) -v | grep GNU),)
$(error this is not GNU Make)
endif
ifeq "${MAKE_VERSION}" ""
$(info GNU Make not detected)
$(error ${MIN_MAKE_VER_MSG})
endif
$ /usr/bin/make -f testmake
"testmake", line 5: make: 1254-055 Dependency line needs colon or double colon operator.
"testmake", line 6: make: 1254-055 Dependency line needs colon or double colon operator.
"testmake", line 7: make: 1254-055 Dependency line needs colon or double colon operator.
"testmake", line 8: make: 1254-055 Dependency line needs colon or double colon operator.
"testmake", line 11: make: 1254-055 Dependency line needs colon or double colon operator.
"testmake", line 12: make: 1254-055 Dependency line needs colon or double colon operator.
"testmake", line 13: make: 1254-055 Dependency line needs colon or double colon operator.
make: 1254-058 Fatal errors encountered -- cannot continue.
I run into similar issues on both archaic and modern versions (Solaris 8 & 10) of Sun's make. That one's less critical, but would be nice to manage.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
如前所述,GNU
make
在makefile
或Makefile
之前检查GNUmakefile
,我使用了一个简单的修复,例如您所描述的默认(诱饵)Makefile
会导致错误/警告:GNU make 文档 建议当
Makefile
是 GNU make 专用时使用GNUmakefile
名称,所以这是我的首选解决方案。在本机
make
更喜欢不同 Makefile 名称的平台上,您可以对此进行变体,例如在 FreeBSD 上,我在BSDmakefile
中有上述诱饵,优先使用它到Makefile
(从而防止系统make
破坏我的构建)。 AFAICT AIX 或 Solarismake
没有可以通过这种方式使用的备用名称。尝试调用 GNU make 的包装器 Makefile 的一个问题是传递所有参数。
一个看似可移植的测试(到目前为止,我发现它可以在古老的 OSF1、BSD 和 Solaris 系统的混合上工作),您可以使用
SOMETHING=$(shell ...)
来检测是否是 GNUmake
正在运行,非 GNU 版本不会设置SOMETHING
。由于延迟评估变量,您无法轻松使用它正如预期的那样。这依赖于在使用$()
扩展时静默处理带有空格的宏名称的实现(即将$(shell foo)
视为变量/宏名称而不是 function,即使在该实现会导致错误)。打印清除错误的唯一可移植方法是使用上述技巧,让一个始终运行的虚拟目标:
这假设您有一个 POSIX
sh
shell。(我见过当系统和 GNU make 都被称为“
make
”时检查$(MAKE) -v
的测试会失败,系统make
密谋反对你并调用 GNUmake
...你需要仔细检查环境变量PATH
、MAKE
以及可能的SHELL
处理每种情况。)As noted, GNU
make
checks forGNUmakefile
beforemakefile
orMakefile
, I've used a trivial fix such as you described, a default (decoy)Makefile
that causes an error/warning:The GNU make documentation recommends using the
GNUmakefile
name when theMakefile
is GNU make specific, so that's my preferred solution.On platforms where the native
make
prefers a different Makefile name, you can do a variation on this, e.g. on FreeBSD I have the above decoy in theBSDmakefile
which is used in preference toMakefile
(thus preventing the systemmake
from mangling my build). AFAICT the AIX or Solarismake
do not have an alternate name you could use in this way.One problem with a wrapper
Makefile
which tries to call GNUmake
is passing all the arguments.A seemingly portable test (so far, I've found it to work on a mix of ancient OSF1, BSD and Solaris systems) you can use
SOMETHING=$(shell ...)
to detect if GNUmake
is running, non GNU versions will not setSOMETHING
. Because of deferred evaluation of variables, you cannot use this as easily as might be expected though. This relies on the implementation silently handling macro names with spaces when expanded with$()
(i.e. treats$(shell foo)
as a variable/macro name rather than a function, even though an assignment to such a name in that implementation would cause an error).The only portable way you can print a clear error is to have a dummy target that is always run, using the above trick:
This assumes you have a POSIX
sh
shell.(I have seen tests which inspect
$(MAKE) -v
fail when both system and GNU make are called "make
", the systemmake
conspires against you and invokes GNUmake
... You'd need some carefully checking of environment variablesPATH
,MAKE
and possiblySHELL
to handle every case.)我不知道 GNUMake 有什么绝对独特的内部功能,但这里有一个拼凑:调用“make -v”并解析“GNU”的输出(因为非 GNU Make 似乎不太可能有
MAKE
设置为 GNU Make):编辑:
和丹·莫尔丁一样,我开始看到这个问题的真正严重性。正如所写的,它需要一个在 所有 版本的 Make 中语法正确的 Makefile。我无法访问 Sun Make(而且我找不到它的手册),所以我不知道这是否可能,或者如果可以的话如何编写它,或者如果可以的话如何测试它。
但我可以建议一种可能有效的方法。也许这样的东西可以变得通用:
就是这样,这就是整个 makefile。然后用 Perl(或 bash,或任何你喜欢的东西)编写
runGNUMake
脚本,该脚本将执行类似我的“make -v”kludge 的操作,然后打印错误消息或运行“make -f realMakefile” 。I don't know of any internal feature that is definitely unique to GNUMake, but here's a kludge: call "make -v" and parse the output for "GNU" (since it seems unlikely that a non-GNU Make would have
MAKE
set to a GNU Make):EDIT:
Like Dan Moulding, I am starting to see the real size of this problem. As written, it requires a Makefile that is syntactically correct in all versions of Make. I don't have access to Sun Make (and I can't find manuals for it) so I don't know whether that's even possible, or how to write it if it is, or how to test it if I did.
But I can suggest an approach that might work. Maybe something like this can be made universal:
That's it, that's the whole makefile. Then write the
runGNUMake
script in Perl (or bash, or whatever you like) that will do something like my "make -v" kludge and then either print the error message or run "make -f realMakefile".