/cpp/scons/scons-local-2.0.0.final.0/SCons/Tool/tex.py

http://zxing.googlecode.com/ · Python · 807 lines · 794 code · 1 blank · 12 comment · 8 complexity · 27a12fbbdc7645542b06d6eae483c88f MD5 · raw file

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