【问题标题】:Make says file is up to date, but it does not existMake 说文件是最新的,但它不存在
【发布时间】:2018-11-18 08:45:02
【问题描述】:

我想要

我正在尝试编译一些包含 python 代码 sn-ps 和这些 sn-ps 输出的乳胶。我需要始终使用 sn-ps 及其输出中所做的最后更改来更新文档,因此我的想法是维护一个可以监视此更改并生成更新输出的 makefile。

所以如果我修改文件a/11.py,我希望make 执行它以生成新的输出a/11.out

我有

这是我的makefile

DOC=myPdf
STY=st
PY_DIR=a/
TEX=pdflatex -shell-escape -interaction=batchmode -file-line-error

$(DOC).pdf: $(PY_DIR)11.out $(PY_DIR)12.out $(DOC).tex $(STY).sty
    $(TEX) $(DOC).tex

$(PY_DIR)11.out:
    $(cd PY_DIR && python3 11.py > 11.out)

$(PY_DIR)12.out:
    $(cd PY_DIR && python3 12.py > 12.out)

.PHONY: clean
clean:
    rm *.aux *.log > /dev/null 2>&1

我想知道

即使文件a/11.out 不存在,而我指示make a/11.out make 说:make: 'a/11.out' is up to date.(我还在学习make,所以我可能有更多错误)。

我看到了

感谢您的宝贵时间:)


更新

这是我的新版本,基于 Renaud 的回答(感谢您的帮助),一些 python 脚本旨在输出文本(xxxt.py),而另一些则用于绘制图像(xxxi.py),所以有他们没有重定向:

DOC    :=myPdf
STY    :=st
PY_DIR :=a/
TEX    :=pdflatex -shell-escape -interaction=batchmode -file-line-error
PYS    := $(wildcard $(PY_DIR)*.py)
OUTS   := $(patsubst %.py,%.out,$(PYS))
.PHONY: all clean

all: $(DOC).pdf

%.pdf: %.tex $(STY).sty $(OUTS)
    $(TEX) $<

$(PY_DIR)%.out: $(PY_DIR)%t.py
    cd $(PY_DIR) && python3 $*t.py > $*.out

$(PY_DIR)%.png: $(PY_DIR)%i.py
    cd $(PY_DIR) && python3 $*i.py

clean:
    rm *.aux *.log > /dev/null 2>&1

目录如下所示:

./st.sty
./myPdf.tex
./myPdf.pdf
./a/11t.py
./a/11.out
./a/12i.py
./a/12.png
./a/21t.py
./a/...

但是,现在在修改 myPdf.tex 之后,make 会说 make: Nothing to be done for 'all'.

我做错了什么?

【问题讨论】:

    标签: makefile gnu-make


    【解决方案1】:

    你的食谱是错误的。 Make 在将它们传递给 shell 之前扩展配方。由于没有名为 cd PY_DIR &amp;&amp; python3 11.py &gt; 11.out 的 make 变量,$(cd PY_DIR &amp;&amp; python3 11.py &gt; 11.out) 扩展为空字符串,并且 make 认为对于 $(PY_DIR)11.out 没有什么可做的。只需将您的食谱编写为纯 shell(并使用未扩展的 PY_DIR 修复其他错误):

    $(PY_DIR)11.out:
        cd $(PY_DIR) && python3 11.py > 11.out
    
    $(PY_DIR)12.out:
        cd $(PY_DIR) && python3 12.py > 12.out
    

    注意:如果你想在你的 python 脚本更改时重新运行配方,你应该让他知道输出文件依赖于 python 脚本。最好的方法可能是使用pattern rule 而不是每个文件一个特定的规则:

    $(PY_DIR)%.out: $(PY_DIR)%.py
        cd $(PY_DIR) && python3 $*.py > $*.out
    

    $* 是一个make automatic variable,它作为模式的主干扩展)。

    更多改进:

    • 您可以要求 make 单独查找 python 脚本,计算输出文件的名称并将所有这些存储在您可以在其他规则中使用的 make 变量中。
    • 您可以为xx.tex -&gt; xx.pdf 进程使用模式规则。并为其使用另一个 make 自动变量:$&lt; 作为第一个先决条件扩展。
    DOC    := myPdf
    STY    := st
    PY_DIR := a/
    TEX    := pdflatex -shell-escape -interaction=batchmode -file-line-error
    
    PYS    := $(wildcard $(PY_DIR)*.py)
    OUTS   := $(patsubst %.py,%.out,$(PYS))
    
    .PRECIOUS: $(OUTS)
    .PHONY: all clean
    
    all: $(DOC).pdf
    
    %.pdf: %.tex $(OUTS) $(STY).sty
        $(TEX) $<
    
    $(PY_DIR)%.out: $(PY_DIR)%.py
        cd $(PY_DIR) && python3 $*.py > $*.out
    
    .PHONY: clean
    clean:
        rm *.aux *.log > /dev/null 2>&1
    

    注意:我将$(OUTS) 声明为precious,这样make 在构建$(DOC).pdf 时不会删除它们。

    更新xx.outxx.png生产使用新规范和分离的python脚本:

    DOC    := myPdf
    STY    := st
    PY_DIR := a
    TEX    := pdflatex -shell-escape -interaction=batchmode -file-line-error
    PYTS   := $(wildcard $(PY_DIR)/*t.py)
    PYIS   := $(wildcard $(PY_DIR)/*i.py)
    OUTS   := $(patsubst $(PY_DIR)/%t.py,$(PY_DIR)/%.out,$(PYTS))
    PNGS   := $(patsubst $(PY_DIR)/%i.py,$(PY_DIR)/%.png,$(PYIS))
    
    .PRECIOUS: $(OUTS) $(PNGS)
    .PHONY: all clean
    
    all: $(DOC).pdf
    
    %.pdf: %.tex $(STY).sty $(OUTS) $(PNGS)
        $(TEX) $<
    
    $(PY_DIR)/%.out: $(PY_DIR)/%t.py
        cd $(PY_DIR) && python3 $*t.py > $*.out
    
    $(PY_DIR)/%.png: $(PY_DIR)/%i.py
        cd $(PY_DIR) && python3 $*i.py
    
    clean:
        rm -f *.aux *.log > /dev/null 2>&1
    

    注意事项:

    • 我稍微修改了PY_DIR 的定义,这样在Makefile 的其他部分使用时,很明显它是一个目录路径。我猜只是口味问题。
    • 我将-f 选项添加到您的clean 配方中,这样即使要删除的文件不存在,它也不会失败。

    更新

    正如MadScientist 在评论中所指出的,使用$* 不如引用目标 ($@) 和先决条件 ($&lt;) 通用。但是由于我们不是直接对它们进行操作,而是对它们的目录 ($(PY_DIR)) 和基本文件名 (xx[it].py, xx.out, xx.png) 进行操作,因此从 $* 切换到其他更通用的自动变量是没那么简单。

    但是 make 还有一些技巧可以在这里提供帮助:$@$&lt;... 具有扩展为仅目录部分或文件部分的变体($(@F)$(@D)...)。请注意,根据GNU make manual

    这些变体在 GNU make 中是半过时的,因为函数 dirnotdir 可以用来获得类似的效果。

    无论如何,如果我们想避免使用$*,我们可以使用以下方法:

    $(PY_DIR)/%.out: $(PY_DIR)/%t.py
        cd $(@D) && python3 $(<F) > $(@F)
    
    $(PY_DIR)/%.png: $(PY_DIR)/%i.py
        cd $(@D) && python3 $(<F)
    

    或者(现代版):

    $(PY_DIR)/%.out: $(PY_DIR)/%t.py
        cd $(dir $@) && python3 $(notdir $<) > $(notdir $@)
    
    $(PY_DIR)/%.png: $(PY_DIR)/%i.py
        cd $(dir $@) && python3 $(notdir $<)
    

    【讨论】:

    • 你不应该使用$*.out作为要生成的文件。您必须始终准确地使用$@ 作为要生成的文件,否则您的makefile 将无法正常工作(除非碰巧$*.out$@ 是同一个东西,在这种情况下它们不是)。跨度>
    • 你考虑过cd $(PY_DIR) &amp;&amp; ...吗?我认为$@ 不会在这里工作。当然,我很高兴能学到一些关于 make 的新知识。不,我们不能真正从顶层目录调用 python:python 对调用它的位置(模块路径等)很挑剔。我们需要这个cd $(PY_DIR) &amp;&amp; ... 的东西。
    • 哇,我需要一些时间来消化这个,我现在试试,我会告诉你它是怎么回事,非常感谢你的解释。
    • 我不明白 $(OUTS) 的第一个改进。现在 make 说nothing to be done for 'all'。即使我修改了.tex 文件
    • 您确定您删除了所有其他 pdf 构建规则并仅保留模式规则吗?您没有忘记删除旧的$(DOC).pdf: 规则吗?无论如何,您的新 Makefile 存在一些新问题。让我更新一下答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-13
    • 1970-01-01
    • 2014-03-14
    • 2015-07-23
    • 2020-10-06
    相关资源
    最近更新 更多