2010-10-21 2 views
1

Я использую GNU Make для запуска анализа научных данных, где у нас есть куча скриптов Matlab, которые задумываются над некоторыми входными данными, а затем выплевывают несколько файлов. Он делает это довольно сложным образом, поэтому мне пришлось сделать некоторые неприятные трюки Makefile при попытке описать его функцию Make. Вот пример:Очистить фрагмент файла 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) 

Таким образом, это в основном ужасно, потому что я не понял, как использовать шаблон эффективно правила в этой ситуации, и потому что я должен генерировать тонны имен файлов с использованием оболочки.

Как бы вы написали что-то вроде этого? Вы предварительно сгенерировали бы имена файлов и помещали их в включенный Makefile? Выясните отличный способ использования правил шаблонов? Есть ли способ сделать это без $(eval ...)?

+1

Пусть я думаю: каждый бит начал жизнь как инструмент * ad hoc *, и вы склеивали их вместе, чтобы сформировать больший и лучший анализ? Мой дискурс начался именно так. В конце концов он рухнул под собственным весом, и мне пришлось переписать его с нуля. Не то чтобы я сожалел об этом, инструменты * ad hoc * были необходимы, и я извлек ценные уроки на этом пути. – dmckee

+0

Как вы догадались ?! : -P Да, инструменты на самом деле не настолько дружелюбны, что имеют дело с абстрактными вещами, которые Make действительно не хочет думать (т. Е. Они не являются файлами). – rescdsk

+0

Я закончил создание глобальной структуры для отправки данных для каждой последовательной задачи. Я думаю, что у моделей люди даже имеют название для этого подхода. – dmckee

ответ

1

Существует несколько способов сделать это, ни один из них не идеален (пока кто-то не помещает обработку регулярных выражений в Make).

Во-первых, я замечаю, что одна команда делает все цели для данной камеры, но она запускается для каждой цели, что является пустой тратой. Итак, давайте начнем с целями для САМ1

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) 
Смежные вопросы