当有人运行`make`时检测(非)GNU Make

时间:2010-08-03 22:47:19

标签: makefile gnu-make

我有一个项目,其makefile使用GNU Make独有的功能。遗憾的是,在运行make时,我们必须支持GNU make仍然不是默认值的平台。

我的一位同事被这种方式所困扰,当非GNU使实现无法正确构建我们的代码时(它将自动变量扩展为空字符串)。我希望通过生成显式错误消息来防止再次发生这种情况。

我可以在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)上遇到了类似的问题。那个人不太重要,但管理起来会很好。

2 个答案:

答案 0 :(得分:6)

如上所述,GNU makeGNUmakefilemakefile之前检查Makefile,我使用了一个简单的修复,如您所描述的,默认(诱饵){导致错误/警告的{1}}:

Makefile

default: @echo "This requires GNU make, run gmake instead" exit 70 是GNU make特定的时候,GNU make documentation建议使用GNUmakefile名称,这是我的首选解决方案。

在原生Makefile更喜欢不同Makefile名称的平台上,您可以对此进行更改,例如:在FreeBSD上我在make中有上面的诱饵,它优先于BSDmakefile使用(从而防止系统Makefile破坏我的构建)。 AFAICT AIX或Solaris make没有可以这种方式使用的备用名称。

尝试调用GNU make的包装器Makefile的一个问题是传递所有参数。

一个看似便携的测试(到目前为止,我发现它适用于古老的OSF1,BSD和Solaris系统)您可以使用make来检测GNU SOMETHING=$(shell ...)是否正在运行,非GNU版本不会设置make。由于deferred evaluation of variables,您无法像预期的那样轻松使用它。这依赖于使用SOMETHING扩展时静默处理带空格的宏名称的实现(即将$()视为变量/宏名称而不是function,即使对此类名称的赋值也是如此在该实现中会导致错误。)

您可以打印清除错误的唯一可移植方式是使用上述技巧创建一个始终运行的虚拟目标:

$(shell foo)

这假设您有一个POSIX GNUMAKE=$(shell echo GNUMAKE) default: gnumake all gnumake: @[ "$(GNUMAKE)" = "GNUMAKE" ] || { echo GNU make required ; exit 70; } shell。

(我已经看到当系统和GNU make都被称为“sh”时检查$(MAKE) -v失败的测试,系统make密谋反对你并调用GNU make ...您需要仔细检查环境变量makePATH以及可能MAKE来处理每个案例。)

答案 1 :(得分:2)

我不知道任何内部功能肯定是GNUMake独有的,但这里有一个kludge:调用“make -v”并解析输出为“GNU”(因为非GNU Make似乎不太可能将MAKE设置为GNU Make):

ifeq ($(shell $(MAKE) -v | grep GNU),)
$(error this is not GNU Make)
endif

修改:
像Dan Molding一样,我开始看到这个问题的实际大小。如上所述,它需要一个在所有版本的Make中语法正确的Makefile。我无法访问Sun Make(我找不到它的手册)所以我不知道这是否可能,或者如果它是如何写的,或者如果我这样做的话如何测试它。< / p>

但我可以建议一种可行的方法。也许这样的事情可以普及:

default:
  ./runGNUMake.pl

就是这样,那就是整个makefile。然后用Perl(或bash,或者你喜欢的任何东西)编写runGNUMake脚本,它会像我的“make -v”kludge一样,然后打印错误信息或运行“make -f realMakefile”。