如果Makefile中的目标内有条件语句

110
我想设置一个Makefile来搜索和复制一些文件(if-else条件),但我无法确定到底哪里出了问题?(尽管我相当确定是因为空格/制表符的组合写在了错误的地方) 请帮我一下,好吗?
这是我目前拥有的内容:
obj-m = linuxmon.o

KDIR = /lib/modules/$(shell uname -r)/build
UNAME := $(shell uname -m)

all:

    $(info Checking if custom header is needed)
    ifeq ($(UNAME), x86_64)
        $(info Yes)
        F1_EXISTS=$(shell [ -e /usr/include/asm/unistd_32.h ] && echo 1 || echo 0 )
        ifeq ($(F1_EXISTS), 1)
            $(info Copying custom header)
            $(shell sed -e 's/__NR_/__NR32_/g' /usr/include/asm/unistd_32.h > unistd_32.h)
        else    
            F2_EXISTS=$(shell [[ -e /usr/include/asm-i386/unistd.h ]] && echo 1 || echo 0 )
            ifeq ($(F2_EXISTS), 1)
                $(info Copying custom header)
                $(shell sed -e 's/__NR_/__NR32_/g' /usr/include/asm-i386/unistd.h > unistd_32.h)
            else
                $(error asm/unistd_32.h and asm-386/unistd.h does not exist)
            endif
        endif
        $(info No)
    endif

    @make -C $(KDIR) M=$(PWD) modules

clean:
    make -C $(KDIR) M=$(PWD) clean
    rm unistd_32.h

无论如何,这将打印出"Yes" , "Copying header"两次,然后会因为sed无法读取/usr/include/asm-i386/unistd.h而退出程序(当然它无法读取,因为我在一个x64系统上)。 可以说make只是没有理解if/else,而是按照顺序一行行地运行所有内容。

2个回答

212

您可以直接使用Shell命令。如果要抑制输出回显,请使用“@”符号。例如:

clean:
    @if [ "test" = "test" ]; then\
        echo "Hello world";\
    fi

请注意,每行代码末尾的分号;和反斜杠\是必须的。

这是因为make将每行代码解释为单独的命令,除非该行以\结尾。


29
我所需要的问题的简单答案。 - jcubic
1
那个不适用于Windows。答案是使用Make ifeqifneq - s.ouchene
4
@s.ouchene,无论如何都不应该在Windows上使用make。Make是针对Unix和Linux设计的。请使用跨平台构建系统,例如cmake。 - cael ras
@GabrielStaples 在答案中已经提到了。你的建议有点跑题了。 - Omer Dagan
2
@caelras 离题了但需要澄清:Make可能最初在Unix领域开发,但只要你使用兼容Windows的make或者可以运行它的环境,它也可以在Windows上使用。有几种‘make’方言。GNU Make是Unix-like操作系统中最流行的,通常与autotools一起使用。它也可以在Windows下运行,需要进行一些工作,例如在Cygwin下。CMake则完全不同;它是一个不同的构建管理器。在C++世界中很受欢迎,但不仅限于Windows,在类Unix操作系统中也可以使用。 - PRouleau
显示剩余2条评论

98

这里有几个问题,所以我将从我的通常的高层建议开始:从小和简单开始,逐渐增加复杂性,在每一步测试,并且不要添加到不起作用的代码。 (我真的应该把它设置为热键。)

你正在混合使用 Make 语法和 shell 语法,这种方式令人眩晕。你永远不应该让它变得如此庞大而没有进行测试。让我们从外部向内部工作。

UNAME := $(shell uname -m)

all:
    $(info Checking if custom header is needed)
    ifeq ($(UNAME), x86_64)
    ... do some things to build unistd_32.h
    endif

    @make -C $(KDIR) M=$(PWD) modules

所以您想在调用第二个make之前构建unistd_32.h(可能),您可以将其设置为先决条件。并且,由于您只想在某些情况下这样做,因此可以将其放在条件语句中:

ifeq ($(UNAME), x86_64)
all: unistd_32.h
endif

all:
    @make -C $(KDIR) M=$(PWD) modules

unistd_32.h:
    ... do some things to build unistd_32.h

现在开始构建unistd_32.h

F1_EXISTS=$(shell [ -e /usr/include/asm/unistd_32.h ] && echo 1 || echo 0 )
ifeq ($(F1_EXISTS), 1)
    $(info Copying custom header)
    $(shell sed -e 's/__NR_/__NR32_/g' /usr/include/asm/unistd_32.h > unistd_32.h)
else    
    F2_EXISTS=$(shell [[ -e /usr/include/asm-i386/unistd.h ]] && echo 1 || echo 0 )
    ifeq ($(F2_EXISTS), 1)
        $(info Copying custom header)
        $(shell sed -e 's/__NR_/__NR32_/g' /usr/include/asm-i386/unistd.h > unistd_32.h)
    else
        $(error asm/unistd_32.h and asm-386/unistd.h does not exist)
    endif
endif

你正在尝试从unistd_32.h构建unistd.h;唯一的技巧是,unistd_32.h可能在两个位置之一。最简单的清理方法是使用vpath指令:
vpath unistd.h /usr/include/asm /usr/include/asm-i386

unistd_32.h: unistd.h
    sed -e 's/__NR_/__NR32_/g' $< > $@

谢谢,但这里缺少两个if语句。这将由make自动完成吗? - alexandernst
是的。如果这两个头文件都不存在,Make 将会抱怨它不知道如何构建 unistd_32.h - Beta
1
好的,这真的让它更简单了。只有一件事,我能打印错误消息而不是让make抱怨不知道如何构建它吗? - alexandernst
哦,我刚试了一下,但是不起作用。这是我的代码:http://pastebin.com/cHP7ZL26,但它说第14行缺少分隔符。 - alexandernst
谢谢您的澄清 :) 但是我有个坏消息,现在我又遇到了另一个错误:http://pastebin.com/8FDYk83q - alexandernst
显示剩余6条评论

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