make makes many problems

このエントリーをはてなブックマークに追加
235デフォルトの名無しさん
たくさんサブディレクトリがあるとしてのお話です。

DIR_LIST:=たくさんサブディレクトリ
ARC_LIST:=$(addsuffix /lib.a,$(DIR_LIST))

さて、このARC_LISTを、それぞれのディレクトリ内のすべての.oファイルから作るとして、
はじめに思いついたのが、

$(ARC_LIST) : %/lib.c : $(wildcard %/*.o)

というやつだったのですが、このwildcardの中の%がどうやら展開されないようです。

foo/lib.c : $(wildcard foo/*.o)

こうすれば一応依存関係は作れるんですが、DIR_LISTはmakeが起動されるまでわかりません。

なんか解決法はないですか?
236デフォルトの名無しさん:03/02/08 01:49
>>235

ARC_RULE:=$(DIR_LIST:%=.%.arc_rule)
.%.arc_rule:
@echo '$*/lib.a: $$(wildcard $*/*.o)' > $@
@echo ' $$(AR) $$(ARFLAGS) $$@ $$?' >> $@
clean::
rm -f $(ARC_RULE)
include $(ARC_RULE)
237デフォルトの名無しさん:03/02/08 01:57
>>235
まちがいがあったので修正版。

ARC_RULE:=$(DIR_LIST:%=.%.arc_rule)
.%.arc_rule:
    @echo '$*/lib.a: $$(wildcard $*/*.o)' > $@
    @echo '    $$(AR) $$(ARFLAGS) $$@ $$?' >> $@
clean::
    rm -f $(ARC_RULE)
ifneq ($(MAKECMDGOALS),clean)
include $(ARC_RULE)
endif
238235:03/02/08 02:14
>>236
あーいっこづつ別のファイルに出せばいいんですね。
そういうやつを一個のファイルに出してみて、「いける?」とか思って、
「あーでもこのファイル更新するタイミングがわからん」とか思ってあきらめてました。
いけそうですね。まだ試せないけど。ありがとーデス。
239236:03/02/08 18:43
>>235
期待通りの動作になるかもしれませんが、wildcardで
全部アーカイブにするのは作り方としてよくないとおもいます。
(ソースコードを生成するためのプログラムのオブジェクトまで
拾ってしまう可能性がある。)
lib.aにするところまでサブディレクトリのMakefileで記述したほうが
いいとおもいます。

>>239
> (ソースコードを生成するためのプログラムのオブジェクトまで
> 拾ってしまう可能性がある。)
それはまた別のディレクトリにすべきなんじゃないの?

> lib.aにするところまでサブディレクトリのMakefileで記述したほうが
> いいとおもいます。
ともあれこれには同意。
241235:03/02/08 19:30
> lib.aにするところまでサブディレクトリのMakefileで記述

そうした場合には、ディレクトリの数だけ無条件でmakeを起動してしまうわけですよね。
実は、なんとかそれを避けれないかということで、いろいろやって>>235のようになったのですよ。
242236:03/02/09 00:44
>そうした場合には、ディレクトリの数だけ無条件でmakeを起動してしまうわけですよね。
>実は、なんとかそれを避けれないかということで、いろいろやって>>235のようになったのですよ。
ライブラリの元になるオブジェクトはいつ作るのでしょうか?
wildcardでマッチさせようとしているので、makeを起動する前にすでに
オブジェクトができているはずです。だとしたけ結局makeを
複数回起動しているのでは?

243235:03/02/09 00:56
>>242
あ、すんません、実際にwildcardをかけるのは.cとかなんですよ。
foo/lib.c : $(patsubst %.c,%.o,$(wildcard foo/*.o))
ってな感じです。wildcardが適用されない問題に絞るために端折ってました。
244236:03/02/09 01:10
235で$(wildcard foo/*.o)の部分は$(wildcard foo/*.c)でしょうね。
237の一部差し替え。

.%.arc_rule:
    @echo '$*_SRC:=$$(wildcard $*/*.c)' > $@
    @echo '$*_OBJ:=$$($*_SRC:%.c=%.o)' >> $@
    @echo '$*/lib.a: $$(*_OBJ)' >> $@
    @echo '    $$(AR) $$(ARFLAGS) $$@ $$?' >> $@
245236:03/02/09 01:18
しまった。また間違いがありました。

.%.arc_rule:
    @echo '$*_SRC:=$$(wildcard $*/*.c)' > $@
    @echo '$*_OBJ:=$$($*_SRC:%.c=%.o)' >> $@
    @echo '$*/lib.a: $$($*_OBJ)' >> $@
    @echo '    $$(AR) $$(ARFLAGS) $$@ $$?' >> $@
    @echo 'clean::' >> $@
    @echo '    rm -f $$($*_OBJ)' >> $@

246235:03/02/09 01:20
>>244
どうも。
仕事キッチリなお方ですな。
>>236 質問!
> ARC_RULE:=$(DIR_LIST:%=.%.arc_rule)
っていったい何をやっているの?
248235:03/02/11 00:36
上手くいきましたよ。

さて、後はソースファイルが削除されたときの・・・。

>>247
ARC_RULE:=$(patsubst %,.%.arc_rule,$(DIR_LIST))
↑の、ちょっと短く書ける書式。
249247:03/02/11 11:58
>>248
あ、そっか。ふだんはこの書き方を使わないから悩んじゃったよ。ありがと。
>>248
こんなんでどうよ。

.%.arc_rule:
    @echo '$*_SRC:=$(wildcard $*/*.c)' > $@
    @echo '$*_OBJ:=$$($*_SRC:.c=.o)' >> $@
    @echo '$*/lib.a: $$($*_OBJ)' >> $@
    @echo '    $$(AR) $$(ARFLAGS) $$@ $$?' >> $@
    @echo 'ifneq($*_SRC,$$(wildcard $*/*.c))' >> $@
    @echo '$@: .force' >> $@
    @echo 'endif' >> $@
    @echo 'clean::' >> $@
    @echo '    rm -f $$($*_OBJ)' >> $@

.PHONY: .force
251235:03/02/11 17:10
>>250
> ifneq($*_SRC,$(wildcard $*/*.c))
ぱっと見、これが常に偽になりそうです・・・。
> $@ : .force
これは、$*/lib.a : .force ですかね。

ちょっと修正して、こんな感じになるかなぁ?(↓見やすくするための擬似表記です)

$*_SRC:=$(wildcard $*/*.c)
$*_OBJ:=$($*_SRC:.c=.o)
$*/lib.a : $($*_OBJ)
ifneq($*_OBJ,$(wildcard $*/*.o))
$*/lib.a : .force
endif
252235:03/02/11 18:16
だめだ、対応するソースの無くなった.oを消さなきゃ。
253デフォルトの名無しさん:03/02/12 00:38
makeのかわりにjam使ってる人いますか?
↓jam
http://www.perforce.com/jam/jam.html
>>251
> > ifneq($*_SRC,$(wildcard $*/*.c))
> ぱっと見、これが常に偽になりそうです・・・。
なんで? $*_SRCと右の$(wildcard $*/*.c)はワイルドカードが展開されるタイ
ミングが違うはずだが。

> > $@ : .force
> これは、$*/lib.a : .force ですかね。
ちがう。ソースが追加/削除されたら.arc_ruleを書き換えたいんだろ?
255235:03/02/13 00:57
>>254
ごめんなさい。完全に勘違いしてました。
試させてもらいました。

ソースを削除したとき、.arc_ruleは更新されますが、
lib.aの中に削除されたソースから生成した.oが含まれたままになってしまい、
リンク時に有効な.oファイルとして認識されてしまいます。

削除されたソースファイル名を認識して、対応する.oファイルを削除し、
lib.aからも削除するようにしないいといけないのですが、
既に存在しないファイルに対してmakeがアクションをおこすような指示をどう書けばいいのかが
思いつきません。
>>255
そうなるとたしかに$*/lib.aは強制的に作り直さなきゃだな。

    @{ \
    echo '$*_SRC:=$(wildcard $*/*.c)'; \
    echo '$*_OBJ:=$$($*_SRC:.c=.o)'; \
    echo '$*/lib.a: $$($*_OBJ)'; \
    echo '    @rm -f $$@'; \
    echo '    $$(AR) $$(ARFLAGS) $$@ $$?'; \
    echo '    $$(RANLIB) $$@'; \
    echo 'ifneq($*_SRC,$$(wildcard $*/*.c))'; \
    echo '$@ $*/lib.a: .force'; \
    echo 'endif'; \
    } > $@
257235:03/02/14 01:31
>>256
そいつだと、%.arc_ruleが作り直された段階で
$*/lib.a: .force の関係がキャンセルされてしまうみたいです。
なので、%.arc_ruleの出力時に$*/lib.aを削除するようにしました。

最終的にはこのようになりまして、(↓全角スペースがタブのかわり)

.PHONY : .force_update

$(ARC_LIST) : %/lib.a :
 $(AR) $(ARFLAGS) $@ $?

ARC_RULES:=$(addsuffix /.arc_rule,$(DIR_LIST))
$(ARC_RULES) : %/arc_rule :
 @{ \
  echo '.$*_SRC:=$(wildcard $*/*.c)' ;\
  echo '.$*_OBJ:=$$(.$*_SRC:.c=.o)' ;\
  echo '$*/lib.a : $$(.$*_OBJ)' ;\
  echo 'ifneq ($$(.$*_SRC),$$(wildcard $*/*.c))' ;\
  echo '$@ : .force_update' ;\
  echo 'endif' ;\
 } >@ ;\
 $(RM) -f $*/lib.a
include $(ARC_RULES)

動作は良好です。
ソースの追加、削除、引越しを完全に追跡してくれます。
快適です。

助言くださったみなさま、ありがとうございました。

優良スレage
258デフォルトの名無しさん:03/02/14 01:32
SRCS=`find *.c`
INCS=`find *.h`
>>257
> >>256
> そいつだと、%.arc_ruleが作り直された段階で
> $*/lib.a: .force の関係がキャンセルされてしまうみたいです。
> なので、%.arc_ruleの出力時に$*/lib.aを削除するようにしました。
$*/lib.aを%.arc_ruleに依存するようにするのはどうよ。
>>259
対応するソースの無くなったオブジェクトがlib.aに残る問題を考えると、
あのタイミングで削除してしまったほうが効率もよく、すっきりします。