2010-10-21 64 views
1

我使用GNU Make來運行科學數據分析,在那裏我們有一堆思考一些輸入數據然後吐出幾個文件的Matlab腳本。它以相當複雜的方式實現了這一點,所以在嘗試描述它的Make功能時,我不得不做一些令人討厭的Makefile技巧。這裏有一個例子:清理我的makefile片段?

seg_cams_nozero := cam1 cam2 cam3 
seg_per_camera := $(shell echo {,dyn_}{hands,obj{1,2,3,4,5}}.mat) 
# the complete list of things we want 
segmentation_outputs := $(foreach cam,$(seg_cams_nozero),$(foreach product,$(seg_per_camera),derived/cont_$(cam)_$(product))) 

# how to make some product, independent of what camera 
define seg_per_product 
derived/cont_cam%_$$(product): /path/to/input/file_%.mat 
     run_a_script $$* 
endef 

$(foreach product,$(seg_per_camera),$(eval $(seg_per_product))) 

segmentation: $(segmentation_outputs) 

所以,這基本上是可怕的,因爲我還沒有想出如何使用模式在這種情況下有效的規則,因爲我要生成噸使用shell文件名。

你會怎麼寫這樣的東西?你會預先生成文件名並將它們放在一個包含的Makefile中嗎?找出使用模式規則的好方法?有沒有辦法做到這一點沒有$(eval ...)

+1

設我猜想:每一點都是作爲* ad hoc *工具開始的,您將它們粘合在一起形成更大更好的分析?我的論文分析就是這樣開始的。最後它在自身的重量下崩潰了,我不得不從頭開始重寫它。並不是我感到遺憾,*特設*工具是必要的,我在此過程中學到了寶貴的經驗教訓。 – dmckee 2010-10-21 20:48:25

+0

你猜怎麼着? :-P是的,這些工具實際上不是那種友善的,處理抽象的事情,Make並不真正想要的東西(即它們不是文件)。 – rescdsk 2010-10-21 20:49:53

+0

我最終構建了一個全局框架來將數據分發給每個順序任務。我認爲人們甚至對這種方式有一個名稱。 – dmckee 2010-10-21 20:51:58

回答

1

有幾種方法可以做到這一點,它們都不是完美的(直到有人將正則表達式處理放入Make中)。

首先,我注意到一個命令會爲給定的相機制作所有的目標,但是它會針對每個目標執行,這是浪費。因此,我們從cam1的目標開始

cam1_outputs := $(addprefix derived/cont_cam1_, $(seg_per_camera)) 

並使第一個「主要」(並將其從列表中刪除)。這將是其餘的先決條件,並且將是唯一一個實際需要腳本運行的人。 (有可能是使用更先進的方法稍微更優雅的方式,但是這會爲現在要做的。)

cam1_primary := $(firstword $(cam1_outputs)) 
cam1_outputs := $(filter-out $(cam1_primary), $(cam1_outputs)) 

$(cam1_outputs): $(cam1_primary) 

$(cam1_primary): /path/to/input/file_1.mat 
    run_a_script 1 

現在將其擴展到其他兩個攝像頭。我們可以重寫「主」治國模式規則:

$(cam1_primary) $(cam2_primary) $(cam3_primary): derived/cont_cam%_hands.mat: /path/to/input/file_%.mat 
    run_a_script $* 

其餘部分,我們可以只拼出所有三個攝像頭,但是這將意味着大量的冗餘代碼。我們可以define一個模板和eval它,但我喜歡避免,如果可能的話。所以我們就用一個小技巧:

cam2_primary := $(subst cam1,cam2,$(cam1_primary)) 
# ...and the same for the rest... 

(這是一個有點多餘,但不是太可怕)

把它放在一起,我們得到:

# Mention this first so it'll be the default target 
segmentation: 

seg_cams_nozero := cam1 cam2 cam3 

# seg_per_camera := $(shell echo {,dyn_}{hands,obj{1,2,3,4,5}}.mat) 
# Let's do this without the shell: 
seg_per_camera := hands $(addprefix obj, 1 2 3 4 5) 
seg_per_camera += $(addprefix dyn_, $(seg_per_camera)) 
seg_per_camera := $(addsuffix .mat, $(seg_per_camera)) 

cam1_outputs := $(addprefix derived/cont_cam1_, $(seg_per_camera)) 

# Now's a good time for this. 
segmentation_outputs := $(cam1_outputs) 
segmentation_outputs += $(subst cam1,cam2,$(cam1_outputs)) 
segmentation_outputs += $(subst cam1,cam3,$(cam1_outputs)) 

cam1_primary := $(firstword $(cam1_outputs)) 
cam1_outputs := $(filter-out $(cam1_primary), $(cam1_outputs)) 
$(cam1_outputs): $(cam1_primary) 

cam2_primary := $(subst cam1,cam2,$(cam1_primary)) 
cam2_outputs := $(subst cam1,cam2,$(cam1_outputs)) 
$(cam2_outputs): $(cam2_primary) 

cam3_primary := $(subst cam1,cam3,$(cam1_primary)) 
cam3_outputs := $(subst cam1,cam3,$(cam1_outputs)) 
$(cam3_outputs): $(cam3_primary) 

$(cam1_primary) $(cam2_primary) $(cam3_primary): derived/cont_cam%_hands.mat: /path/to/input/file_%.mat 
    run_a_script $* 

segmentation: $(segmentation_outputs)