アプリケーションのメインディレクトリに「lib」ディレクトリがあります。このディレクトリには、それぞれ独自のMakefileを持つ任意の数のサブディレクトリが含まれています。
メインディレクトリに、各サブディレクトリのMakefileを呼び出す単一のMakefileを作成したいと思います。サブディレクトリを手動でリストすればこれが可能であることはわかっていますが、自動的に実行したいと思います。
私は次のようなことを考えていましたが、明らかに機能しません。クリーン、テストなどのターゲットもあるので、%はおそらくまったく良い考えではないことに注意してください。
LIBS=lib/*
all: $(LIBS)
%:
(cd $@; $(MAKE))
どんな助けでも大歓迎です!
以下は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
シェルコマンドを使用せずに、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)
不明な数のサブディレクトリ内のすべてとは異なるターゲットを呼び出したい場合はどうなりますか?
次の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))))
お役に立てれば。並列処理を処理するときに本当に役立ちます:これらのターゲットを持つmakefileを使用してツリー内のすべての-j12をクリーンにします...いつものように:makeで遊ぶのは危険であり、プログラミングのさまざまなメタレベルが近すぎます、-)