我正在尝试编译一些包含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,所以我可能有更多的错误)。
$(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'.
我在做什么错了?
答案 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,它会随着模式的茎而扩展)。
更多改进:
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.out
和xx.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].py
,xx.out
,xx.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)