Merge pull request #2774 from tk0miya/latex_engine

Add `latex_engine` to switch the LaTeX engine by conf.py
This commit is contained in:
Takeshi KOMIYA
2016-07-21 01:05:51 +09:00
committed by GitHub
10 changed files with 82 additions and 240 deletions

View File

@@ -35,7 +35,6 @@ Features added
--------------
* Add ``:caption:`` option for sphinx.ext.inheritance_diagram.
* #894: Add ``lualatexpdf`` and ``xelatexpdf`` as a make target to build PDF using lualatex or xelatex
* #2471: Add config variable for default doctest flags.
* Convert linkcheck builder to requests for better encoding handling
* #2463, #2516: Add keywords of "meta" directive to search index
@@ -77,7 +76,7 @@ Features added
entries in 3rd party extensions.
* Python domain signature parser now uses the xref mixin for 'exceptions',
allowing exception classes to be autolinked.
* #2513: Add `latex_engine` to switch the LaTeX engine by conf.py
Bugs fixed
----------

View File

@@ -1469,6 +1469,16 @@ Options for LaTeX output
These options influence LaTeX output. See further :doc:`latex`.
.. confval:: latex_engine
The LaTeX engine to build the docs. The setting can have the following
values:
* pdflatex -- PDFLaTeX (default)
* xelatex -- XeLaTeX
* lualatex -- LuaLaTeX
* platex -- pLaTeX (default if `language` is 'ja')
.. confval:: latex_documents
This value determines how to group the document tree into LaTeX source files.

View File

@@ -20,13 +20,14 @@ from docutils.frontend import OptionParser
from sphinx import package_dir, addnodes, highlighting
from sphinx.util import texescape
from sphinx.config import string_classes
from sphinx.config import string_classes, ENUM
from sphinx.errors import SphinxError
from sphinx.locale import _
from sphinx.builders import Builder
from sphinx.environment import NoUri
from sphinx.util.nodes import inline_all_toctrees
from sphinx.util.osutil import SEP, copyfile, make_filename
from sphinx.util.fileutil import copy_asset_file
from sphinx.util.osutil import SEP, make_filename
from sphinx.util.console import bold, darkgreen
from sphinx.writers.latex import LaTeXWriter
@@ -188,35 +189,33 @@ class LaTeXBuilder(Builder):
self.info(bold('copying images...'), nonl=1)
for src, dest in iteritems(self.images):
self.info(' '+src, nonl=1)
copyfile(path.join(self.srcdir, src),
path.join(self.outdir, dest))
copy_asset_file(path.join(self.srcdir, src),
path.join(self.outdir, dest))
self.info()
# copy TeX support files from texinputs
context = {'latex_engine': self.config.latex_engine}
self.info(bold('copying TeX support files...'))
staticdirname = path.join(package_dir, 'texinputs')
for filename in os.listdir(staticdirname):
if not filename.startswith('.'):
copyfile(path.join(staticdirname, filename),
path.join(self.outdir, filename))
copy_asset_file(path.join(staticdirname, filename),
self.outdir, context=context)
# copy additional files
if self.config.latex_additional_files:
self.info(bold('copying additional files...'), nonl=1)
for filename in self.config.latex_additional_files:
self.info(' '+filename, nonl=1)
copyfile(path.join(self.confdir, filename),
path.join(self.outdir, path.basename(filename)))
copy_asset_file(path.join(self.confdir, filename), self.outdir)
self.info()
# the logo is handled differently
if self.config.latex_logo:
logobase = path.basename(self.config.latex_logo)
logotarget = path.join(self.outdir, logobase)
if not path.isfile(path.join(self.confdir, self.config.latex_logo)):
raise SphinxError('logo file %r does not exist' % self.config.latex_logo)
elif not path.isfile(logotarget):
copyfile(path.join(self.confdir, self.config.latex_logo), logotarget)
else:
copy_asset_file(path.join(self.confdir, self.config.latex_logo), self.outdir)
self.info('done')
@@ -264,6 +263,10 @@ def setup(app):
app.add_builder(LaTeXBuilder)
app.connect('builder-inited', validate_config_values)
app.add_config_value('latex_engine',
lambda self: 'pdflatex' if self.language != 'ja' else 'platex',
None,
ENUM('pdflatex', 'xelatex', 'lualatex', 'platex'))
app.add_config_value('latex_documents',
lambda self: [(self.master_doc, make_filename(self.project) + '.tex',
self.project, '', 'manual')],

View File

@@ -41,8 +41,6 @@ BUILDERS = [
("", "latex", "to make LaTeX files, you can set PAPER=a4 or PAPER=letter"),
("posix", "latexpdf", "to make LaTeX files and run them through pdflatex"),
("posix", "latexpdfja", "to make LaTeX files and run them through platex/dvipdfmx"),
("posix", "lualatexpdf", "to make LaTeX files and run them through lualatex"),
("posix", "xelatexpdf", "to make LaTeX files and run them through xelatex"),
("", "text", "to make text files"),
("", "man", "to make manual pages"),
("", "texinfo", "to make Texinfo files"),
@@ -172,18 +170,6 @@ class Make(object):
with cd(self.builddir_join('latex')):
os.system('make all-pdf-ja')
def build_lualatexpdf(self):
if self.run_generic_build('latex') > 0:
return 1
with cd(self.builddir_join('latex')):
os.system('make PDFLATEX=lualatex all-pdf')
def build_xelatexpdf(self):
if self.run_generic_build('latex') > 0:
return 1
with cd(self.builddir_join('latex')):
os.system('make PDFLATEX=xelatex all-pdf')
def build_text(self):
if self.run_generic_build('text') > 0:
return 1

View File

@@ -565,8 +565,6 @@ help:
\t@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
\t@echo " latexpdf to make LaTeX files and run them through pdflatex"
\t@echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
\t@echo " lualatexpdf to make LaTeX files and run them through lualatex"
\t@echo " xelatexpdf to make LaTeX files and run them through xelatex"
\t@echo " text to make text files"
\t@echo " man to make manual pages"
\t@echo " texinfo to make Texinfo files"
@@ -686,20 +684,6 @@ latexpdfja:
\t$(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
\t@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
.PHONY: lualatexpdf
lualatexpdf:
\t$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
\t@echo "Running LaTeX files through lualatex..."
\t$(MAKE) PDFLATEX=lualatex -C $(BUILDDIR)/latex all-pdf
\t@echo "lualatex finished; the PDF files are in $(BUILDDIR)/latex."
.PHONY: xelatexpdf
xelatexpdf:
\t$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
\t@echo "Running LaTeX files through xelatex..."
\t$(MAKE) PDFLATEX=xelatex -C $(BUILDDIR)/latex all-pdf
\t@echo "xelatex finished; the PDF files are in $(BUILDDIR)/latex."
.PHONY: text
text:
\t$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text

View File

@@ -5,7 +5,6 @@
\ifdefined\pdfpxdimen
\let\sphinxpxdimen\pdfpxdimen\else\newdimen\sphinxpxdimen
\fi \sphinxpxdimen=<%= pxunit %>\relax
\usepackage{iftex}
<%= passoptionstopackages %>
<%= inputenc %>
<%= utf8extra %>

View File

@@ -13,11 +13,16 @@ LATEXOPTS =
FMT = pdf
LATEX = latex
PDFLATEX = pdflatex
PDFLATEX = {{ latex_engine }}
MAKEINDEX = makeindex
{% if latex_engine == 'platex' %}
all: all-pdf-ja
all-pdf: all-pdf-ja
{% else %}
all: $(ALLPDF)
all-pdf: $(ALLPDF)
{% endif -%}
all-dvi: $(ALLDVI)
all-ps: $(ALLPS)

View File

@@ -1,97 +0,0 @@
%%
%% This is file `iftex.sty',
%%
%% __________________________________
%% Copyright © 20102013 Persian TeX Group
%%
%% License information appended.
%%
%%
\csname iftexloaded\endcsname
\let\iftexloaded\endinput
\expandafter\ifx\csname ProvidesPackage\endcsname\relax\else
\ProvidesPackage{iftex}
[2013/04/04 v0.2 Provides if(tex) conditional for PDFTeX, XeTeX, and LuaTeX]
\fi
\def\RequirePDFTeX{%
\ifPDFTeX\else
\begingroup
\errorcontextlines=-1\relax
\newlinechar=10\relax
\errmessage{^^J
********************************************^^J
* PDFTeX is required to compile this document.^^J
* Sorry!^^J
********************************************}%
\endgroup
\fi}
\def\RequireXeTeX{%
\ifXeTeX\else
\begingroup
\errorcontextlines=-1\relax
\newlinechar=10\relax
\errmessage{^^J
********************************************^^J
* XeTeX is required to compile this document.^^J
* Sorry!^^J
********************************************}%
\endgroup
\fi}
\def\RequireLuaTeX{%
\ifLuaTeX\else
\begingroup
\errorcontextlines=-1\relax
\newlinechar=10\relax
\errmessage{^^J
********************************************^^J
* LuaTeX is required to compile this document.^^J
* Sorry!^^J
********************************************}%
\endgroup
\fi}
\expandafter\ifx\csname ifPDFTeX\endcsname\relax\else
\expandafter\endinput
\fi
\expandafter\ifx\csname ifXeTeX\endcsname\relax\else
\expandafter\endinput
\fi
\expandafter\ifx\csname ifLuaTeX\endcsname\relax\else
\expandafter\endinput
\fi
\newif\ifPDFTeX
\begingroup\expandafter\expandafter\expandafter\endgroup
\expandafter\ifx\csname pdfmatch\endcsname\relax
\PDFTeXfalse
\else
\PDFTeXtrue
\fi
\newif\ifXeTeX
\begingroup\expandafter\expandafter\expandafter\endgroup
\expandafter\ifx\csname XeTeXinterchartoks\endcsname\relax
\XeTeXfalse
\else
\XeTeXtrue
\fi
\newif\ifLuaTeX
\begingroup\expandafter\expandafter\expandafter\endgroup
\expandafter\ifx\csname directlua\endcsname\relax
\LuaTeXfalse
\else
\LuaTeXtrue
\fi
%%
%% Copyright © 20102013 by Persian TeX Group <persian-tex@tug.org>
%%
%% Distributable under the LaTeX Project Public License,
%% version 1.3c or higher (your choice). The latest version of
%% this license is at: http://www.latex-project.org/lppl.txt
%%
%% This work is "maintained" (as per LPPL maintenance status)
%% by Persian TeX Group.
%%
%%
%%
%%
%%
%% End of file `iftex.sty'.

View File

@@ -265,9 +265,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
'classoptions': '',
'extraclassoptions': '',
'passoptionstopackages': '',
'inputenc': ('\\ifPDFTeX\n'
' \\usepackage[utf8]{inputenc}\n'
'\\fi'),
'inputenc': '',
'utf8extra': ('\\ifdefined\\DeclareUnicodeCharacter\n'
' \\DeclareUnicodeCharacter{00A0}{\\nobreakspace}\n'
'\\fi'),
@@ -358,6 +356,8 @@ class LaTeXTranslator(nodes.NodeVisitor):
else:
docclass = builder.config.latex_docclass.get('manual', 'report')
self.elements['docclass'] = docclass
if builder.config.latex_engine == 'pdflatex':
self.elements['inputenc'] = '\\usepackage[utf8]{inputenc}'
if builder.config.today:
self.elements['date'] = builder.config.today
else:

View File

@@ -12,17 +12,24 @@ from __future__ import print_function
import os
import re
from itertools import product
from subprocess import Popen, PIPE
from six import PY3
from sphinx.errors import SphinxError
from sphinx.util.osutil import cd, ensuredir
from sphinx.writers.latex import LaTeXTranslator
from util import SkipTest, remove_unicode_literals, with_app, strip_escseq
from test_build_html import ENV_WARNINGS
LATEX_ENGINES = ['pdflatex', 'lualatex', 'xelatex']
DOCCLASSES = ['howto', 'manual']
STYLEFILES = ['article.sty', 'fancyhdr.sty', 'fancybox.sty', 'titlesec.sty', 'amsmath.sty',
'framed.sty', 'color.sty', 'fancyvrb.sty', 'threeparttable.sty']
LATEX_WARNINGS = ENV_WARNINGS + """\
%(root)s/index.rst:\\d+: WARNING: unknown option: &option
%(root)s/index.rst:\\d+: WARNING: citation not found: missing
@@ -34,70 +41,58 @@ if PY3:
LATEX_WARNINGS = remove_unicode_literals(LATEX_WARNINGS)
def run_latex(outdir):
"""Run pdflatex, xelatex, and lualatex in the outdir"""
cwd = os.getcwd()
os.chdir(outdir)
# only run latex if all needed packages are there
def kpsetest(*filenames):
try:
latexes = ('pdflatex', 'xelatex', 'lualatex')
available_latexes = len(latexes)
for latex in latexes:
try:
os.mkdir(latex)
p = Popen([latex, '--interaction=nonstopmode',
'-output-directory=%s' % latex, 'SphinxTests.tex'],
stdout=PIPE, stderr=PIPE)
except OSError: # most likely the latex executable was not found
available_latexes -= 1
else:
stdout, stderr = p.communicate()
if p.returncode != 0:
print(stdout)
print(stderr)
assert False, '%s exited with return code %s' % (
latex, p.returncode)
finally:
os.chdir(cwd)
p = Popen(['kpsewhich'] + list(filenames), stdout=PIPE)
except OSError:
# no kpsewhich... either no tex distribution is installed or it is
# a "strange" one -- don't bother running latex
return None
else:
p.communicate()
if p.returncode != 0:
# not found
return False
# found
return True
if available_latexes == 0: # no latex is available, skip the test
raise SkipTest
def test_latex():
if kpsetest(*STYLEFILES) is False:
raise SkipTest('not running latex, the required styles doesn\'t seem to be installed')
for engine, docclass in product(LATEX_ENGINES, DOCCLASSES):
yield build_latex_doc, engine, docclass
@with_app(buildername='latex')
def test_latex(app, status, warning):
def build_latex_doc(app, status, warning, engine, docclass):
app.config.latex_engine = engine
app.config.latex_documents[0] = app.config.latex_documents[0][:4] + (docclass,)
LaTeXTranslator.ignore_missing_images = True
app.builder.build_all()
# file from latex_additional_files
assert (app.outdir / 'svgimg.svg').isfile()
# only run latex if all needed packages are there
def kpsetest(filename):
try:
p = Popen(['kpsewhich', filename], stdout=PIPE)
except OSError:
# no kpsewhich... either no tex distribution is installed or it is
# a "strange" one -- don't bother running latex
return None
else:
p.communicate()
if p.returncode != 0:
# not found
return False
# found
return True
if kpsetest('article.sty') is None:
raise SkipTest('not running latex, it doesn\'t seem to be installed')
for filename in ['fancyhdr.sty', 'fancybox.sty', 'titlesec.sty',
'amsmath.sty', 'framed.sty', 'color.sty', 'fancyvrb.sty',
'threeparttable.sty']:
if not kpsetest(filename):
raise SkipTest('not running latex, the %s package doesn\'t '
'seem to be installed' % filename)
# now, try to run latex over it
run_latex(app.outdir)
with cd(app.outdir):
try:
ensuredir(engine)
p = Popen([engine, '--interaction=nonstopmode',
'-output-directory=%s' % engine, 'SphinxTests.tex'],
stdout=PIPE, stderr=PIPE)
except OSError: # most likely the latex executable was not found
raise SkipTest
else:
stdout, stderr = p.communicate()
if p.returncode != 0:
print(stdout)
print(stderr)
assert False, '%s exited with return code %s' % (
engine, p.returncode)
@with_app(buildername='latex')
@@ -126,48 +121,6 @@ def test_writer(app, status, warning):
'\\end{wrapfigure}' in result)
@with_app(buildername='latex',
confoverrides={'latex_documents': [
('contents', 'SphinxTests.tex', 'Sphinx Tests Documentation',
'Georg Brandl \\and someone else', 'howto'),
]},
srcdir='latex_howto')
def test_latex_howto(app, status, warning):
LaTeXTranslator.ignore_missing_images = True
app.builder.build_all()
# file from latex_additional_files
assert (app.outdir / 'svgimg.svg').isfile()
# only run latex if all needed packages are there
def kpsetest(filename):
try:
p = Popen(['kpsewhich', filename], stdout=PIPE)
except OSError:
# no kpsewhich... either no tex distribution is installed or it is
# a "strange" one -- don't bother running latex
return None
else:
p.communicate()
if p.returncode != 0:
# not found
return False
# found
return True
if kpsetest('article.sty') is None:
raise SkipTest('not running latex, it doesn\'t seem to be installed')
for filename in ['fancyhdr.sty', 'fancybox.sty', 'titlesec.sty',
'amsmath.sty', 'framed.sty', 'color.sty', 'fancyvrb.sty',
'threeparttable.sty']:
if not kpsetest(filename):
raise SkipTest('not running latex, the %s package doesn\'t '
'seem to be installed' % filename)
# now, try to run latex over it
run_latex(app.outdir)
@with_app(buildername='latex', testroot='warnings', freshenv=True)
def test_latex_warnings(app, status, warning):
app.builder.build_all()