在makefile中使用条件规则

21

我将Makefile的意图用伪代码表示,然后指出我遇到的问题。我正在寻找一个在测试环境中更加用户友好的Makefile。正确使用Makefile的方法如下之一。

    make CATEGORY=parser TEST=basic.
    make ALL

如果用户按照下面指示的方式“仅仅”提供命令,那么它应该打印一条消息,显示“分类已定义,测试未定义”,反之亦然。

    make CATEGORY=parser
    make TEST=basic

我尝试用以下方式编写Makefile,但它出现了错误:

    help:
        echo"Usage: make CATEGORY=<advanced|basic> TEST=<test-case>
        echo"       make ALL

    ifdef CATEGORY
        ifdef TEST
            CATEGORY_TEST_DEFINED = 1
        else
             echo "TEST not defined"
    else
        echo "CATEGORY not defined"
    endif



    ifeq ($(CATEGORY_TEST_DEFINED), 1)
    $(CATEGORY):
        cd $(PROJ)/$(CATEGORY)
        make -f test.mk $(TEST)
    endif

    ifdef ALL
    $(ALL):
         for i in `ls`
         cd $$(i)
         make all
    endif

我有以下几个问题:

  1. Makefile中的规则是否可以选择性地使用(使用ifdef来选择规则和目标)。

  2. echo命令无法工作。echo应该能够帮助用户正确使用。


跟随@Beta的观点,您应该查看FAQ,尤其是 如何在这里提问? 部分。 - Jonathan Leffler
3个回答

28

问题在于echo属于shell;Make可以将其作为命令传递给shell,但Make无法执行它。使用info代替:

ifdef CATEGORY
$(info CATEGORY defined)
else
$(info CATEGORY undefined)
endif
如果你想使规则具有条件性:
ifdef CATEGORY
ifdef TEST
$(CATEGORY):
    whatever
else
$(info TEST not defined)
else
$(info CATEGORY not defined)
endif

感谢您的输入。如果Make无法执行shell命令,那么我见过一些Makefile文件中会有(这里难以对齐)例如,hello: (换行,缩进一个Tab)@echo "你好"。make hello 的输出将会是 -> 你好 - Mike
@Mike:是的,在那种情况下,echo 是在 hello 规则中的一个命令。当你运行“make hello”时,Make会将该命令发送到shell。如果你想这样做,你必须将“未定义”消息与某个目标相关联,这似乎很凌乱。 - Beta

9
这里最大的问题是所有ifdef/ifndef/ifeq/...语句必须在列0,否则会导致错误。与缩进问题相比,回显是一个较小的问题。

3

这些语句有些含糊不清:

help:
    echo"Usage: make CATEGORY=<advanced|basic> TEST=<test-case>
    echo"       make ALL

echo和字符串之间需要一个空格,并且字符串需要被终止:

help:
    echo "Usage: make CATEGORY=<advanced|basic> TEST=<test-case>"
    echo "       make ALL"

这几行内容有问题:

ifdef CATEGORY
    ifdef TEST
        CATEGORY_TEST_DEFINED = 1
    else
         echo "TEST not defined"
else
    echo "CATEGORY not defined"
endif

在第二个 else 之前,肯定需要一个 endif,即使它在语法上不是必需的,我也建议使用。
ifdef CATEGORY
    ifdef TEST
        CATEGORY_TEST_DEFINED = 1
    else
         echo "TEST not defined"
    endif
else
    echo "CATEGORY not defined"
endif

此外,make 仅在处理目标(规则)时执行命令,例如 echo。它不会在此处执行 echo,而只是反对您在没有将其定义为目标操作的情况下定义命令。尽管 GNU Make 在 makefile 中添加了许多功能,但 makefile 中的语言是声明性语言而不是过程性语言。
另一种处理方法是为宏定义默认值:
CATEGORY = advanced
TEST     = all

定义一些合理的默认值;如果用户需要,可以覆盖这些默认值。你可以采用以下规则:

${CATEGORY}/${TEST}: ...dependencies...
    ...actions...

你可以将help作为第一条规则。我有一些目录,其中第一条规则是:
null:
    @echo "You must specify a target with this makefile!"

这与您拥有的内容相同(除了make在运行命令之前不会回显该命令,因此我只能看到消息而不是回显命令行和消息; 这就是@的作用)。 来源于此的 makefile 还具有一个规则all,通常是最明智的第一个(默认)规则。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接