无法使带有变量的Makefile正常工作

时间:2019-06-21 17:01:58

标签: makefile

我有一个makefile,我正在尝试获取一个命令,以便有条件地在目标中运行。

如果我这样做:

namespace: ## create the kubernetes namespace
K_DESC := $(shell kubectl describe namespace $(KUBE_NAMESPACE) > /dev/null ; echo $$?);
ifneq ($(K_DESC),0)
    kubectl create namespace $(KUBE_NAMESPACE)
else
    kubectl describe namespace $(KUBE_NAMESPACE)
endif

我收到错误消息:Makefile:53: *** recipe commences before first target. Stop.

如果我这样做:

namespace: ## create the kubernetes namespace
    K_DESC := $(shell kubectl describe namespace $(KUBE_NAMESPACE) > /dev/null ; echo $$?);
ifneq ($(K_DESC),0)
    kubectl create namespace $(KUBE_NAMESPACE)
else
    kubectl describe namespace $(KUBE_NAMESPACE)
endif

我收到错误消息:K_DESC := 0; /bin/sh: 1: K_DESC: not found Makefile:51: recipe for target 'namespace' failed make: *** [namespace] Error 127

不知道还可以尝试什么,试图解决一个问题会困扰另一个问题。

3 个答案:

答案 0 :(得分:1)

如果您真正想做的是有条件地执行命令,则可以执行以下操作:

namespace:
    if ./$(SCRIPT) > /dev/null ; \
  then kubectl describe namespace $(KUBE_NAMESPACE) ; \
  else kubectl create namespace $(KUBE_NAMESPACE); \
  fi

(请注意,“ if”之前的空格是一个制表符;所有其他空格都是空格。并不是必须要使用换行符,我将其放在中间以使配方易于阅读。)

如果您真正想做的是为变量分配一个值,然后在一个食谱中全部分支,则将执行此操作:

namespace9:
    kubectl describe namespace $(KUBE_NAMESPACE) > /dev/null ; \
  K_DESC=$$?; \
  if [ $$K_DESC -eq 0 ] ; \
  then kubectl describe namespace $(KUBE_NAMESPACE) ; \
  else kubectl create namespace $(KUBE_NAMESPACE); \
  fi

答案 1 :(得分:0)

您不能在制作配方正文中进行变量分配。尝试按以下顺序进行操作:

K_DESC := $(shell kubectl describe namespace $(KUBE_NAMESPACE) > /dev/null ; echo $$?)

namespace: ## create the kubernetes namespace
ifneq ($(K_DESC),0)
    kubectl create namespace $(KUBE_NAMESPACE)
else
    kubectl describe namespace $(KUBE_NAMESPACE)
endif

发生“配方在第一个目标之前开始”是因为GNU Make认为这两行实际上是两个规则:

namespace: ## create the kubernetes namespace
K_DESC := $(shell kubectl describe namespace $(KUBE_NAMESPACE) > /dev/null ; echo $$?)

也就是说,它认为您有一个没有构建配方的空规则namespace:,然后是另一个目标为K_DESC的规则。

此外,如果namespace不是实际文件,则应将其标记为伪造目标:

.PHONY: namespace  # somewhere above the namespace: rule

否则,Make实际上正在寻找名为namespace的文件。如果您执行touch namespace,则make namespace将停止工作,因为该文件存在!

答案 2 :(得分:-2)

这里有很多错误:

首先,如果您在命令行上输入K_DESC := blah,则会出现错误K_DESC: not found。这是因为bash在分配中不使用空格-或使用:=(假定K_DESC是程序名称,而:=blah是参数)。接下来,此行设置 shell 变量K_DESC -而不是makefile变量。这意味着ifneq是一个 makefile 构造,它不知道您在shell中设置的值(另外还有一些计时问题,因为ifneq将会是在您的配方运行之前很久就以makefile读取时间运行,因此仍然无济于事。

为此,在运行配方第一行的特定Shell实例中分配了所分配的值。因此,当第一行结束时,该外壳程序退出,并且该变量被忘记(运行第二行的外壳程序实例不知道该变量)。

然后,您要调用$(shell command) -因为只有一个$,所以make将假定它是一个make函数,并在读取时进行扩展。相反,您想做$$(command ...)。 Make将$$转换为$,并将其与您要运行的命令一起传递给Shell实例。

所以...要做您想做的事情,您可能想要做:

namespace:
    K_DESC=$$(kubectl describe namespace $(KUBE_NAMESPACE) > /dev/null ; echo $$?); \
    if [ $$K_DESC == 1 ]; then \
        kubectl create namespace $(KUBE_NAMESPACE) \
    else \
        kubectl describe namespace $(KUBE_NAMESPACE) \
    fi

请注意,我在每行的末尾添加了\,以将它们统一为一个配方行(因此,没有变量脱离上下文)。

或者,更古朴地,您可以这样做:

namespace: 
    @     kubectl describe namespace $(KUBE_NAMESPACE) > /dev/null 2>&1 \
       || kubectl create namespace $(KUBE_NAMESPACE)

注意-> /dev/null 2>&1将阻止第一个命令的任何输出(stdout和stderr)。