プログラムがMakefileから呼び出し可能かどうかを確認するにはどうすればよいですか?
(つまり、プログラムはパスに存在するか、呼び出し可能でなければなりません。)
たとえば、インストールされているコンパイラを確認するために使用できます。
たとえば、この質問のようなものですが、基礎となるシェルがPOSIX互換であるとは想定していません。
automake
さまざまな前提条件をチェックして適切なものを書き出すスクリプトを用意することMakefile
です。
プログラムがMakefileから呼び出し可能かどうかを確認するにはどうすればよいですか?
(つまり、プログラムはパスに存在するか、呼び出し可能でなければなりません。)
たとえば、インストールされているコンパイラを確認するために使用できます。
たとえば、この質問のようなものですが、基礎となるシェルがPOSIX互換であるとは想定していません。
automake
さまざまな前提条件をチェックして適切なものを書き出すスクリプトを用意することMakefile
です。
回答:
Makefileを別のターゲットOSで実行できるようにする必要があり、必要な実行可能ファイルが存在しない場合は、失敗するPATH
前に長時間実行するのではなく、ビルドを早期に失敗させたい場合があります。
engineerchuanが提供する優れたソリューションは、ターゲットを作成する必要があります。ただし、テストする実行可能ファイルが多く、Makefileに多数の独立したターゲットがあり、それぞれにテストが必要な場合、各ターゲットには依存関係としてテストターゲットが必要です。これにより、一度に複数のターゲットを作成するときに、余分なタイピングと処理時間が大幅に増加します。
0xfが提供するソリューションは、ターゲットを作成せずに実行可能ファイルをテストできます。これにより、個別または一緒にビルドできるターゲットが複数ある場合に、入力と実行にかかる時間を大幅に節約できます。
後者の解決策に対する私の改善は、新しい変数を定義するのではなく、GNU Make ディレクティブで直接、各実行可能ファイルにオプションがあることに依存するのではなく、which
実行可能ファイル(where
Windows)を使用して、GNU Makeを使用することです。必要な実行可能ファイルがにない場合にビルドを停止する関数。たとえば、実行可能ファイルをテストするには:--version
ifeq
error
${PATH}
lzop
ifeq (, $(shell which lzop))
$(error "No lzop in $(PATH), consider doing apt-get install lzop")
endif
チェックする実行可能ファイルが複数ある場合foreach
は、which
実行可能ファイルで関数を使用することができます。
EXECUTABLES = ls dd dudu lxop
K := $(foreach exec,$(EXECUTABLES),\
$(if $(shell which $(exec)),some string,$(error "No $(exec) in PATH")))
:=
RHS式の即時評価を強制するために必要な代入演算子の使用に注意してください。Makefileがを変更する場合、PATH
上記の最後の行の代わりに次のものが必要になります。
$(if $(shell PATH=$(PATH) which $(exec)),some string,$(error "No $(exec) in PATH")))
これにより、次のような出力が得られます。
ads$ make
Makefile:5: *** "No dudu in PATH. Stop.
where my_exe 2>NUL
代わりにを使用しますwhich
。
私は@kenorbと@ 0xFのソリューションを混合してこれを取得しました:
DOT := $(shell command -v dot 2> /dev/null)
all:
ifndef DOT
$(error "dot is not available please install graphviz")
endif
dot -Tpdf -o pres.pdf pres.dot
"command -v"は、実行可能ファイルが利用できない場合は何も出力しないので美しく機能し、変数DOTが定義されることはなく、コードでいつでも確認できます。この例ではエラーをスローしていますが、必要に応じてもっと便利なことを行うことができます。
変数が使用可能な場合、「command -v」は、DOT変数を定義して、コマンドパスを出力する安価な操作を実行します。
command
組み込みのbash which
です。移植性を高めるために、使用を検討してください。
command -v
POSIXのようなシェル環境が必要です。これは、cygwinまたは同様のエミュレーションを使用しないWindowsでは機能しません。
command
、多くの場合、仕事があるしないため、その不在のではないが、理由の独特の最適化 GNUのメイクがないこと:コマンドが「シンプル十分」である場合には、シェルバイパスします。これは残念ながら、コマンドを少し変更しないと組み込みが機能しない場合があることを意味します。
shell
関数を使用して、標準出力に何かを出力するようにプログラムを呼び出します。たとえば、--version
ます。
GNU Makeは、に渡されたコマンドの終了ステータスを無視しshell
ます。「コマンドが見つかりません」という潜在的なメッセージを回避するには、標準エラーを/dev/null
ます。
次に、使用して結果を確認することがifdef
、ifndef
、$(if)
など
YOUR_PROGRAM_VERSION := $(shell your_program --version 2>/dev/null)
all:
ifdef YOUR_PROGRAM_VERSION
@echo "Found version $(YOUR_PROGRAM_VERSION)"
else
@echo Not found
endif
おまけとして、出力(プログラムバージョンなど)は、Makefileの他の部分で役立つ場合があります。
*** missing separator. Stop.
後、すべての行にタブを追加するall:
と、エラーが発生しますmake: ifdef: Command not found
ifdef
、else
、endif
ライン。@echo
行がタブで始まることを確認してください。
ifdef
空でない変数値をチェックすることが記載されています。変数が空でない場合、それは何に評価されますか?
ifdef
or ifndef
(受け入れられた回答のように)を使用すると、評価される変数が:=
遅延セット(=
)ではなくすぐにセット()される場合にのみ機能します。ただし、即時に設定された変数を使用する場合の欠点は、宣言時に評価されるのに対し、遅延して設定された変数は呼び出されたときに評価されることです。これは:=
、Makeが変数を使用しないルールのみを実行している場合でも、変数に対してコマンドを実行することを意味します。これを回避するには、=
withifneq ($(MY_PROG),)
ここで既存のソリューションのいくつかをクリーンアップしました...
REQUIRED_BINS := composer npm node php npm-shrinkwrap
$(foreach bin,$(REQUIRED_BINS),\
$(if $(shell command -v $(bin) 2> /dev/null),$(info Found `$(bin)`),$(error Please install `$(bin)`)))
の $(info ...)
あなたはこれが静かになりたい場合は、除外することができます。
これはすぐに失敗します。ターゲットは必要ありません。
私のソリューションには、必要なコマンドがすべて存在する場合にフラグファイルを配置する小さなヘルパースクリプト1が含まれています。これには、必要なコマンドのチェックが1回だけ行われ、すべてのmake
呼び出しで行われないという利点があります。
check_cmds.sh
#!/bin/bash
NEEDED_COMMANDS="jlex byaccj ant javac"
for cmd in ${NEEDED_COMMANDS} ; do
if ! command -v ${cmd} &> /dev/null ; then
echo Please install ${cmd}!
exit 1
fi
done
touch .cmd_ok
Makefile
.cmd_ok:
./check_cmds.sh
build: .cmd_ok target1 target2
1command -v
テクニックの詳細については、こちらをご覧ください。
if
ステートメントで「予期しないファイルの終わり」が表示されます。
私にとって、上記のすべての回答はLinuxに基づいており、Windowsでは機能しません。私は新しいので、私のアプローチは理想的ではないかもしれません。しかし、LinuxとWindowsの両方で動作する完全な例は次のとおりです。
# detect what shell is used
ifeq ($(findstring cmd.exe,$(SHELL)),cmd.exe)
$(info "shell Windows cmd.exe")
DEVNUL := NUL
WHICH := where
else
$(info "shell Bash")
DEVNUL := /dev/null
WHICH := which
endif
# detect platform independently if gcc is installed
ifeq ($(shell ${WHICH} gcc 2>${DEVNUL}),)
$(error "gcc is not in your system PATH")
else
$(info "gcc found")
endif
オプションで、使用できるツールをさらに検出する必要がある場合:
EXECUTABLES = ls dd
K := $(foreach myTestCommand,$(EXECUTABLES),\
$(if $(shell ${WHICH} $(myTestCommand) 2>${DEVNUL} ),\
$(myTestCommand) found,\
$(error "No $(myTestCommand) in PATH)))
$(info ${K})
私はrequire
他のすべての前に実行するターゲットを個人的に定義しています。このターゲットは、すべての要件のバージョンコマンドを一度に1つずつ実行し、コマンドが無効な場合は適切なエラーメッセージを出力します。
all: require validate test etc
require:
@echo "Checking the programs required for the build are installed..."
@shellcheck --version >/dev/null 2>&1 || (echo "ERROR: shellcheck is required."; exit 1)
@derplerp --version >/dev/null 2>&1 || (echo "ERROR: derplerp is required."; exit 1)
# And the rest of your makefile below.
以下のスクリプトの出力は
Checking the programs required for the build are installed...
ERROR: derplerp is required.
makefile:X: recipe for target 'prerequisites' failed
make: *** [prerequisites] Error 1
別のmakefileターゲットで特別な小さなプログラムをコンパイルすることで解決します。その唯一の目的は、探していた実行時のものをチェックすることです。
次に、このプログラムをさらに別のmakefileターゲットで呼び出しました。
私が正しく思い出せば、それはこのようなものでした:
real: checker real.c
cc -o real real.c `./checker`
checker: checker.c
cc -o checker checker.c
のSTDERR
出力をチェックするソリューション--version
は、バージョンをのSTDOUT
代わりに出力するプログラムでは機能しませんSTDERR
。STDERR
またはへの出力を確認する代わりにSTDOUT
、プログラムの戻りコードを確認してください。プログラムが存在しない場合、その終了コードは常にゼロ以外になります。
#!/usr/bin/make -f
# /programming/7123241/makefile-as-an-executable-script-with-shebang
ECHOCMD:=/bin/echo -e
SHELL := /bin/bash
RESULT := $(shell python --version >/dev/null 2>&1 || (echo "Your command failed with $$?"))
ifeq (,${RESULT})
EXISTS := true
else
EXISTS := false
endif
all:
echo EXISTS: ${EXISTS}
echo RESULT: ${RESULT}