diff options
author | Steven Knight <knight@baldmt.com> | 2005-11-07 03:44:30 (GMT) |
---|---|---|
committer | Steven Knight <knight@baldmt.com> | 2005-11-07 03:44:30 (GMT) |
commit | bb6479932a423a2a06fcc6ae8ea25f807f260170 (patch) | |
tree | 57c19a423016e8fdddbb3b697eaacfd81d24063c | |
parent | e2f5354d117a41c5fe8895b5011e9d4b74ab8701 (diff) | |
download | SCons-bb6479932a423a2a06fcc6ae8ea25f807f260170.zip SCons-bb6479932a423a2a06fcc6ae8ea25f807f260170.tar.gz SCons-bb6479932a423a2a06fcc6ae8ea25f807f260170.tar.bz2 |
Make all relevant builders of .tex and .ltx files consistent with respect to handling generating bibliographies and re-running LaTeX to resolve undefined references. (Joel B. Mohler) Add a $LATEXRETRIES to configure the number of undefined reference re-runs.
-rw-r--r-- | doc/man/scons.1 | 9 | ||||
-rw-r--r-- | src/CHANGES.txt | 14 | ||||
-rw-r--r-- | src/engine/SCons/Tool/latex.py | 19 | ||||
-rw-r--r-- | src/engine/SCons/Tool/latex.xml | 12 | ||||
-rw-r--r-- | src/engine/SCons/Tool/pdflatex.py | 11 | ||||
-rw-r--r-- | src/engine/SCons/Tool/pdftex.py | 33 | ||||
-rw-r--r-- | src/engine/SCons/Tool/tex.py | 61 | ||||
-rw-r--r-- | test/TEX/multi-run.py | 109 |
8 files changed, 232 insertions, 36 deletions
diff --git a/doc/man/scons.1 b/doc/man/scons.1 index 5249f75..46ad813 100644 --- a/doc/man/scons.1 +++ b/doc/man/scons.1 @@ -6202,6 +6202,15 @@ env = Environment(LATEXCOMSTR = "Building $TARGET from LaTeX input $SOURCES") .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 diff --git a/src/CHANGES.txt b/src/CHANGES.txt index 4e8e377..cdf7e91 100644 --- a/src/CHANGES.txt +++ b/src/CHANGES.txt @@ -375,6 +375,9 @@ RELEASE 0.97 - XXX - 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. @@ -437,6 +440,13 @@ RELEASE 0.97 - XXX 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 @@ -739,10 +749,6 @@ RELEASE 0.97 - XXX 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. diff --git a/src/engine/SCons/Tool/latex.py b/src/engine/SCons/Tool/latex.py index 7f16681..45150aa 100644 --- a/src/engine/SCons/Tool/latex.py +++ b/src/engine/SCons/Tool/latex.py @@ -38,9 +38,15 @@ import SCons.Defaults 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.""" @@ -49,13 +55,14 @@ def generate(env): 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') diff --git a/src/engine/SCons/Tool/latex.xml b/src/engine/SCons/Tool/latex.xml index 58a4df5..b8b1bb3 100644 --- a/src/engine/SCons/Tool/latex.xml +++ b/src/engine/SCons/Tool/latex.xml @@ -35,6 +35,18 @@ General options passed to the LaTeX structured formatter and typesetter. </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 diff --git a/src/engine/SCons/Tool/pdflatex.py b/src/engine/SCons/Tool/pdflatex.py index 3af09ed..ce3ba67 100644 --- a/src/engine/SCons/Tool/pdflatex.py +++ b/src/engine/SCons/Tool/pdflatex.py @@ -36,9 +36,15 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" 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: @@ -47,12 +53,13 @@ def generate(env): 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') diff --git a/src/engine/SCons/Tool/pdftex.py b/src/engine/SCons/Tool/pdftex.py index 92a622a..6606f0d 100644 --- a/src/engine/SCons/Tool/pdftex.py +++ b/src/engine/SCons/Tool/pdftex.py @@ -36,9 +36,30 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" 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: @@ -47,11 +68,21 @@ def generate(env): 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') diff --git a/src/engine/SCons/Tool/tex.py b/src/engine/SCons/Tool/tex.py index 40a8211..b444f76 100644 --- a/src/engine/SCons/Tool/tex.py +++ b/src/engine/SCons/Tool/tex.py @@ -43,7 +43,7 @@ import SCons.Node 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") @@ -57,34 +57,50 @@ BibTeXAction = SCons.Action.Action("$BIBTEXCOM", "$BIBTEXCOMSTR") # 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): @@ -105,8 +121,7 @@ def TeXLaTeXFunction(target = None, source= None, env=None): 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.""" @@ -115,7 +130,7 @@ def generate(env): except KeyError: bld = SCons.Defaults.DVI() env['BUILDERS']['DVI'] = bld - + bld.add_action('.tex', TeXLaTeXAction) env['TEX'] = 'tex' @@ -123,9 +138,10 @@ def generate(env): 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('') @@ -135,6 +151,5 @@ def generate(env): env['MAKEINDEXFLAGS'] = SCons.Util.CLVar('') env['MAKEINDEXCOM'] = '$MAKEINDEX $MAKEINDEXFLAGS $SOURCES' - def exists(env): return env.Detect('tex') diff --git a/test/TEX/multi-run.py b/test/TEX/multi-run.py new file mode 100644 index 0000000..f827ac9 --- /dev/null +++ b/test/TEX/multi-run.py @@ -0,0 +1,109 @@ +#!/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() |