Makefile:使用@ if,eval:variable在运行时重新定义变量总是取最后一个eval的值

时间:2015-10-29 11:46:36

标签: makefile

所以我试图破解我的一个makefile变得更简单(更简单,好像没有定义很多规则如何将子目录转换为.deb)。

build-if-need-status-vars:
    @if [ ! -f debs/1.deb ]; then \
            $(eval STATUS_REBUILD=1) \
            echo "component: file not found: 1"; exit;\
        else \
            if [ $(shell find sources/ -newer debs/1.deb 2>/dev/null | wc -l) -gt 0 ]; then \
                $(eval STATUS_REBUILD=1) echo "component: newer files exists: 1"; exit;\
            else \
                $(eval STATUS_REBUILD=0) echo "component: no newer files: 0"; \
            fi;\
    fi
    @echo "status $(STATUS_REBUILD)"


actual-target: build-if-need-status-vars
ifeq ($(STATUS_REBUILD), 1)
    @echo first status: 1
else
    @echo second status: 0
    @echo different action
endif

all: actual-target
.PHONY: actual-target   

测试: mkdir -p test/{sources,debs}; touch test/debs/1.deb; sleep 2; touch test/sources/1.src;(在那里创建makefile并运行)

结果:

  

组件:找不到文件:1

     

状态0

     

第二个状态:0

无论执行什么条件块,STATUS_REBUILD将始终为0(最后评估值),请尝试:touch test / debs / 1.deb

所以似乎总是使用最后一个$(eval)..如何避免这种行为并保持正确的赋值(从build-if-need-status-var中的第一个匹配)?

1 个答案:

答案 0 :(得分:2)

$(eval)是一个制作级功能。在配方扩展阶段的配方中,它会在您的配方中进行扩展。

在makefile解析的第二阶段(在手册here中简要讨论)中扩展了配方的内容。

我相信,但不能肯定地说(没有测试),食谱在它们即将运行之前不会扩展(但是为了这里的目的,不会改变任何方式)。

所以你的问题是所有 $(eval)调用在make运行你的shell脚本时被扩展,所以你总是看到最后一行有效的最后一个值运行

所有人都说你实际上并不需要需要一个make-level变量。你的食谱只有两个shell执行。

您可以在与第一行(拆分)相同的执行中包含最后一行,并使用shell变量。

build-if-need-status-vars:
    @if [ ! -f debs/1.deb ]; then \
        STATUS_REBUILD=1; \
        echo "component: file not found"; \
    else \
        if [ $(shell find sources/ -newer debs/1.deb 2>/dev/null | wc -l) -gt 0 ]; then \
            STATUS_REBUILD=1; echo "component: newer files exists"; \
        else \
            STATUS_REBUILD=0; echo "component: no newer files"; \
        fi;\
    fi; \
    echo "status $$STATUS_REBUILD"

请注意,我需要移除exit件才能使其正常工作。如果真正的makefile中有必要(因为这是一个精简的样本),那么你可以通过将if包装在子shell中和/或重写配方来保留它们。