23

アプリケーションのメインディレクトリに「lib」ディレクトリがあります。このディレクトリには、それぞれ独自のMakefileを持つ任意の数のサブディレクトリが含まれています。

メインディレクトリに、各サブディレクトリのMakefileを呼び出す単一のMakefileを作成したいと思います。サブディレクトリを手動でリストすればこれが可能であることはわかっていますが、自動的にリストしたいと思います。

次のようなことを考えていましたが、明らかにうまくいきません。クリーン、テストなどのターゲットもあるので、%はおそらくまったく良い考えではないことに注意してください。

LIBS=lib/*

all: $(LIBS)

%:
  (cd $@; $(MAKE))

どんな助けでも大歓迎です!

4

3 に答える 3

34

以下は GNU で動作しますmake:

LIBS=$(wildcard lib/*)
all: $(LIBS)
.PHONY: force
$(LIBS): force
  cd $@ && pwd

にディレクトリ以外のものがある可能性がある場合はlib、代わりに次を使用できます。

LIBS=$(shell find lib -type d)

複数のターゲットの問題に対処するには、ディレクトリごとに特別なターゲットを作成してから、サブビルドのプレフィックスを削除します。

LIBS=$(wildcard lib/*)
clean_LIBS=$(addprefix clean_,$(LIBS))
all: $(LIBS)
clean: $(clean_LIBS)
.PHONY: force
$(LIBS): force
  echo make -C $@
$(clean_LIBS): force
  echo make -C $(patsubst clean_%,%,$@) clean
于 2009-12-19T13:42:54.007 に答える
3

シェル コマンドを使用せずに、gmake コマンドのみでサブディレクトリを一覧表示する方法もあります。

test:
  @echo $(filter %/, $(wildcard lib/*/))

これにより、末尾に'/'. それを削除するには、代替パターンを使用できます。

subdirs = $(filter %/, $(wildcard lib/*/))
test:
  @echo $(subdirs:%/=%)

次に、各サブディレクトリでメイクファイルを実行するルールを実際に作成するには、小さなトリックを使用できます。存在しないディレクトリに偽のターゲットを作成します。この場合、例はどんな説明よりも多くのことを教えてくれると思います:

FULL_DIRS =$(filter %/, $(wildcard lib/*/))
LIB_DIRS  =$(FULL_DIRS:%/=%)
DIRS_CMD  =$(foreach subdir, $(LIB_DIRS), make-rule/$(subdir))

make-rule/%:
  cd $* && $(MAKE)

all: DIRS_CMD

基本的に、ターゲット'all'は前提条件としてすべてのサブディレクトリをリストします。たとえば、LIB_DIRS含まれているlib/folder1 lib/folder2場合、展開は次のようになります。

all: make-rule/lib/folder1 make-rule/lib/folder2

その後、「make」はルールを実行するために、'all'各前提条件を既存のターゲットと一致させようとします。この場合、ターゲットは'make-rule/%:''$*'、文字列を抽出するために'make-rule/'使用され、レシピの引数として使用されます。たとえば、最初の前提条件は次のように一致して展開されます。

make-rule/lib/folder1:
  cd lib/folder1 && $(MAKE)
于 2013-01-21T21:54:03.140 に答える
1

不明な数のサブディレクトリにあるすべてのターゲットとは異なるターゲットを呼び出したい場合はどうすればよいでしょうか?

次の Makefile はマクロを使用するため、多数のサブディレクトリに転送用のダミー ターゲットを作成して、指定されたターゲットをコマンド ラインから各サブディレクトリに適用します。

# all direct directories of this dir. uses "-printf" to get rid of the "./"
DIRS=$(shell find . -maxdepth 1 -mindepth 1 -type d -not -name ".*" -printf '%P\n')
# "all" target is there by default, same logic as via the macro
all: $(DIRS)

$(DIRS):
    $(MAKE) -C $@
.PHONY: $(DIRS)

# if explcit targets where given: use them in the macro down below. each target will be delivered to each subdirectory contained in $(DIRS).
EXTRA_TARGETS=$(MAKECMDGOALS)

define RECURSIVE_MAKE_WITH_TARGET
# create new variable, with the name of the target as prefix. it holds all
# subdirectories with the target as suffix
$(1)_DIRS=$$(addprefix $(1)_,$$(DIRS))

# create new target with the variable holding all the subdirectories+suffix as
# prerequisite
$(1): $$($1_DIRS)

# use list to create target to fullfill prerequisite. the rule is to call
# recursive make into the subdir with the target
$$($(1)_DIRS):
      $$(MAKE) -C $$(patsubst $(1)_%,%,$$@) $(1)

# and make all targets .PHONY
.PHONY: $$($(1)_DIRS)
endef

# evaluate the macro for all given list of targets
$(foreach t,$(EXTRA_TARGETS),$(eval $(call RECURSIVE_MAKE_WITH_TARGET,$(t))))

お役に立てれば。並列処理を扱う場合に非常に役立ちます: make -j12 は、これらのターゲットを持つ makefile を使用してツリー内のすべてをクリーンアップします... いつものように: make で遊ぶのは危険です。プログラミングの異なるメタレベルが近すぎます ,-)

于 2015-10-30T14:00:39.757 に答える