【问题标题】:Testing if a file exists in makefile target, and quitting if not present测试 makefile 目标中是否存在文件,如果不存在则退出
【发布时间】:2012-12-30 04:49:47
【问题描述】:

如果文件不存在,有没有办法以错误条件退出?我目前正在做这样的事情:

all: foo

foo:
    test -s /opt/local/bin/gsort || echo "GNU sort does not exist! Exiting..." && exit

运行make 运行all 目标,该目标运行foo

预期如果test -s 条件失败,则执行echo/exit 语句。

但是,即使/usr/bin/gsort 存在,我也会得到echo 语句的结果,但exit 命令不会运行。这与我希望实现的目标相反。

执行上述操作的正确方法是什么?

【问题讨论】:

  • 如果我在命令行上尝试此操作,在括号中使用 || 的右侧,以获得一个子 shell,使其按预期工作。我不知道它在makefile中是否相同。没有括号,即使测试是肯定的,也会执行“退出”。

标签: makefile gnu


【解决方案1】:

我意识到这在这一点上有点老了,但你甚至不需要使用 subshel​​l 来测试 Make 中是否存在文件。

这还取决于您希望/期望它如何运行。

使用通配符函数,像这样:

all: foo
foo:
ifeq (,$(wildcard /opt/local/bin/gsort))
    $(error GNU Sort does not exist!)
endif

是一种很好的方法。注意这里 ifeq 子句没有缩进,因为它在目标本身之前被评估。

如果您希望对每个目标都无条件地发生这种情况,您可以将其移到目标之外:

ifeq (,$(wildcard /opt/local/bin/gsort))
$(error GNU Sort does not exist!)
endif

【讨论】:

    【解决方案2】:

    exit 单独返回最后执行的命令的状态。在这种情况下,它返回零,这意味着一切正常。

    这是因为||&&equal precedence,并且shell 将命令解释为就像它是编写的一样

    ( test ... || echo ... ) && exit
    

    如果您想发出失败信号,您必须以非零值退出,例如exit 1。 如果要回显退出,只需将命令按顺序排列,以;

    分隔
    all: foo
    
    foo:
        test -s /opt/local/bin/gsort || { echo "GNU sort does not exist! Exiting..."; exit 1; }
    

    【讨论】:

      【解决方案3】:

      make 中的每个命令行都在其自己的子 shell 中运行。所以运行exit 只是退出那个子shell——而不是整个makefile。默认情况下,如果任何子 shell 返回不成功的退出状态,make 将停止执行(按照惯例,0 表示成功,因此其他任何内容都将停止执行)。最简单的方法就是使用test 命令的退出状态:

      all: foo
      
      foo:
          test -s /opt/local/bin/gsort
      

      打印诊断消息会使事情稍微复杂化,因为像echo 这样的命令将返回退出状态0,导致make 认为一切正常。要解决此问题,您需要在它之后运行一个命令,该命令将为子 shell 提供非零退出状态:

      all: foo
      
      foo:
          test -s /opt/local/bin/gsort || { echo "GNU sort does not exist! Exiting..."; exit 1; }
      

      甚至只是

      all: foo
      
      foo:
          test -s /opt/local/bin/gsort || { echo "GNU sort does not exist! Exiting..."; false; }
      

      【讨论】:

        【解决方案4】:

        简单地做:

        all: /opt/local/bin/gsort
        

        如果/opt/local/bin/gsort 丢失,您将收到“没有规则来制作目标`/opt/local/bin/gsort'”错误消息。

        但是,如果您还想对它进行一些很好的解释:

        /opt/local/bin/gsort:
            echo "GNU sort does not exist! Exiting..."
            false
        

        在 GNU/Make 中,如果目标未声明 .PHONEY 并且没有任何依赖项,则如果不存在与该目标匹配的文件,则将调用该规则。

        上面的代码只有在/opt/local/bin/gsort不存在时才会触发false命令,会返回非0值,make会失败。

        【讨论】:

        • 有没有办法让make继续检查每个丢失的文件,然后返回false?这样,如果有人丢失了很多文件,所有文件都会显示出来,而不是一次显示一个。
        • @thepiercingarrow 使用make -k,见gnu.org/software/make/manual/html_node/Testing.html
        【解决方案5】:

        由于您正在检查gsort 可执行文件是否存在,您可以使用whichtype shell 命令,例如:

        all: foo
          :
        
        foo:
          which gsort || exit 1
          # or
          type gsort || exit 1
        

        您不需要错误消息,因为它会自动打印:

        /bin/sh:第 0 行:类型:gsort:未找到

        这很明显。


        也可以使用test[(语法见:help test/help [),例如

        test -x /opt/local/bin/gsort || { echo Error msg; exit 1; }
        

        检查给定文件是否存在以及是否可执行,否则显示消息并退出。括号对于通过对命令进行分组来覆盖运算符的正常优先级(从左到右)很重要(有关更多信息,请参阅man bash 中的Compound Commands 部分)。


        另一种方法是使用规则的目标来检查文件是否存在并作为依赖添加到all,例如

        all: /opt/local/bin/gsort
          @echo Success.
        
        /opt/local/bin/gsort:
          @echo "GNU sort does not exist! Exiting..."
          exit 1
        

        结果:

        $ make
        GNU sort does not exist! Exiting...
        exit 1
        make: *** [/opt/local/bin/gsort] Error 1
        

        【讨论】:

          猜你喜欢
          • 2014-01-12
          • 1970-01-01
          • 2018-10-09
          • 1970-01-01
          • 2014-09-02
          • 2011-02-25
          • 2021-11-15
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多