代码之家  ›  专栏  ›  技术社区  ›  rescdsk

清理我的makefile片段?

  •  1
  • rescdsk  · 技术社区  · 14 年前

    我正在使用GNU Make来运行科学数据分析,在这里我们有一堆Matlab脚本,它们考虑一些输入数据,然后输出几个文件。它以一种相当复杂的方式来实现这一点,所以在试图描述要生成的函数时,我不得不使用一些讨厌的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 回复  |  直到 14 年前
        1
  •  1
  •   Beta    14 年前

    有几种方法可以做到这一点,没有一种是完美的(直到有人将regex处理放入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
    

    现在把这个扩展到另外两个摄像头。我们可以将“primary”规则重写为模式规则:

    $(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)