tl; dr:我想从同一规则构建base.ext
和base_variant.ext
。
我经常有一个Makefile可以构建一些目标的变种,默认版本开始类似base.ext
和变体例如base_variant.ext
。这些是从相同(一组)来源构建的,只有一些小差异。这些规则可能非常复杂,我真的不想重复它们。
随着岁月的流逝,我逐渐变得更加烦恼,因为我不能使用下面的Makefile之类的东西:
options = ...
%_variant.ext: options += ....
base%.ext: sources
command $^ $(options) > $@
对于Makefile的不同用途,这是一个真正回归的模式。它可以用于构建可执行文件,这可能类似于:
SRC=$(wildcard *.c)
%_instr.o:%.c
$(CC) -some-instrumentation-flags $^ -o $@
# Ideally I would like this rule to build foo from implicit-rules binaries,
# and foo_instr from the objects generated by the rule above
foo%:$(SRC:.c=%.o)
$(CC) $^ -o $@
在提供MCVE的过程中,这里有一个带有beamer演示的示例,其中beamer.pdf
是基线版本,beamer_notes.pdf
在第二个屏幕上有#34;注释"已启用,beamer_handout.pdf
是一个更密集的版本,页面更少:
% beamer.tex
\documentclass[ignorenonframetext,pdfusetitle,17pt]{beamer}
\usepackage{pgfpages}
\mode<handout:0>{\setbeameroption{show notes on second screen=right}}
\mode<handout:1>{\setbeameroption{hide notes}}
\title{some talk} \author{some author}
\begin{document}
\begin{frame}{Hello world}
\maketitle
\end{frame}
\end{document}
# Makefile
SRC=beamer.tex
options:=
default:$(SRC:.tex=.pdf)
handout:$(SRC:.tex=_handout.pdf)
handout:options:=handout
notes:$(SRC:.tex=_notes.pdf)
notes:options:=notes
$(SRC:.tex=%.pdf):$(SRC)
pdflatex -jobname="$(@:.pdf=)" '\PassOptionsToClass{$(options)}{beamer}\input{$<}'
# here a bunch more rules potentially to deal with bibliographies etc
.PHONY:default handout notes
现在这个Makefile并不像我想的那样工作:
$ make
make: *** No rule to make target 'beamer.pdf', needed by 'default'. Stop.
但make handout
和make notes
按预期工作。是否有任何方式使这项工作?
到目前为止,我发现了3种不完美的方式:
将最终规则更改为%: $(SRC)
,但只要在Makefile中有多个规则就会变得一团糟
拥有默认目标版本beamer_.pdf
(通常会开始生活在一个所有默认目标都有一个带有尾随下划线的愚蠢base_.ext
名称的世界中)
beamer_.pdf
的规则并将其移至beamer.pdf
:beamer_.pdf: beamer.pdf
mv $< $@
beamer_.pdf
始终会重建,即使beamer.pdf
比其来源更新。我已尝试制作beamer_.pdf
PHONY,但无济于事。是否有其他人遇到此问题并找到了令人满意的解决方案?
答案 0 :(得分:1)
对于3.82之前的make
版本,有一个相当简单的解决方案:
# Makefile
SRC=beamer.tex
default: $(SRC:.tex=.pdf)
handout: $(SRC:.tex=_handout.pdf)
notes: $(SRC:.tex=_notes.pdf)
$(SRC:.tex=.pdf) $(SRC:.tex=_%.pdf) : $(SRC)
pdflatex -jobname="$(@:.pdf=)" '\PassOptionsToClass{$*}{beamer}\input{$<}
.PHONY:default handout notes
也就是说,您可以为两个目标规范使用相同的源和规则,非模式规范(显式规则)和模式规则(隐式规则)。它曾经工作过。不幸的是,在3.82版本中不推荐使用此语法。
然而,在版本4.1中,它再次被接受,尽管有警告。
来自资源中的文件NEWS
:
- 更改混合显式和隐式规则的致命错误,即 在GNU中引入3.82,给出了一个非致命的错误。但是,这种语法 仍然被弃用,并可能在未来的版本中返回非法 GNU make。应修复依赖此语法的Makefile。
事实上,linux内核源代码中的许多makefile仍在使用它,而且可能是。 (阅读用于混合显式和隐式规则的宽松约束 here以获取更多信息。)
截至当前版本4.2,它仍然有效,并带有警告。但是,它不是一个永久的解决方案,因为它可能会再次消失。
评论中已经提到的罐头食谱是要走的路。请注意,$*
的处理方式不同:当在隐式规则的配方中使用时,它会扩展到词干的值(匹配%
的字符串),而在明确规则的配方中,它是空的或,如果目标以“已知”后缀结束,则会扩展到没有后缀的目标。
# Makefile
SRC=beamer.tex
define my_rules
pdflatex -jobname="$(@:.pdf=)" '\PassOptionsToClass{$*}{beamer}\input{$<}
# Other complicated rules...
endef
default: $(SRC:.tex=.pdf)
handout: $(SRC:.tex=_handout.pdf)
notes: $(SRC:.tex=_notes.pdf)
$(SRC:.tex=.pdf) : $(SRC)
$(my_rules)
$(SRC:.tex=_%.pdf) : $(SRC)
$(my_rules)
.PHONY:default handout notes