Make说文件是最新的,但不存在

时间:2018-11-18 08:45:02

标签: makefile gnu-make

我想要

我正在尝试编译一些包含python代码片段和这些片段输出的乳胶。我需要始终使用片段及其输出中所做的最后更改来更新文档,因此该想法是维护一个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),而其他python脚本则用于绘制图像(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: Nothing to be done for 'all'.

我在做什么错了?

1 个答案:

答案 0 :(得分:1)

您的食谱有误。在将配方传递到外壳之前,Make将其展开。由于没有名为cd PY_DIR && python3 11.py > 11.out的make变量,因此$(cd PY_DIR && python3 11.py > 11.out)会扩展为空字符串,并且make认为与$(PY_DIR)11.out无关。只需将您的食谱写为普通外壳即可(并使用未展开的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 -> xx.pdf流程中使用模式规则。并为其使用另一个make自动变量:$<,它会首先扩展。
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,这样在完成$(DOC).pdf的构建时,make不会删除它们。

更新,其中包含用于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在评论中指出的那样,使用$*的通用性要比引用目标($@)和先决条件($<)小。但是由于我们不是直接对它们进行操作,而是对其目录($(PY_DIR))和基本文件名(xx[it].pyxx.outxx.png)进行操作,因此从{{1} }到其他更通用的自动变量并不是那么简单。

make可以使用更多技巧来帮助您:$*$@ ...具有变体($<$(@F) ...)目录部分或文件部分。请注意,根据GNU make manual

  

由于函数$(@D),这些变体在GNU make中已经过时。   和dir可以达到类似的效果。

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

$*

或(现代版本):

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

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