2009-12-19 31 views
14

Uygulamalarımın ana dizininde her birinin kendi Makefile'sine sahip rastgele bir alt dizin içeren "lib" dizinim var.joker yardımcı alt dizinleri hedefler

Ana dizinde, her bir alt yönlendiricinin Makefile adını veren tek bir Makefile olmasını isterim. Alt dizinleri manuel olarak listelediğimde bunun mümkün olduğunu biliyorum, ancak otomatik olarak yapılmasını istiyorum.

Aşağıdaki gibi bir şey düşünüyordum, ama açıkçası işe yaramıyor. Temiz, test vb. Hedeflerim olduğunu da unutmayın, bu yüzden% muhtemelen hiç de iyi bir fikir değildir.

LIBS=lib/* 

all: $(LIBS) 

%: 
    (cd [email protected]; $(MAKE)) 

Herhangi bir yardım için teşekkür ederiz!

cevap

23

şu GNU make ile çalışacaktır:

LIBS=$(shell find lib -type d) 

birden hedefler sorunu gidermek için size: lib yılında dizinleri dışında bir şey olabilir Eğer

LIBS=$(wildcard lib/*) 
all: $(LIBS) 
.PHONY: force 
$(LIBS): force 
    cd [email protected] && pwd 

, alternatif olarak kullanabilirsiniz Her bir dizin için özel hedefler oluşturabilir, ardından alt yapı için önekleri kapatabilir:

LIBS=$(wildcard lib/*) 
clean_LIBS=$(addprefix clean_,$(LIBS)) 
all: $(LIBS) 
clean: $(clean_LIBS) 
.PHONY: force 
$(LIBS): force 
    echo make -C [email protected] 
$(clean_LIBS): force 
    echo make -C $(patsubst clean_%,%,[email protected]) clean 
gmake ile alt dizinleri listeleme bir yolu da vardır
+0

Wow, Teşekkürler. ÇALIŞIYOR bir cazibe gibi! – Zed

+1

Neden "$ (clean_LIBS)" öğesini sahte olarak tanımladınız? Örneğin. .PHONY: $ (LIBS) $ (clean_LIBS) ', sonra bence 'force' gerekmiyor. –

+0

@dma_k: Mükemmel bir nokta yaratıyorsunuz. Önerinizi test etmedim, ama mantığınız bana doğru geliyor. Aslında, GNU Make kullanım kılavuzunun burada önerdiği gibi çok şey duyuyor (bkz. Alt dizinlerdeki bit): http://www.gnu.org/software/make/manual/make.html#Phony-Targets – mrkj

2

herhangi kabuk komutlarını kullanmadan, sadece komutları: Bu '/' firar ile tüm alt dizinleri listeler

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

. Bunu kaldırmak için yedek deseni kullanabilirsiniz:

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

Sonra aslında küçük bir hile kullanabilirsiniz her alt dizinde makefiles yürütme kuralları oluşturmak - varolmayan dizinde sahte hedef. Ben bir örnek herhangi bir açıklama daha anlatacağım bu durumda düşünüyorum:
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 

Temelde, 'all' listeler önkoşul olarak tüm alt dizinleri hedef.

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

Ardından 'marka', kural 'all' yürütmek amacıyla, mevcut bir hedef ile her önkoşulu eşleştirmeye çalışır: Örneğin, LIB_DIRS eğer lib/folder1 lib/folder2 sonra genişleme şu şekilde görünecektir içeriyordu. Bu durumda hedef, 'make-rule/''dan sonra dizeyi ayıklamak ve tarifi argüman olarak kullanmak için '$*' kullanan 'make-rule/%:' şeklindedir. Örneğin, ilk önkoşul şekilde eşleştirilir ve bunun gibi genişletilmiş:

make-rule/lib/folder1: 
    cd lib/folder1 && $(MAKE) 
+0

'all: DIRS_CMD' yerine şu anki yineleme düzgün şekilde genişlemediği için "$: $ DIRS_CMD" olmalıdır. 'Make' çizgisi boyunca bir şey elde ediyordum: *** 'all' tarafından ihtiyaç duyulan 'DIRS_CMD' hedefini yapmak için kural yok. Dur. – jnt30

+0

Bu mümkün. Benim için bence dolar olmadan çalıştı ama kaynaklara sahip değilim ve doğrulayamıyorum. – Amiramix

0

Eğer alt dizinleri sayısı bilinmeyen tüm farklı hedefleri aramak istiyorsanız ne olacak? Bu yardımcı olur

# 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 [email protected] 
.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)_%,%,[email protected]) $(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)))) 

Hope:

aşağıdaki Makefile makrolar böylece her birine komut satırından verilen hedef uygulamak için alt dizinleri bir dizi için bir iletme kukla-hedef oluşturmak kullanır.Paralelizmle uğraşırken gerçekten faydalı: make -j12, bu hedefleri olan makefillerle bir ağacın tümünü temizleyin ... Her zaman olduğu gibi: make ile oynamak tehlikeli, farklı meta-seviyeleri programlamaya çok yakın, -)

İlgili konular