2016-09-20 97 views
2

我想創建一個使用monorepo的Makefile,並且正在基於源文件目錄的動態輸出目錄掙扎。基於源文件目錄的動態輸出目錄的Makefile

我的項目被佈置像這樣:

% tree . 
. 
├── Makefile 
└── packages 
   ├── bar 
   │   └── src 
   │    └── index.js 
   │    └── other-file.js 
   └── foo 
    └── src 
     └── index.js 

5 directories, 4 files 

欲處理每個*.js文件每個包的內部(例如,./packages/foo/src/index.js),併發射輸出到另一個目錄(具體地,./packages/foo/lib/index.js)。

例如make bar將:

  • 過程./packages/bar/src/index.js - >./packages/bar/lib/index.js
  • 過程./packages/bar/src/other-file.js - >./packages/bar/lib/other-file.js

我也將潛在地喜歡用這種模式用於在./src其他類型的文件的如處理.less文件。

的Makefile

PACKAGES_ROOT = ./packages 
packages := $(shell ls $(PACKAGES_ROOT)) 

package_source_dir := $(addprefix packages/,$(addsuffix /src/,$(packages))) 
package_dest_dir := $(subst src,lib,$(package_source_dir)) 

package_source := $(foreach sdir, $(package_source_dir), $(wildcard $(sdir)*.js*)) 
package_dest := $(subst src,lib,$(package_source)) 

.PHONY: all checkdirs clean 
all: checkdirs 

checkdirs: $(package_dest_dir) 

$(package_dest_dir): 
    mkdir -p [email protected] 

$(packages): 
    @echo "[email protected]" 

clean: 
    rm -rf $(package_dest_dir) 

我不知道我是否需要使用VPATH還是什麼...幫助嗎?

注意:Makefile目前只是足以製作和刪除所有目標目錄。

+2

雖然你的問題並不完全是[this one]的重複(http://stackoverflow.com/questions/39015453/building-c-program-out-of-source-tree-with-gnu-make/39033569 #39033569),你可以在這裏找到幾種不同的方法來實現你想要做的事情。花時間閱讀並理解答案。 – Tim

+0

謝謝你指點我正確的方向。我實際上已經嘗試過動態規則生成,但是我的'define'永遠不會被調用。再給它一次,並更新我的問題(並希望回答)。 –

回答

1

像這樣的東西應該做的工作:

# Directories 
PKGS_ROOT := packages 
PKGS_SRCDIR := src 
PKGS_OUTDIR := lib 

# Expands to the source directory for the specified package 
pkg-srcdir = $(PKGS_ROOT)/$1/$(PKGS_SRCDIR) 
# Expands to the output directory for the specified package 
pkg-libdir = $(PKGS_ROOT)/$1/$(PKGS_OUTDIR) 
# Expands to all output targets for the specified package 
pkg-libs = $(addprefix $(call pkg-libdir,$1)/,$(notdir $(wildcard $(call pkg-srcdir,$1)/*.js))) 

# Defines the following rules for the specified package: 
# - build rule for .js files 
# - rule to create the output directory if missing 
# - package rule to build all outputs 
# - clean-package rule to remove the output directory 
# Adds the following prerequisites: 
# - package target to 'all' rule 
# - clean-package target to 'clean' rule 
define pkg-rules 
$(call pkg-libdir,$1)/%.js: $(call pkg-srcdir,$1)/%.js | $(call pkg-libdir,$1) 
    @echo Making [email protected] from $$^ 
    @cp $$^ [email protected] 
$(call pkg-libdir,$1): 
    @mkdir [email protected] 
$1: $(call pkg-libs,$1) 
clean-$1: 
    rm -rf $(call pkg-libdir,$1) 
all: $1 
clean: clean-$1 
.PHONY: $1 clean-$1 
endef 

# Creates rules for the specified package 
add-pkg = $(eval $(call pkg-rules,$1)) 

# Create rules for all packages 
PKGS := $(notdir $(wildcard $(PKGS_ROOT)/*)) 
$(foreach p,$(PKGS),$(call add-pkg,$p)) 

# Will be filled in by pkg-rules 
.PHONY: all clean 

.DEFAULT_GOAL := all 

的各個功能/助理/操作應該不難理解。我將目錄抽象爲前三名助手,以避免在需要時不得不更改大量事件。讓我們深入pkg-rules,其中定義了實際的動態規則。

pkg-rules通過foo。它會創建以下規則:

  • packages/foo/lib/%.js: packages/foo/src/%.js | packages/foo/lib:這是建立在輸出.js文件的形式規則。它還將輸出目錄作爲訂單唯一的前提條件(與執行順序無關 - 這意味着目錄目標只有在不存在時纔會構建,而不會查看時間戳)。
  • packages/foo/lib:此規則創建輸出目錄。您沒有嵌套目錄,如果目錄存在,配方將不會執行,因此不需要-p。順便說一下,可能有嵌套的目錄並複製源樹,但它需要更多的詭計(可能是次要擴展,$(@D),使用更爲巧妙的patsubst代替notdir,使用shell進行遞歸通配符,提取目錄等)。
  • foo: packages/foo/lib/index.js:在評論中我稱之爲「包目標/規則」。這是一個空虛的假冒規則,它將所有包裹輸出作爲先決條件。
  • clean-foo:在評論中,我稱之爲「清理包目標/規則」。這是一個假冒規則,它刪除了包輸出目錄。

它還將增加爲前提條件的包裝和清潔包的目標,以通用allclean規則。

foo,clean-bar,allclean這樣的目標的行爲與您預期的完全相同。

1

您可以生成一個臨時生成文件:

packages:= $(shell ls $(PACKAGES_ROOT)) 

packages.mk : Makefile $(abspath .) 
    for package in $(packages); do \ 
     echo "packages/$(package)/lib/%.js:packages/$(package)/src/%.js" >> [email protected] ; \ 
     echo " echo recipe for $(dir)" >> [email protected]; \ 
     echo >> [email protected]; \ 
    done 

-include "packages.mk" 

這假定目錄不是動態的其他規則創建的,因爲$(packages)將只包含其中存在的時候makefile文件是第一次讀取的目錄。

相關問題