如何编写Makefile规则以仅在文件存在时删除文件(干净)?

时间:2015-11-07 11:00:49

标签: makefile

在我看来,Makefile规则可以粗略地分为“正面”和“负面”规则:“正面”规则创建缺失或更新过时文件,而“负面”规则删除文件。

编写“肯定”规则的先决条件非常简单:如果目标和先决条件是文件名,默认情况下make会在目标丢失或过时时运行配方(在此上下文中可能缺少文件)被视为无限旧文件。)

但是,请考虑“否定”规则,例如目标clean。写它的通常方法似乎是这样的:

clean:
    rm -f *.log *.synctex.gz *.aux *.out *.toc

这显然不是最好的方法:

    即使没有任何事情可以执行
  1. rm

  2. 需要使用-f标志来抑制其错误消息和退出状态,该标志具有其他(可能不合需要的)效果,并且

  3. 与目标clean无关的事实不会向用户报告,这与“正面”目标的正常情况不同。

  4. 我的问题是:如何编写一个Makefile规则,只有在某些文件存在时才由make处理? (就像对make clean有用的那样。)

3 个答案:

答案 0 :(得分:3)

  

如何编写Makefile规则,只有在某些文件存在时才由make处理? (就像清洁一样有用。)

你可以这样做:

filenames := a b c

files := $(strip $(foreach f,$(filenames),$(wildcard $(f))))

all: $(filenames)

$(filenames):
    touch $@

clean:
ifneq ($(files),)
    rm -f $(files)
endif

示例会话:

$ make
touch a
touch b
touch c
$ make clean
rm -f a b c
$ make clean
make: Nothing to be done for 'clean'.

可能出于某些目的而有用,但它对我来说是make clean的紧张改进。

答案 1 :(得分:2)

这很容易解决:

clean:
    for file in *.log *.synctex.gz *.aux *.out *.toc; do \
        if [ -e "$file" ]; then \
            rm "$$file" || exit 1; \
        else \
            printf 'No such file: %s\n' "$file" \
        fi \
    done

除非您的shell支持并已启用nullglob或类似内容,否则if语句是必需的。

如果您的printf支持%q,则应使用该%s代替AGPBI: {"kind":"simple","text":"Uncaught translation error: com.android.dex.util.ExceptionWithContext","sources":[{}]} AGPBI: {"kind":"simple","text":"1 error; aborting","sources":[{}]} ,以避免在打印奇怪的文件名时可能损坏您的终端。

答案 2 :(得分:-1)

一个元答案是:你确定要这样做吗?

其他答案告诉我,治愈方法比疾病更糟糕,因为一个涉及到POSIX make(ifneq)的扩展,另一个使用扩展到七行的复合命令。这两者有时都是必要的权宜之计 - 我不是批评任何一个答案 - 但如果可以的话,这两件事都是我在Makefile中避免的事情。如果我发现自己想要在clean规则中执行此操作,也许是因为您在对@MikeKinghans的回答中提及的原因,我会非常努力地更改Makefile的其余部分以避免需要它。

依次反思你的三个原点:

  1. rm即使无所事事也会被执行:那又怎样?例如,替代方案仍然需要扩展*.log *.synctex.gz ...,因此避免rm只能获得极小的效率提升。 Make是一种高级工具,通常不关心效率。

  2. 需要使用-f标志来抑制其错误消息和退出状态:-f标志通常不会抑制错误和退出状态,它仅表示rm不认为不存在或未经许可的文件是错误。

  3. 没有任何关于目标清理的事实没有报告给用户:用户真的应该关心吗?

  4. 最后一点是最有趣的。人们在Stackoverflow和其他地方询问make,有时通过尝试将其用作过程语言来使自己变得困难 - make不是Python或Fortran。相反,它是一个目标编程语言(如果我们想要了解它):你编写规则片段来实现子目标,以便用户(你,后来)不必关心细节或目录的当前状态,但可以简单地指出目标,程序会做任何必要的事情来实现目标。因此,无论是否有任何事情要做,用户都不应该“关心”。

    我认为这个答案的简短版本是:保持make规则尽可能简单(因此可读性和健壮性)是惯用的,即使是以一点点粗暴或重复为代价。