1

我正在使用 gnu make 编译 LaTeX 文档。我过去做过很多这样的工作,但现在我需要以两种不同的格式编译文档,一种是为了便于阅读,即用于分发,另一种是为了便于修改。作为我正在做的事情的背景,我在我的 LaTeX 文件中实现了LaTeX 条件表达式。这是该文件的示例。

% 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 问题的建议:来自相同来源的两个目标使用不同的标志编译了两次,但我希望尽可能避免使用子目录。考虑到这一点,我提出了以下生成文件。

# 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 cleanand make 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。我错过了什么?

4

1 回答 1

2

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

无论如何,你不能这样做。具有多个目标的模式规则意味着该规则仅运行一次。它运行一次,当它运行时,它将构建一个主要目标,而构建的其余目标是副作用。仅针对特定于目标的模式变量检查主要目标,因此 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{$<}"

如果您想更多地组合这些,您可以将配方放入一个变量中,然后在两个规则中使用它。

于 2013-06-26T22:00:03.897 回答