type t (* void *)

関数型言語や英語学習の事とか。

Makefile: Makefileデザイン一考

Makefileいろいろ

Emacs23は最低限文化的なEmacsだと思うインターネットの闇です。

問題

「今のビルド環境、絶対パスとかレガシーなスクリプトが多すぎて手に負えない。作りなおして」 と言われた。新人の私が。

問題設定

  • 管理しているソースから複数のプロダクトを作る
    ここでは便宜上それらをsofta, softb, softcと呼ぶ
    それらは全ての.cファイルを使うわけではなくsoftaでは使うけどsoftbでは使わない.cファイルが普通にファイルに並んでいる
  • さらにいろいろなアーキテクチャで動作させる
    便宜上mips, arm32で動かさなきゃいけないことにしよう
    それらも割とフリーダムにこのアーキでは使わないソースだ、とか#ifdefで切り分けとかがガンガン行われている
  • そのごっちゃになっているのを管理しているのは各プログラムフェーズごとに区切られたディレクトリに存在するlist.txtファイル
    例えば以下のようにディレクトリがあるとき、どのようにlist.txtが配置されているのか示す。

        include/
          front/
          middle/
          back/
        src/
          front/
            list.txt
            opt1.c
            opt2.c
            ...
          middle/
            list_mips.txt
            list_arm32.txt
            analysis.c
            fusion.c
            ...
          back/
            list_mips_softa.txt
            list_mips_softb.txt
            list_mips_softc.txt
            list_arm32_softa.txt
            list_arm32_softb.txt
            list_arm32_softc.txt
            ...
         include/
           front/
           middle/
           back/
    
    • list.txtファイルはアーキ・ソフトに関係ないところではこの名前がついている
    • それらごとに依存ファイルが違う場合にはそれぞれlistファイルが存在し、 その中に使うファイルが書かれている
  • 昔のレガシービルド環境ではそれらlist.txtファイルの配置やベタ書きされたこのファイルはこういうふうにコンパイルしなきゃダメ、 みたいな情報からMakefileを自動生成してビルドしているが、絶対パスモリモリで大変厳しいことになっている

私の試行

絶対パスを含まないクリーンなMakefileを書くぞと決意
考えられる問題は

  • アーキ・ソフトウエアごとに切り分けされた膨大な依存関係をどのように記述するのか
  • ヘッダーファイルもごちゃごちゃで、ファイルをまたぐと同じ名前のヘッダーファイルが存在するため どのように-Iの指定をしていくのか
  • どうやって対象にしたいアーキやソフトウエアを選択するのか

autoconfのようなツールの知見もないし社内システムだからそんなに綺麗にしなくてもいいし
プロジェクトは割とひぃひぃ言っているのであまり労力もかけなくない

考えたアプローチを下に示してみる

  • トップレベルはMakefile
    ここから各ソフトウエア(softa, softb, softc)をビルドするMakefile_ARCH_SOFTを呼び出す
  • アーキはmakeコマンドを実行するときに受け取ることにする
    使うときはmake ARCH=mipsのようにしてもらう
  • 依存関係の記述はめんどくさいので今までのlist.txtファイルを流用する(後述)
  • 登場人物は

  • Makefileは全部の入り口
    ここでは受け取ったアーキテクチャごとに分岐するということだけを行う

inclde Makefile.shared

include setopt

all: fofta softb softc

softa: 
ifeq($(TARGET_ARCH), mips)
    $(MAKE) -f Makefile_mips_softa
else
ifeq($(TARGET_ARCH), arm32)
    $(MAKE) -f Makefile_arm32_softb
end
end

softb:
...(同様)...

softc:
...(同様)...

clean:
...
  • Makefile.sharedは設定が書かれた全部で共有すべきもの
export TARGET_ARCH=
export HOST_ARCH=
export SOFT=

CC=cc
DEBUG=
LIB=-lgc -lm -ldl
DEF=-D USE_HUSHIGINA_MACRO -D ENABLE_FAST -D HOGEHOGE_DEBUG

# なぜかsrc/の中のファイルでもヘッダーが存在するものがあるので殴りたい
INCLUDE=-I include/front -I include/middle -I include/back -I src/back
CFLAG=$(LIB) $(INCLUDE)

.c.o:
  $(CC) $(CFLAG) $(DEBUG) -c -o $@ @< 
  • Makefile_mips_softaを代表して示してみる
SOFT=softa

ifdef TARGET_ARCH
include setopt
end

INCLUDE+= -I include/aa -I include/bb
DEF+= -D XXX_SOFTA -D ...

include Makefile.shared
include common_shared
include common_softa

ARCH_OBJS=aa.a bb.a cc.a ...

OBJS=$(COMMON_OBJS) $(ARCH_OBJS) $(SOFT_OBJS)

softa: $(OBJS)
    $(CC) -o $@ 

aa.a: $(shell bash selector.sh src/aa $(SOFT) $(TARGET_ARCH))
    $(AR) $@ rcs src/aa/*.o
...

このMakefileはたくさんのMakefile断片をインクルードしている - ビルドに必要な共通の設定が書かれたMakefile.shared - 全てのソフトウエアで共通の依存関係が書かれたcommon_shared - softaに特有の.aファイルの依存関係が書かれたcommon_softa - アーキテクチャ固有の依存関係はベタ書きしている
- setopt$(ARCH_TARGET)などがセットされているかチェックしなければはじく

またselector.shは重要な役割を果たす
DIRECTORYと$(TARGET_ARCH)$(SOFT)を受け取り適切なlist.txtファイルを選ぶシェルスクリプトである
例えば上のaa.a: $(shell bash selector.sh src/aa $(SOFT) $(ARCH))では ディレクトsrc/aaといまビルドしたいソフト名softa, アーキ名を受け取り list.txtがあればlist.txtの中身、list_mips.txtがあればその中身、list_softa.txtがあればその中身、 list_mips_softa.txtがあればその中身とまさに適切なlist.txtを選ぶセレクターの役割を果たす

これらによって作られた.aファイルを集めてきて実行形式を作る

辛さ

  • なんかMakefileの種類がどんどん増えてきたんですけど……
    同じことを二度書きたくないのでcommon_sharedcommon_softaといったように依存関係を分けたのだけど、 ファイルの数が増えていってイヤンだなぁと思ってきている
  • selector.shは最初は賢いように思ってたのだけど、なかなかつらい
    なんせ毎回実行するわけだからヘボいマシンだと実行自体に時間がかかってしまう
    また依存関係をmakeが解析するときにこれは実行されるので結構実行される順番に気を使わないといけない
    includeする順番によってはあれ、フラグまだ足してなかった!!!!みたいなことになる
  • .c.oのルールでヘッダーファイルを見に行くオプションを全部に胸痛にしたので、
    全部書いたので同じヘッダーファイルがあった場合にオプションの並び順で見に行く先がかわる!!!!!!!
    これは大変つらい、むしろ同じファイル名を政治的に変更しに行くことを考えたほうが良さそう
  • #ifdefとかでソースが切り分けしまくってるから違うアーキ・ソフトをコンパイルしようとすると
    全部ビルドしなおし。ビルド時間……

結論

いい方法あったら教えてください
よい転職先は、まぁもうちょっと経ったら教えてください……