0

さまざまなディレクトリに多数のCファイルがありmake: nothing to be done for 'all'、再帰的なMakefileでエラーが発生します。ただし、依存関係を微調整すれば、それを機能させることができます...しかし、なぜそうしなければならないのかわかりません。

これが私のオリジナルのMakefileです:

APP_DIRS=rescoco ressys resvm

.PHONY: all

all: $(APP_DIRS)

$(APP_DIRS):
    $(MAKE) --directory $@

clean:
    $(RM) *~

今、私が私の行を変更した場合:それはうまく構築.PHONYされます。.PHONY: all $(APP_DIRS)

もう1つの可能性は、行を変更した場合$(APP_DIRS):です$(APP_DIRS): clean

(注:.PHONYターゲットを削除しても、何も変更されません)


では、ここで何が起こっているのでしょうか。Makefileは、依存関係を正しくリストしていないことを通知しようとしていますか?私はmake次のようなことをすると思っていました:

  • 構築する.PHONYには最初に構築する必要がありますall
  • 構築するallには最初に構築する必要があります$(APP_DIRS)
  • $(APP_DIRS)前提条件がないので、そのためのコマンドを実行します(これにより、再帰的なmakeが実行されます)。

明らかに私は間違っています。しかし、なぜ?


参考までに、私のファイルが次のように構成されていることが重要な場合:

Makefile       #top level makefile as seen above
/rescoco
    rescoco.c
    Makefile   #builds rescoco src and moves archive to ../lib directory
/ressys
    ressys.c
    Makefile   #same as above but for ressys
/resvm
    resvm.c
    Makefile   #same as above but for resvm
/lib

私のビルドコマンドは単純makeです。で実行した場合、make -nまたはmake -n all出力がまったく得られなかった場合:

:~/proj$ make -n all
make: Nothing to be done for 'all'.
:~/proj$ 
4

3 に答える 3

2

最初に知っておくべきこと:

  • 依存関係としてディレクトリがある場合、ディレクトリの変更タイムスタンプが更新された場合にのみ、makeはターゲットの構築(つまり、そのようなディレクトリターゲットのレシピの実行)を検討します。これは、ディレクトリに新しいファイルを追加した場合にのみ発生しますが、ディレクトリ内のファイルを変更した場合には発生しません。サブディレクトリにファイルを追加しても、ディレクトリのタイムスタンプは変更されません。
  • PHONYターゲットは、そのようなターゲットを実行してもターゲットの名前のファイルが作成されない場合に使用することを目的としています。つまり、ファイルが既に存在するかどうかに関係なく、ルールを実行するようにします。

したがって、Makefileは本質的にこれを伝えるだけです:

  • ターゲットをビルドするには、ビルドallする必要があり$(APP_DIRS)ます。allはPHONYターゲットなので、常にのレシピを実行しallます。
  • $(APP_DIRS)PHONYターゲットではなく、依存関係はありません。したがって、* $(APP_DIRS)まだ存在しない場合(つまり、ファイルまたはディレクトリ)のみ、レシピを実行します。それ以外の場合は、このターゲットに対して何もしません。
  • cleanには前提条件がなく、がないPHONYため、(コマンドラインまたは別のMakefileから)makeによって明示的に呼び出された場合にのみこのルールを実行することを期待しています。またclean、ではないPHONYので、レシピcleanは実行後に呼び出されるファイルを作成することを期待しています(これはあなたの場合は正しくありません)

したがって、.PHONY行を次のように変更します。

.PHONY: all $(APP_DIRS)

Makefileを実行し、常に$(APP_DIRS)のレシピを実行します。

したがって、makeが常にすべての$(APP_DIRS)ディレクトリに移動し、それらに対してmakeを再度呼び出す場合は、に追加する必要があります$(APP_DIRS).PHONYこれにより、$(APP_DIRS)がPHONYターゲットになり、ファイルの/に関係なくレシピが実行されます。ディレクトリのタイムスタンプ(存在する場合)。

あなたの特定のユースケースでは、これがあなたが使用すべきMakefileだと思います:

APP_DIRS=rescoco ressys resvm

.PHONY: all clean $(APP_DIRS)

all: $(APP_DIRS)

$(APP_DIRS):
    $(MAKE) --directory $@

clean:
    $(RM) *~

ボーナス:

  • に変更$(APP_DIRS):すると、$(APP_DIRS): cleanターゲット$(APP_DIRS)によって異なりcleanます。
  • PHONYcleanのマークは付いていませんが、makeはclean現在のディレクトリにある名前のファイルを認識しません。そのため、先に進み、のレシピを実行しようとしcleanます。
  • $(APP_DIRS)(つまりclean)の依存関係が構築されたため、これにより、Makefileは$(APP_DIRS)を構築するためのレシピを実行します。

これにより、興味深い観察結果が得られます。-PHONYターゲットに依存するターゲットは、常に再構築されます(つまり、レシピが実行されます)。

この単純なMakefileを取ります:

all: target1

target1: target2
    @echo "$@"
    @touch $@

target2: target3
    @echo "$@"
    @touch $@

target3:
    @echo "$@"

.PHONY: all target3

初めて実行するmakeと、次の出力が表示されます。

target3
target2
target1

この後、ファイルtarget1target2が作成されます。それでも、makeもう一度実行すると、次の出力が表示されます。

target3
target2
target1

ご覧のとおり、PHONY依存関係は上に伝播され、その逆ではありません。PHONYであるというtarget2理由だけで再構築され、再構築されたという理由だけで再構築されます。target3target1target2

于 2013-03-21T17:54:27.857 に答える
0

ディレクトリのリストを使用して、「APP_DIRS」という名前の変数を定義しています。それは結構です。

その後、

$(APP_DIRS): make blah blah,これは本質的に同等ですrescoco ressys resvm: make blah blah

これは明らかに有効ではありません。

したがって、$(APP_DIRS)が変数であり、ターゲット名ではないふりをする必要があります。これは、それを使用しているように見えます。

そうは言っても、なぜ.PHONY:すべての$(APP_DIRS)が機能するのか考えてみてください

于 2013-03-21T17:57:26.567 に答える
0

これがあなたがそれをすることができる方法です、あなたがそれを望まないならば、ただワイルドカードを取り除いてください。
ワイルドカードサブディレクトリターゲットを作成します

于 2013-03-21T17:59:24.600 に答える