link もっと前
   2019年 9月 17日 -
      2019年 9月 8日  
link もっと後

link 未来から過去へ表示(*)
link 過去から未来へ表示

日々

link permalink

今まで知らなかった make の挙動

シェルから make に渡す環境変数と make 変数の関係を知らなくて、かなりハマったのでメモしておきます。

まず、どういう関係か説明します。下記のような Makefile を 2つ用意します。

ディレクトリ構成
$ tree
.
|-- Makefile
`-- sub
    `-- Makefile
親: Makefile

VAR_A = aaa
VAR_B = bbb

all:
	@echo "In parent"
	@echo "VAR_A: '$(VAR_A)'"
	@echo "VAR_B: '$(VAR_B)'"
	@echo "VAR_C: '$(VAR_C)'"
	make -C sub
子: sub/Makefile

all:
	@echo "In sub"
	@echo "VAR_A: '$(VAR_A)'"
	@echo "VAR_B: '$(VAR_B)'"
	@echo "VAR_C: '$(VAR_C)'"

親 Makefile は変数 VAR_A, VAR_B を書き換え、子 sub/Makefile を再帰的に呼び出します。各 Makefile では変数の値を表示しています。

では、トップディレクトリにて make を実行してみましょう。

通常の実行結果
$ make
In parent
VAR_A: 'aaa'    ★VAR_A は設定した値になっている★
VAR_B: 'bbb'    ★VAR_B は設定した値になっている★
VAR_C: ''       ★VAR_C は特に書き換えていないので空★
make -C sub
make[1]: Entering directory '/home/katsuhiro/share/falcon/projects/c/makefile_env_var/sub'
In sub
VAR_A: ''    ★VAR_A は渡されない★
VAR_B: ''    ★VAR_B は渡されない★
VAR_C: ''    ★VAR_C は渡されない★
make[1]: Leaving directory '/home/katsuhiro/share/falcon/projects/c/makefile_env_var/sub'

ご覧の通り、親の Makefile で値を設定した VAR_A や VAR_B といった変数は、子の sub/Makefile に「引き継がれません」

make 変数の渡し方

外部から make に変数を渡すには、下記の 2つの方法があります。

  • 環境変数として渡す方法。例: VAR_A=A make
  • make に渡す方法。例: make VAR_A=A

私は今まで、この 2つの渡し方に何も差はないと思っていたのですが、実は全く動きが違いました。

環境変数の場合

下記のように VAR_A, VAR_C を環境変数として与えると、子 Makefile 側の結果がかなり変わります。

VAR_A, VAR_C を環境変数として渡したときの実行結果
$ VAR_A=A VAR_C=C make
In parent
VAR_A: 'aaa'    ★VAR_A は親が設定した値になる★
VAR_B: 'bbb'
VAR_C: 'C'      ★VAR_C は特に書き換えていないので、渡された値のまま★
make -C sub
make[1]: Entering directory '/home/katsuhiro/share/falcon/projects/c/makefile_env_var/sub'
In sub
VAR_A: 'aaa'    ★VAR_A が渡される、A ではなく親が設定した値 aaa になっている★
VAR_B: ''
VAR_C: 'C'      ★VAR_C が渡される、値は変わらず★
make[1]: Leaving directory '/home/katsuhiro/share/falcon/projects/c/makefile_env_var/sub'

何も渡さなかった場合の実行結果と異なり、子の sub/Makefile にも VAR_A, VAR_C が渡されます。もし、親 Makefile が変数の値を書き換えた場合は、書き換えた値が子 Makefile に渡されます。

この動作は知りませんでした。特に子プロセスへの変数の渡し方が変わる点が衝撃的です。

make に渡す場合

下記のように VAR_A, VAR_C を make に渡すと、環境変数として渡す場合とは違う結果になります。

VAR_A, VAR_C を make の変数として渡したときの実行結果
$ make VAR_A=A VAR_C=C
In parent
VAR_A: 'A'      ★VAR_A は親が設定した値にならない★
VAR_B: 'bbb'
VAR_C: 'C'
make -C sub
make[1]: Entering directory '/home/katsuhiro/share/falcon/projects/c/makefile_env_var/sub'
In sub
VAR_A: 'A'      ★VAR_A が渡される、VAR_A は親が設定した値にならない★
VAR_B: ''
VAR_C: 'C'      ★VAR_C が渡される、値は変わらず★
make[1]: Leaving directory '/home/katsuhiro/share/falcon/projects/c/makefile_env_var/sub'

環境変数で渡した場合と同様に、子 Makefile に変数の内容が渡されます。その点は同じです。しかし、親 Makefile で行っている aaa という値の代入が無効化され、渡される値が全く違います。

この動作も知りませんでした……。私は Makefile や make とは長い付き合いですし、動きも何となくわかっていた気分になっていましたが、勘違いだったようです。make は難しすぎます。

ハマったポイント

この動きによって、何が困ったかを紹介しておきます。同じ状況に陥る人は、まずもっていないと思いますけど、ご参考まで。

現象としては「make でビルドすると成功するが、debuild(Debian のパッケージング作成スクリプト)経由でビルドすると失敗する」です。この現象から原因が予想できた人、あなたは凄い(少なくとも私より凄い)です!この先は読む必要はございません。

下記のような感じの、ちょっと変わった Makefile を使っているソフトウェアをビルドしていました。

  • 親 Makefile から、子の ./configure を呼ぶ
  • 親 Makefile は CFLAGS や LDFLAGS を固定値に設定している(固有のライブラリをリンクするため)

もう一つ大事な点は、親 Makefile が使っている LDFLAGS を、子 ./configure に渡すと「そんなライブラリはないというエラー」になってしまう欠点があることです。

じゃあビルドエラーが起きるのか?というとそうではなく、先ほどご紹介した通り、何も指定せずに make を起動すれば、親 Makefile の変数は、子 ./configure に渡りませんから、make だけ実行すればエラーを起こさずビルドできるのです。

debuild と環境変数の罠

一見、正常にビルドできて問題ないように見えますが、このソフトウェアを *.deb にパッケージングしようとするとハマります。Debian のパッケージ作成スクリプト debuild は下記のような動作をするからです。

  • debuild はエラーチェック、セキュリティ強化のため CFLAGS, LDFLAGS にいくつかオプションを指定する
  • CFLAGS, LDFLAGS は「環境変数」で make に渡される

そろそろ何が起きるか予想が付くでしょう。そう、こうなるんです。

  • debuild が、親 Makefile に環境変数で CFLAGS, LDFLAGS を渡す
  • 親 Makefile が CFLAGS, LDFLAGS を書き換える
  • 親 Makefile が、子 ./configure に書き換わった後の CFLAGS, LDFLAGS を渡す

この華麗なコンボが決まって、make とするとビルドが成功し、debuild 経由だとビルドが失敗する、謎のビルド環境ができあがります。

感想

こんなバグ、初見で分かる、はずもなし。

Makefile は大抵の人には難しすぎます。Makefile を手で書いているといつか地獄に落ちますよ、CMake とか automake を使いましょう。便利だよ!

[編集者: すずき]
[更新: 2019年 9月 19日 02:27]
link 編集する

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



link permalink

台風 15号

超強力な台風 15号(Faxai)が来るということで、家でじっとしていました。

我が家は北と東に窓がありまして、北側の窓にガンガン風と雨が吹き付けていました。あまりの風圧にサッシが耐えらず、雨が窓サッシの隙間から霧吹きのように吹き出していました。途中で気づいてテープや紙で抑えたので、畳が水浸しになる被害は防げました。

真夜中に壁に飛来物が当たり、ものすごい音がしていました。窓の真横に当たったらしく、窓にはギリギリ当たりませんでした。窓に当たったら、窓が粉砕されていたと思います。本当に幸運でした。

後は何だろ、若干停電した程度でしょうか。特に被害はありませんでした。災害への備えは日頃からやっておいて損はないですね。

家財

台風が過ぎた後に車を見に行ってみましたが、特に飛来物が当たった形跡もなく、何ともなかったです。良かった良かった。

[編集者: すずき]
[更新: 2019年 10月 13日 22:03]
link 編集する

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



link もっと前
   2019年 9月 17日 -
      2019年 9月 8日  
link もっと後

管理用メニュー

link 記事を新規作成

合計:  counter total
本日:  counter today

link About www.katsuster.net
RDF ファイル RSS 1.0
QR コード QR コード

最終更新: 10/13 23:20

カレンダー

<2019>
<<<09>>>
1234567
891011121314
15161718192021
22232425262728
2930-----

最近のコメント 5件

  • link 19年09月01日
    すずき 「私も正直びっくりです。間違って違う製品を...」
    (更新:09/04 23:39)
  • link 19年09月01日
    hdk 「車向けの製品の中でも、車載コンピューター...」
    (更新:09/02 23:20)
  • link 19年07月18日
    hdk 「あっ、AAMはマニュアルのオペレーション...」
    (更新:07/25 00:02)
  • link 19年07月18日
    すずき 「AAM(ASCII Adjust AX ...」
    (更新:07/24 22:22)
  • link 19年07月18日
    hdk 「加算減算は符号のありなしどちらも命令が同...」
    (更新:07/24 07:25)

最近の記事 3件

link もっとみる
  • link 19年10月06日
    すずき 「[RISC-V のバイナリダンプを逆アセンブルする] 相変わらず空...」
    (更新:10/13 23:20)
  • link 19年10月12日
    すずき 「[台風 19号] あの台風 15号(Faxai)(2019年 9月...」
    (更新:10/13 22:04)
  • link 19年09月08日
    すずき 「[台風 15号] 超強力な台風 15号(Faxai)が来るというこ...」
    (更新:10/13 22:03)

こんてんつ

open/close wiki
open/close Java API

過去の日記

open/close 2002年
open/close 2003年
open/close 2004年
open/close 2005年
open/close 2006年
open/close 2007年
open/close 2008年
open/close 2009年
open/close 2010年
open/close 2011年
open/close 2012年
open/close 2013年
open/close 2014年
open/close 2015年
open/close 2016年
open/close 2017年
open/close 2018年
open/close 2019年
open/close 過去日記について

その他の情報

open/close アクセス統計
open/close サーバ一覧
open/close サイトの情報