Очистить мой фрагмент make-файла? - PullRequest
1 голос
/ 22 октября 2010

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

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 Ответ

1 голос
/ 22 октября 2010

Есть несколько способов сделать это, но ни один из них не совершенен (пока кто-то не поместит обработку регулярных выражений в 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)
...