如何从Makefile中使用shell内置函数?

时间:2013-07-09 11:56:42

标签: shell makefile

我只是偶然发现了这个问题。我试着写一个非常基本的Makefile目标:

core: myprogram
        ulimit -c 10000
        ./myprogram
        ulimit -c 0

我们的想法是将核心大小限制设置为正确的值,使程序崩溃,然后将核心大小限制重置为零。当我调用此规则时,收到以下错误消息:

$ make core
cc -Wall -Wextra -m32 -g  -o example example.c 
ulimit -c 100000
make: ulimit: Command not found
make: *** [core] Error 127

首先,我有点惊讶,但我认为问题来自ulimit是内置shell的事实。而且,令人惊讶的是(至少对我而言),这些内置函数无法从Makefile调用。

此外,ulimit既可以是内置函数(我的Debian就是这种情况)仅限二进制程序(/usr/bin/ulimit)。

所以,我的问题很简单,如何以一种优雅和可移植的方式解决这个问题,并从Makefile内部调用内置函数?

5 个答案:

答案 0 :(得分:13)

您收到此错误的原因是make(特别是GNU make)尝试执行许多优化。其中一个是如果命令出现是一个不需要shell的简单命令,那么make将直接通过fork / exec调用它而不运行shell。如果该命令仅作为内置shell存在,那么这将不起作用。您的命令行ulimit -c 10000是一个简单的命令,并且ulimit没有被定义为只有shell内置的make,所以make会尝试直接fork / exec ulimit。因此,解决您的直接问题的方法是简单地添加一个特殊于shell的字符(最明显的是;),这将暗示需要将此命令发送到shell。 / p>

但是,这对你不起作用。

与H2CO3上面的评论完全相反:考虑到它提供的功能,它怎么可能是[内置shell]?你要问自己的真正问题恰恰相反: how鉴于它提供的功能,它可能不是一个吗? ulimit的手册页明确指出: ulimit实用程序应设置或报告对shell写入的文件施加的文件大小写入限制及其子进程,进一步:由于ulimit会影响当前的shell执行环境,因此它始终作为常规内置shell提供。

您必须记住,UNIX中的进程几乎不可能修改其父进程的任何方面。它只能修改自身或它调用的任何子进程。这包括环境变量,工作目录,还包括ulimit设置。

那么,好,这对你的情况如何?您必须记住,make配方中的每个逻辑行都是在单独的shell 中调用的。所以对于像这样的命令:

core: myprogram
        ulimit -c 10000 ;
        ./myprogram
        ulimit -c 0 ;

(添加分号以强制使用shell)基本上调用的是:

core: myprogram
        /bin/sh -c 'ulimit -c 10000 ;'
        /bin/sh -c './myprogram'
        /bin/sh -c 'ulimit -c 0 ;'

如您所见,每个ulimit都在自己的shell中调用,因此它实际上没用。它将修改该shell的核心文件大小限制,然后shell退出并且更改丢失,然后在具有原始ulimit的新shell中调用您的程序,然后调用第三个shell并将core的ulimit设置为0 (也没用)。

您需要做的是将所有这些命令放在一个逻辑行上,如下所示:

core: myprogram
        ulimit -c 10000; ./myprogram

(你不需要设置限制,因为shell无论如何都会退出。)

作为旁注,这个是为什么make不太担心这些shell内置的原因。在需要使用像分号这样的特殊shell字符的上下文中,这样的内置基本上不可能用于任何效果。

答案 1 :(得分:3)

任何Makefile的默认shell都是sh。如果必须使用特定shell的内置函数,请在Makefile

中指定该shell
SHELL:=bash

请注意,这是糟糕的做法,因为您的Makefile应该在任何计算机上运行,​​而不仅仅是bash安装。

如果您想支持任何一种变体(外部与内置),您可以检查bash resp的可用性。 ulimit通过which设置一个包含要使用的命令的变量(ulimitbash -c "ulimit"),具体取决于该检查的结果。

编辑:MadScientist对ulimit的“当前仅限shell”方面绝对正确。为了文档的目的,我会完整地保留这个答案,但它对perror的具体问题没有帮助。

答案 2 :(得分:2)

你可以说:

core: myprogram
        $(shell /bin/bash -c "ulimit -c 10000")
        ./myprogram
        $(shell /bin/bash -c "ulimit -c 0")

答案 3 :(得分:0)

在官方GNU make文档(http://www.gnu.org/software/make/manual/make.html)第5.3.2章中,它说“用作shell的程序取自变量SHELL。如果你的makefile中没有设置这个变量,程序/ bin / sh用作shell。“ 您可以将SHELL设置为/ bin / bash。

答案 4 :(得分:0)

简短答案:在命令末尾添加分号(;)。这样,您将使用内置工具调用FULL Shell。

        ulimit -c 10000;

代替

        ulimit -c 10000