15
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Makefileで外部プログラムの実行結果を変数に取り込む

Last updated at Posted at 2020-05-30

Makefileで外部のプログラムやコマンドを実行した結果を変数に取り込む方法を調べて結構苦労したのでメモとして残しておく。
結論としては\$(shell ), ` `とあと \$(eval )あたりを駆使する。

簡単な例

例としてdate +%M:%S:%Nで時刻を取得してそれを変数VALに取り込む例を考える。

例1
VAL := $(shell date +%M:%S:%N)
run :
    @echo $(VAL)
例2
VAL := `date +%M:%S:%N`
run :
    @echo $(VAL)
結果1
> make run
52:14:280298700
結果2
> make run
52:59:203304400

このように\$(shell )か` `のどちらかを使えば良いだけである。これだけだと大した話ではないのだが、状況が少し込み入って来るといろいろと面倒にな事がある。

変数の受け渡しと複数回の参照

まずMakefile内で設定した変数を外部プログラムに環境変数として渡したい場合を考える。ここでは渡したい変数としてMSGを設定する。環境変数として外部に渡す為にMSGの前にexportを付ける。またMakefileのrun内のechoでのVALの表示回数を3回に増やす。実行する外部プログラムは以下の様にやはり現在時刻の取得としてその後ろに\$MSGの値を付けたシェルスクリプトにする。

./now.sh
#!/bin/sh
TIME=`date +%M:%S:%N`
echo "$TIME : $MSG"
例3
export MSG := Hello!
VAL := $(shell ./now.sh)
run :
    @echo $(VAL)
    @echo $(VAL)
    @echo $(VAL)
例4
export MSG := Hello!
VAL := `./now.sh`
run :
    @echo $(VAL)
    @echo $(VAL)
    @echo $(VAL)

これらを実行するとどうなるか。。。

結果3
> make run
26:32:118294900 :
26:32:118294900 :
26:32:118294900 :
結果4
> make run
26:27:190915200 : Hello!
26:27:223885900 : Hello!
26:27:256983200 : Hello!

このようにまず、\$(shell )を使った結果3ではexportを使っているのに\$MSGが環境変数として./now.shに渡っていない。` `を使用した結果4では\$MSGはきちんと渡っているが、echo \$VALでVALの値を表示する度に./now.shが実行されて違う値となってしまう。
まとめるとそれぞれ以下の欠点があると言える。

  • \$(shell)ではMakefile内でexportで設定した変数が渡らない。
  • ` `はコマンドそのものがマクロとして代入され参照される度にそのコマンドが実行されてしまう。

以下にそれぞれ解決策を提示する。

解決策

  • \$(shell)内で環境変数の設定をするshシェルコマンドを追加。
例3)解決策1【exportで環境変数を設定してから実行】
MSG := Hello!
VAL := $(shell export MSG=$(MSG); ./now.sh)
run :
    @echo $(VAL)
    @echo $(VAL)
    @echo $(VAL)
例3)解決策2【envで環境変数を指定して実行】
MSG := Hello!
VAL := $(shell env MSG=$(MSG) ./now.sh)
run :
    @echo $(VAL)
    @echo $(VAL)
    @echo $(VAL)
  • いったん結果をファイルにダンプしてからcatでその内容を表示する。
例4)解決策1【catコマンドのマクロを設定】
export MSG := Hello!
VAL := `cat dump.txt`
run :
    ./now.sh > dump.txt
    @echo $(VAL)
    @echo $(VAL)
    @echo $(VAL)
例4)解決策2【run内でcatコマンドのマクロを設定】
export MSG := Hello!
run :
    ./now.sh > dulmlp.txt
    $(eval VAL := `cat dump.txt`)
    @echo $(VAL)
    @echo $(VAL)
    @echo $(VAL)
例4)解決策3【$(shell)内のcatでファイルの内容を取得】
export MSG := Hello!
run :
    ./now.sh > dump.txt
    $(eval VAL := $(shell cat dump.txt))
    @echo $(VAL)
    @echo $(VAL)
    @echo $(VAL)
結果3
> make run
42:37:754889100 : Hello!
42:37:754889100 : Hello!
42:37:754889100 : Hello!
結果4
> make run
42:42:755746800 : Hello!
42:42:755746800 : Hello!
42:42:755746800 : Hello!

どれもきちんとMSGも表示されかつVALの値も同じとなった。

例4の解決策は値のファイルへのダンプおよびVALへの値の取得を別ルールとして分離すると分かりやすくて良いかもしれない。

例4)解決策【VAL取得の分離】
export MSG := Hello!
#VAL := `cat dump.txt`
run : get_VAL
    @echo $(VAL)
    @echo $(VAL)
    @echo $(VAL)
get_VAL :
    ./now.sh > dump.txt
    $(eval VAL := $(shell cat dump.txt))
#   $(eval VAL := `cat dump.txt`)

又、以下も可能であった。

例4)解決策【最初にファイルダンプ】
export MSG := Hello!
DUMP := `./now.sh > dump.txt`
VAL := $(shell cat dump.txt)
run : 
    @echo $(VAL)
    @echo $(VAL)
    @echo $(VAL)

尚、ファイルにダンプせずできないものかと以下試してみたがうまくは行かなかった。

例4)失敗策【ファイルダンプせず値の取得】
export MSG := Hello!
NOW := `./now.sh`
VAL := $(shell echo $(NOW))
run :
    @echo $(VAL)
    @echo $(VAL)
    @echo $(VAL)
結果4
> make run
04:25:965031000 :
04:25:965031000 :
04:25:965031000 :

実行は一回だが$(shell)内での実行とみなされやはりMSGが渡っていない。

\$(shell export)を使ったやり方の方が優れている気もするがそうとも言えない。渡す変数が大量になってくると書くのが大変になって入れ忘れなどのミスを誘発しやすくなる。その場合は` `を使った方法にした方が良いだろう。` `の方はどうしてもファイルダンプしなくてはならない。それが難しい場合は欠点となる。
いずれにせよ、上記のような込み入った状況以外の単純な状況ではどちらでも大差はない。

###まとめ

変数への代入方法   変数の受け渡し
$(shell) コマンドの実行結果の値を代入。 自動では環境変数として渡されない。シェルコマンドで明示的に記述する。
` ` コマンド自体をマクロとして代入。     Makefileのexportで環境変数として自動的に渡される。
$(eval) 実行部分で変数を動的に設定。

###参考記事
makeでシェルの結果を利用する
Qiita : GNU make変数の伝播についてまとめ
Qiita : Makefileで実行時に変数代入したい
Qiita : makefile 動的に変数に代入 共通して使う
Qiita : シェル変数と環境変数の違いをコマンドラインで確認する
Qiita : 今さら聞けない!環境変数とシェル変数の違いと定義方法
Qiita : Linux 環境変数有効範囲
【 env 】コマンド――環境変数を指定してコマンドを実行する
【 export 】コマンド――環境変数やシェル変数を設定する

15
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?