9

私はちょうどこの問題に出くわしました。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が、シェルがビルトインであることに問題があると思います。そして、驚くべきことに (少なくとも私にとっては)、これらの組み込み関数は から呼び出すことはできませんMakefile

さらに、ulimit組み込み関数のみ(私のDebianの場合)またはバイナリプログラムのみ(/usr/bin/ulimit)の両方にすることができます。

だから、私の質問は簡単です、可能であればエレガントで移植可能な方法でこの問題を回避し、Makefile の内部から組み込み関数を呼び出す方法は?

4

5 に答える 5

21

このエラーが発生する理由は、make (特に GNU make) が多くの最適化を実行しようとするためです。それらの 1 つは、コマンドがシェルを必要としない単純なコマンドのように見える場合、make は fork/exec を介して直接コマンドを呼び出し、シェルを実行しないことです。コマンドがシェルの組み込みとしてのみ存在する場合、これは機能しません。コマンドラインulimit -c 10000は単純なコマンドであり、ulimit は make が認識しているシェル組み込みだけとして定義されていないため、make はulimit直接 fork/exec を試みます。したがって、差し迫った問題を回避する方法は、シェルに特別な文字を追加するだけです (最も明白なものは です;)。これにより、このコマンドをシェルに送信する必要があることが示唆されます。

ただし、これはうまくいきません。

上記の H2CO3 のコメントとは正反対です:それが提供する機能を考えると、[シェルの組み込み] である可能性はありますか? あなたが自問しなければならない本当の質問は反対です:それが提供する機能を考えると、どうしてそれがそうではないでしょうか? ulimit のマニュアル ページには次のように明確に記載されていますシェルレギュラービルトイン。

UNIX のプロセスがその親プロセスのどの側面も変更することは事実上不可能であることを覚えておく必要があります。それ自体、または呼び出す子プロセスのみを変更できます。これには、環境変数、作業ディレクトリが含まれ、ulimit 設定も含まれます。

では、これはあなたの状況にどのように当てはまりますか? make レシピの各論理行は個別のシェルで呼び出されることを覚えておく必要があります。したがって、次のようなコマンドの場合:

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

(セミコロンを追加してシェルを強制します) make が基本的に呼び出すのは次のとおりです。

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

ご覧のとおり、各 ulimit は独自のシェルで呼び出されるため、事実上役に立ちません。そのシェルのコアファイルサイズ制限を変更し、シェルが終了して変更が失われ、プログラムが元の ulimit を使用して新しいシェルで呼び出され、次に 3 番目のシェルが呼び出され、コアの ulimit が 0 に設定されます。 (これも駄目)。

次のように、これらすべてのコマンドを単一の論理行に配置する必要があります。

core: myprogram
        ulimit -c 10000; ./myprogram

(シェルはとにかく終了するので、制限を元に戻す必要はありません)。

補足として、これが make がこれらのシェル組み込み関数についてあまり気にしない理由です。このようなビルトインは、セミコロンなどの特殊なシェル文字を使用する必要がないコンテキストでは、基本的に使用できません。

于 2013-07-09T14:00:42.173 に答える
3

任意のデフォルト シェルMakefilesh. 特定のシェルのビルトインを使用する必要がある場合は、そのシェルを次のように指定しますMakefile

SHELL:=bash

インストール済みのマシンだけでなく、任意のマシンで動作する必要があるため、これは悪い習慣であることに注意してください。Makefilebash

いずれかのバリアント (外部対組み込み) をサポートする場合は、bashresp の可用性を確認できます。ulimit経由で、そのチェックの結果に応じて使用するコマンド ( vs. )whichを含む変数を設定します。ulimitbash -c "ulimit"

編集: MadScientist の「現在のシェルのみ」の側面については完全に正しいですulimit。ドキュメントの目的でこの回答をそのままにしておきますが、perror の特定の問題には役立ちません。

于 2013-07-09T12:05:18.617 に答える
2

あなたは言うことができます:

core: myprogram
        $(shell /bin/bash -c "ulimit -c 10000")
        ./myprogram
        $(shell /bin/bash -c "ulimit -c 0")
于 2013-07-09T12:08:10.527 に答える
0

公式の GNU make ドキュメント ( http://www.gnu.org/software/make/manual/make.html ) の 5.3.2 章では、「シェルとして使用されるプログラムは、変数 SHELL から取得されます。変数が makefile に設定されていない場合、プログラム /bin/sh がシェルとして使用されます。" SHELL を /bin/bash に設定できます。

于 2015-01-05T13:47:19.373 に答える