.IP LATEXFLAGS
General options passed to the LaTeX structured formatter and typesetter.
+.IP LATEXRETRIES
+The maximum number of times that LaTeX
+will be re-run if the
+.B .log
+generated by the $LATEXCOM command
+indicates that there are undefined references.
+The default is to try to resolve undefined references
+by re-running LaTeX up to three times.
+
.IP LATEXSUFFIXES
The list of suffixes of files that will be scanned
for LaTeX implicit dependencies
- Document the --debug=explain option in the man page. (How did we
miss this?)
+ - Add a $LATEXRETRIES variable to allow configuration of the number of
+ times LaTex can be re-called to try to resolve undefined references.
+
From Chen Lee:
- Handle Visual Studio project and solution files in Unicode.
BCC compiler; some versions apparently require that the file name
argument be concatenated with the option.
+ From Joel B. Mohler:
+
+ - Extend latex.py, pdflatex.py, pdftex.py and tex.py so that building
+ from both TeX and LaTeX files uses the same logic to call $BIBTEX
+ when it's necessary, to call $MAKEINDEX when it's necessary, and to
+ call $TEX or $LATEX multiple times to handle undefined references.
+
From Elliot Murphy:
- Enhance the tests to guarantee persistence of ListOption
external environment, or settable internally) to put a shortened
SCons execution line in the Visual Studio project file.
- - Don't throw an exception if the configuration changes and a stored
- implicit dependency now has a different type (File or Dir) than it
- did last time.
-
From Greg Ward:
- Fix a misplaced line in the man page.
import SCons.Scanner.LaTeX
import SCons.Util
import SCons.Tool
+import SCons.Tool.tex
LaTeXAction = SCons.Action.Action('$LATEXCOM', '$LATEXCOMSTR')
+def LaTeXAuxFunction(target = None, source= None, env=None):
+ SCons.Tool.tex.InternalLaTeXAuxAction( LaTeXAction, target, source, env )
+
+LaTeXAuxAction = SCons.Action.Action(LaTeXAuxFunction, strfunction=None)
+
def generate(env):
"""Add Builders and construction variables for LaTeX to an Environment."""
except KeyError:
bld = SCons.Defaults.DVI()
env['BUILDERS']['DVI'] = bld
-
- for suffix in SCons.Tool.LaTeXSuffixes:
- bld.add_action(suffix, LaTeXAction)
- env['LATEX'] = 'latex'
- env['LATEXFLAGS'] = SCons.Util.CLVar('')
- env['LATEXCOM'] = '$LATEX $LATEXFLAGS $SOURCES'
+ bld.add_action('.ltx', LaTeXAuxAction)
+ bld.add_action('.latex', LaTeXAuxAction)
+
+ env['LATEX'] = 'latex'
+ env['LATEXFLAGS'] = SCons.Util.CLVar('')
+ env['LATEXCOM'] = '$LATEX $LATEXFLAGS $SOURCES'
+ env['LATEXRETRIES'] = 3
def exists(env):
return env.Detect('latex')
</summary>
</cvar>
+<cvar name="LATEXRETRIES">
+<summary>
+The maximum number of times that LaTeX
+will be re-run if the
+<filename>.log</filename>
+generated by the &cv-LATEXCOM; command
+indicates that there are undefined references.
+The default is to try to resolve undefined references
+by re-running LaTeX up to three times.
+</summary>
+</cvar>
+
<cvar name="TEXINPUTS">
<summary>
List of directories that the LaTeX programm will search
import SCons.Action
import SCons.Defaults
import SCons.Util
+import SCons.Tool.tex
PDFLaTeXAction = SCons.Action.Action('$PDFLATEXCOM', '$PDFLATEXCOMSTR')
+def PDFLaTeXAuxFunction(target = None, source= None, env=None):
+ SCons.Tool.tex.InternalLaTeXAuxAction( PDFLaTeXAction, target, source, env )
+
+PDFLaTeXAuxAction = SCons.Action.Action(PDFLaTeXAuxFunction, strfunction=None)
+
def generate(env):
"""Add Builders and construction variables for pdflatex to an Environment."""
try:
bld = SCons.Defaults.PDF()
env['BUILDERS']['PDF'] = bld
- bld.add_action('.ltx', PDFLaTeXAction)
- bld.add_action('.latex', PDFLaTeXAction)
+ bld.add_action('.ltx', PDFLaTeXAuxAction)
+ bld.add_action('.latex', PDFLaTeXAuxAction)
env['PDFLATEX'] = 'pdflatex'
env['PDFLATEXFLAGS'] = SCons.Util.CLVar('')
env['PDFLATEXCOM'] = '$PDFLATEX $PDFLATEXFLAGS $SOURCE'
+ env['LATEXRETRIES'] = 3
def exists(env):
return env.Detect('pdflatex')
import SCons.Action
import SCons.Defaults
import SCons.Util
+import SCons.Tool.tex
PDFTeXAction = SCons.Action.Action('$PDFTEXCOM', '$PDFTEXCOMSTR')
+# Define an action to build a latex file. This action might be needed more
+# than once if we are dealing with labels and bibtex
+PDFLaTeXAction = SCons.Action.Action("$PDFLATEXCOM", "$PDFLATEXCOMSTR")
+
+def PDFLaTeXAuxAction(target = None, source= None, env=None):
+ SCons.Tool.tex.InternalLaTeXAuxAction( PDFLaTeXAction, target, source, env )
+
+def PDFTeXLaTeXFunction(target = None, source= None, env=None):
+ """A builder for TeX and LaTeX that scans the source file to
+ decide the "flavor" of the source and then executes the appropriate
+ program."""
+ if SCons.Tool.tex.is_LaTeX(source):
+ PDFLaTeXAuxAction(target,source,env)
+ else:
+ PDFTeXAction(target,source,env)
+ return 0
+
+PDFTeXLaTeXAction = SCons.Action.Action(PDFTeXLaTeXFunction,
+ strfunction=None)
+
def generate(env):
"""Add Builders and construction variables for pdftex to an Environment."""
try:
bld = SCons.Defaults.PDF()
env['BUILDERS']['PDF'] = bld
- bld.add_action('.tex', PDFTeXAction)
+ bld.add_action('.tex', PDFTeXLaTeXAction)
env['PDFTEX'] = 'pdftex'
env['PDFTEXFLAGS'] = SCons.Util.CLVar('')
env['PDFTEXCOM'] = '$PDFTEX $PDFTEXFLAGS $SOURCE'
+ # Duplicate from latex.py. If latex.py goes away, then this is still OK.
+ env['PDFLATEX'] = 'pdflatex'
+ env['PDFLATEXFLAGS'] = SCons.Util.CLVar('')
+ env['PDFLATEXCOM'] = '$PDFLATEX $PDFLATEXFLAGS $SOURCES'
+ env['LATEXRETRIES'] = 3
+
+ env['BIBTEX'] = 'bibtex'
+ env['BIBTEXFLAGS'] = SCons.Util.CLVar('')
+ env['BIBTEXCOM'] = '$BIBTEX $BIBTEXFLAGS $SOURCES'
+
def exists(env):
return env.Detect('pdftex')
import SCons.Node.FS
import SCons.Util
-# Define an action to build a generic tex file. This is sufficient for all
+# Define an action to build a generic tex file. This is sufficient for all
# tex files.
TeXAction = SCons.Action.Action("$TEXCOM", "$TEXCOMSTR")
# Define an action to run MakeIndex on a file.
MakeIndexAction = SCons.Action.Action("$MAKEINDEXCOM", "$MAKEINDEXOMSTR")
-def LaTeXAuxAction(target = None, source= None, env=None):
+def InternalLaTeXAuxAction(XXXLaTeXAction, target = None, source= None, env=None):
"""A builder for LaTeX files that checks the output in the aux file
and decides how many times to use LaTeXAction, and BibTeXAction."""
# Get the base name of the target
basename, ext = os.path.splitext(str(target[0]))
+
# Run LaTeX once to generate a new aux file.
- LaTeXAction(target,source,env)
- # Now if bibtex will need to be run.
- content = open(basename + ".aux","rb").read()
- if string.find(content, "bibdata") != -1:
- bibfile = env.fs.File(basename)
- BibTeXAction(None,bibfile,env)
- # Now if makeindex will need to be run.
- idxfilename = basename + ".idx"
+ XXXLaTeXAction(target,source,env)
+
+ # Decide if various things need to be run, or run again. We check
+ # for the existence of files before opening them--even ones like the
+ # aux file that TeX always creates--to make it possible to write tests
+ # with stubs that don't necessarily generate all of the same files.
+
+ # Now decide if bibtex will need to be run.
+ auxfilename = basename + '.aux'
+ if os.path.exists(auxfilename):
+ content = open(auxfilename, "rb").read()
+ if string.find(content, "bibdata") != -1:
+ bibfile = env.fs.File(basename)
+ BibTeXAction(None,bibfile,env)
+
+ # Now decide if makeindex will need to be run.
+ idxfilename = basename + '.idx'
if os.path.exists(idxfilename):
idxfile = env.fs.File(basename)
# TODO: if ( idxfile has changed) ...
MakeIndexAction(None,idxfile,env)
LaTeXAction(target,source,env)
-
- # Now check if latex needs to be run yet again.
- for trial in range(3):
- content = open(basename + ".log","rb").read()
- if not re.search("^LaTeX Warning:.*Rerun",content,re.MULTILINE):
+
+ # Now decide if latex needs to be run yet again.
+ logfilename = basename + '.log'
+ for trial in range(int(env.subst('$LATEXRETRIES'))):
+ if not os.path.exists(logfilename):
break
- LaTeXAction(target,source,env)
+ content = open(logfilename, "rb").read()
+ if not re.search("^LaTeX Warning:.*Rerun",content,re.MULTILINE) and not re.search("^LaTeX Warning:.*undefined references",content,re.MULTILINE):
+ break
+ XXXLaTeXAction(target,source,env)
return 0
+def LaTeXAuxAction(target = None, source= None, env=None):
+ InternalLaTeXAuxAction( LaTeXAction, target, source, env )
+
LaTeX_re = re.compile("\\\\document(style|class)")
def is_LaTeX(flist):
TeXAction(target,source,env)
return 0
-TeXLaTeXAction = SCons.Action.Action(TeXLaTeXFunction,
- strfunction=None)
+TeXLaTeXAction = SCons.Action.Action(TeXLaTeXFunction, strfunction=None)
def generate(env):
"""Add Builders and construction variables for TeX to an Environment."""
except KeyError:
bld = SCons.Defaults.DVI()
env['BUILDERS']['DVI'] = bld
-
+
bld.add_action('.tex', TeXLaTeXAction)
env['TEX'] = 'tex'
env['TEXCOM'] = '$TEX $TEXFLAGS $SOURCE'
# Duplicate from latex.py. If latex.py goes away, then this is still OK.
- env['LATEX'] = 'latex'
- env['LATEXFLAGS'] = SCons.Util.CLVar('')
- env['LATEXCOM'] = '$LATEX $LATEXFLAGS $SOURCE'
+ env['LATEX'] = 'latex'
+ env['LATEXFLAGS'] = SCons.Util.CLVar('')
+ env['LATEXCOM'] = '$LATEX $LATEXFLAGS $SOURCE'
+ env['LATEXRETRIES'] = 3
env['BIBTEX'] = 'bibtex'
env['BIBTEXFLAGS'] = SCons.Util.CLVar('')
env['MAKEINDEXFLAGS'] = SCons.Util.CLVar('')
env['MAKEINDEXCOM'] = '$MAKEINDEX $MAKEINDEXFLAGS $SOURCES'
-
def exists(env):
return env.Detect('tex')
--- /dev/null
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Validate that both .tex and .ltx files can handle a LaTeX-style
+bibliography (by calling $BIBTEX to generate a .bbl file) and
+correctly re-run to resolve undefined references.
+"""
+
+import string
+
+import TestSCons
+
+test = TestSCons.TestSCons()
+
+tex = test.where_is('tex')
+latex = test.where_is('latex')
+
+if not tex and not latex:
+ test.skip_test("Could not find tex or latex; skipping test(s).\n")
+
+test.subdir('work1', 'work2')
+
+
+input_file = r"""
+\documentclass{article}
+
+\begin{document}
+As stated in \cite{X}, this is a bug-a-boo.
+\bibliography{fooref}
+\bibliographystyle{plain}
+\end{document}
+"""
+
+bibfile = r"""
+@Article{X,
+ author = "Mr. X",
+ title = "A determination of bug-a-boo-ness",
+ journal = "Journal of B.a.B.",
+ year = 1920,
+ volume = 62,
+ pages = 291
+}
+"""
+
+if tex:
+
+ test.write(['work1', 'SConstruct'], """\
+DVI( "foo.tex" )
+PDF( "foo.tex" )
+""")
+
+ test.write(['work1', 'foo.tex'], input_file)
+ test.write(['work1', 'fooref.bib'], bibfile)
+
+ test.run(chdir = 'work1', arguments = '.')
+
+ test.must_exist(['work1', 'foo.bbl'])
+
+ foo_log = test.read(['work1', 'foo.log'])
+ if string.find(foo_log, 'undefined references') != -1:
+ print 'foo.log contains "undefined references":'
+ print foo_log
+ test.fail_test(1)
+
+if latex:
+
+ test.write(['work2', 'SConstruct'], """\
+DVI( "foo.ltx" )
+PDF( "foo.ltx" )
+""")
+
+ test.write(['work2', 'foo.ltx'], input_file)
+ test.write(['work2', 'fooref.bib'], bibfile)
+
+ test.run(chdir = 'work2', arguments = '.')
+
+ test.must_exist(['work2', 'foo.bbl'])
+
+ foo_log = test.read(['work2', 'foo.log'])
+ if string.find(foo_log, 'undefined references') != -1:
+ print 'foo.log contains "undefined references":'
+ print foo_log
+ test.fail_test(1)
+
+test.pass_test()