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

直接在目标依赖项中定义“出错时继续”策略

  •  1
  • norbjd  · 技术社区  · 7 年前

    下面是一个简单的Makefile,有4个目标( a , b , c all B 可以失败(在这里用 exit 1 ).

    a:
        echo "a"
    
    b:
        exit 1
    
    c:
        echo "c"
    
    all: a b c
    

    make all , C 从未打印为 失败和目标 C 因此,它没有运行。但在我的特殊情况下,我想要 C B

    我想知道是否有办法定义“出错时继续”策略 直接地 在目标的依赖关系中 全部的 .

    我知道可以通过以下方式达到预期的行为:

    • make -i all ( --ignore-errors )或 make -k all ( --keep-going )
    • 使用 "recursive" make
    • 在中为失败的命令加前缀 B 具有 - -exit 1 )
    • 分别使用 make a; make b || make c

    但所有这些选项都意味着要修改目标 A. B ,或修改方式 被称为。

    只是修改 这个 全部的 目标依赖项(类似于 all: a -b c 但这个定义显然不起作用)?

    附加要求 : 全部 如果出现以下情况,则应返回退出代码1 B 失败,即使 C 目标成功。

    2 回复  |  直到 7 年前
        1
  •  2
  •   Renaud Pacalet    7 年前

    如果您想运行 a, -b, c 即使 -<something> 如果失败,您可以使用模式规则 目标:

    a c:
        @echo "$@"
    
    b:
        @echo "$@"; exit 1
    
    all: a -b c
    
    -%:
        -@$(MAKE) $*
    

    演示(带有 --no-print-directory 对于更简单的输出):

    $ make --no-print-directory all
    a
    b
    Makefile:5: recipe for target 'b' failed
    make[1]: *** [b] Error 1
    Makefile:10: recipe for target '-b' failed
    make: [-b] Error 2 (ignored)
    c
    

    但如果你也想” 回想起 “他们的退出状态,事情就有点困难了。我们需要将退出状态存储在某个地方,例如存储在一个文件中,并将其重新用于 all 配方:

    a c:
        @echo "$@"
    
    b:
        @echo "$@"; exit 1
    
    all: a -b c
        @exit_status=`cat b_exit_status`; exit $$exit_status
    
    -%:
        -@$(MAKE) $*; echo "$$?" > $*_exit_status
    

    演示:

    $ make --no-print-directory all
    a
    b
    Makefile:5: recipe for target 'b' failed
    make[1]: *** [b] Error 1
    c
    Makefile:8: recipe for target 'all' failed
    make: *** [all] Error 2
    

    硬连线-配方中可能失败的目标的名称 不太优雅。但这应该很容易解决:

    a b c:
        @echo "$@"
    
    d:
        @echo "$@"; exit 1
    
    all: a -b c -d
        @for f in $(patsubst -%,%_exit_status,$(filter -%,$^)); do \
            tmp=`cat $$f`; \
            printf '%s: %s\n' "$$f" "$$tmp"; \
            if [ "$$tmp" -ne 0 ]; then exit $$tmp; fi; \
        done
    
    -%:
        -@$(MAKE) $*; echo "$$?" > $*_exit_status
    
    .PHONY: clean
    clean:
        rm -f *_exit_status
    

    $ make --no-print-directory all
    a
    b
    c
    d
    Makefile:5: recipe for target 'd' failed
    make[1]: *** [d] Error 1
    b_exit_status: 0
    d_exit_status: 2
    Makefile:8: recipe for target 'all' failed
    make: *** [all] Error 2
    
        2
  •  0
  •   Vroomfondel    7 年前

    虽然不能通过先决条件名称传输参数(或者至少只有在完全更改先决条件的情况下),但可以使用特定于目标的变量。但解决方案并不完美,每个配方行前面都有一个额外的变量:

    CIE_DASH = $(if $(filter $@,$(CONTINUE_SET)),-)
    
    all: a b c
    all: CONTINUE_SET += b
    
    a: 
        $(CIE_DASH)echo "a"
    
    b: CONTINUE_SET += e
    b: e 
        $(CIE_DASH)exit 1
    
    e:
        $(CIE_DASH)exit 1
    c:
        $(CIE_DASH)echo "c"