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

发布于 2024-09-12 08:31:06 字数 1500 浏览 2 评论 0原文

我有一个项目,其 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

忘你却要生生世世 2024-09-19 08:31:06

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

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

GNU make 文档 建议当 Makefile 是 GNU make 专用时使用 GNUmakefile 名称,所以这是我的首选解决方案。

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

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

一个看似可移植的测试(到目前为止,我发现它可以在古老的 OSF1、BSD 和 Solaris 系统的混合上工作),您可以使用 SOMETHING=$(shell ...) 来检测是否是 GNU make 正在运行,非 GNU 版本不会设置 SOMETHING。由于延迟评估变量,您无法轻松使用它正如预期的那样。这依赖于在使用 $() 扩展时静默处理带有空格的宏名称的实现(即将 $(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 处理每种情况。)

As noted, GNU make checks for GNUmakefile before makefile or Makefile, I've used a trivial fix such as you described, a default (decoy) Makefile that causes an error/warning:

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

The GNU make documentation recommends using the GNUmakefile name when the Makefile 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 the BSDmakefile which is used in preference to Makefile (thus preventing the system make from mangling my build). AFAICT the AIX or Solaris make do not have an alternate name you could use in this way.

One problem with a wrapper Makefile which tries to call GNU make 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 GNU make is running, non GNU versions will not set SOMETHING. 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:

GNUMAKE=$(shell echo GNUMAKE)

default: gnumake all

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

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 system make conspires against you and invokes GNU make ... You'd need some carefully checking of environment variables PATH, MAKE and possibly SHELL to handle every case.)

傲性难收 2024-09-19 08:31:06

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

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

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

但我可以建议一种可能有效的方法。也许这样的东西可以变得通用:

default:
  ./runGNUMake.pl

就是这样,这就是整个 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):

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

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:

default:
  ./runGNUMake.pl

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".

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文