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

Phi*_*ler 5 makefile gnu-make

我有一个项目,其makefile使用GNU Make独有的功能.遗憾的是,我们必须支持的平台在运行时GNU make仍然不是默认值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.
Run Code Online (Sandbox Code Playgroud)

我在Sun的make的古老版本和现代版本(Solaris 8和10)上遇到了类似的问题.那个人不太重要,但管理起来会很好.

mr.*_*tic 6

如前所述,GNU make检查GNUmakefile之前makefileMakefile,我用一个简单的修复,如你所说,默认(诱饵)Makefile会导致一个错误/警告:

default:
    @echo "This requires GNU make, run gmake instead"
    exit 70
Run Code Online (Sandbox Code Playgroud)

GNU make文档建议在GNU make特定GNUmakefile时使用该名称,这Makefile是我的首选解决方案.

在本机make更喜欢不同的Makefile名称的平台上,你可以对此做一个变化,例如在FreeBSD上我有BSDmakefile优先使用的上述诱饵Makefile(从而防止系统make破坏我的构建).AFAICT AIX或Solaris make没有可以这种方式使用的备用名称.

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

一个看似便携的测试(到目前为止,我发现它适用于古老的OSF1,BSD和Solaris系统的混合)你可以SOMETHING=$(shell ...)用来检测GNU make是否正在运行,非GNU版本将不会设置SOMETHING.由于对变量延迟评估,您不能像预期的那样容易地使用它.这依赖于在与扩大默默处理与空间的宏名执行$()(即对待$(shell foo)作为变量/宏的名称,而不是一个功能,即使分配到这样的名称在执行会导致错误).

可以打印清晰错误的唯一可移植方法是使用上面的技巧来创建一个始终运行的虚拟目标:

GNUMAKE=$(shell echo GNUMAKE)

default: gnumake all

gnumake:
        @[ "$(GNUMAKE)" = "GNUMAKE" ] || { echo GNU make required ; exit 70; }
Run Code Online (Sandbox Code Playgroud)

假设您有一个POSIX shshell.

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


Bet*_*eta 1

我不知道 GNUMake 有什么绝对独特的内部功能,但这里有一个拼凑:调用“make -v”并解析“GNU”的输出(因为非 GNU Make 似乎不太可能设置MAKE为GNU 品牌):

ifeq ($(shell $(MAKE) -v | grep GNU),)
$(error this is not GNU Make)
endif
Run Code Online (Sandbox Code Playgroud)

编辑:
像丹·莫尔丁一样,我开始看到这个问题的真正严重性。正如所写的,它需要一个在所有版本的 Make 中语法正确的 Makefile 。我无法访问 Sun Make(而且我找不到它的手册),所以我不知道这是否可能,或者如果可以的话如何编写它,或者如果可以的话如何测试它。

但我可以建议一种可能有效的方法。也许这样的事情可以变得普遍:

default:
  ./runGNUMake.pl
Run Code Online (Sandbox Code Playgroud)

就是这样,这就是整个 makefile。然后runGNUMake用 Perl(或 bash,或任何你喜欢的东西)编写脚本,该脚本将执行类似我的“make -v”kludge 的操作,然后打印错误消息或运行“make -f realMakefile”。