无法使带有变量的Makefile工作

无法使带有变量的Makefile工作,makefile,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)

我有一个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
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在第一个目标之前开始。停下来

如果我这样做:

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
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:未找到 Makefile:51:目标“命名空间”的配方失败 make:**[namespace]错误127


不知道还能尝试什么,试图解决一个问题会弄乱另一个问题。

这里有很多错误:

首先,如果在命令行中键入K_DESC:=blah,则会出现错误K_DESC:notfound。这是因为bash在赋值中不使用空格,或者使用:=它假定K_DESC是一个程序名,并且:=和blah是参数。接下来,此行设置shell变量K_DESC-而不是makefile变量。这意味着ifneq是一个makefile构造,它不知道您在shell中设置的值,而且还存在一些计时问题,因为ifneq将在makefile读取时运行,在您的配方运行之前很久,所以它对您没有任何帮助

此外,在运行配方第一行的特定shell实例中指定了分配的值。因此,当第一行结束时,该shell退出,并且该变量被遗忘,运行第二行的shell实例不知道该变量

然后,调用$shell命令-因为只有一个$,make将假定它是make函数,并在读取时展开它。而是要执行$$命令。。。。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。

不能在make recipe主体中执行变量赋值。尝试以下顺序:

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 $$?)
也就是说,它认为您有一个空的规则命名空间:没有构建配方,后跟另一个目标为K_DESC的规则

此外,如果名称空间不是实际文件,则应将其标记为虚假目标:

.PHONY: namespace  # somewhere above the namespace: rule

否则Make实际上是在寻找一个名为namespace的文件。如果触摸名称空间,则makenamespace将停止工作,因为文件存在

如果您真正想做的是有条件地执行一个命令,这将完成:

namespace:
    if ./$(SCRIPT) > /dev/null ; \
  then kubectl describe namespace $(KUBE_NAMESPACE) ; \
  else kubectl create namespace $(KUBE_NAMESPACE); \
  fi
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
请注意,if前面的空白是一个制表符;所有其他空格都是空格。而且断行并不是绝对必要的,我把它们放进去是为了让食谱可读


如果您真正想做的是给变量赋值,然后在其上分支,所有这些都在一个配方中,那么这将完成:

namespace:
    if ./$(SCRIPT) > /dev/null ; \
  then kubectl describe namespace $(KUBE_NAMESPACE) ; \
  else kubectl create namespace $(KUBE_NAMESPACE); \
  fi
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

为什么要通过K_DESC:=$shell。。。到壳里去?它是一种代码;shell只会抱怨语法。对不起,我的错。这些天,我使用多种语言/脚本编程,语法混乱。你好。这并不能解决我的问题。K_DESC变量中的命令在Makefile中运行良好。问题真的是,我描述的东西。最后您提出的解决方案非常优雅,但不幸的是,kubectl在名称空间不存在时会输出错误消息,因此无法工作。您描述的命令将在makefile的主上下文中工作,但如果放入目标的配方中,则会将其解释为shell脚本,在这种情况下,您不能使用空格或:=来表示。。。忽略了one-bash只喜欢=。所以你想做什么-你想在make-read时间或者在调用配方时运行它吗?我认为你需要更清楚地描述你想做什么。。。您希望在调用目标时,代码作为配方的一部分运行,还是在读取makefile时,代码作为makefile的一部分运行?Makefile配方是shell脚本,在这种情况下,您需要用shell语法重写代码。如果您试图在make首次读取文件时在make上下文中执行此操作,那么将其与目标关联到底要做什么?请记住,使用此解决方案,K_DESC将在makefile读取时设置,而不是在调用namespace:target时设置。如果您有可能影响kubectl…输出的任何其他配方,那么即使在命名空间目标之前运行,它们也不会反映在K_DESC中。@HardcoreHenry我不打算在这里尝试解决真正的问题;将某些Kubernetes命名空间的生成视为Makefile目标。我假设这只是一个小工具,能够使名称空间成为make提供的常见反模式
通过目标词汇表创建命令语言。make认为前两行都是规则并不是真的。它将第一行解析为规则namespace:,然后是下一行,该行是变量赋值K_DESC:=。。。。但是,不能混合使用makerecipe行和变量赋值。一旦make看到目标后的第一个非配方行,则rcipe结束,不能再向其添加更多配方行。当然,您的解决方案是正确的:在规则开始之前将变量赋值移动到。我不明白这里的$SCRIPT变量是什么。让它与第二个示例一起使用。必须添加2>&1/dev/null 2>&1才能删除错误消息。@jbssm:抱歉!我对$SCRIPT的编辑很粗心。我在测试中使用它作为kubectl descripe namespace$KUBE_namespace的替代,但忘了调回。但结局好的一切都好。