summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--QMTest/TestCmd.py24
-rw-r--r--doc/user/add-method.in2
-rw-r--r--doc/user/add-method.xml2
-rw-r--r--doc/user/builders-writing.in6
-rw-r--r--doc/user/builders-writing.xml6
-rw-r--r--doc/user/command-line.in30
-rw-r--r--doc/user/command-line.xml30
-rw-r--r--doc/user/depends.in6
-rw-r--r--doc/user/depends.xml6
-rw-r--r--doc/user/environments.in4
-rw-r--r--doc/user/environments.xml4
-rw-r--r--src/CHANGES.txt13
-rw-r--r--src/engine/SCons/Node/FS.py2
-rw-r--r--src/engine/SCons/Node/__init__.py3
-rw-r--r--src/engine/SCons/Taskmaster.py31
-rw-r--r--src/engine/SCons/TaskmasterTests.py91
-rw-r--r--src/engine/SCons/Tool/tex.py38
-rw-r--r--test/TEX/multibib.py97
-rw-r--r--test/explain/basic.py2
19 files changed, 345 insertions, 52 deletions
diff --git a/QMTest/TestCmd.py b/QMTest/TestCmd.py
index 1d5e4d0..a27df27 100644
--- a/QMTest/TestCmd.py
+++ b/QMTest/TestCmd.py
@@ -128,6 +128,7 @@ There are a bunch of methods that let you do different things:
test.match_exact("actual 1\nactual 2\n", "expected 1\nexpected 2\n")
test.match_exact(["actual 1\n", "actual 2\n"],
["expected 1\n", "expected 2\n"])
+ test.match_caseinsensitive("Actual 1\nACTUAL 2\n", "expected 1\nEXPECTED 2\n")
test.match_re("actual 1\nactual 2\n", regex_string)
test.match_re(["actual 1\n", "actual 2\n"], list_of_regexes)
@@ -180,6 +181,8 @@ matching in the same way as the match_*() methods described above.
test = TestCmd.TestCmd(match = TestCmd.match_exact)
+ test = TestCmd.TestCmd(match = TestCmd.match_caseinsensitive)
+
test = TestCmd.TestCmd(match = TestCmd.match_re)
test = TestCmd.TestCmd(match = TestCmd.match_re_dotall)
@@ -190,6 +193,8 @@ These functions are also available as static methods:
test = TestCmd.TestCmd(match = TestCmd.TestCmd.match_exact)
+ test = TestCmd.TestCmd(match = TestCmd.TestCmd.match_caseinsensitive)
+
test = TestCmd.TestCmd(match = TestCmd.TestCmd.match_re)
test = TestCmd.TestCmd(match = TestCmd.TestCmd.match_re_dotall)
@@ -200,6 +205,8 @@ These static methods can be accessed by a string naming the method:
test = TestCmd.TestCmd(match = 'match_exact')
+ test = TestCmd.TestCmd(match = 'match_caseinsensitive')
+
test = TestCmd.TestCmd(match = 'match_re')
test = TestCmd.TestCmd(match = 'match_re_dotall')
@@ -328,6 +335,7 @@ __all__ = [
'no_result',
'pass_test',
'match_exact',
+ 'match_caseinsensitive',
'match_re',
'match_re_dotall',
'python',
@@ -466,6 +474,20 @@ def match_exact(lines = None, matches = None):
return
return 1
+def match_caseinsensitive(lines = None, matches = None):
+ """
+ """
+ if not is_List(lines):
+ lines = lines.split("\n")
+ if not is_List(matches):
+ matches = matches.split("\n")
+ if len(lines) != len(matches):
+ return
+ for i in range(len(lines)):
+ if lines[i].lower() != matches[i].lower():
+ return
+ return 1
+
def match_re(lines = None, res = None):
"""
"""
@@ -1127,6 +1149,8 @@ class TestCmd(object):
match_exact = staticmethod(match_exact)
+ match_caseinsensitive = staticmethod(match_caseinsensitive)
+
match_re = staticmethod(match_re)
match_re_dotall = staticmethod(match_re_dotall)
diff --git a/doc/user/add-method.in b/doc/user/add-method.in
index 7efd923..2deb07a 100644
--- a/doc/user/add-method.in
+++ b/doc/user/add-method.in
@@ -65,7 +65,7 @@
<para>
- As mentioned, a psuedo-builder also provides more flexibility
+ As mentioned, a pseudo-builder also provides more flexibility
in parsing arguments than you can get with a &Builder;.
The next example shows a pseudo-builder with a
named argument that modifies the filename, and a separate argument
diff --git a/doc/user/add-method.xml b/doc/user/add-method.xml
index 51bc04b..3aac7a8 100644
--- a/doc/user/add-method.xml
+++ b/doc/user/add-method.xml
@@ -64,7 +64,7 @@
<para>
- As mentioned, a psuedo-builder also provides more flexibility
+ As mentioned, a pseudo-builder also provides more flexibility
in parsing arguments than you can get with a &Builder;.
The next example shows a pseudo-builder with a
named argument that modifies the filename, and a separate argument
diff --git a/doc/user/builders-writing.in b/doc/user/builders-writing.in
index 93a183c..749a8ba 100644
--- a/doc/user/builders-writing.in
+++ b/doc/user/builders-writing.in
@@ -98,8 +98,8 @@ This functionality could be invoked as in the following example:
<para>
Although &SCons; provides many useful methods
- for building common software products:
- programs, libraries, documents.
+ for building common software products
+ (programs, libraries, documents, etc.),
you frequently want to be
able to build some other type of file
not supported directly by &SCons;.
@@ -109,7 +109,7 @@ This functionality could be invoked as in the following example:
(In fact, the &SCons; interfaces for creating
&Builder; objects are flexible enough and easy enough to use
that all of the the &SCons; built-in &Builder; objects
- are created the mechanisms described in this section.)
+ are created using the mechanisms described in this section.)
</para>
diff --git a/doc/user/builders-writing.xml b/doc/user/builders-writing.xml
index c8ff003..f42a61f 100644
--- a/doc/user/builders-writing.xml
+++ b/doc/user/builders-writing.xml
@@ -98,8 +98,8 @@ This functionality could be invoked as in the following example:
<para>
Although &SCons; provides many useful methods
- for building common software products:
- programs, libraries, documents.
+ for building common software products
+ (programs, libraries, documents, etc.),
you frequently want to be
able to build some other type of file
not supported directly by &SCons;.
@@ -109,7 +109,7 @@ This functionality could be invoked as in the following example:
(In fact, the &SCons; interfaces for creating
&Builder; objects are flexible enough and easy enough to use
that all of the the &SCons; built-in &Builder; objects
- are created the mechanisms described in this section.)
+ are created using the mechanisms described in this section.)
</para>
diff --git a/doc/user/command-line.in b/doc/user/command-line.in
index abf8953..33f88ec 100644
--- a/doc/user/command-line.in
+++ b/doc/user/command-line.in
@@ -62,7 +62,7 @@
Any command-line argument containing an <literal>=</literal>
(equal sign) is considered a variable setting with the form
- <varname>variable</varname>=<varname>value</varname>
+ <varname>variable</varname>=<varname>value</varname>.
&SCons; provides direct access to
all of the command-line variable settings,
the ability to apply command-line variable settings
@@ -885,7 +885,7 @@
<scons_example name="Variables1">
<file name="SConstruct" printme="1">
- vars = Variables()
+ vars = Variables(None, ARGUMENTS)
vars.Add('RELEASE', 'Set to 1 to build for release', 0)
env = Environment(variables = vars,
CPPDEFINES={'RELEASE_BUILD' : '${RELEASE}'})
@@ -902,8 +902,9 @@
<para>
This &SConstruct; file first creates a &Variables; object
- (the <literal>vars = Variables()</literal> call),
- and then uses the object's &Add;
+ which uses the values from the command-line options dictionary &ARGUMENTS;
+ (the <literal>vars = Variables(None, ARGUMENTS)</literal> call).
+ It then uses the object's &Add;
method to indicate that the &RELEASE;
variable can be set on the command line,
and that its default value will be <literal>0</literal>
@@ -942,7 +943,7 @@
&PathOption;, &PackageOption; and &AddOptions;.
These older names still work,
and you may encounter them in older
- &SConscript; fles,
+ &SConscript; files,
but they have been officially deprecated
as of &SCons; version 2.0.
@@ -975,7 +976,7 @@
<scons_example name="Variables_Help">
<file name="SConstruct" printme="1">
- vars = Variables('custom.py')
+ vars = Variables(None, ARGUMENTS)
vars.Add('RELEASE', 'Set to 1 to build for release', 0)
env = Environment(variables = vars)
Help(vars.GenerateHelpText(env))
@@ -1098,6 +1099,23 @@
<scons_output_command>scons -Q</scons_output_command>
</scons_output>
+ <para>
+
+ Finally, you can combine both methods with:
+
+ </para>
+
+ <screen>
+ vars = Variables('custom.py', ARGUMENTS)
+ </screen>
+
+ <para>
+
+ where values in the option file &custom_py; get overwritten
+ by the ones specified on the command line.
+
+ </para>
+
</section>
<section>
diff --git a/doc/user/command-line.xml b/doc/user/command-line.xml
index 1bb84e2..1006c6b 100644
--- a/doc/user/command-line.xml
+++ b/doc/user/command-line.xml
@@ -62,7 +62,7 @@
Any command-line argument containing an <literal>=</literal>
(equal sign) is considered a variable setting with the form
- <varname>variable</varname>=<varname>value</varname>
+ <varname>variable</varname>=<varname>value</varname>.
&SCons; provides direct access to
all of the command-line variable settings,
the ability to apply command-line variable settings
@@ -875,7 +875,7 @@
</para>
<programlisting>
- vars = Variables()
+ vars = Variables(None, ARGUMENTS)
vars.Add('RELEASE', 'Set to 1 to build for release', 0)
env = Environment(variables = vars,
CPPDEFINES={'RELEASE_BUILD' : '${RELEASE}'})
@@ -885,8 +885,9 @@
<para>
This &SConstruct; file first creates a &Variables; object
- (the <literal>vars = Variables()</literal> call),
- and then uses the object's &Add;
+ which uses the values from the command-line options dictionary &ARGUMENTS;
+ (the <literal>vars = Variables(None, ARGUMENTS)</literal> call).
+ It then uses the object's &Add;
method to indicate that the &RELEASE;
variable can be set on the command line,
and that its default value will be <literal>0</literal>
@@ -928,7 +929,7 @@
&PathOption;, &PackageOption; and &AddOptions;.
These older names still work,
and you may encounter them in older
- &SConscript; fles,
+ &SConscript; files,
but they have been officially deprecated
as of &SCons; version 2.0.
@@ -960,7 +961,7 @@
</para>
<programlisting>
- vars = Variables('custom.py')
+ vars = Variables(None, ARGUMENTS)
vars.Add('RELEASE', 'Set to 1 to build for release', 0)
env = Environment(variables = vars)
Help(vars.GenerateHelpText(env))
@@ -1069,6 +1070,23 @@
cc -o foo foo.o bar.o
</screen>
+ <para>
+
+ Finally, you can combine both methods with:
+
+ </para>
+
+ <screen>
+ vars = Variables('custom.py', ARGUMENTS)
+ </screen>
+
+ <para>
+
+ where values in the option file &custom_py; get overwritten
+ by the ones specified on the command line.
+
+ </para>
+
</section>
<section>
diff --git a/doc/user/depends.in b/doc/user/depends.in
index 88828fe..f601312 100644
--- a/doc/user/depends.in
+++ b/doc/user/depends.in
@@ -593,11 +593,11 @@
<para>
- Another thing to look out for, is the fact that the three
+ Another thing to look out for is the fact that the three
attributes above may not be present at the time of the first run.
- Without any prior build, no targets got created and no
+ Without any prior build, no targets have been created and no
<filename>.sconsign</filename> DB file exists yet.
- So, it is recommended to always check whether the
+ So, you should always check whether the
<varname>prev_ni</varname> attribute in question is available.
</para>
diff --git a/doc/user/depends.xml b/doc/user/depends.xml
index a5e84d6..df2a911 100644
--- a/doc/user/depends.xml
+++ b/doc/user/depends.xml
@@ -589,11 +589,11 @@
<para>
- Another thing to look out for, is the fact that the three
+ Another thing to look out for is the fact that the three
attributes above may not be present at the time of the first run.
- Without any prior build, no targets got created and no
+ Without any prior build, no targets have been created and no
<filename>.sconsign</filename> DB file exists yet.
- So, it is recommended to always check whether the
+ So, you should always check whether the
<varname>prev_ni</varname> attribute in question is available.
</para>
diff --git a/doc/user/environments.in b/doc/user/environments.in
index f767676..9f39347 100644
--- a/doc/user/environments.in
+++ b/doc/user/environments.in
@@ -684,7 +684,7 @@ environment, of directory names, suffixes, etc.
<para>
Another way to get information from
- a construction environment.
+ a construction environment
is to use the &subst; method
on a string containing <literal>$</literal> expansions
of construction variable names.
@@ -874,7 +874,7 @@ environment, of directory names, suffixes, etc.
<para>
You can, however, control the settings
- in the default contstruction environment
+ in the default construction environment
by using the &DefaultEnvironment; function
to initialize various settings:
diff --git a/doc/user/environments.xml b/doc/user/environments.xml
index b2a8505..eaf4ba3 100644
--- a/doc/user/environments.xml
+++ b/doc/user/environments.xml
@@ -684,7 +684,7 @@ environment, of directory names, suffixes, etc.
<para>
Another way to get information from
- a construction environment.
+ a construction environment
is to use the &subst; method
on a string containing <literal>$</literal> expansions
of construction variable names.
@@ -875,7 +875,7 @@ environment, of directory names, suffixes, etc.
<para>
You can, however, control the settings
- in the default contstruction environment
+ in the default construction environment
by using the &DefaultEnvironment; function
to initialize various settings:
diff --git a/src/CHANGES.txt b/src/CHANGES.txt
index fbe4f25..f32c3f1 100644
--- a/src/CHANGES.txt
+++ b/src/CHANGES.txt
@@ -4,6 +4,19 @@
Change Log
+RELEASE 2.X.X -
+
+ From Alexey Klimkin:
+ - Fixed the Taskmaster, curing spurious build failures in
+ multi-threaded runs (#2720).
+
+ From Dirk Baechle:
+ - Improved documentation of command-line variables (#2809).
+ - Fixed scons-doc.py to properly convert main XML files (#2812).
+
+ From Rob Managan:
+ - Updated the TeX builder to support LaTeX's multibib package.
+
RELEASE 2.1.0 - Mon, 09 Sep 2011 20:54:57 -0700
diff --git a/src/engine/SCons/Node/FS.py b/src/engine/SCons/Node/FS.py
index f106d46..f31ca83 100644
--- a/src/engine/SCons/Node/FS.py
+++ b/src/engine/SCons/Node/FS.py
@@ -2715,7 +2715,7 @@ class File(Base):
so only do thread safe stuff here. Do thread unsafe stuff in
built().
- Returns true iff the node was successfully retrieved.
+ Returns true if the node was successfully retrieved.
"""
if self.nocache:
return None
diff --git a/src/engine/SCons/Node/__init__.py b/src/engine/SCons/Node/__init__.py
index 2fbe2c6..992284d 100644
--- a/src/engine/SCons/Node/__init__.py
+++ b/src/engine/SCons/Node/__init__.py
@@ -216,6 +216,7 @@ class Node(object):
self.precious = None
self.noclean = 0
self.nocache = 0
+ self.cached = 0 # is this node pulled from cache?
self.always_build = None
self.includes = None
self.attributes = self.Attrs() # Generic place to stick information about the Node.
@@ -306,7 +307,7 @@ class Node(object):
so only do thread safe stuff here. Do thread unsafe stuff in
built().
- Returns true iff the node was successfully retrieved.
+ Returns true if the node was successfully retrieved.
"""
return 0
diff --git a/src/engine/SCons/Taskmaster.py b/src/engine/SCons/Taskmaster.py
index 58a8d90..64ab84d 100644
--- a/src/engine/SCons/Taskmaster.py
+++ b/src/engine/SCons/Taskmaster.py
@@ -227,20 +227,26 @@ class Task(object):
if T: T.write(self.trace_message(u'Task.execute()', self.node))
try:
- everything_was_cached = 1
+ cached_targets = []
for t in self.targets:
- if t.retrieve_from_cache():
- # Call the .built() method without calling the
- # .push_to_cache() method, since we just got the
- # target from the cache and don't need to push
- # it back there.
- t.set_state(NODE_EXECUTED)
- t.built()
- else:
- everything_was_cached = 0
+ if not t.retrieve_from_cache():
break
- if not everything_was_cached:
+ cached_targets.append(t)
+ if len(cached_targets) < len(self.targets):
+ # Remove targets before building. It's possible that we
+ # partially retrieved targets from the cache, leaving
+ # them in read-only mode. That might cause the command
+ # to fail.
+ #
+ for t in cached_targets:
+ try:
+ t.fs.unlink(t.path)
+ except (IOError, OSError):
+ pass
self.targets[0].build()
+ else:
+ for t in cached_targets:
+ t.cached = 1
except SystemExit:
exc_value = sys.exc_info()[1]
raise SCons.Errors.ExplicitExit(self.targets[0], exc_value.code)
@@ -292,7 +298,8 @@ class Task(object):
for side_effect in t.side_effects:
side_effect.set_state(NODE_NO_STATE)
t.set_state(NODE_EXECUTED)
- t.push_to_cache()
+ if not t.cached:
+ t.push_to_cache()
t.built()
t.visited()
diff --git a/src/engine/SCons/TaskmasterTests.py b/src/engine/SCons/TaskmasterTests.py
index 66c6b9c..85ade8d 100644
--- a/src/engine/SCons/TaskmasterTests.py
+++ b/src/engine/SCons/TaskmasterTests.py
@@ -86,16 +86,61 @@ class Node(object):
def prepare(self):
self.prepared = 1
+ self.get_binfo()
def build(self):
global built_text
built_text = self.name + " built"
+ def remove(self):
+ pass
+
+ # The following four methods new_binfo(), del_binfo(),
+ # get_binfo(), clear() as well as its calls have been added
+ # to support the cached_execute() test (issue #2720).
+ # They are full copies (or snippets) of their actual
+ # counterparts in the Node class...
+ def new_binfo(self):
+ binfo = "binfo"
+ return binfo
+
+ def del_binfo(self):
+ """Delete the build info from this node."""
+ try:
+ delattr(self, 'binfo')
+ except AttributeError:
+ pass
+
+ def get_binfo(self):
+ """Fetch a node's build information."""
+ try:
+ return self.binfo
+ except AttributeError:
+ pass
+
+ binfo = self.new_binfo()
+ self.binfo = binfo
+
+ return binfo
+
+ def clear(self):
+ # The del_binfo() call here isn't necessary for normal execution,
+ # but is for interactive mode, where we might rebuild the same
+ # target and need to start from scratch.
+ self.del_binfo()
+
def built(self):
global built_text
if not self.cached:
built_text = built_text + " really"
-
+
+ # Clear the implicit dependency caches of any Nodes
+ # waiting for this Node to be built.
+ for parent in self.waiting_parents:
+ parent.implicit = None
+
+ self.clear()
+
def has_builder(self):
return not self.builder is None
@@ -954,6 +999,50 @@ class TaskmasterTestCase(unittest.TestCase):
assert built_text is None, built_text
assert cache_text == ["n7 retrieved", "n8 retrieved"], cache_text
+ def test_cached_execute(self):
+ """Test executing a task with cached targets
+ """
+ # In issue #2720 Alexei Klimkin detected that the previous
+ # workflow for execute() led to problems in a multithreaded build.
+ # We have:
+ # task.prepare()
+ # task.execute()
+ # task.executed()
+ # -> node.visited()
+ # for the Serial flow, but
+ # - Parallel - - Worker -
+ # task.prepare()
+ # requestQueue.put(task)
+ # task = requestQueue.get()
+ # task.execute()
+ # resultQueue.put(task)
+ # task = resultQueue.get()
+ # task.executed()
+ # ->node.visited()
+ # in parallel. Since execute() used to call built() when a target
+ # was cached, it could unblock dependent nodes before the binfo got
+ # restored again in visited(). This resulted in spurious
+ # "file not found" build errors, because files fetched from cache would
+ # be seen as not up to date and wouldn't be scanned for implicit
+ # dependencies.
+ #
+ # The following test ensures that execute() only marks targets as cached,
+ # but the actual call to built() happens in executed() only.
+ # Like this, the binfo should still be intact after calling execute()...
+ global cache_text
+
+ n1 = Node("n1")
+ # Mark the node as being cached
+ n1.cached = 1
+ tm = SCons.Taskmaster.Taskmaster([n1])
+ t = tm.next_task()
+ t.prepare()
+ t.execute()
+ assert cache_text == ["n1 retrieved"], cache_text
+ # If no binfo exists anymore, something has gone wrong...
+ has_binfo = hasattr(n1, 'binfo')
+ assert has_binfo == True, has_binfo
+
def test_exception(self):
"""Test generic Taskmaster exception handling
diff --git a/src/engine/SCons/Tool/tex.py b/src/engine/SCons/Tool/tex.py
index b0c518e..0d871ad 100644
--- a/src/engine/SCons/Tool/tex.py
+++ b/src/engine/SCons/Tool/tex.py
@@ -86,6 +86,7 @@ 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)
bibunit_re = re.compile(r"^[^%\n]*\\begin\{bibunit\}", re.MULTILINE)
+multibib_re = re.compile(r"^[^%\n]*\\newcites\{([^\}]*)\}", 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)
@@ -236,6 +237,9 @@ def InternalLaTeXAuxAction(XXXLaTeXAction, target = None, source= None, env=None
must_rerun_latex = True
+ # .aux files already processed by BibTex
+ already_bibtexed = []
+
#
# routine to update MD5 hash and compare
#
@@ -298,21 +302,23 @@ def InternalLaTeXAuxAction(XXXLaTeXAction, target = None, source= None, env=None
# The information that bibtex reads from the .aux file is
# pass-independent. If we find (below) that the .bbl file is unchanged,
# then the last latex saw a correct bibliography.
- # Therefore only do this on the first pass
- if count == 1:
- for auxfilename in auxfiles:
+ # Therefore only do this once
+ # Go through all .aux files and remember the files already done.
+ for auxfilename in auxfiles:
+ if auxfilename not in already_bibtexed:
+ already_bibtexed.append(auxfilename)
target_aux = os.path.join(targetdir, auxfilename)
if os.path.isfile(target_aux):
content = open(target_aux, "rb").read()
if content.find("bibdata") != -1:
if Verbose:
- print "Need to run bibtex"
+ print "Need to run bibtex on ",auxfilename
bibfile = env.fs.File(SCons.Util.splitext(target_aux)[0])
result = BibTeXAction(bibfile, bibfile, env)
if result != 0:
check_file_error_message(env['BIBTEX'], 'blg')
- must_rerun_latex = must_rerun_latex or check_MD5(suffix_nodes['.bbl'],'.bbl')
-
+ #must_rerun_latex = must_rerun_latex or check_MD5(suffix_nodes['.bbl'],'.bbl')
+ must_rerun_latex = True
# Now decide if latex will need to be run again due to index.
if check_MD5(suffix_nodes['.idx'],'.idx') or (count == 1 and run_makeindex):
# We must run makeindex
@@ -553,6 +559,8 @@ def ScanFiles(theFile, target, paths, file_tests, file_tests_search, env, graphi
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)
+ if Verbose and file_tests[i][0]:
+ print " found match for ",file_tests[i][-1][-1]
incResult = includeOnly_re.search(content)
if incResult:
@@ -621,6 +629,7 @@ def tex_emitter_core(target, source, env, graphics_extensions):
makeindex_re,
bibliography_re,
bibunit_re,
+ multibib_re,
tableofcontents_re,
listoffigures_re,
listoftables_re,
@@ -636,6 +645,7 @@ def tex_emitter_core(target, source, env, graphics_extensions):
['.idx', '.ind', '.ilg','makeindex'],
['.bbl', '.blg','bibliography'],
['.bbl', '.blg','bibunit'],
+ ['.bbl', '.blg','multibib'],
['.toc','contents'],
['.lof','figures'],
['.lot','tables'],
@@ -678,6 +688,8 @@ def tex_emitter_core(target, source, env, graphics_extensions):
for (theSearch,suffix_list) in file_tests:
# add side effects if feature is present.If file is to be generated,add all side effects
+ if Verbose and theSearch:
+ print "check side effects for ",suffix_list[-1]
if (theSearch != None) or (not source[0].exists() ):
file_list = [targetbase,]
# for bibunit we need a list of files
@@ -687,6 +699,18 @@ def tex_emitter_core(target, source, env, graphics_extensions):
# remove the suffix '.aux'
for i in range(len(file_list)):
file_list[i] = SCons.Util.splitext(file_list[i])[0]
+ # for multibib we need a list of files
+ if suffix_list[-1] == 'multibib':
+ file_list = []
+ for multibibmatch in multibib_re.finditer(content):
+ if Verbose:
+ print "multibib match ",multibibmatch.group(1)
+ if multibibmatch != None:
+ baselist = multibibmatch.group(1).split(',')
+ if Verbose:
+ print "multibib list ", baselist
+ for i in range(len(baselist)):
+ file_list.append(os.path.join(targetdir, baselist[i]))
# now define the side effects
for file_name in file_list:
for suffix in suffix_list[:-1]:
@@ -826,7 +850,7 @@ def generate_common(env):
env['LATEX'] = 'latex'
env['LATEXFLAGS'] = SCons.Util.CLVar('-interaction=nonstopmode -recorder')
env['LATEXCOM'] = CDCOM + '${TARGET.dir} && $LATEX $LATEXFLAGS ${SOURCE.file}'
- env['LATEXRETRIES'] = 3
+ env['LATEXRETRIES'] = 4
env['PDFLATEX'] = 'pdflatex'
env['PDFLATEXFLAGS'] = SCons.Util.CLVar('-interaction=nonstopmode -recorder')
diff --git a/test/TEX/multibib.py b/test/TEX/multibib.py
new file mode 100644
index 0000000..8486e15
--- /dev/null
+++ b/test/TEX/multibib.py
@@ -0,0 +1,97 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Test creation of a Tex document that uses the multibib oackage
+
+Test courtesy Rob Managan.
+"""
+
+import TestSCons
+import os
+
+test = TestSCons.TestSCons()
+
+latex = test.where_is('latex')
+if not latex:
+ test.skip_test("Could not find 'latex'; skipping test.\n")
+
+test.subdir(['src'])
+
+
+test.write(['SConstruct'], """\
+import os
+
+env = Environment()
+
+DVI('multibib.tex')
+""")
+
+
+test.write(['lit.bib'],r"""
+@book{Knuth:1991, author = {Knuth, Donald E.}, title = {The TEX book}, publisher = {Addison-Wesley, Reading, Massachusetts}, year = {1991}}
+@book{Lamport:1994, author = {Lamport, Leslie}, title = {LATEX: A Document Preparation System}, publisher = {Addison-Wesley, Reading, Massachusetts, 2 edition}, year = {1994} }
+@book{Adobe:1985, author = {Adobe System Incorporated}, title = {Postscript Language Tutorial and Cookbook}, publisher = {Addison-Wesley, Reading, Massachusetts}, year = {1985}}
+
+""")
+
+test.write(['multibib.tex'],r"""
+\documentclass{article}
+\usepackage{multibib}
+\newcites{ltex}{\TeX\ and \LaTeX\ References}
+\begin{document}
+References to the \TeX book \citeltex{Knuth:1991} and to Lamport's \LaTeX\ book, which appears only in the references\nociteltex{Lamport:1994}. Finally a cite to a Postscript tutorial \cite{Adobe:1985}.
+\bibliographystyleltex{alpha}
+\bibliographyltex{lit}
+\renewcommand{\refname}{Postscript References}
+\bibliographystyle{plain}
+\bibliography{lit}
+\end{document}
+""")
+
+
+test.run(arguments = '', stderr=None)
+
+
+# All (?) the files we expect will get created in the docs directory
+files = [
+ 'ltex.aux',
+ 'ltex.bbl',
+ 'ltex.blg',
+ 'multibib.aux',
+ 'multibib.bbl',
+ 'multibib.blg',
+ 'multibib.fls',
+ 'multibib.log',
+ 'multibib.dvi',
+]
+
+for f in files:
+ test.must_exist([ f])
+
+#test.must_not_exist(['docs/Fig1.pdf',])
+
+test.pass_test()
diff --git a/test/explain/basic.py b/test/explain/basic.py
index bca8436..1f0a16c 100644
--- a/test/explain/basic.py
+++ b/test/explain/basic.py
@@ -305,7 +305,9 @@ scons: rebuilding `file3' because `zzz' is a new dependency
%(_python_)s %(cat_py)s file3 xxx yyy zzz
""" % locals())
+test.set_match_function(TestSCons.match_caseinsensitive)
test.run(chdir='src', arguments=args, stdout=expect)
+test.set_match_function(TestSCons.match_exact)
test.must_match(['src', 'file3'], "xxx 1\nyyy 2\nzzz 2\n")