Add some documentation to the SCons-version-switching hack
[senf.git] / tools / scons-1.2.0 / engine / SCons / Tool / tex.py
1 """SCons.Tool.tex
2
3 Tool-specific initialization for TeX.
4
5 There normally shouldn't be any need to import this module directly.
6 It will usually be imported through the generic SCons.Tool.Tool()
7 selection method.
8
9 """
10
11 #
12 # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation
13 #
14 # Permission is hereby granted, free of charge, to any person obtaining
15 # a copy of this software and associated documentation files (the
16 # "Software"), to deal in the Software without restriction, including
17 # without limitation the rights to use, copy, modify, merge, publish,
18 # distribute, sublicense, and/or sell copies of the Software, and to
19 # permit persons to whom the Software is furnished to do so, subject to
20 # the following conditions:
21 #
22 # The above copyright notice and this permission notice shall be included
23 # in all copies or substantial portions of the Software.
24 #
25 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
26 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
27 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 #
33
34 __revision__ = "src/engine/SCons/Tool/tex.py 3842 2008/12/20 22:59:52 scons"
35
36 import os.path
37 import re
38 import string
39 import shutil
40
41 import SCons.Action
42 import SCons.Node
43 import SCons.Node.FS
44 import SCons.Util
45 import SCons.Scanner.LaTeX
46
47 Verbose = False
48
49 must_rerun_latex = True
50
51 # these are files that just need to be checked for changes and then rerun latex
52 check_suffixes = ['.toc', '.lof', '.lot', '.out', '.nav', '.snm']
53
54 # these are files that require bibtex or makeindex to be run when they change
55 all_suffixes = check_suffixes + ['.bbl', '.idx', '.nlo', '.glo']
56
57 #
58 # regular expressions used to search for Latex features
59 # or outputs that require rerunning latex
60 #
61 # search for all .aux files opened by latex (recorded in the .log file)
62 openout_aux_re = re.compile(r"\\openout.*`(.*\.aux)'")
63
64 #printindex_re = re.compile(r"^[^%]*\\printindex", re.MULTILINE)
65 #printnomenclature_re = re.compile(r"^[^%]*\\printnomenclature", re.MULTILINE)
66 #printglossary_re = re.compile(r"^[^%]*\\printglossary", re.MULTILINE)
67
68 # search to find rerun warnings
69 warning_rerun_str = '(^LaTeX Warning:.*Rerun)|(^Package \w+ Warning:.*Rerun)'
70 warning_rerun_re = re.compile(warning_rerun_str, re.MULTILINE)
71
72 # search to find citation rerun warnings
73 rerun_citations_str = "^LaTeX Warning:.*\n.*Rerun to get citations correct"
74 rerun_citations_re = re.compile(rerun_citations_str, re.MULTILINE)
75
76 # search to find undefined references or citations warnings
77 undefined_references_str = '(^LaTeX Warning:.*undefined references)|(^Package \w+ Warning:.*undefined citations)'
78 undefined_references_re = re.compile(undefined_references_str, re.MULTILINE)
79
80 # used by the emitter
81 auxfile_re = re.compile(r".", re.MULTILINE)
82 tableofcontents_re = re.compile(r"^[^%\n]*\\tableofcontents", re.MULTILINE)
83 makeindex_re = re.compile(r"^[^%\n]*\\makeindex", re.MULTILINE)
84 bibliography_re = re.compile(r"^[^%\n]*\\bibliography", re.MULTILINE)
85 listoffigures_re = re.compile(r"^[^%\n]*\\listoffigures", re.MULTILINE)
86 listoftables_re = re.compile(r"^[^%\n]*\\listoftables", re.MULTILINE)
87 hyperref_re = re.compile(r"^[^%\n]*\\usepackage.*\{hyperref\}", re.MULTILINE)
88 makenomenclature_re = re.compile(r"^[^%\n]*\\makenomenclature", re.MULTILINE)
89 makeglossary_re = re.compile(r"^[^%\n]*\\makeglossary", re.MULTILINE)
90 beamer_re = re.compile(r"^[^%\n]*\\documentclass\{beamer\}", re.MULTILINE)
91
92 # search to find all files included by Latex
93 include_re = re.compile(r'^[^%\n]*\\(?:include|input){([^}]*)}', re.MULTILINE)
94
95 # search to find all graphics files included by Latex
96 includegraphics_re = re.compile(r'^[^%\n]*\\(?:includegraphics(?:\[[^\]]+\])?){([^}]*)}', re.MULTILINE)
97
98 # search to find all files opened by Latex (recorded in .log file)
99 openout_re = re.compile(r"\\openout.*`(.*)'")
100
101 # list of graphics file extensions for TeX and LaTeX
102 TexGraphics   = SCons.Scanner.LaTeX.TexGraphics
103 LatexGraphics = SCons.Scanner.LaTeX.LatexGraphics
104
105 # An Action sufficient to build any generic tex file.
106 TeXAction = None
107
108 # An action to build a latex file.  This action might be needed more
109 # than once if we are dealing with labels and bibtex.
110 LaTeXAction = None
111
112 # An action to run BibTeX on a file.
113 BibTeXAction = None
114
115 # An action to run MakeIndex on a file.
116 MakeIndexAction = None
117
118 # An action to run MakeIndex (for nomencl) on a file.
119 MakeNclAction = None
120
121 # An action to run MakeIndex (for glossary) on a file.
122 MakeGlossaryAction = None
123
124 # Used as a return value of modify_env_var if the variable is not set.
125 _null = SCons.Scanner.LaTeX._null
126
127 modify_env_var = SCons.Scanner.LaTeX.modify_env_var
128
129 def FindFile(name,suffixes,paths,env,requireExt=False):
130     if requireExt:
131         name = SCons.Util.splitext(name)[0]
132     if Verbose:
133         print " searching for '%s' with extensions: " % name,suffixes
134
135     for path in paths:
136         testName = os.path.join(path,name)
137         if Verbose:
138             print " look for '%s'" % testName
139         if os.path.exists(testName):
140             if Verbose:
141                 print " found '%s'" % testName
142             return env.fs.File(testName)
143         else:
144             name_ext = SCons.Util.splitext(testName)[1]
145             if name_ext:
146                 continue
147
148             # if no suffix try adding those passed in
149             for suffix in suffixes:
150                 testNameExt = testName + suffix
151                 if Verbose:
152                     print " look for '%s'" % testNameExt
153
154                 if os.path.exists(testNameExt):
155                     if Verbose:
156                         print " found '%s'" % testNameExt
157                     return env.fs.File(testNameExt)
158     if Verbose:
159         print " did not find '%s'" % name
160     return None
161
162 def InternalLaTeXAuxAction(XXXLaTeXAction, target = None, source= None, env=None):
163     """A builder for LaTeX files that checks the output in the aux file
164     and decides how many times to use LaTeXAction, and BibTeXAction."""
165
166     global must_rerun_latex
167
168     # This routine is called with two actions. In this file for DVI builds
169     # with LaTeXAction and from the pdflatex.py with PDFLaTeXAction
170     # set this up now for the case where the user requests a different extension
171     # for the target filename
172     if (XXXLaTeXAction == LaTeXAction):
173        callerSuffix = ".dvi"
174     else:
175        callerSuffix = env['PDFSUFFIX']
176
177     basename = SCons.Util.splitext(str(source[0]))[0]
178     basedir = os.path.split(str(source[0]))[0]
179     basefile = os.path.split(str(basename))[1]
180     abspath = os.path.abspath(basedir)
181     targetext = os.path.splitext(str(target[0]))[1]
182     targetdir = os.path.split(str(target[0]))[0]
183
184     saved_env = {}
185     for var in SCons.Scanner.LaTeX.LaTeX.env_variables:
186         saved_env[var] = modify_env_var(env, var, abspath)
187
188     # Create base file names with the target directory since the auxiliary files
189     # will be made there.   That's because the *COM variables have the cd
190     # command in the prolog. We check
191     # for the existence of files before opening them--even ones like the
192     # aux file that TeX always creates--to make it possible to write tests
193     # with stubs that don't necessarily generate all of the same files.
194
195     targetbase = os.path.join(targetdir, basefile)
196
197     # if there is a \makeindex there will be a .idx and thus
198     # we have to run makeindex at least once to keep the build
199     # happy even if there is no index.
200     # Same for glossaries and nomenclature
201     src_content = source[0].get_contents()
202     run_makeindex = makeindex_re.search(src_content) and not os.path.exists(targetbase + '.idx')
203     run_nomenclature = makenomenclature_re.search(src_content) and not os.path.exists(targetbase + '.nlo')
204     run_glossary = makeglossary_re.search(src_content) and not os.path.exists(targetbase + '.glo')
205
206     saved_hashes = {}
207     suffix_nodes = {}
208
209     for suffix in all_suffixes:
210         theNode = env.fs.File(targetbase + suffix)
211         suffix_nodes[suffix] = theNode
212         saved_hashes[suffix] = theNode.get_csig()
213
214     if Verbose:
215         print "hashes: ",saved_hashes
216
217     must_rerun_latex = True
218
219     #
220     # routine to update MD5 hash and compare
221     #
222     # TODO(1.5):  nested scopes
223     def check_MD5(filenode, suffix, saved_hashes=saved_hashes, targetbase=targetbase):
224         global must_rerun_latex
225         # two calls to clear old csig
226         filenode.clear_memoized_values()
227         filenode.ninfo = filenode.new_ninfo()
228         new_md5 = filenode.get_csig()
229
230         if saved_hashes[suffix] == new_md5:
231             if Verbose:
232                 print "file %s not changed" % (targetbase+suffix)
233             return False        # unchanged
234         saved_hashes[suffix] = new_md5
235         must_rerun_latex = True
236         if Verbose:
237             print "file %s changed, rerunning Latex, new hash = " % (targetbase+suffix), new_md5
238         return True     # changed
239
240     # generate the file name that latex will generate
241     resultfilename = targetbase + callerSuffix
242
243     count = 0
244
245     while (must_rerun_latex and count < int(env.subst('$LATEXRETRIES'))) :
246         result = XXXLaTeXAction(target, source, env)
247         if result != 0:
248             return result
249
250         count = count + 1
251
252         must_rerun_latex = False
253         # Decide if various things need to be run, or run again.
254
255         # Read the log file to find all .aux files
256         logfilename = targetbase + '.log'
257         logContent = ''
258         auxfiles = []
259         if os.path.exists(logfilename):
260             logContent = open(logfilename, "rb").read()
261             auxfiles = openout_aux_re.findall(logContent)
262
263         # Now decide if bibtex will need to be run.
264         # The information that bibtex reads from the .aux file is
265         # pass-independent. If we find (below) that the .bbl file is unchanged,
266         # then the last latex saw a correct bibliography.
267         # Therefore only do this on the first pass
268         if count == 1:
269             for auxfilename in auxfiles:
270                 target_aux = os.path.join(targetdir, auxfilename)
271                 if os.path.exists(target_aux):
272                     content = open(target_aux, "rb").read()
273                     if string.find(content, "bibdata") != -1:
274                         if Verbose:
275                             print "Need to run bibtex"
276                         bibfile = env.fs.File(targetbase)
277                         result = BibTeXAction(bibfile, bibfile, env)
278                         if result != 0:
279                             return result
280                         must_rerun_latex = check_MD5(suffix_nodes['.bbl'],'.bbl')
281                         break
282
283         # Now decide if latex will need to be run again due to index.
284         if check_MD5(suffix_nodes['.idx'],'.idx') or (count == 1 and run_makeindex):
285             # We must run makeindex
286             if Verbose:
287                 print "Need to run makeindex"
288             idxfile = suffix_nodes['.idx']
289             result = MakeIndexAction(idxfile, idxfile, env)
290             if result != 0:
291                 return result
292
293         # TO-DO: need to add a way for the user to extend this list for whatever
294         # auxiliary files they create in other (or their own) packages
295         # Harder is case is where an action needs to be called -- that should be rare (I hope?)
296
297         for index in check_suffixes:
298             check_MD5(suffix_nodes[index],index)
299
300         # Now decide if latex will need to be run again due to nomenclature.
301         if check_MD5(suffix_nodes['.nlo'],'.nlo') or (count == 1 and run_nomenclature):
302             # We must run makeindex
303             if Verbose:
304                 print "Need to run makeindex for nomenclature"
305             nclfile = suffix_nodes['.nlo']
306             result = MakeNclAction(nclfile, nclfile, env)
307             if result != 0:
308                 return result
309
310         # Now decide if latex will need to be run again due to glossary.
311         if check_MD5(suffix_nodes['.glo'],'.glo') or (count == 1 and run_glossary):
312             # We must run makeindex
313             if Verbose:
314                 print "Need to run makeindex for glossary"
315             glofile = suffix_nodes['.glo']
316             result = MakeGlossaryAction(glofile, glofile, env)
317             if result != 0:
318                 return result
319
320         # Now decide if latex needs to be run yet again to resolve warnings.
321         if warning_rerun_re.search(logContent):
322             must_rerun_latex = True
323             if Verbose:
324                 print "rerun Latex due to latex or package rerun warning"
325
326         if rerun_citations_re.search(logContent):
327             must_rerun_latex = True
328             if Verbose:
329                 print "rerun Latex due to 'Rerun to get citations correct' warning"
330
331         if undefined_references_re.search(logContent):
332             must_rerun_latex = True
333             if Verbose:
334                 print "rerun Latex due to undefined references or citations"
335
336         if (count >= int(env.subst('$LATEXRETRIES')) and must_rerun_latex):
337             print "reached max number of retries on Latex ,",int(env.subst('$LATEXRETRIES'))
338 # end of while loop
339
340     # rename Latex's output to what the target name is
341     if not (str(target[0]) == resultfilename  and  os.path.exists(resultfilename)):
342         if os.path.exists(resultfilename):
343             print "move %s to %s" % (resultfilename, str(target[0]), )
344             shutil.move(resultfilename,str(target[0]))
345
346     # Original comment (when TEXPICTS was not restored):
347     # The TEXPICTS enviroment variable is needed by a dvi -> pdf step
348     # later on Mac OSX so leave it
349     #
350     # It is also used when searching for pictures (implicit dependencies).
351     # Why not set the variable again in the respective builder instead
352     # of leaving local modifications in the environment? What if multiple
353     # latex builds in different directories need different TEXPICTS?
354     for var in SCons.Scanner.LaTeX.LaTeX.env_variables:
355         if var == 'TEXPICTS':
356             continue
357         if saved_env[var] is _null:
358             try:
359                 del env['ENV'][var]
360             except KeyError:
361                 pass # was never set
362         else:
363             env['ENV'][var] = saved_env[var]
364
365     return result
366
367 def LaTeXAuxAction(target = None, source= None, env=None):
368     result = InternalLaTeXAuxAction( LaTeXAction, target, source, env )
369     return result
370
371 LaTeX_re = re.compile("\\\\document(style|class)")
372
373 def is_LaTeX(flist):
374     # Scan a file list to decide if it's TeX- or LaTeX-flavored.
375     for f in flist:
376         content = f.get_contents()
377         if LaTeX_re.search(content):
378             return 1
379     return 0
380
381 def TeXLaTeXFunction(target = None, source= None, env=None):
382     """A builder for TeX and LaTeX that scans the source file to
383     decide the "flavor" of the source and then executes the appropriate
384     program."""
385     if is_LaTeX(source):
386         result = LaTeXAuxAction(target,source,env)
387     else:
388         result = TeXAction(target,source,env)
389     return result
390
391 def TeXLaTeXStrFunction(target = None, source= None, env=None):
392     """A strfunction for TeX and LaTeX that scans the source file to
393     decide the "flavor" of the source and then returns the appropriate
394     command string."""
395     if env.GetOption("no_exec"):
396         if is_LaTeX(source):
397             result = env.subst('$LATEXCOM',0,target,source)+" ..."
398         else:
399             result = env.subst("$TEXCOM",0,target,source)+" ..."
400     else:
401         result = ''
402     return result
403
404 def tex_eps_emitter(target, source, env):
405     """An emitter for TeX and LaTeX sources when
406     executing tex or latex. It will accept .ps and .eps
407     graphics files
408     """
409     (target, source) = tex_emitter_core(target, source, env, TexGraphics)
410
411     return (target, source)
412
413 def tex_pdf_emitter(target, source, env):
414     """An emitter for TeX and LaTeX sources when
415     executing pdftex or pdflatex. It will accept graphics
416     files of types .pdf, .jpg, .png, .gif, and .tif
417     """
418     (target, source) = tex_emitter_core(target, source, env, LatexGraphics)
419
420     return (target, source)
421
422 def ScanFiles(theFile, target, paths, file_tests, file_tests_search, env, graphics_extensions, targetdir):
423     # for theFile (a Node) update any file_tests and search for graphics files
424     # then find all included files and call ScanFiles for each of them
425     content = theFile.get_contents()
426     if Verbose:
427         print " scanning ",str(theFile)
428
429     for i in range(len(file_tests_search)):
430         if file_tests[i][0] == None:
431             file_tests[i][0] = file_tests_search[i].search(content)
432
433     # For each file see if any graphics files are included
434     # and set up target to create ,pdf graphic
435     # is this is in pdflatex toolchain
436     graphic_files = includegraphics_re.findall(content)
437     if Verbose:
438         print "graphics files in '%s': "%str(theFile),graphic_files
439     for graphFile in graphic_files:
440         graphicNode = FindFile(graphFile,graphics_extensions,paths,env,requireExt=True)
441         # if building with pdflatex see if we need to build the .pdf version of the graphic file
442         # I should probably come up with a better way to tell which builder we are using.
443         if graphics_extensions == LatexGraphics:
444             # see if we can build this graphics file by epstopdf
445             graphicSrc = FindFile(graphFile,TexGraphics,paths,env,requireExt=True)
446             # it seems that FindFile checks with no extension added
447             # so if the extension is included in the name then both searches find it
448             # we don't want to try to build a .pdf from a .pdf so make sure src!=file wanted
449             if (graphicSrc != None) and (graphicSrc != graphicNode):
450                 if Verbose:
451                     if graphicNode == None:
452                         print "need to build '%s' by epstopdf %s -o %s" % (graphFile,graphicSrc,graphFile)
453                     else:
454                         print "no need to build '%s', but source file %s exists" % (graphicNode,graphicSrc)
455                 graphicNode = env.PDF(graphicSrc)
456                 env.Depends(target[0],graphicNode)
457
458     # recursively call this on each of the included files
459     inc_files = [ ]
460     inc_files.extend( include_re.findall(content) )
461     if Verbose:
462         print "files included by '%s': "%str(theFile),inc_files
463     # inc_files is list of file names as given. need to find them
464     # using TEXINPUTS paths.
465
466     for src in inc_files:
467         srcNode = srcNode = FindFile(src,['.tex','.ltx','.latex'],paths,env,requireExt=False)
468         if srcNode != None:
469             file_test = ScanFiles(srcNode, target, paths, file_tests, file_tests_search, env, graphics_extensions, targetdir)
470     if Verbose:
471         print " done scanning ",str(theFile)
472     return file_tests
473
474 def tex_emitter_core(target, source, env, graphics_extensions):
475     """An emitter for TeX and LaTeX sources.
476     For LaTeX sources we try and find the common created files that
477     are needed on subsequent runs of latex to finish tables of contents,
478     bibliographies, indices, lists of figures, and hyperlink references.
479     """
480     targetbase = SCons.Util.splitext(str(target[0]))[0]
481     basename = SCons.Util.splitext(str(source[0]))[0]
482     basefile = os.path.split(str(basename))[1]
483
484     basedir = os.path.split(str(source[0]))[0]
485     targetdir = os.path.split(str(target[0]))[0]
486     abspath = os.path.abspath(basedir)
487     target[0].attributes.path = abspath
488
489     #
490     # file names we will make use of in searching the sources and log file
491     #
492     emit_suffixes = ['.aux', '.log', '.ilg', '.blg', '.nls', '.nlg', '.gls', '.glg'] + all_suffixes
493     auxfilename = targetbase + '.aux'
494     logfilename = targetbase + '.log'
495
496     env.SideEffect(auxfilename,target[0])
497     env.SideEffect(logfilename,target[0])
498     env.Clean(target[0],auxfilename)
499     env.Clean(target[0],logfilename)
500
501     content = source[0].get_contents()
502
503     idx_exists = os.path.exists(targetbase + '.idx')
504     nlo_exists = os.path.exists(targetbase + '.nlo')
505     glo_exists = os.path.exists(targetbase + '.glo')
506
507     # set up list with the regular expressions
508     # we use to find features used
509     file_tests_search = [auxfile_re,
510                          makeindex_re,
511                          bibliography_re,
512                          tableofcontents_re,
513                          listoffigures_re,
514                          listoftables_re,
515                          hyperref_re,
516                          makenomenclature_re,
517                          makeglossary_re,
518                          beamer_re ]
519     # set up list with the file suffixes that need emitting
520     # when a feature is found
521     file_tests_suff = [['.aux'],
522                   ['.idx', '.ind', '.ilg'],
523                   ['.bbl', '.blg'],
524                   ['.toc'],
525                   ['.lof'],
526                   ['.lot'],
527                   ['.out'],
528                   ['.nlo', '.nls', '.nlg'],
529                   ['.glo', '.gls', '.glg'],
530                   ['.nav', '.snm', '.out', '.toc'] ]
531     # build the list of lists
532     file_tests = []
533     for i in range(len(file_tests_search)):
534         file_tests.append( [None, file_tests_suff[i]] )
535
536     # TO-DO: need to add a way for the user to extend this list for whatever
537     # auxiliary files they create in other (or their own) packages
538
539     # get path list from both env['TEXINPUTS'] and env['ENV']['TEXINPUTS']
540     savedpath = modify_env_var(env, 'TEXINPUTS', abspath)
541     paths = env['ENV']['TEXINPUTS']
542     if SCons.Util.is_List(paths):
543         pass
544     else:
545         # Split at os.pathsep to convert into absolute path
546         # TODO(1.5)
547         #paths = paths.split(os.pathsep)
548         paths = string.split(paths, os.pathsep)
549
550     # now that we have the path list restore the env
551     if savedpath is _null:
552         try:
553             del env['ENV']['TEXINPUTS']
554         except KeyError:
555             pass # was never set
556     else:
557         env['ENV']['TEXINPUTS'] = savedpath
558     if Verbose:
559         print "search path ",paths
560
561     file_tests = ScanFiles(source[0], target, paths, file_tests, file_tests_search, env, graphics_extensions, targetdir)
562
563     for (theSearch,suffix_list) in file_tests:
564         if theSearch:
565             for suffix in suffix_list:
566                 env.SideEffect(targetbase + suffix,target[0])
567                 env.Clean(target[0],targetbase + suffix)
568
569     # read log file to get all other files that latex creates and will read on the next pass
570     if os.path.exists(logfilename):
571         content = open(logfilename, "rb").read()
572         out_files = openout_re.findall(content)
573         env.SideEffect(out_files,target[0])
574         env.Clean(target[0],out_files)
575
576     return (target, source)
577
578
579 TeXLaTeXAction = None
580
581 def generate(env):
582     """Add Builders and construction variables for TeX to an Environment."""
583
584     # A generic tex file Action, sufficient for all tex files.
585     global TeXAction
586     if TeXAction is None:
587         TeXAction = SCons.Action.Action("$TEXCOM", "$TEXCOMSTR")
588
589     # An Action to build a latex file.  This might be needed more
590     # than once if we are dealing with labels and bibtex.
591     global LaTeXAction
592     if LaTeXAction is None:
593         LaTeXAction = SCons.Action.Action("$LATEXCOM", "$LATEXCOMSTR")
594
595     # Define an action to run BibTeX on a file.
596     global BibTeXAction
597     if BibTeXAction is None:
598         BibTeXAction = SCons.Action.Action("$BIBTEXCOM", "$BIBTEXCOMSTR")
599
600     # Define an action to run MakeIndex on a file.
601     global MakeIndexAction
602     if MakeIndexAction is None:
603         MakeIndexAction = SCons.Action.Action("$MAKEINDEXCOM", "$MAKEINDEXCOMSTR")
604
605     # Define an action to run MakeIndex on a file for nomenclatures.
606     global MakeNclAction
607     if MakeNclAction is None:
608         MakeNclAction = SCons.Action.Action("$MAKENCLCOM", "$MAKENCLCOMSTR")
609
610     # Define an action to run MakeIndex on a file for glossaries.
611     global MakeGlossaryAction
612     if MakeGlossaryAction is None:
613         MakeGlossaryAction = SCons.Action.Action("$MAKEGLOSSARYCOM", "$MAKEGLOSSARYCOMSTR")
614
615     global TeXLaTeXAction
616     if TeXLaTeXAction is None:
617         TeXLaTeXAction = SCons.Action.Action(TeXLaTeXFunction,
618                               strfunction=TeXLaTeXStrFunction)
619
620     import dvi
621     dvi.generate(env)
622
623     bld = env['BUILDERS']['DVI']
624     bld.add_action('.tex', TeXLaTeXAction)
625     bld.add_emitter('.tex', tex_eps_emitter)
626
627     env['TEX']      = 'tex'
628     env['TEXFLAGS'] = SCons.Util.CLVar('-interaction=nonstopmode')
629     env['TEXCOM']   = 'cd ${TARGET.dir} && $TEX $TEXFLAGS ${SOURCE.file}'
630
631     # Duplicate from latex.py.  If latex.py goes away, then this is still OK.
632     env['LATEX']        = 'latex'
633     env['LATEXFLAGS']   = SCons.Util.CLVar('-interaction=nonstopmode')
634     env['LATEXCOM']     = 'cd ${TARGET.dir} && $LATEX $LATEXFLAGS ${SOURCE.file}'
635     env['LATEXRETRIES'] = 3
636
637     env['BIBTEX']      = 'bibtex'
638     env['BIBTEXFLAGS'] = SCons.Util.CLVar('')
639     env['BIBTEXCOM']   = 'cd ${TARGET.dir} && $BIBTEX $BIBTEXFLAGS ${SOURCE.filebase}'
640
641     env['MAKEINDEX']      = 'makeindex'
642     env['MAKEINDEXFLAGS'] = SCons.Util.CLVar('')
643     env['MAKEINDEXCOM']   = 'cd ${TARGET.dir} && $MAKEINDEX $MAKEINDEXFLAGS ${SOURCE.file}'
644
645     env['MAKEGLOSSARY']      = 'makeindex'
646     env['MAKEGLOSSARYSTYLE'] = '${SOURCE.filebase}.ist'
647     env['MAKEGLOSSARYFLAGS'] = SCons.Util.CLVar('-s ${MAKEGLOSSARYSTYLE} -t ${SOURCE.filebase}.glg')
648     env['MAKEGLOSSARYCOM']   = 'cd ${TARGET.dir} && $MAKEGLOSSARY ${SOURCE.filebase}.glo $MAKEGLOSSARYFLAGS -o ${SOURCE.filebase}.gls'
649
650     env['MAKENCL']      = 'makeindex'
651     env['MAKENCLSTYLE'] = '$nomencl.ist'
652     env['MAKENCLFLAGS'] = '-s ${MAKENCLSTYLE} -t ${SOURCE.filebase}.nlg'
653     env['MAKENCLCOM']   = 'cd ${TARGET.dir} && $MAKENCL ${SOURCE.filebase}.nlo $MAKENCLFLAGS -o ${SOURCE.filebase}.nls'
654
655     # Duplicate from pdflatex.py.  If latex.py goes away, then this is still OK.
656     env['PDFLATEX']      = 'pdflatex'
657     env['PDFLATEXFLAGS'] = SCons.Util.CLVar('-interaction=nonstopmode')
658     env['PDFLATEXCOM']   = 'cd ${TARGET.dir} && $PDFLATEX $PDFLATEXFLAGS ${SOURCE.file}'
659
660 def exists(env):
661     return env.Detect('tex')