| OLD | NEW |
| 1 """SCons.Tool.tex | 1 """SCons.Tool.tex |
| 2 | 2 |
| 3 Tool-specific initialization for TeX. | 3 Tool-specific initialization for TeX. |
| 4 | 4 |
| 5 There normally shouldn't be any need to import this module directly. | 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() | 6 It will usually be imported through the generic SCons.Tool.Tool() |
| 7 selection method. | 7 selection method. |
| 8 | 8 |
| 9 """ | 9 """ |
| 10 | 10 |
| 11 # | 11 # |
| 12 # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundat
ion | 12 # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons F
oundation |
| 13 # | 13 # |
| 14 # Permission is hereby granted, free of charge, to any person obtaining | 14 # Permission is hereby granted, free of charge, to any person obtaining |
| 15 # a copy of this software and associated documentation files (the | 15 # a copy of this software and associated documentation files (the |
| 16 # "Software"), to deal in the Software without restriction, including | 16 # "Software"), to deal in the Software without restriction, including |
| 17 # without limitation the rights to use, copy, modify, merge, publish, | 17 # without limitation the rights to use, copy, modify, merge, publish, |
| 18 # distribute, sublicense, and/or sell copies of the Software, and to | 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 | 19 # permit persons to whom the Software is furnished to do so, subject to |
| 20 # the following conditions: | 20 # the following conditions: |
| 21 # | 21 # |
| 22 # The above copyright notice and this permission notice shall be included | 22 # The above copyright notice and this permission notice shall be included |
| 23 # in all copies or substantial portions of the Software. | 23 # in all copies or substantial portions of the Software. |
| 24 # | 24 # |
| 25 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY | 25 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
| 26 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE | 26 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
| 27 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | 27 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
| 28 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE | 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 | 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 | 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. | 31 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| 32 # | 32 # |
| 33 | 33 |
| 34 __revision__ = "src/engine/SCons/Tool/tex.py 3842 2008/12/20 22:59:52 scons" | 34 __revision__ = "src/engine/SCons/Tool/tex.py 3897 2009/01/13 06:45:54 scons" |
| 35 | 35 |
| 36 import os.path | 36 import os.path |
| 37 import re | 37 import re |
| 38 import string | 38 import string |
| 39 import shutil | 39 import shutil |
| 40 | 40 |
| 41 import SCons.Action | 41 import SCons.Action |
| 42 import SCons.Node | 42 import SCons.Node |
| 43 import SCons.Node.FS | 43 import SCons.Node.FS |
| 44 import SCons.Util | 44 import SCons.Util |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 121 # An action to run MakeIndex (for glossary) on a file. | 121 # An action to run MakeIndex (for glossary) on a file. |
| 122 MakeGlossaryAction = None | 122 MakeGlossaryAction = None |
| 123 | 123 |
| 124 # Used as a return value of modify_env_var if the variable is not set. | 124 # Used as a return value of modify_env_var if the variable is not set. |
| 125 _null = SCons.Scanner.LaTeX._null | 125 _null = SCons.Scanner.LaTeX._null |
| 126 | 126 |
| 127 modify_env_var = SCons.Scanner.LaTeX.modify_env_var | 127 modify_env_var = SCons.Scanner.LaTeX.modify_env_var |
| 128 | 128 |
| 129 def FindFile(name,suffixes,paths,env,requireExt=False): | 129 def FindFile(name,suffixes,paths,env,requireExt=False): |
| 130 if requireExt: | 130 if requireExt: |
| 131 name = SCons.Util.splitext(name)[0] | 131 name,ext = SCons.Util.splitext(name) |
| 132 # if the user gave an extension use it. |
| 133 if ext: |
| 134 name = name + ext |
| 132 if Verbose: | 135 if Verbose: |
| 133 print " searching for '%s' with extensions: " % name,suffixes | 136 print " searching for '%s' with extensions: " % name,suffixes |
| 134 | 137 |
| 135 for path in paths: | 138 for path in paths: |
| 136 testName = os.path.join(path,name) | 139 testName = os.path.join(path,name) |
| 137 if Verbose: | 140 if Verbose: |
| 138 print " look for '%s'" % testName | 141 print " look for '%s'" % testName |
| 139 if os.path.exists(testName): | 142 if os.path.exists(testName): |
| 140 if Verbose: | 143 if Verbose: |
| 141 print " found '%s'" % testName | 144 print " found '%s'" % testName |
| (...skipping 29 matching lines...) Expand all Loading... |
| 171 # for the target filename | 174 # for the target filename |
| 172 if (XXXLaTeXAction == LaTeXAction): | 175 if (XXXLaTeXAction == LaTeXAction): |
| 173 callerSuffix = ".dvi" | 176 callerSuffix = ".dvi" |
| 174 else: | 177 else: |
| 175 callerSuffix = env['PDFSUFFIX'] | 178 callerSuffix = env['PDFSUFFIX'] |
| 176 | 179 |
| 177 basename = SCons.Util.splitext(str(source[0]))[0] | 180 basename = SCons.Util.splitext(str(source[0]))[0] |
| 178 basedir = os.path.split(str(source[0]))[0] | 181 basedir = os.path.split(str(source[0]))[0] |
| 179 basefile = os.path.split(str(basename))[1] | 182 basefile = os.path.split(str(basename))[1] |
| 180 abspath = os.path.abspath(basedir) | 183 abspath = os.path.abspath(basedir) |
| 184 |
| 181 targetext = os.path.splitext(str(target[0]))[1] | 185 targetext = os.path.splitext(str(target[0]))[1] |
| 182 targetdir = os.path.split(str(target[0]))[0] | 186 targetdir = os.path.split(str(target[0]))[0] |
| 183 | 187 |
| 184 saved_env = {} | 188 saved_env = {} |
| 185 for var in SCons.Scanner.LaTeX.LaTeX.env_variables: | 189 for var in SCons.Scanner.LaTeX.LaTeX.env_variables: |
| 186 saved_env[var] = modify_env_var(env, var, abspath) | 190 saved_env[var] = modify_env_var(env, var, abspath) |
| 187 | 191 |
| 188 # Create base file names with the target directory since the auxiliary files | 192 # 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 | 193 # will be made there. That's because the *COM variables have the cd |
| 190 # command in the prolog. We check | 194 # command in the prolog. We check |
| 191 # for the existence of files before opening them--even ones like the | 195 # 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 | 196 # 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. | 197 # with stubs that don't necessarily generate all of the same files. |
| 194 | 198 |
| 195 targetbase = os.path.join(targetdir, basefile) | 199 targetbase = os.path.join(targetdir, basefile) |
| 196 | 200 |
| 197 # if there is a \makeindex there will be a .idx and thus | 201 # 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 | 202 # we have to run makeindex at least once to keep the build |
| 199 # happy even if there is no index. | 203 # happy even if there is no index. |
| 200 # Same for glossaries and nomenclature | 204 # Same for glossaries and nomenclature |
| 201 src_content = source[0].get_contents() | 205 src_content = source[0].get_text_contents() |
| 202 run_makeindex = makeindex_re.search(src_content) and not os.path.exists(targ
etbase + '.idx') | 206 run_makeindex = makeindex_re.search(src_content) and not os.path.exists(targ
etbase + '.idx') |
| 203 run_nomenclature = makenomenclature_re.search(src_content) and not os.path.e
xists(targetbase + '.nlo') | 207 run_nomenclature = makenomenclature_re.search(src_content) and not os.path.e
xists(targetbase + '.nlo') |
| 204 run_glossary = makeglossary_re.search(src_content) and not os.path.exists(ta
rgetbase + '.glo') | 208 run_glossary = makeglossary_re.search(src_content) and not os.path.exists(ta
rgetbase + '.glo') |
| 205 | 209 |
| 206 saved_hashes = {} | 210 saved_hashes = {} |
| 207 suffix_nodes = {} | 211 suffix_nodes = {} |
| 208 | 212 |
| 209 for suffix in all_suffixes: | 213 for suffix in all_suffixes: |
| 210 theNode = env.fs.File(targetbase + suffix) | 214 theNode = env.fs.File(targetbase + suffix) |
| 211 suffix_nodes[suffix] = theNode | 215 suffix_nodes[suffix] = theNode |
| (...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 366 | 370 |
| 367 def LaTeXAuxAction(target = None, source= None, env=None): | 371 def LaTeXAuxAction(target = None, source= None, env=None): |
| 368 result = InternalLaTeXAuxAction( LaTeXAction, target, source, env ) | 372 result = InternalLaTeXAuxAction( LaTeXAction, target, source, env ) |
| 369 return result | 373 return result |
| 370 | 374 |
| 371 LaTeX_re = re.compile("\\\\document(style|class)") | 375 LaTeX_re = re.compile("\\\\document(style|class)") |
| 372 | 376 |
| 373 def is_LaTeX(flist): | 377 def is_LaTeX(flist): |
| 374 # Scan a file list to decide if it's TeX- or LaTeX-flavored. | 378 # Scan a file list to decide if it's TeX- or LaTeX-flavored. |
| 375 for f in flist: | 379 for f in flist: |
| 376 content = f.get_contents() | 380 content = f.get_text_contents() |
| 377 if LaTeX_re.search(content): | 381 if LaTeX_re.search(content): |
| 378 return 1 | 382 return 1 |
| 379 return 0 | 383 return 0 |
| 380 | 384 |
| 381 def TeXLaTeXFunction(target = None, source= None, env=None): | 385 def TeXLaTeXFunction(target = None, source= None, env=None): |
| 382 """A builder for TeX and LaTeX that scans the source file to | 386 """A builder for TeX and LaTeX that scans the source file to |
| 383 decide the "flavor" of the source and then executes the appropriate | 387 decide the "flavor" of the source and then executes the appropriate |
| 384 program.""" | 388 program.""" |
| 385 if is_LaTeX(source): | 389 if is_LaTeX(source): |
| 386 result = LaTeXAuxAction(target,source,env) | 390 result = LaTeXAuxAction(target,source,env) |
| (...skipping 28 matching lines...) Expand all Loading... |
| 415 executing pdftex or pdflatex. It will accept graphics | 419 executing pdftex or pdflatex. It will accept graphics |
| 416 files of types .pdf, .jpg, .png, .gif, and .tif | 420 files of types .pdf, .jpg, .png, .gif, and .tif |
| 417 """ | 421 """ |
| 418 (target, source) = tex_emitter_core(target, source, env, LatexGraphics) | 422 (target, source) = tex_emitter_core(target, source, env, LatexGraphics) |
| 419 | 423 |
| 420 return (target, source) | 424 return (target, source) |
| 421 | 425 |
| 422 def ScanFiles(theFile, target, paths, file_tests, file_tests_search, env, graphi
cs_extensions, targetdir): | 426 def ScanFiles(theFile, target, paths, file_tests, file_tests_search, env, graphi
cs_extensions, targetdir): |
| 423 # for theFile (a Node) update any file_tests and search for graphics files | 427 # 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 | 428 # then find all included files and call ScanFiles for each of them |
| 425 content = theFile.get_contents() | 429 content = theFile.get_text_contents() |
| 426 if Verbose: | 430 if Verbose: |
| 427 print " scanning ",str(theFile) | 431 print " scanning ",str(theFile) |
| 428 | 432 |
| 429 for i in range(len(file_tests_search)): | 433 for i in range(len(file_tests_search)): |
| 430 if file_tests[i][0] == None: | 434 if file_tests[i][0] == None: |
| 431 file_tests[i][0] = file_tests_search[i].search(content) | 435 file_tests[i][0] = file_tests_search[i].search(content) |
| 432 | 436 |
| 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,requireEx
t=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 a
re 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=Tru
e) | |
| 446 # it seems that FindFile checks with no extension added | |
| 447 # so if the extension is included in the name then both searches fin
d 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" % (graph
File,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 | 437 # recursively call this on each of the included files |
| 459 inc_files = [ ] | 438 inc_files = [ ] |
| 460 inc_files.extend( include_re.findall(content) ) | 439 inc_files.extend( include_re.findall(content) ) |
| 461 if Verbose: | 440 if Verbose: |
| 462 print "files included by '%s': "%str(theFile),inc_files | 441 print "files included by '%s': "%str(theFile),inc_files |
| 463 # inc_files is list of file names as given. need to find them | 442 # inc_files is list of file names as given. need to find them |
| 464 # using TEXINPUTS paths. | 443 # using TEXINPUTS paths. |
| 465 | 444 |
| 466 for src in inc_files: | 445 for src in inc_files: |
| 467 srcNode = srcNode = FindFile(src,['.tex','.ltx','.latex'],paths,env,requ
ireExt=False) | 446 srcNode = srcNode = FindFile(src,['.tex','.ltx','.latex'],paths,env,requ
ireExt=False) |
| (...skipping 23 matching lines...) Expand all Loading... |
| 491 # | 470 # |
| 492 emit_suffixes = ['.aux', '.log', '.ilg', '.blg', '.nls', '.nlg', '.gls', '.g
lg'] + all_suffixes | 471 emit_suffixes = ['.aux', '.log', '.ilg', '.blg', '.nls', '.nlg', '.gls', '.g
lg'] + all_suffixes |
| 493 auxfilename = targetbase + '.aux' | 472 auxfilename = targetbase + '.aux' |
| 494 logfilename = targetbase + '.log' | 473 logfilename = targetbase + '.log' |
| 495 | 474 |
| 496 env.SideEffect(auxfilename,target[0]) | 475 env.SideEffect(auxfilename,target[0]) |
| 497 env.SideEffect(logfilename,target[0]) | 476 env.SideEffect(logfilename,target[0]) |
| 498 env.Clean(target[0],auxfilename) | 477 env.Clean(target[0],auxfilename) |
| 499 env.Clean(target[0],logfilename) | 478 env.Clean(target[0],logfilename) |
| 500 | 479 |
| 501 content = source[0].get_contents() | 480 content = source[0].get_text_contents() |
| 502 | 481 |
| 503 idx_exists = os.path.exists(targetbase + '.idx') | 482 idx_exists = os.path.exists(targetbase + '.idx') |
| 504 nlo_exists = os.path.exists(targetbase + '.nlo') | 483 nlo_exists = os.path.exists(targetbase + '.nlo') |
| 505 glo_exists = os.path.exists(targetbase + '.glo') | 484 glo_exists = os.path.exists(targetbase + '.glo') |
| 506 | 485 |
| 507 # set up list with the regular expressions | 486 # set up list with the regular expressions |
| 508 # we use to find features used | 487 # we use to find features used |
| 509 file_tests_search = [auxfile_re, | 488 file_tests_search = [auxfile_re, |
| 510 makeindex_re, | 489 makeindex_re, |
| 511 bibliography_re, | 490 bibliography_re, |
| (...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 652 env['MAKENCLFLAGS'] = '-s ${MAKENCLSTYLE} -t ${SOURCE.filebase}.nlg' | 631 env['MAKENCLFLAGS'] = '-s ${MAKENCLSTYLE} -t ${SOURCE.filebase}.nlg' |
| 653 env['MAKENCLCOM'] = 'cd ${TARGET.dir} && $MAKENCL ${SOURCE.filebase}.nlo $
MAKENCLFLAGS -o ${SOURCE.filebase}.nls' | 632 env['MAKENCLCOM'] = 'cd ${TARGET.dir} && $MAKENCL ${SOURCE.filebase}.nlo $
MAKENCLFLAGS -o ${SOURCE.filebase}.nls' |
| 654 | 633 |
| 655 # Duplicate from pdflatex.py. If latex.py goes away, then this is still OK. | 634 # Duplicate from pdflatex.py. If latex.py goes away, then this is still OK. |
| 656 env['PDFLATEX'] = 'pdflatex' | 635 env['PDFLATEX'] = 'pdflatex' |
| 657 env['PDFLATEXFLAGS'] = SCons.Util.CLVar('-interaction=nonstopmode') | 636 env['PDFLATEXFLAGS'] = SCons.Util.CLVar('-interaction=nonstopmode') |
| 658 env['PDFLATEXCOM'] = 'cd ${TARGET.dir} && $PDFLATEX $PDFLATEXFLAGS ${SOURC
E.file}' | 637 env['PDFLATEXCOM'] = 'cd ${TARGET.dir} && $PDFLATEX $PDFLATEXFLAGS ${SOURC
E.file}' |
| 659 | 638 |
| 660 def exists(env): | 639 def exists(env): |
| 661 return env.Detect('tex') | 640 return env.Detect('tex') |
| OLD | NEW |