首页 文章

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

提问于
浏览
5

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

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

What can I write in a Makefile to distinguish GNU make from non-GNU make, print a clear error, and exit?

我已经找到了一个解决方法,将我的真实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 回答

  • 2

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

    default:
        @echo "This requires GNU make, run gmake instead"
        exit 70
    

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

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

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

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

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

    GNUMAKE=$(shell echo GNUMAKE)
    
    default: gnumake all
    
    gnumake:
            @[ "$(GNUMAKE)" = "GNUMAKE" ] || { echo GNU make required ; exit 70; }
    

    假设您有一个POSIX sh shell .

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

  • 6

    我没有't know of any internal feature that is definitely unique to GNUMake, but here' s kludge:调用"make -v"并解析"GNU"的输出(因为非GNU Make似乎不太可能将 MAKE 设置为GNU Make):

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

    EDIT:
    像Dan Molding一样,我开始看到这个问题的实际大小 . 如上所述,它需要一个在 all 版本的Make中语法正确的Makefile . 我没有't have access to Sun Make (and I can' t找到它的手册)所以我甚至不可能't know whether that',或者如果它是如何写它,或者如果我这样做如何测试它 .

    但我可以建议一种可行的方法 . 也许像这样的东西可以普及:

    default:
      ./runGNUMake.pl
    

    那个's it, that'是整个makefile . 然后在Perl(或bash,或任何你喜欢的)中编写 runGNUMake 脚本,它将执行类似我的"make -v" kludge的操作,然后打印错误消息或运行"make -f realMakefile" .

相关问题