【问题标题】:Makefile: exit on conditionalMakefile:有条件退出
【发布时间】:2020-02-24 10:27:04
【问题描述】:

我想在执行 Makefile 中的某些代码之前检查是否设置了环境变量。如果没有设置,我想用一个简单的错误消息抛出一个错误:

run:
  [ -z "$(MY_APP)" ] && echo "MY_APP must be set" && exit 1
  echo "MY_APP is set. Yay!"
  echo "Let's continue on with the command..."

MY_APP 未设置时,我收到以下错误,这是所需的:

[ -z "" ] && echo "MY_APP must be set" && exit 1
MY_APP must be set
make: *** [run] Error 1

但是,当设置MY_APP 时,我收到以下错误:

[ -z "EXAMPLE_NAME" ] && echo "MY_APP must be set" && exit 1
make: *** [run] Error 1

知道我做错了什么吗?有没有更好的方法来做到这一点?

【问题讨论】:

    标签: bash makefile


    【解决方案1】:

    您可以使用error 控制函数有条件地退出 Makefile,至少在 GNU 版本中是这样。

    这个 sn-p 是一个有用的条件,可以放入 Makefile 的头部。如果没有从 Makefile 的目录中调用 make,它将退出并显示帮助消息。

    MAKEFILE_DIR:=$(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))
    ifneq (${MAKEFILE_DIR}, $(shell pwd))
     INVALID_LOCATION:=`make` must be called from within ${MAKEFILE_DIR} (or with option -C ${MAKEFILE_DIR})
     $(error ERROR: $(INVALID_LOCATION))
    endif
    

    见:https://www.gnu.org/software/make/manual/html_node/Make-Control-Functions.html

    如果您的路径是相对于 Makefile 并且您不希望它们以基为前缀的情况下很有用。

    【讨论】:

      【解决方案2】:

      您可以使用Makefile conditional syntax 测试环境变量,如下所示:

      sometarget:
      ifndef MY_APP
          @echo "MY_APP environment variable missing"
          exit 1
      endif
      
          somecommand to_run_if_my_app_is_set
      

      请注意,ifndef/ifdef 操作的是变量的名称,而不是变量本身。

      【讨论】:

        【解决方案3】:

        您似乎正在尝试使用 Makefile 来运行未构建目标的命令(目标名称 run 是赠品)。您已经被 Makefile 和 shell 警告之一所困扰。 Makefile 警告:在每行之后检查退出状态,如果不为零则立即中止。 Shell 警告:test 命令 ([) 返回非零退出状态,因此整行返回非零。

        经验法则是:规则的配方应该创建一个命名为规则目标的文件名。

        这是一条规则(澄清条款):

        target:
          recipe command lines
          should create file named target
        

        这个经验法则有一些例外。最值得注意的是make cleanmake install。两者通常都不会创建名为 cleaninstall 的文件。有人可能会争辩说,make run 也可能是这条经验法则的一个例外。

        如果您的run 与典型的clean 一样简单,那么我可能同意例外。但通常命令是使用命令行参数运行的。不久之后,您将希望 make run 接受参数。并且让 make 接受自定义命令行参数一点也不好玩。

        您尝试使用环境变量来操纵行为,这比命令行参数的问题要少一些。但问题仍然足以让您大吃一惊。

        我的修复建议:

        • 将复杂的配方放入 shell 脚本中。在那里,您拥有 shell 脚本的所有功能和灵活性,而没有 makefile 的笨拙。例如这里解释:Basic if else statement in Makefile
        • 如果是典型的run 目标,请在makefile 周围编写一个封装shell 脚本,让makefile 重建目标然后运行目标。例如这里解释的:Passing arguments to "make run"

        【讨论】:

          【解决方案4】:

          回想一下 && 条件要求所有条件都必须为 TRUE 才能通过。由于第一个条件失败,整个命令将返回状态 1,有效地停止了 make

          您可以使用以下内容,这样只有在缺少 MY_APP 时测试才会失败。

          请注意,我使用的是“false”而不是“exit 1”。最好使用“${MY_APP}”,这样可以更轻松地从 Make 复制/粘贴到 shell 提示符/脚本。

          run:
              { [ -z "$(MY_APP)" ] && echo "MY_APP must be set" && false } || true
              ...
          
          # Or just if-Then-Else
              if [ -z "${MY_APP} ] ; then echo "MY_APP must be set" ; false ; fi
              ...
          

          【讨论】:

          • 简单的规则是,您几乎总是希望在 makefile 配方中使用 ||,而不是 &&。这意味着有时会反转您的测试(记住您的布尔逻辑!)。在这种情况下,您可以使用:[ -n "$(MY_APP)" ] || { echo "MY_APP must be set"; exit 1; }
          猜你喜欢
          • 2021-07-13
          • 1970-01-01
          • 1970-01-01
          • 2013-12-10
          • 1970-01-01
          • 1970-01-01
          • 2011-04-24
          • 1970-01-01
          • 2018-03-21
          相关资源
          最近更新 更多