Makefile:一次只编译一半目标

时间:2013-06-26 18:50:32

标签: makefile pdflatex

我正在使用gnu make编译LaTeX文档。我过去已经做了很多,但现在我需要以两种不同的格式编译文档,一种用于易于阅读,即用于分发,一种用于简单修改。作为我正在做的事情的背景,我在我的LaTeX文件中实现了LaTeX conditional expression。以下是该文件的示例。

% TheTexFile.tex
% This accepts makefile definitions
%   \isTwoColumn
%   \isDoubleSpaced
\ifdefined\isTwoColumn
    \documentclass[letterpaper, twocolumn]{article}
\else
    \documentclass[letterpaper]{article}
\fi
%\documentclass[letterpaper]{article}
\ifdefined\isDoubleSpaced
  \usepackage{setspace}
  \doublespacing
\fi

\begin{document}
  Some document text for a document that should be able to be compiled using
  two different methods.  There seems to be a problem though, but OP thinks
  that it is in the makefile not in the LaTeX since it can be compiled using
  both methods by issuing the same commands that are in the makefile directly
  enter code here`from the command line.
\end{document}

我可以使用不同的make目标来编译这些,但是我总是发送旧版本,因为我只编译其中一个,通常是易读的,大多数人需要查看其他版本,即提出修订建议。我已按照Makefile: two targets from the same sources compiled twice with different flags问题的建议,但我希望尽可能避免使用子目录。考虑到这一点,我想出了以下makefile。

# The makefile

# The targets
OBJS=TheTexFile.pdf

# The different build methods
DBL_SPACE_PREFIX=DBL_SPACE_
TWO_COL_PREFIX=TWO_COL_
DBL_SPACE_OBJS=$(addprefix $(DBL_SPACE_PREFIX), $(OBJS))
TWO_COL_OBJS=$(addprefix $(TWO_COL_PREFIX), $(OBJS))

# A variable for defining the job information (output files)
JOBNAME=$(shell echo $@ | sed 's/\.pdf//')

all: $(TWO_COL_OBJS) $(DBL_SPACE_OBJS) clean

$(DBL_SPACE_PREFIX)%.pdf: TEXDEF=\def\isDoubleSpaced{1}
$(TWO_COL_PREFIX)%.pdf: TEXDEF=\def\isTwoColumn{1}

$(DBL_SPACE_PREFIX)%.pdf $(TWO_COL_PREFIX)%.pdf: %.tex

    pdflatex -jobname=$(JOBNAME) -shell-escape --enable-write18 "$(TEXDEF) \input{$<}"
    pdflatex -jobname=$(JOBNAME) -shell-escape --enable-write18 "$(TEXDEF) \input{$<}"
    bibtex $(JOBNAME)
    pdflatex -jobname=$(JOBNAME) -shell-escape --enable-write18 "$(TEXDEF) \input{$<}"
    pdflatex -jobname=$(JOBNAME) -shell-escape --enable-write18 "$(TEXDEF) \input{$<}"

.PHONY: clean
clean:
    # Get rid of pdflatex files
    rm *.aux *.bbl *.blg *.log *.nav *.out *.snm *.toc

.PHONY: cleanall
cleanall:
    rm $(DBL_SPACE_OBJS) $(TWO_COL_OBJS)

这几乎完美无缺。当我确保删除所有目标时发出问题,即发出命令make cleanmake cleanall,然后发出make。第一次,只编译TWO_COL_OBJS。如果我单独留下所有目标并重新发出命令,则编译DBL_SPACE_OBJS。现在我已经编译了所有对象,但是我必须发出两次相同的命令,这是我想要避免的。

同样,如果我在all中反转目标对象,即

all: $(TWO_COL_OBJS) $(DBL_SPACE_OBJS) clean

变为

all: $(DBL_SPACE_OBJS) $(TWO_COL_OBJS) clean

我将第一次获得所有DBL_SPACE_OBJS而第二次获得TWO_COL_OBJS。我错过了什么?

1 个答案:

答案 0 :(得分:2)

首先,您真的不希望clean规则成为all规则的先决条件,是吗?

无论如何,你不能这样做。具有多个目标的模式规则意味着该规则仅在ONCE上运行。它运行一次,当它运行时,它将构建一个主要目标,其余的目标构建是副作用。仅针对特定于目标的模式变量检查主目标,因此TEXDEF值将仅设置为其中一个值,这就是您只获得一个输出的原因。即使它确实会针对特定于目标的模式变量检查所有不同的目标,您如何期望make知道对于其中一个命令您想要一个值而另一个命令您想要一个不同的值?如果你考虑一下,这是不可能的。

相反,您必须制作两个不同的模式规则,一个用于构建每种类型的输出。你应该写这个(注意你不再需要JOBNAME,但即使你这样做,你也不需要使用shell来删除后缀......):

$(DBL_SPACE_PREFIX)%.pdf: %.tex
        pdflatex -jobname=$@ -shell-escape --enable-write18 "$(TEXDEF) \input{$<}"
        bibtex $@
        pdflatex -jobname=$@ -shell-escape --enable-write18 "$(TEXDEF) \input{$<}"

$(TWO_COL_PREFIX)%.pdf: %.tex
        pdflatex -jobname=$@ -shell-escape --enable-write18 "$(TEXDEF) \input{$<}"
        bibtex $@
        pdflatex -jobname=$@ -shell-escape --enable-write18 "$(TEXDEF) \input{$<}"

如果你想要将这些更多组合起来,你可以将配方放入变量中,并在两个规则中使用它。