清理我的makefile片段?

时间:2010-10-21 20:43:31

标签: file makefile combinations

我正在使用GNU Make来运行科学数据分析,我们有一堆Matlab脚本来思考一些输入数据,然后吐出几个文件。它以相当复杂的方式执行此操作,因此在尝试将其函数描述为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)

所以,这基本上是可怕的,因为在这种情况下我还没有想出如何有效地使用模式规则,因为我必须使用shell生成大量的文件名。

你会怎么写这样的东西?你会预先生成文件名并将它们放在包含的Makefile中吗?找出使用模式规则的好方法?有没有办法在没有$(eval ...)的情况下做到这一点?

1 个答案:

答案 0 :(得分: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)