5 # Permission is hereby granted, free of charge, to any person obtaining
6 # a copy of this software and associated documentation files (the
7 # "Software"), to deal in the Software without restriction, including
8 # without limitation the rights to use, copy, modify, merge, publish,
9 # distribute, sublicense, and/or sell copies of the Software, and to
10 # permit persons to whom the Software is furnished to do so, subject to
11 # the following conditions:
13 # The above copyright notice and this permission notice shall be included
14 # in all copies or substantial portions of the Software.
16 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
17 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
18 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 This tests the -j command line option, and the num_jobs
27 SConscript settable option.
30 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
36 _python_ = TestSCons._python_
41 # if threads are not supported, then
42 # there is nothing to test
47 test = TestSCons.TestSCons()
49 test.write('build.py', r"""
52 file = open(sys.argv[1], 'wb')
53 file.write(str(time.time()) + '\n')
55 file.write(str(time.time()))
61 test.write(['foo','foo.in'], r"""
65 test.write('SConstruct', """
66 MyBuild = Builder(action = r'%(_python_)s build.py $TARGETS')
67 env = Environment(BUILDERS = { 'MyBuild' : MyBuild })
69 env.MyBuild(target = 'f1', source = 'f1.in')
70 env.MyBuild(target = 'f2', source = 'f2.in')
72 def copyn(env, target, source):
77 shutil.copy(str(source[0]), str(t))
79 t = env.Command(target=['foo/foo1.out', 'foo/foo2.out'],
85 def RunTest(args, extra):
86 """extra is used to make scons rebuild the output file"""
87 test.write('f1.in', 'f1.in'+extra)
88 test.write('f2.in', 'f2.in'+extra)
90 test.run(arguments = args)
93 start1,finish1 = list(map(float, str.split("\n")))
96 start2,finish2 = list(map(float, str.split("\n")))
98 return start2, finish1
100 # Test 2 parallel jobs.
101 # fail if the second file was not started
102 # before the first one was finished.
103 start2, finish1 = RunTest('-j 2 f1 f2', "first")
104 test.fail_test(not (start2 < finish1))
106 # re-run the test with the same input, fail if we don't
107 # get back the same times, which would indicate that
108 # SCons rebuilt the files even though nothing changed
109 s2, f1 = RunTest('-j 2 f1 f2', "first")
110 test.fail_test(start2 != s2)
111 test.fail_test(finish1 != f1)
113 # Test a single serial job.
114 # fail if the second file was started
115 # before the first one was finished
116 start2, finish1 = RunTest('f1 f2', "second")
117 test.fail_test(start2 < finish1)
119 # Make sure that a parallel build using a list builder
121 test.run(arguments='-j 2 out')
124 # Test that we fall back and warn properly if there's no threading.py
125 # module (simulated), which is the case if this version of Python wasn't
126 # built with threading support.
128 test.subdir('pythonlib')
130 test.write(['pythonlib', 'threading.py'], """\
134 save_pythonpath = os.environ.get('PYTHONPATH', '')
135 os.environ['PYTHONPATH'] = test.workpath('pythonlib')
137 #start2, finish1 = RunTest('-j 2 f1, f2', "fifth")
139 test.write('f1.in', 'f1.in pythonlib\n')
140 test.write('f2.in', 'f2.in pythonlib\n')
142 test.run(arguments = "-j 2 f1 f2", stderr=None)
145 """scons: warning: parallel builds are unsupported by this version of Python;
146 \tignoring -j or num_jobs option.
148 test.must_contain_all_lines(test.stderr(), [warn])
150 str = test.read("f1")
151 start1,finish1 = list(map(float, str.split("\n")))
153 str = test.read("f2")
154 start2,finish2 = list(map(float, str.split("\n")))
156 test.fail_test(start2 < finish1)
158 os.environ['PYTHONPATH'] = save_pythonpath
161 # Test SetJobs() with no -j:
162 test.write('SConstruct', """
163 MyBuild = Builder(action = r'%(_python_)s build.py $TARGETS')
164 env = Environment(BUILDERS = { 'MyBuild' : MyBuild })
166 env.MyBuild(target = 'f1', source = 'f1.in')
167 env.MyBuild(target = 'f2', source = 'f2.in')
169 def copyn(env, target, source):
174 shutil.copy(str(source[0]), str(t))
176 t = env.Command(target=['foo/foo1.out', 'foo/foo2.out'], source='foo/foo.in', action=copyn)
177 env.Install('out', t)
179 assert GetOption('num_jobs') == 1
180 SetOption('num_jobs', 2)
181 assert GetOption('num_jobs') == 2
184 # This should be a parallel build because the SConscript sets jobs to 2.
185 # fail if the second file was not started
186 # before the first one was finished
187 start2, finish1 = RunTest('f1 f2', "third")
188 test.fail_test(not (start2 < finish1))
190 # Test SetJobs() with -j:
191 test.write('SConstruct', """
192 MyBuild = Builder(action = r'%(_python_)s build.py $TARGETS')
193 env = Environment(BUILDERS = { 'MyBuild' : MyBuild })
195 env.MyBuild(target = 'f1', source = 'f1.in')
196 env.MyBuild(target = 'f2', source = 'f2.in')
198 def copyn(env, target, source):
203 shutil.copy(str(source[0]), str(t))
205 t = env.Command(target=['foo/foo1.out', 'foo/foo2.out'], source='foo/foo.in', action=copyn)
206 env.Install('out', t)
208 assert GetOption('num_jobs') == 1
209 SetOption('num_jobs', 2)
210 assert GetOption('num_jobs') == 1
213 # This should be a serial build since -j 1 overrides the call to SetJobs().
214 # fail if the second file was started
215 # before the first one was finished
216 start2, finish1 = RunTest('-j 1 f1 f2', "fourth")
217 test.fail_test(start2 < finish1)
225 # indent-tabs-mode:nil
227 # vim: set expandtab tabstop=4 shiftwidth=4: