Issue 2332 (preparation): refactor print statements so we can
[scons.git] / src / engine / SCons / Tool / tex.py
index 72d925bbdd436d56d6172cd7f2a2f48685cb8b5e..3a84d21631f03a67e719975d68735710f5cd470c 100644 (file)
@@ -1,6 +1,7 @@
 """SCons.Tool.tex
 
 Tool-specific initialization for TeX.
+Generates .dvi files from .tex files
 
 There normally shouldn't be any need to import this module directly.
 It will usually be imported through the generic SCons.Tool.Tool()
@@ -35,13 +36,14 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
 
 import os.path
 import re
-import string
 import shutil
+import sys
 
 import SCons.Action
 import SCons.Node
 import SCons.Node.FS
 import SCons.Util
+import SCons.Scanner.LaTeX
 
 Verbose = False
 
@@ -51,14 +53,14 @@ must_rerun_latex = True
 check_suffixes = ['.toc', '.lof', '.lot', '.out', '.nav', '.snm']
 
 # these are files that require bibtex or makeindex to be run when they change
-all_suffixes = check_suffixes + ['.bbl', '.idx', '.nlo', '.glo']
+all_suffixes = check_suffixes + ['.bbl', '.idx', '.nlo', '.glo', '.acn']
 
 #
 # regular expressions used to search for Latex features
 # or outputs that require rerunning latex
 #
-# search for all .aux files opened by latex (recorded in the .log file)
-openout_aux_re = re.compile(r"\\openout.*`(.*\.aux)'")
+# search for all .aux files opened by latex (recorded in the .fls file)
+openout_aux_re = re.compile(r"INPUT *(.*\.aux)")
 
 #printindex_re = re.compile(r"^[^%]*\\printindex", re.MULTILINE)
 #printnomenclature_re = re.compile(r"^[^%]*\\printnomenclature", re.MULTILINE)
@@ -78,18 +80,31 @@ undefined_references_re = re.compile(undefined_references_str, re.MULTILINE)
 
 # used by the emitter
 auxfile_re = re.compile(r".", re.MULTILINE)
-tableofcontents_re = re.compile(r"^[^%]*\\tableofcontents", re.MULTILINE)
-makeindex_re = re.compile(r"^[^%]*\\makeindex", re.MULTILINE)
-bibliography_re = re.compile(r"^[^%]*\\bibliography", re.MULTILINE)
-listoffigures_re = re.compile(r"^[^%]*\\listoffigures", re.MULTILINE)
-listoftables_re = re.compile(r"^[^%]*\\listoftables", re.MULTILINE)
-hyperref_re = re.compile(r"^[^%]*\\usepackage.*\{hyperref\}", re.MULTILINE)
-makenomenclature_re = re.compile(r"^[^%]*\\makenomenclature", re.MULTILINE)
-makeglossary_re = re.compile(r"^[^%]*\\makeglossary", re.MULTILINE)
-beamer_re = re.compile(r"^[^%]*\\documentclass\{beamer\}", re.MULTILINE)
+tableofcontents_re = re.compile(r"^[^%\n]*\\tableofcontents", re.MULTILINE)
+makeindex_re = re.compile(r"^[^%\n]*\\makeindex", re.MULTILINE)
+bibliography_re = re.compile(r"^[^%\n]*\\bibliography", re.MULTILINE)
+listoffigures_re = re.compile(r"^[^%\n]*\\listoffigures", re.MULTILINE)
+listoftables_re = re.compile(r"^[^%\n]*\\listoftables", re.MULTILINE)
+hyperref_re = re.compile(r"^[^%\n]*\\usepackage.*\{hyperref\}", re.MULTILINE)
+makenomenclature_re = re.compile(r"^[^%\n]*\\makenomenclature", re.MULTILINE)
+makeglossary_re = re.compile(r"^[^%\n]*\\makeglossary", re.MULTILINE)
+makeglossaries_re = re.compile(r"^[^%\n]*\\makeglossaries", re.MULTILINE)
+makeacronyms_re = re.compile(r"^[^%\n]*\\makeglossaries", re.MULTILINE)
+beamer_re = re.compile(r"^[^%\n]*\\documentclass\{beamer\}", re.MULTILINE)
+
+# search to find all files included by Latex
+include_re = re.compile(r'^[^%\n]*\\(?:include|input){([^}]*)}', re.MULTILINE)
+includeOnly_re = re.compile(r'^[^%\n]*\\(?:include){([^}]*)}', re.MULTILINE)
+
+# search to find all graphics files included by Latex
+includegraphics_re = re.compile(r'^[^%\n]*\\(?:includegraphics(?:\[[^\]]+\])?){([^}]*)}', re.MULTILINE)
 
 # search to find all files opened by Latex (recorded in .log file)
-openout_re = re.compile(r"\\openout.*`(.*)'")
+openout_re = re.compile(r"OUTPUT *(.*)")
+
+# list of graphics file extensions for TeX and LaTeX
+TexGraphics   = SCons.Scanner.LaTeX.TexGraphics
+LatexGraphics = SCons.Scanner.LaTeX.LatexGraphics
 
 # An Action sufficient to build any generic tex file.
 TeXAction = None
@@ -110,40 +125,53 @@ MakeNclAction = None
 # An action to run MakeIndex (for glossary) on a file.
 MakeGlossaryAction = None
 
+# An action to run MakeIndex (for acronyms) on a file.
+MakeAcronymsAction = None
+
 # Used as a return value of modify_env_var if the variable is not set.
-class _Null:
-    pass
-_null = _Null
-
-# The user specifies the paths in env[variable], similar to other builders.
-# They may be relative and must be converted to absolute, as expected
-# by LaTeX and Co. The environment may already have some paths in
-# env['ENV'][var]. These paths are honored, but the env[var] paths have
-# higher precedence. All changes are un-done on exit.
-def modify_env_var(env, var, abspath):
-    try:
-        save = env['ENV'][var]
-    except KeyError:
-        save = _null
-    env.PrependENVPath(var, abspath)
-    try:
-        if SCons.Util.is_List(env[var]):
-            #FUTURE env.PrependENVPath(var, [os.path.abspath(str(p)) for p in env[var]])
-            env.PrependENVPath(var, map(lambda p: os.path.abspath(str(p)), env[var]))
+_null = SCons.Scanner.LaTeX._null
+
+modify_env_var = SCons.Scanner.LaTeX.modify_env_var
+
+def check_file_error_message(utility, filename='log'):
+    msg = '%s returned an error, check the %s file\n' % (utility, filename)
+    sys.stdout.write(msg)
+
+def FindFile(name,suffixes,paths,env,requireExt=False):
+    if requireExt:
+        name,ext = SCons.Util.splitext(name)
+        # if the user gave an extension use it.
+        if ext:
+            name = name + ext
+    if Verbose:
+        print " searching for '%s' with extensions: " % name,suffixes
+
+    for path in paths:
+        testName = os.path.join(path,name)
+        if Verbose:
+            print " look for '%s'" % testName
+        if os.path.exists(testName):
+            if Verbose:
+                print " found '%s'" % testName
+            return env.fs.File(testName)
         else:
-            # Split at os.pathsep to convert into absolute path
-            #FUTURE env.PrependENVPath(var, [os.path.abspath(p) for p in str(env[var]).split(os.pathsep)])
-            env.PrependENVPath(var, map(lambda p: os.path.abspath(p), str(env[var]).split(os.pathsep)))
-    except KeyError:
-        pass
-    # Convert into a string explicitly to append ":" (without which it won't search system
-    # paths as well). The problem is that env.AppendENVPath(var, ":")
-    # does not work, refuses to append ":" (os.pathsep).
-    if SCons.Util.is_List(env['ENV'][var]):
-        env['ENV'][var] = os.pathsep.join(env['ENV'][var])
-    # Append the trailing os.pathsep character here to catch the case with no env[var]
-    env['ENV'][var] = env['ENV'][var] + os.pathsep
-    return save
+            name_ext = SCons.Util.splitext(testName)[1]
+            if name_ext:
+                continue
+
+            # if no suffix try adding those passed in
+            for suffix in suffixes:
+                testNameExt = testName + suffix
+                if Verbose:
+                    print " look for '%s'" % testNameExt
+
+                if os.path.exists(testNameExt):
+                    if Verbose:
+                        print " found '%s'" % testNameExt
+                    return env.fs.File(testNameExt)
+    if Verbose:
+        print " did not find '%s'" % name
+    return None
 
 def InternalLaTeXAuxAction(XXXLaTeXAction, target = None, source= None, env=None):
     """A builder for LaTeX files that checks the output in the aux file
@@ -164,6 +192,7 @@ def InternalLaTeXAuxAction(XXXLaTeXAction, target = None, source= None, env=None
     basedir = os.path.split(str(source[0]))[0]
     basefile = os.path.split(str(basename))[1]
     abspath = os.path.abspath(basedir)
+
     targetext = os.path.splitext(str(target[0]))[1]
     targetdir = os.path.split(str(target[0]))[0]
 
@@ -184,10 +213,12 @@ def InternalLaTeXAuxAction(XXXLaTeXAction, target = None, source= None, env=None
     # we have to run makeindex at least once to keep the build
     # happy even if there is no index.
     # Same for glossaries and nomenclature
-    src_content = source[0].get_contents()
+    src_content = source[0].get_text_contents()
     run_makeindex = makeindex_re.search(src_content) and not os.path.exists(targetbase + '.idx')
     run_nomenclature = makenomenclature_re.search(src_content) and not os.path.exists(targetbase + '.nlo')
     run_glossary = makeglossary_re.search(src_content) and not os.path.exists(targetbase + '.glo')
+    run_glossaries = makeglossaries_re.search(src_content) and not os.path.exists(targetbase + '.glo')
+    run_acronyms = makeacronyms_re.search(src_content) and not os.path.exists(targetbase + '.acn')
 
     saved_hashes = {}
     suffix_nodes = {}
@@ -205,7 +236,8 @@ def InternalLaTeXAuxAction(XXXLaTeXAction, target = None, source= None, env=None
     #
     # routine to update MD5 hash and compare
     #
-    def check_MD5(filenode, suffix):
+    # TODO(1.5):  nested scopes
+    def check_MD5(filenode, suffix, saved_hashes=saved_hashes, targetbase=targetbase):
         global must_rerun_latex
         # two calls to clear old csig
         filenode.clear_memoized_values()
@@ -237,13 +269,22 @@ def InternalLaTeXAuxAction(XXXLaTeXAction, target = None, source= None, env=None
         must_rerun_latex = False
         # Decide if various things need to be run, or run again.
 
-        # Read the log file to find all .aux files
+        # Read the log file to find warnings/errors
         logfilename = targetbase + '.log'
         logContent = ''
-        auxfiles = []
         if os.path.exists(logfilename):
             logContent = open(logfilename, "rb").read()
-            auxfiles = openout_aux_re.findall(logContent)
+
+
+        # Read the fls file to find all .aux files
+        flsfilename = targetbase + '.fls'
+        flsContent = ''
+        auxfiles = []
+        if os.path.exists(flsfilename):
+            flsContent = open(flsfilename, "rb").read()
+            auxfiles = openout_aux_re.findall(flsContent)
+        if Verbose:
+            print "auxfiles ",auxfiles
 
         # Now decide if bibtex will need to be run.
         # The information that bibtex reads from the .aux file is
@@ -255,12 +296,13 @@ def InternalLaTeXAuxAction(XXXLaTeXAction, target = None, source= None, env=None
                 target_aux = os.path.join(targetdir, auxfilename)
                 if os.path.exists(target_aux):
                     content = open(target_aux, "rb").read()
-                    if string.find(content, "bibdata") != -1:
+                    if content.find("bibdata") != -1:
                         if Verbose:
                             print "Need to run bibtex"
                         bibfile = env.fs.File(targetbase)
                         result = BibTeXAction(bibfile, bibfile, env)
                         if result != 0:
+                            check_file_error_message(env['BIBTEX'], 'blg')
                             return result
                         must_rerun_latex = check_MD5(suffix_nodes['.bbl'],'.bbl')
                         break
@@ -273,6 +315,7 @@ def InternalLaTeXAuxAction(XXXLaTeXAction, target = None, source= None, env=None
             idxfile = suffix_nodes['.idx']
             result = MakeIndexAction(idxfile, idxfile, env)
             if result != 0:
+                check_file_error_message(env['MAKEINDEX'], 'ilg')
                 return result
 
         # TO-DO: need to add a way for the user to extend this list for whatever
@@ -290,16 +333,32 @@ def InternalLaTeXAuxAction(XXXLaTeXAction, target = None, source= None, env=None
             nclfile = suffix_nodes['.nlo']
             result = MakeNclAction(nclfile, nclfile, env)
             if result != 0:
-                return result
+                check_file_error_message('%s (nomenclature)' % env['MAKENCL'],
+                                         'nlg')
+                #return result
 
         # Now decide if latex will need to be run again due to glossary.
-        if check_MD5(suffix_nodes['.glo'],'.glo') or (count == 1 and run_glossary):
+        if check_MD5(suffix_nodes['.glo'],'.glo') or (count == 1 and run_glossaries) or (count == 1 and run_glossary):
             # We must run makeindex
             if Verbose:
                 print "Need to run makeindex for glossary"
             glofile = suffix_nodes['.glo']
             result = MakeGlossaryAction(glofile, glofile, env)
             if result != 0:
+                check_file_error_message('%s (glossary)' % env['MAKEGLOSSARY'],
+                                         'glg')
+                #return result
+
+        # Now decide if latex will need to be run again due to acronyms.
+        if check_MD5(suffix_nodes['.acn'],'.acn') or (count == 1 and run_acronyms):
+            # We must run makeindex
+            if Verbose:
+                print "Need to run makeindex for acronyms"
+            acrfile = suffix_nodes['.acn']
+            result = MakeAcronymsAction(acrfile, acrfile, env)
+            if result != 0:
+                check_file_error_message('%s (acronyms)' % env['MAKEACRONYMS'],
+                                         'alg')
                 return result
 
         # Now decide if latex needs to be run yet again to resolve warnings.
@@ -341,7 +400,7 @@ def InternalLaTeXAuxAction(XXXLaTeXAction, target = None, source= None, env=None
             continue
         if saved_env[var] is _null:
             try:
-                env['ENV'].pop(var)
+                del env['ENV'][var]
             except KeyError:
                 pass # was never set
         else:
@@ -355,22 +414,92 @@ def LaTeXAuxAction(target = None, source= None, env=None):
 
 LaTeX_re = re.compile("\\\\document(style|class)")
 
-def is_LaTeX(flist):
-    # Scan a file list to decide if it's TeX- or LaTeX-flavored.
+def is_LaTeX(flist,env,abspath):
+    """Scan a file list to decide if it's TeX- or LaTeX-flavored."""
+
+    # We need to scan files that are included in case the
+    # \documentclass command is in them.
+
+    # get path list from both env['TEXINPUTS'] and env['ENV']['TEXINPUTS']
+    savedpath = modify_env_var(env, 'TEXINPUTS', abspath)
+    paths = env['ENV']['TEXINPUTS']
+    if SCons.Util.is_List(paths):
+        pass
+    else:
+        # Split at os.pathsep to convert into absolute path
+        # TODO(1.5)
+        #paths = paths.split(os.pathsep)
+        paths = paths.split(os.pathsep)
+
+    # now that we have the path list restore the env
+    if savedpath is _null:
+        try:
+            del env['ENV']['TEXINPUTS']
+        except KeyError:
+            pass # was never set
+    else:
+        env['ENV']['TEXINPUTS'] = savedpath
+    if Verbose:
+        print "is_LaTeX search path ",paths
+        print "files to search :",flist
+
+    # Now that we have the search path and file list, check each one
     for f in flist:
-        content = f.get_contents()
+        if Verbose:
+            print " checking for Latex source ",str(f)
+
+        content = f.get_text_contents()
         if LaTeX_re.search(content):
+            if Verbose:
+                print "file %s is a LaTeX file" % str(f)
             return 1
+        if Verbose:
+            print "file %s is not a LaTeX file" % str(f)
+
+        # now find included files
+        inc_files = [ ]
+        inc_files.extend( include_re.findall(content) )
+        if Verbose:
+            print "files included by '%s': "%str(f),inc_files
+        # inc_files is list of file names as given. need to find them
+        # using TEXINPUTS paths.
+
+        # search the included files
+        for src in inc_files:
+            srcNode = FindFile(src,['.tex','.ltx','.latex'],paths,env,requireExt=False)
+            # make this a list since is_LaTeX takes a list.
+            fileList = [srcNode,]
+            if Verbose:
+                print "FindFile found ",srcNode
+            if srcNode is not None:
+                file_test = is_LaTeX(fileList, env, abspath)
+
+            # return on first file that finds latex is needed.
+            if file_test:
+                return file_test
+
+        if Verbose:
+            print " done scanning ",str(f)
+
     return 0
 
 def TeXLaTeXFunction(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 is_LaTeX(source):
+
+    # find these paths for use in is_LaTeX to search for included files
+    basedir = os.path.split(str(source[0]))[0]
+    abspath = os.path.abspath(basedir)
+
+    if is_LaTeX(source,env,abspath):
         result = LaTeXAuxAction(target,source,env)
+        if result != 0:
+            check_file_error_message(env['LATEX'])
     else:
         result = TeXAction(target,source,env)
+        if result != 0:
+            check_file_error_message(env['TEX'])
     return result
 
 def TeXLaTeXStrFunction(target = None, source= None, env=None):
@@ -378,7 +507,12 @@ def TeXLaTeXStrFunction(target = None, source= None, env=None):
     decide the "flavor" of the source and then returns the appropriate
     command string."""
     if env.GetOption("no_exec"):
-        if is_LaTeX(source):
+
+        # find these paths for use in is_LaTeX to search for included files
+        basedir = os.path.split(str(source[0]))[0]
+        abspath = os.path.abspath(basedir)
+
+        if is_LaTeX(source,env,abspath):
             result = env.subst('$LATEXCOM',0,target,source)+" ..."
         else:
             result = env.subst("$TEXCOM",0,target,source)+" ..."
@@ -386,61 +520,183 @@ def TeXLaTeXStrFunction(target = None, source= None, env=None):
         result = ''
     return result
 
-def tex_emitter(target, source, env):
+def tex_eps_emitter(target, source, env):
+    """An emitter for TeX and LaTeX sources when
+    executing tex or latex. It will accept .ps and .eps
+    graphics files
+    """
+    (target, source) = tex_emitter_core(target, source, env, TexGraphics)
+
+    return (target, source)
+
+def tex_pdf_emitter(target, source, env):
+    """An emitter for TeX and LaTeX sources when
+    executing pdftex or pdflatex. It will accept graphics
+    files of types .pdf, .jpg, .png, .gif, and .tif
+    """
+    (target, source) = tex_emitter_core(target, source, env, LatexGraphics)
+
+    return (target, source)
+
+def ScanFiles(theFile, target, paths, file_tests, file_tests_search, env, graphics_extensions, targetdir, aux_files):
+    """ For theFile (a Node) update any file_tests and search for graphics files
+    then find all included files and call ScanFiles recursively for each of them"""
+
+    content = theFile.get_text_contents()
+    if Verbose:
+        print " scanning ",str(theFile)
+
+    for i in range(len(file_tests_search)):
+        if file_tests[i][0] is None:
+            file_tests[i][0] = file_tests_search[i].search(content)
+
+    incResult = includeOnly_re.search(content)
+    if incResult:
+        aux_files.append(os.path.join(targetdir, incResult.group(1)))
+    if Verbose:
+        print "\include file names : ", aux_files
+    # recursively call this on each of the included files
+    inc_files = [ ]
+    inc_files.extend( include_re.findall(content) )
+    if Verbose:
+        print "files included by '%s': "%str(theFile),inc_files
+    # inc_files is list of file names as given. need to find them
+    # using TEXINPUTS paths.
+
+    for src in inc_files:
+        srcNode = FindFile(src,['.tex','.ltx','.latex'],paths,env,requireExt=False)
+        if srcNode is not None:
+            file_tests = ScanFiles(srcNode, target, paths, file_tests, file_tests_search, env, graphics_extensions, targetdir, aux_files)
+    if Verbose:
+        print " done scanning ",str(theFile)
+    return file_tests
+
+def tex_emitter_core(target, source, env, graphics_extensions):
     """An emitter for TeX and LaTeX sources.
     For LaTeX sources we try and find the common created files that
     are needed on subsequent runs of latex to finish tables of contents,
     bibliographies, indices, lists of figures, and hyperlink references.
     """
-    targetbase = SCons.Util.splitext(str(target[0]))[0]
     basename = SCons.Util.splitext(str(source[0]))[0]
     basefile = os.path.split(str(basename))[1]
+    targetdir = os.path.split(str(target[0]))[0]
+    targetbase = os.path.join(targetdir, basefile)
 
+    basedir = os.path.split(str(source[0]))[0]
+    abspath = os.path.abspath(basedir)
+    target[0].attributes.path = abspath
+    
     #
     # file names we will make use of in searching the sources and log file
     #
-    emit_suffixes = ['.aux', '.log', '.ilg', '.blg', '.nls', '.nlg', '.gls', '.glg'] + all_suffixes
+    emit_suffixes = ['.aux', '.log', '.ilg', '.blg', '.nls', '.nlg', '.gls', '.glg', '.alg'] + all_suffixes
     auxfilename = targetbase + '.aux'
     logfilename = targetbase + '.log'
+    flsfilename = targetbase + '.fls'
 
     env.SideEffect(auxfilename,target[0])
     env.SideEffect(logfilename,target[0])
+    env.SideEffect(flsfilename,target[0])
+    if Verbose:
+        print "side effect :",auxfilename,logfilename,flsfilename
     env.Clean(target[0],auxfilename)
     env.Clean(target[0],logfilename)
+    env.Clean(target[0],flsfilename)
+
+    content = source[0].get_text_contents()
 
-    content = source[0].get_contents()
     idx_exists = os.path.exists(targetbase + '.idx')
     nlo_exists = os.path.exists(targetbase + '.nlo')
     glo_exists = os.path.exists(targetbase + '.glo')
-
-    file_tests = [(auxfile_re.search(content),['.aux']),
-                  (makeindex_re.search(content) or idx_exists,['.idx', '.ind', '.ilg']),
-                  (bibliography_re.search(content),['.bbl', '.blg']),
-                  (tableofcontents_re.search(content),['.toc']),
-                  (listoffigures_re.search(content),['.lof']),
-                  (listoftables_re.search(content),['.lot']),
-                  (hyperref_re.search(content),['.out']),
-                  (makenomenclature_re.search(content) or nlo_exists,['.nlo', '.nls', '.nlg']),
-                  (makeglossary_re.search(content) or glo_exists,['.glo', '.gls', '.glg']),
-                  (beamer_re.search(content),['.nav', '.snm', '.out', '.toc']) ]
-    # Note we add the various makeindex files if the file produced by latex exists (.idx, .glo, .nlo)
-    # This covers the case where the \makeindex, \makenomenclature, or \makeglossary
-    # is not in the main file but we want to clean the files and those made by makeindex
+    acr_exists = os.path.exists(targetbase + '.acn')
+
+    # set up list with the regular expressions
+    # we use to find features used
+    file_tests_search = [auxfile_re,
+                         makeindex_re,
+                         bibliography_re,
+                         tableofcontents_re,
+                         listoffigures_re,
+                         listoftables_re,
+                         hyperref_re,
+                         makenomenclature_re,
+                         makeglossary_re,
+                         makeglossaries_re,
+                         makeacronyms_re,
+                         beamer_re ]
+    # set up list with the file suffixes that need emitting
+    # when a feature is found
+    file_tests_suff = [['.aux'],
+                  ['.idx', '.ind', '.ilg'],
+                  ['.bbl', '.blg'],
+                  ['.toc'],
+                  ['.lof'],
+                  ['.lot'],
+                  ['.out'],
+                  ['.nlo', '.nls', '.nlg'],
+                  ['.glo', '.gls', '.glg'],
+                  ['.glo', '.gls', '.glg'],
+                  ['.acn', '.acr', '.alg'],
+                  ['.nav', '.snm', '.out', '.toc'] ]
+    # build the list of lists
+    file_tests = []
+    for i in range(len(file_tests_search)):
+        file_tests.append( [None, file_tests_suff[i]] )
 
     # TO-DO: need to add a way for the user to extend this list for whatever
     # auxiliary files they create in other (or their own) packages
 
+    # get path list from both env['TEXINPUTS'] and env['ENV']['TEXINPUTS']
+    savedpath = modify_env_var(env, 'TEXINPUTS', abspath)
+    paths = env['ENV']['TEXINPUTS']
+    if SCons.Util.is_List(paths):
+        pass
+    else:
+        # Split at os.pathsep to convert into absolute path
+        # TODO(1.5)
+        #paths = paths.split(os.pathsep)
+        paths = paths.split(os.pathsep)
+
+    # now that we have the path list restore the env
+    if savedpath is _null:
+        try:
+            del env['ENV']['TEXINPUTS']
+        except KeyError:
+            pass # was never set
+    else:
+        env['ENV']['TEXINPUTS'] = savedpath
+    if Verbose:
+        print "search path ",paths
+
+    aux_files = []
+    file_tests = ScanFiles(source[0], target, paths, file_tests, file_tests_search, env, graphics_extensions, targetdir, aux_files)
+
     for (theSearch,suffix_list) in file_tests:
         if theSearch:
             for suffix in suffix_list:
                 env.SideEffect(targetbase + suffix,target[0])
+                if Verbose:
+                    print "side effect :",targetbase + suffix
                 env.Clean(target[0],targetbase + suffix)
 
-    # read log file to get all other files that latex creates and will read on the next pass
-    if os.path.exists(logfilename):
-        content = open(logfilename, "rb").read()
+    for aFile in aux_files:
+        aFile_base = SCons.Util.splitext(aFile)[0]
+        env.SideEffect(aFile_base + '.aux',target[0])
+        if Verbose:
+            print "side effect :",aFile_base + '.aux'
+        env.Clean(target[0],aFile_base + '.aux')
+    # read fls file to get all other files that latex creates and will read on the next pass
+    # remove files from list that we explicitly dealt with above
+    if os.path.exists(flsfilename):
+        content = open(flsfilename, "rb").read()
         out_files = openout_re.findall(content)
+        myfiles = [auxfilename, logfilename, flsfilename, targetbase+'.dvi',targetbase+'.pdf']
+        for filename in out_files[:]:
+            if filename in myfiles:
+                out_files.remove(filename)
         env.SideEffect(out_files,target[0])
+        if Verbose:
+            print "side effect :",out_files
         env.Clean(target[0],out_files)
 
     return (target, source)
@@ -451,6 +707,25 @@ TeXLaTeXAction = None
 def generate(env):
     """Add Builders and construction variables for TeX to an Environment."""
 
+    global TeXLaTeXAction
+    if TeXLaTeXAction is None:
+        TeXLaTeXAction = SCons.Action.Action(TeXLaTeXFunction,
+                              strfunction=TeXLaTeXStrFunction)
+
+    env.AppendUnique(LATEXSUFFIXES=SCons.Tool.LaTeXSuffixes)
+
+    generate_common(env)
+
+    import dvi
+    dvi.generate(env)
+
+    bld = env['BUILDERS']['DVI']
+    bld.add_action('.tex', TeXLaTeXAction)
+    bld.add_emitter('.tex', tex_eps_emitter)
+
+def generate_common(env):
+    """Add internal Builders and construction variables for LaTeX to an Environment."""
+
     # A generic tex file Action, sufficient for all tex files.
     global TeXAction
     if TeXAction is None:
@@ -482,28 +757,28 @@ def generate(env):
     if MakeGlossaryAction is None:
         MakeGlossaryAction = SCons.Action.Action("$MAKEGLOSSARYCOM", "$MAKEGLOSSARYCOMSTR")
 
-    global TeXLaTeXAction
-    if TeXLaTeXAction is None:
-        TeXLaTeXAction = SCons.Action.Action(TeXLaTeXFunction,
-                              strfunction=TeXLaTeXStrFunction)
-
-    import dvi
-    dvi.generate(env)
-
-    bld = env['BUILDERS']['DVI']
-    bld.add_action('.tex', TeXLaTeXAction)
-    bld.add_emitter('.tex', tex_emitter)
+    # Define an action to run MakeIndex on a file for acronyms.
+    global MakeAcronymsAction
+    if MakeAcronymsAction is None:
+        MakeAcronymsAction = SCons.Action.Action("$MAKEACRONYMSCOM", "$MAKEACRONYMSCOMSTR")
 
     env['TEX']      = 'tex'
-    env['TEXFLAGS'] = SCons.Util.CLVar('-interaction=nonstopmode')
+    env['TEXFLAGS'] = SCons.Util.CLVar('-interaction=nonstopmode -recorder')
     env['TEXCOM']   = 'cd ${TARGET.dir} && $TEX $TEXFLAGS ${SOURCE.file}'
 
-    # Duplicate from latex.py.  If latex.py goes away, then this is still OK.
+    env['PDFTEX']      = 'pdftex'
+    env['PDFTEXFLAGS'] = SCons.Util.CLVar('-interaction=nonstopmode -recorder')
+    env['PDFTEXCOM']   = 'cd ${TARGET.dir} && $PDFTEX $PDFTEXFLAGS ${SOURCE.file}'
+
     env['LATEX']        = 'latex'
-    env['LATEXFLAGS']   = SCons.Util.CLVar('-interaction=nonstopmode')
+    env['LATEXFLAGS']   = SCons.Util.CLVar('-interaction=nonstopmode -recorder')
     env['LATEXCOM']     = 'cd ${TARGET.dir} && $LATEX $LATEXFLAGS ${SOURCE.file}'
     env['LATEXRETRIES'] = 3
 
+    env['PDFLATEX']      = 'pdflatex'
+    env['PDFLATEXFLAGS'] = SCons.Util.CLVar('-interaction=nonstopmode -recorder')
+    env['PDFLATEXCOM']   = 'cd ${TARGET.dir} && $PDFLATEX $PDFLATEXFLAGS ${SOURCE.file}'
+
     env['BIBTEX']      = 'bibtex'
     env['BIBTEXFLAGS'] = SCons.Util.CLVar('')
     env['BIBTEXCOM']   = 'cd ${TARGET.dir} && $BIBTEX $BIBTEXFLAGS ${SOURCE.filebase}'
@@ -517,15 +792,21 @@ def generate(env):
     env['MAKEGLOSSARYFLAGS'] = SCons.Util.CLVar('-s ${MAKEGLOSSARYSTYLE} -t ${SOURCE.filebase}.glg')
     env['MAKEGLOSSARYCOM']   = 'cd ${TARGET.dir} && $MAKEGLOSSARY ${SOURCE.filebase}.glo $MAKEGLOSSARYFLAGS -o ${SOURCE.filebase}.gls'
 
+    env['MAKEACRONYMS']      = 'makeindex'
+    env['MAKEACRONYMSSTYLE'] = '${SOURCE.filebase}.ist'
+    env['MAKEACRONYMSFLAGS'] = SCons.Util.CLVar('-s ${MAKEACRONYMSSTYLE} -t ${SOURCE.filebase}.alg')
+    env['MAKEACRONYMSCOM']   = 'cd ${TARGET.dir} && $MAKEACRONYMS ${SOURCE.filebase}.acn $MAKEACRONYMSFLAGS -o ${SOURCE.filebase}.acr'
+
     env['MAKENCL']      = 'makeindex'
-    env['MAKENCLSTYLE'] = '$nomencl.ist'
+    env['MAKENCLSTYLE'] = 'nomencl.ist'
     env['MAKENCLFLAGS'] = '-s ${MAKENCLSTYLE} -t ${SOURCE.filebase}.nlg'
     env['MAKENCLCOM']   = 'cd ${TARGET.dir} && $MAKENCL ${SOURCE.filebase}.nlo $MAKENCLFLAGS -o ${SOURCE.filebase}.nls'
 
-    # Duplicate from pdflatex.py.  If latex.py goes away, then this is still OK.
-    env['PDFLATEX']      = 'pdflatex'
-    env['PDFLATEXFLAGS'] = SCons.Util.CLVar('-interaction=nonstopmode')
-    env['PDFLATEXCOM']   = 'cd ${TARGET.dir} && $PDFLATEX $PDFLATEXFLAGS ${SOURCE.file}'
-
 def exists(env):
     return env.Detect('tex')
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4: