Eliminate unnecessary WIN32/Win32/win32 references in tests, too.
[scons.git] / test / Configure.py
1 #!/usr/bin/env python
2 #
3 # __COPYRIGHT__
4 #
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:
12 #
13 # The above copyright notice and this permission notice shall be included
14 # in all copies or substantial portions of the Software.
15 #
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.
23 #
24
25 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
26
27 import os
28 import re
29 import shutil
30 import string
31 import sys
32
33 import __builtin__
34 try:
35     __builtin__.zip
36 except AttributeError:
37     def zip(*lists):
38         result = []
39         for i in xrange(len(lists[0])):
40             result.append(tuple(map(lambda l, i=i: l[i], lists)))
41         return result
42     __builtin__.zip = zip
43
44 import TestCmd
45 import TestSCons
46
47 if sys.platform == 'win32':
48     lib = 'msvcrt'
49 else:
50     lib = 'm'
51
52 # to use cygwin compilers on cmd.exe -> uncomment following line
53 #lib = 'm'
54
55 work_cnt = 0
56 work_dir = None
57 python = TestSCons.python
58 test = TestSCons.TestSCons()
59 _obj = TestSCons._obj
60 _exe = TestSCons._exe
61
62 RE = 0
63 RE_DOTALL = 1
64 EXACT = 2
65 def reset(match):
66     global test, work_dir, work_cnt
67     work_cnt = work_cnt + 1
68     work_dir='test%d' % work_cnt
69     test.subdir(work_dir)
70     if match == RE:
71         test.match_func = TestCmd.match_re
72     elif match == RE_DOTALL:
73         test.match_func = TestCmd.match_re_dotall
74     elif match == EXACT:
75         test.match_func = TestCmd.match_exact
76
77 def checkFiles(test, files):
78     global work_dir
79     for f in files:
80         test.fail_test( not os.path.isfile( test.workpath(work_dir,f) ) )
81
82 def checklib(lang, name, up_to_date):
83     if lang == 'C':
84         return (".c", _obj, _exe)
85     elif lang == 'C++':
86         return (".cc", _obj, _exe)
87
88 class NoMatch:
89     def __init__(self, p):
90         self.pos = p
91
92 NCR = 0 # non-cached rebuild
93 CR  = 1 # cached rebuild (up to date)
94 NCF = 2 # non-cached build failure
95 CF  = 3 # cached build failure
96
97 def checkLogAndStdout(checks, results, cached,
98                       test, logfile, sconf_dir, sconstruct,
99                       doCheckLog=1, doCheckStdout=1):
100     def matchPart(log, logfile, lastEnd):
101         m = re.match(log, logfile[lastEnd:])
102         if not m:
103             raise NoMatch, lastEnd
104         return m.end() + lastEnd
105     try:
106         #print len(os.linesep)
107         ls = os.linesep
108         nols = "("
109         for i in range(len(ls)):
110             nols = nols + "("
111             for j in range(i):
112                 nols = nols + ls[j]
113             nols = nols + "[^" + ls[i] + "])"
114             if i < len(ls)-1:
115                 nols = nols + "|"
116         nols = nols + ")"
117         lastEnd = 0
118         logfile = test.read(test.workpath(work_dir, logfile))
119         if (doCheckLog and
120             string.find( logfile, "scons: warning: The stored build "
121                          "information has an unexpected class." ) >= 0):
122             test.fail_test()
123         sconf_dir = sconf_dir
124         sconstruct = sconstruct
125
126         log = re.escape("file " + sconstruct + ",line ") + r"\d+:" + ls
127         if doCheckLog: lastEnd = matchPart(log, logfile, lastEnd)
128         log = "\t" + re.escape("Configure(confdir = %s)" % sconf_dir) + ls
129         if doCheckLog: lastEnd = matchPart(log, logfile, lastEnd)
130         rdstr = ""
131         cnt = 0
132         for check,result,cache_desc in zip(checks, results, cached):
133             log   = re.escape("scons: Configure: " + check) + ls
134             if doCheckLog: lastEnd = matchPart(log, logfile, lastEnd)
135             log = ""
136             result_cached = 1
137             for bld_desc in cache_desc: # each TryXXX
138                 for ext, flag in bld_desc: # each file in TryBuild
139                     file = os.path.join(sconf_dir,"conftest_%d%s" % (cnt, ext))
140                     if flag == NCR:
141                         # rebuild will pass
142                         if ext in ['.c', '.cpp']:
143                             log=log + re.escape(file + " <-") + ls
144                             log=log + r"(  \|" + nols + "*" + ls + ")+?"
145                         else:
146                             log=log + "(" + nols + "*" + ls +")*?"
147                         result_cached = 0
148                     if flag == CR:
149                         # up to date
150                         log=log + \
151                              re.escape("scons: Configure: \"%s\" is up to date." 
152                                        % file) + ls
153                         log=log+re.escape("scons: Configure: The original builder "
154                                           "output was:") + ls
155                         log=log+r"(  \|.*"+ls+")+"
156                     if flag == NCF:
157                         # non-cached rebuild failure
158                         log=log + "(" + nols + "*" + ls + ")*?"
159                         result_cached = 0
160                     if flag == CF:
161                         # cached rebuild failure
162                         log=log + \
163                              re.escape("scons: Configure: Building \"%s\" failed "
164                                        "in a previous run and all its sources are"
165                                        " up to date." % file) + ls
166                         log=log+re.escape("scons: Configure: The original builder "
167                                           "output was:") + ls
168                         log=log+r"(  \|.*"+ls+")+"
169                 cnt = cnt + 1
170             if result_cached:
171                 result = "(cached) " + result
172             rdstr = rdstr + re.escape(check) + re.escape(result) + "\n"
173             log=log + re.escape("scons: Configure: " + result) + ls + ls
174             if doCheckLog: lastEnd = matchPart(log, logfile, lastEnd)
175             log = ""
176         if doCheckLog: lastEnd = matchPart(ls, logfile, lastEnd)
177         if doCheckLog and lastEnd != len(logfile):
178             raise NoMatch, lastEnd
179         
180     except NoMatch, m:
181         print "Cannot match log file against log regexp."
182         print "log file: "
183         print "------------------------------------------------------"
184         print logfile[m.pos:]
185         print "------------------------------------------------------"
186         print "log regexp: "
187         print "------------------------------------------------------"
188         print log
189         print "------------------------------------------------------"
190         test.fail_test()
191
192     if doCheckStdout:
193         exp_stdout = test.wrap_stdout(".*", rdstr)
194         if not test.match_re_dotall(test.stdout(), exp_stdout):
195             print "Unexpected stdout: "
196             print "-----------------------------------------------------"
197             print repr(test.stdout())
198             print "-----------------------------------------------------"
199             print repr(exp_stdout)
200             print "-----------------------------------------------------"
201             test.fail_test()
202         
203 try:
204     # 1.1 if checks are ok, the cache mechanism should work
205
206     reset(RE)
207
208     test.write([work_dir,  'SConstruct'], """
209 if int(ARGUMENTS.get('target_signatures_content', 0)):
210     TargetSignatures('content')
211 env = Environment()
212 import os
213 env.AppendENVPath('PATH', os.environ['PATH'])
214 conf = Configure(env)
215 r1 = conf.CheckLibWithHeader( '%s', 'math.h', 'c' )
216 r2 = conf.CheckLibWithHeader( None, 'math.h', 'c' )
217 r3 = conf.CheckLib( '%s', autoadd=0 )
218 r4 = conf.CheckLib( None, autoadd=0 )
219 r5 = conf.CheckCHeader( 'math.h' )
220 r6 = conf.CheckCXXHeader( 'vector' )
221 env = conf.Finish()
222 if not (r1 and r2 and r3 and r4 and r5 and r6):
223      Exit(1)
224 """ % (lib,lib))
225
226     test.run(chdir=work_dir)
227     checkLogAndStdout(["Checking for main() in C library %s... " % lib,
228                        "Checking for main() in C library None... ",
229                        "Checking for main() in C library %s... " % lib,
230                        "Checking for main() in C library None... ",
231                        "Checking for C header file math.h... ",
232                        "Checking for C++ header file vector... "],
233                       ["yes"]*6,
234                       [[((".c", NCR), (_obj, NCR), (_exe, NCR))]]*4 +
235                         [[((".c", NCR), (_obj, NCR))]] +
236                         [[((".cpp", NCR), (_obj, NCR))]],
237                       test, "config.log", ".sconf_temp", "SConstruct")    
238     
239
240     test.run(chdir=work_dir)
241     checkLogAndStdout(["Checking for main() in C library %s... " % lib,
242                        "Checking for main() in C library None... ",
243                        "Checking for main() in C library %s... " % lib,
244                        "Checking for main() in C library None... ",
245                        "Checking for C header file math.h... ",
246                        "Checking for C++ header file vector... "],
247                       ["yes"]*6,
248                       [[((".c", CR), (_obj, CR), (_exe, CR))]]*4 +
249                        [[((".c", CR), (_obj, CR))]] +
250                        [[((".cpp", CR), (_obj, CR))]],
251                       test, "config.log", ".sconf_temp", "SConstruct")
252
253     # same should be true for TargetSignatures('content')
254
255     test.run(chdir=work_dir, arguments='target_signatures_content=1 --config=force')
256     checkLogAndStdout(["Checking for main() in C library %s... " % lib,
257                        "Checking for main() in C library None... ",
258                        "Checking for main() in C library %s... " % lib,
259                        "Checking for main() in C library None... ",
260                        "Checking for C header file math.h... ",
261                        "Checking for C++ header file vector... "],
262                       ["yes"]*6,
263                       [[((".c", NCR), (_obj, NCR), (_exe, NCR))]]*4 +
264                         [[((".c", NCR), (_obj, NCR))]] +
265                         [[((".cpp", NCR), (_obj, NCR))]],
266                       test, "config.log", ".sconf_temp", "SConstruct")    
267
268     test.run(chdir=work_dir, arguments='target_signatures_content=1')
269     checkLogAndStdout(["Checking for main() in C library %s... " % lib,
270                        "Checking for main() in C library None... ",
271                        "Checking for main() in C library %s... " % lib,
272                        "Checking for main() in C library None... ",
273                        "Checking for C header file math.h... ",
274                        "Checking for C++ header file vector... "],
275                       ["yes"]*6,
276                       [[((".c", CR), (_obj, CR), (_exe, CR))]]*4 +
277                        [[((".c", CR), (_obj, CR))]] +
278                        [[((".cpp", CR), (_obj, CR))]],
279                       test, "config.log", ".sconf_temp", "SConstruct")    
280
281     # 1.2 if checks are not ok, the cache mechanism should work as well
282     #     (via explicit cache)
283     reset(EXACT)              # match exactly, "()" is a regexp thing
284
285     test.write([work_dir,  'SConstruct'], """
286 if int(ARGUMENTS.get('target_signatures_content', 0)):
287     TargetSignatures('content')
288 env = Environment()
289 import os
290 env.AppendENVPath('PATH', os.environ['PATH'])
291 conf = env.Configure()
292 r1 = conf.CheckCHeader( 'no_std_c_header.h' ) # leads to compile error
293 r2 = conf.CheckLib( 'no_c_library_SAFFDG' )   # leads to link error
294 env = conf.Finish()
295 if not (not r1 and not r2):
296      print "FAIL: ", r1, r2
297      Exit(1)
298 """)
299
300     test.run(chdir=work_dir)
301     checkLogAndStdout(["Checking for C header file no_std_c_header.h... ",
302                        "Checking for main() in C library no_c_library_SAFFDG... "],
303                       ["no"]*2,
304                       [[((".c", NCR), (_obj, NCF))],
305                        [((".c", NCR), (_obj, NCR), (_exe, NCF))]],
306                       test, "config.log", ".sconf_temp", "SConstruct")
307
308     test.run(chdir=work_dir)
309     checkLogAndStdout(["Checking for C header file no_std_c_header.h... ",
310                        "Checking for main() in C library no_c_library_SAFFDG... "],
311                       ["no"]*2,
312                       [[((".c", CR), (_obj, CF))],
313                        [((".c", CR), (_obj, CR), (_exe, CF))]],
314                       test, "config.log", ".sconf_temp", "SConstruct")
315
316     # 1.3 same should be true for TargetSignatures('content')
317     test.run(chdir=work_dir, arguments='--config=force target_signatures_content=1')
318     checkLogAndStdout(["Checking for C header file no_std_c_header.h... ",
319                        "Checking for main() in C library no_c_library_SAFFDG... "],
320                       ["no"]*2,
321                       [[((".c", NCR), (_obj, NCF))],
322                        [((".c", NCR), (_obj, NCR), (_exe, NCF))]],
323                       test, "config.log", ".sconf_temp", "SConstruct")
324
325     test.run(chdir=work_dir, arguments='target_signatures_content=1')
326     checkLogAndStdout(["Checking for C header file no_std_c_header.h... ",
327                        "Checking for main() in C library no_c_library_SAFFDG... "],
328                       ["no"]*2,
329                       [[((".c", CR), (_obj, CF))],
330                        [((".c", CR), (_obj, CR), (_exe, CF))]],
331                       test, "config.log", ".sconf_temp", "SConstruct")
332
333     
334
335     # 2.1 test that normal builds work together with Sconf
336     reset(RE_DOTALL)
337
338
339     test.write([work_dir,  'SConstruct'], """
340 env = Environment()
341 import os
342 env.AppendENVPath('PATH', os.environ['PATH'])
343 conf = Configure(env)
344 r1 = conf.CheckCHeader( 'math.h' )
345 r2 = conf.CheckCHeader( 'no_std_c_header.h' ) # leads to compile error
346 env = conf.Finish()
347 Export( 'env' )
348 SConscript( 'SConscript' )
349 """)
350     test.write([work_dir,  'SConscript'], """
351 Import( 'env' )
352 env.Program( 'TestProgram', 'TestProgram.c' )
353 """)
354     test.write([work_dir,  'TestProgram.c'], """
355 #include <stdio.h>
356
357 int main() {
358   printf( "Hello\\n" );
359 }
360 """)
361     test.run(chdir=work_dir)
362     checkLogAndStdout(["Checking for C header file math.h... ",
363                        "Checking for C header file no_std_c_header.h... "],
364                       ["yes", "no"],
365                       [[((".c", NCR), (_obj, NCR))],
366                        [((".c", NCR), (_obj, NCF))]],
367                       test, "config.log", ".sconf_temp", "SConstruct")
368
369     test.run(chdir=work_dir)
370     checkLogAndStdout(["Checking for C header file math.h... ",
371                        "Checking for C header file no_std_c_header.h... "],
372                       ["yes", "no"],
373                       [[((".c", CR), (_obj, CR))],
374                        [((".c", CR), (_obj, CF))]],
375                       test, "config.log", ".sconf_temp", "SConstruct")
376
377     # 2.2 test that BuildDir builds work together with Sconf
378     reset(RE_DOTALL)
379
380
381     test.write([work_dir,  'SConstruct'], """
382 env = Environment(LOGFILE='build/config.log')
383 import os
384 env.AppendENVPath('PATH', os.environ['PATH'])
385 BuildDir( 'build', '.' )
386 conf = env.Configure(conf_dir='build/config.tests', log_file='$LOGFILE')
387 r1 = conf.CheckCHeader( 'math.h' )
388 r2 = conf.CheckCHeader( 'no_std_c_header.h' ) # leads to compile error
389 env = conf.Finish()
390 Export( 'env' )
391 # print open( 'build/config.log' ).readlines()
392 SConscript( 'build/SConscript' )
393 """)
394     test.write([work_dir,  'SConscript'], """
395 Import( 'env' )
396 env.Program( 'TestProgram', 'TestProgram.c' )
397 """)
398     test.write([work_dir,  'TestProgram.c'], """
399 #include <stdio.h>
400
401 int main() {
402   printf( "Hello\\n" );
403 }
404 """)
405
406     test.run(chdir=work_dir)
407     checkLogAndStdout(["Checking for C header file math.h... ",
408                        "Checking for C header file no_std_c_header.h... "],
409                       ["yes", "no"],
410                       [[((".c", NCR), (_obj, NCR))],
411                        [((".c", NCR), (_obj, NCF))]],
412                       test,
413                       os.path.join("build", "config.log"),
414                       os.path.join("build", "config.tests"),
415                       "SConstruct")
416     
417     test.run(chdir=work_dir)
418     checkLogAndStdout(["Checking for C header file math.h... ",
419                        "Checking for C header file no_std_c_header.h... "],
420                       ["yes", "no"],
421                       [[((".c", CR), (_obj, CR))],
422                        [((".c", CR), (_obj, CF))]],
423                       test,
424                       os.path.join("build", "config.log"),
425                       os.path.join("build", "config.tests"),
426                       "SConstruct")
427
428     # 2.3 test that Configure calls in SConscript files work
429     #     even if BuildDir is set
430     reset(RE_DOTALL)
431
432     test.subdir( [work_dir, 'sub'], [work_dir, 'sub', 'local'] )
433     test.write([work_dir,  'SConstruct'], """
434 opts = Options()
435 opts.Add('chdir')
436 env = Environment(options=opts)
437 if env['chdir'] == 'yes':
438   SConscriptChdir(1)
439 else:
440   SConscriptChdir(0)
441 BuildDir( 'build', '.' )
442 SConscript( 'build/SConscript' )
443 """)
444     test.write([work_dir,  'sub', 'local', 'local_header.h'],
445                "/* Hello World */" )
446     test.write([work_dir,  'SConscript'], """
447 SConscript( 'sub/SConscript' )
448 """)
449     test.write([work_dir,  'sub', 'SConscript'], """
450 def CustomTest(context):
451   context.Message('Executing Custom Test ... ')
452   ret = context.TryCompile('#include "local_header.h"', '.c')
453   context.Result(ret)
454   return ret
455
456 env = Environment(FOO='fff')
457 env.Append( CPPPATH='local' )
458 import os
459 env.AppendENVPath('PATH', os.environ['PATH'])
460 conf = Configure( env, custom_tests = {'CustomTest' : CustomTest,
461                                        '$FOO' : CustomTest} )
462 if hasattr(conf, 'fff'):
463   conf.Message('$FOO should not have been expanded!')
464   Exit(1)
465 if not conf.CheckCHeader( 'math.h' ):
466   Exit(1)
467 if conf.CheckCHeader( 'no_std_c_header.h' ):
468   Exit(1)
469 if not conf.CustomTest():
470   Exit(1)
471 env = conf.Finish()
472 env.Program( 'TestProgram', 'TestProgram.c' )
473 """)
474     test.write([work_dir, 'sub', 'TestProgram.h'], """
475 /* Just a test header */
476 """)
477     test.write([work_dir, 'sub', 'TestProgram.c'], """
478 #include "TestProgram.h"
479 #include <stdio.h>
480
481 int main() {
482   printf( "Hello\\n" );
483 }
484 """)
485
486     # first with SConscriptChdir(0)
487     test.run(chdir=work_dir, arguments='chdir=no')
488     checkLogAndStdout( ["Checking for C header file math.h... ",
489                         "Checking for C header file no_std_c_header.h... ",
490                         "Executing Custom Test ... "],
491                         ["yes", "no", "yes"],
492                         [[((".c", NCR), (_obj, NCR))],
493                          [((".c", NCR), (_obj, NCF))],
494                          [((".c", NCR), (_obj, NCR))]],
495                         test, "config.log",
496                         ".sconf_temp",
497                         os.path.join("build", "sub", "SConscript"))
498
499     test.run(chdir=work_dir, arguments='chdir=no')
500     checkLogAndStdout( ["Checking for C header file math.h... ",
501                         "Checking for C header file no_std_c_header.h... ",
502                         "Executing Custom Test ... "],
503                         ["yes", "no", "yes"],
504                         [[((".c", CR), (_obj, CR))],
505                          [((".c", CR), (_obj, CF))],
506                          [((".c", CR), (_obj, CR))]],
507                         test, "config.log",
508                         ".sconf_temp",
509                         os.path.join("build", "sub", "SConscript"))
510
511     shutil.rmtree(test.workpath(work_dir, ".sconf_temp"))
512     os.unlink(test.workpath(work_dir, ".sconsign.dblite"))
513
514     # now with SConscriptChdir(1)
515     test.run(chdir=work_dir, arguments='chdir=yes')
516     checkLogAndStdout( ["Checking for C header file math.h... ",
517                         "Checking for C header file no_std_c_header.h... ",
518                         "Executing Custom Test ... "],
519                         ["yes", "no", "yes"],
520                         [[((".c", NCR), (_obj, NCR))],
521                          [((".c", NCR), (_obj, NCF))],
522                          [((".c", NCR), (_obj, NCR))]],
523                         test, "config.log",
524                         ".sconf_temp",
525                         os.path.join("build", "sub", "SConscript"))
526
527     test.run(chdir=work_dir, arguments='chdir=yes')
528     checkLogAndStdout( ["Checking for C header file math.h... ",
529                         "Checking for C header file no_std_c_header.h... ",
530                         "Executing Custom Test ... "],
531                         ["yes", "no", "yes"],
532                         [[((".c", CR), (_obj, CR))],
533                          [((".c", CR), (_obj, CF))],
534                          [((".c", CR), (_obj, CR))]],
535                         test, "config.log",
536                         ".sconf_temp",
537                         os.path.join("build", "sub", "SConscript"))
538
539     # 3.1 test custom tests
540     reset(RE_DOTALL)
541
542     compileOK = '#include <stdio.h>\\nint main() {printf("Hello");return 0;}'
543     compileFAIL = "syntax error"
544     linkOK = compileOK
545     linkFAIL = "void myFunc(); int main() { myFunc(); }"
546     runOK = compileOK
547     runFAIL = "int main() { return 1; }"
548     test.write([work_dir, 'pyAct.py'], 'import sys\nprint sys.argv[1]\nsys.exit(int(sys.argv[1]))\n')
549     test.write([work_dir, 'SConstruct'], """
550 def CheckCustom(test):
551     test.Message( 'Executing MyTest ... ' )
552     retCompileOK = test.TryCompile( '%s', '.c' )
553     retCompileFAIL = test.TryCompile( '%s', '.c' )
554     retLinkOK = test.TryLink( '%s', '.c' )
555     retLinkFAIL = test.TryLink( '%s', '.c' )
556     (retRunOK, outputRunOK) = test.TryRun( '%s', '.c' )
557     (retRunFAIL, outputRunFAIL) = test.TryRun( '%s', '.c' )
558     (retActOK, outputActOK) = test.TryAction( '%s pyAct.py 0 > $TARGET' )
559     (retActFAIL, outputActFAIL) = test.TryAction( '%s pyAct.py 1 > $TARGET' )
560     resOK = retCompileOK and retLinkOK and retRunOK and outputRunOK=="Hello"
561     resOK = resOK and retActOK and int(outputActOK)==0
562     resFAIL = retCompileFAIL or retLinkFAIL or retRunFAIL or outputRunFAIL!=""
563     resFAIL = resFAIL or retActFAIL or outputActFAIL!=""
564     test.Result( int(resOK and not resFAIL) )
565     return resOK and not resFAIL
566
567 env = Environment()
568 import os
569 env.AppendENVPath('PATH', os.environ['PATH'])
570 conf = Configure( env, custom_tests={'CheckCustom' : CheckCustom} )
571 conf.CheckCustom()
572 env = conf.Finish()
573 """ % (compileOK, compileFAIL, linkOK, linkFAIL, runOK, runFAIL,
574        python, python ) )
575     test.run(chdir=work_dir)
576     checkLogAndStdout(["Executing MyTest ... "],
577                       ["yes"],
578                       [[(('.c', NCR), (_obj, NCR)),
579                         (('.c', NCR), (_obj, NCF)),
580                         (('.c', NCR), (_obj, NCR), (_exe, NCR)),
581                         (('.c', NCR), (_obj, NCR), (_exe, NCF)),
582                         (('.c', NCR), (_obj, NCR), (_exe, NCR), (_exe + '.out', NCR)),
583                         (('.c', NCR), (_obj, NCR), (_exe, NCR), (_exe + '.out', NCF)),
584                         (('', NCR),),
585                         (('', NCF),)]],
586                        test, "config.log", ".sconf_temp", "SConstruct")
587
588     test.run(chdir=work_dir)
589     checkLogAndStdout(["Executing MyTest ... "],
590                       ["yes"],
591                       [[(('.c', CR), (_obj, CR)),
592                         (('.c', CR), (_obj, CF)),
593                         (('.c', CR), (_obj, CR), (_exe, CR)),
594                         (('.c', CR), (_obj, CR), (_exe, CF)),
595                         (('.c', CR), (_obj, CR), (_exe, CR), (_exe + '.out', CR)),
596                         (('.c', CR), (_obj, CR), (_exe, CR), (_exe + '.out', CF)),
597                         (('', CR),),
598                         (('', CF),)]],
599                        test, "config.log", ".sconf_temp", "SConstruct")
600
601     # 4.1 test that calling normal builders from an actual configuring
602     # environment works
603     reset(RE_DOTALL)
604
605     test.write([work_dir, 'cmd.py'], r"""
606 import sys
607 sys.stderr.write( 'Hello World on stderr\n' )
608 sys.stdout.write( 'Hello World on stdout\n' )
609 open(sys.argv[1], 'w').write( 'Hello World\n' )
610 """)
611
612     test.write([work_dir, 'SConstruct'], """
613 env = Environment()
614 def CustomTest(*args):
615     return 0
616 conf = env.Configure(custom_tests = {'MyTest' : CustomTest})
617 if not conf.MyTest():
618     env.Command("hello", [], "%s cmd.py $TARGET")
619 env = conf.Finish()
620 """ % python)
621     test.run(chdir=work_dir, stderr="Hello World on stderr\n")
622
623     # 4.2 test that calling Configure from a builder results in a
624     # readable Error
625     reset(EXACT)
626
627     test.write([work_dir, 'SConstruct'], """
628 def ConfigureAction(target, source, env):
629     env.Configure()
630     return 0
631 env = Environment(BUILDERS = {'MyAction' :
632                               Builder(action=Action(ConfigureAction))})
633 env.MyAction('target', [])
634 """)
635     test.run(chdir=work_dir, status=2,
636              stderr="scons: *** Calling Configure from Builders is not supported.\n")
637
638     # 4.3 test the calling Configure from multiple subsidiary,
639     # nested SConscript files does *not* result in an error.
640
641     test.subdir([work_dir, 'dir1'],
642                 [work_dir, 'dir2'],
643                 [work_dir, 'dir2', 'sub1'],
644                 [work_dir, 'dir2', 'sub1', 'sub2'])
645     test.write([work_dir, 'SConstruct'], """
646 env = Environment()
647 SConscript(dirs=['dir1', 'dir2'], exports="env")
648 """)
649     test.write([work_dir, 'dir1', 'SConscript'], """
650 Import("env")
651 conf = env.Configure()
652 conf.Finish()
653 """)
654     test.write([work_dir, 'dir2', 'SConscript'], """
655 Import("env")
656 conf = env.Configure()
657 conf.Finish()
658 SConscript(dirs=['sub1'], exports="env")
659 """)
660     test.write([work_dir, 'dir2', 'sub1', 'SConscript'], """
661 Import("env")
662 conf = env.Configure()
663 conf.Finish()
664 SConscript(dirs=['sub2'], exports="env")
665 """)
666     test.write([work_dir, 'dir2', 'sub1', 'sub2', 'SConscript'], """
667 Import("env")
668 conf = env.Configure()
669 conf.Finish()
670 """)
671     test.run(chdir=work_dir)
672
673     # 5.1 test the ConfigureDryRunError
674     
675     reset(EXACT) # exact match
676     test.write([work_dir,  'SConstruct'], """
677 env = Environment()
678 import os
679 env.AppendENVPath('PATH', os.environ['PATH'])
680 conf = Configure(env)
681 r1 = conf.CheckLib('%s') # will pass
682 r2 = conf.CheckLib('hopefullynolib') # will fail
683 env = conf.Finish()
684 if not (r1 and not r2):
685      Exit(1)
686 """ % (lib))
687
688     test.run(chdir=work_dir, arguments='-n', status=2, stderr="""
689 scons: *** Cannot create configure directory ".sconf_temp" within a dry-run.
690 File "SConstruct", line 5, in ?
691 """)
692     test.must_not_exist([work_dir, 'config.log'])
693     test.subdir([work_dir, '.sconf_temp'])
694     
695     test.run(chdir=work_dir, arguments='-n', status=2, stderr="""
696 scons: *** Cannot update configure test "%s" within a dry-run.
697 File "SConstruct", line 6, in ?
698 """ % os.path.join(".sconf_temp", "conftest_0.c"))
699
700     test.run(chdir=work_dir)
701     checkLogAndStdout( ["Checking for main() in C library %s... " % lib,
702                         "Checking for main() in C library hopefullynolib... "],
703                         ["yes", "no"],
704                         [[((".c", NCR), (_obj, NCR))],
705                          [((".c", NCR), (_obj, NCF))]],
706                         test, "config.log", ".sconf_temp", "SConstruct")
707     oldLog = test.read(test.workpath(work_dir, 'config.log'))
708
709     test.run(chdir=work_dir, arguments='-n')
710     checkLogAndStdout( ["Checking for main() in C library %s... " % lib,
711                         "Checking for main() in C library hopefullynolib... "],
712                         ["yes", "no"],
713                         [[((".c", CR), (_obj, CR))],
714                          [((".c", CR), (_obj, CF))]],
715                         test, "config.log", ".sconf_temp", "SConstruct",
716                         doCheckLog=0)
717     newLog = test.read(test.workpath(work_dir, 'config.log'))
718     if newLog != oldLog:
719         print "Unexpected update of log file within a dry run"
720         test.fail_test()
721
722     # 5.2 test the --config=<auto|force|cache> option
723     reset(EXACT) # exact match
724
725     test.write([work_dir,  'SConstruct'], """
726 env = Environment(CPPPATH='#/include')
727 import os
728 env.AppendENVPath('PATH', os.environ['PATH'])
729 conf = Configure(env)
730 r1 = conf.CheckCHeader('non_system_header1.h')
731 r2 = conf.CheckCHeader('non_system_header2.h')
732 env = conf.Finish()
733 """)
734     test.subdir([work_dir, 'include'])
735     test.write([work_dir, 'include', 'non_system_header1.h'], """
736 /* A header */
737 """)
738
739     test.run(chdir=work_dir, arguments='--config=cache', status=2, stderr="""
740 scons: *** "%s" is not yet built and cache is forced.
741 File "SConstruct", line 6, in ?
742 """ % os.path.join(".sconf_temp", "conftest_0.c"))
743
744     test.run(chdir=work_dir, arguments='--config=auto')
745     checkLogAndStdout( ["Checking for C header file non_system_header1.h... ",
746                         "Checking for C header file non_system_header2.h... "],
747                         ["yes", "no"],
748                         [[((".c", NCR), (_obj, NCR))],
749                          [((".c", NCR), (_obj, NCF))]],
750                         test, "config.log", ".sconf_temp", "SConstruct")
751     test.run(chdir=work_dir, arguments='--config=auto')
752     checkLogAndStdout( ["Checking for C header file non_system_header1.h... ",
753                         "Checking for C header file non_system_header2.h... "],
754                         ["yes", "no"],
755                         [[((".c", CR), (_obj, CR))],
756                          [((".c", CR), (_obj, CF))]],
757                         test, "config.log", ".sconf_temp", "SConstruct")
758     
759     test.run(chdir=work_dir, arguments='--config=force')
760     checkLogAndStdout( ["Checking for C header file non_system_header1.h... ",
761                         "Checking for C header file non_system_header2.h... "],
762                         ["yes", "no"],
763                         [[((".c", NCR), (_obj, NCR))],
764                          [((".c", NCR), (_obj, NCF))]],
765                         test, "config.log", ".sconf_temp", "SConstruct")
766
767     test.run(chdir=work_dir, arguments='--config=cache')
768     checkLogAndStdout( ["Checking for C header file non_system_header1.h... ",
769                         "Checking for C header file non_system_header2.h... "],
770                         ["yes", "no"],
771                         [[((".c", CR), (_obj, CR))],
772                          [((".c", CR), (_obj, CF))]],
773                         test, "config.log", ".sconf_temp", "SConstruct")
774
775     test.write([work_dir, 'include', 'non_system_header2.h'], """
776 /* Another header */
777 """)
778     test.unlink([work_dir, 'include', 'non_system_header1.h'])
779     test.run(chdir=work_dir, arguments='--config=cache')
780     checkLogAndStdout( ["Checking for C header file non_system_header1.h... ",
781                         "Checking for C header file non_system_header2.h... "],
782                         ["yes", "no"],
783                         [[((".c", CR), (_obj, CR))],
784                          [((".c", CR), (_obj, CF))]],
785                         test, "config.log", ".sconf_temp", "SConstruct")
786     
787     test.run(chdir=work_dir, arguments='--config=auto')
788     checkLogAndStdout( ["Checking for C header file non_system_header1.h... ",
789                         "Checking for C header file non_system_header2.h... "],
790                         ["no", "yes"],
791                         [[((".c", CR), (_obj, NCF))],
792                          [((".c", CR), (_obj, NCR))]],
793                         test, "config.log", ".sconf_temp", "SConstruct")
794
795     # 5.3 test -Q option
796     reset(EXACT)
797     test.write([work_dir,  'SConstruct'], """
798 env = Environment()
799 import os
800 env.AppendENVPath('PATH', os.environ['PATH'])
801 conf = Configure(env)
802 r1 = conf.CheckCHeader('stdio.h')
803 env = conf.Finish()
804 """)
805     test.run(chdir=work_dir, arguments='-Q',
806              stdout="scons: `.' is up to date.\n", stderr="")
807
808
809     # 6. check config.h support
810     reset(EXACT)
811     test.write([work_dir, 'SConstruct'], """
812 env = Environment()
813 import os
814 env.AppendENVPath('PATH', os.environ['PATH'])
815 conf = Configure(env, config_h = 'config.h')
816 r1 = conf.CheckFunc('printf')
817 r2 = conf.CheckFunc('noFunctionCall')
818 r3 = conf.CheckType('int')
819 r4 = conf.CheckType('noType')
820 r5 = conf.CheckCHeader('stdio.h', '<>')
821 r6 = conf.CheckCHeader('hopefullynoc-header.h')
822 r7 = conf.CheckCXXHeader('vector', '<>')
823 r8 = conf.CheckCXXHeader('hopefullynocxx-header.h')
824 env = conf.Finish()
825 conf = Configure(env, config_h = 'config.h')
826 r9 = conf.CheckLib('%s', 'sin')
827 r10 = conf.CheckLib('hopefullynolib', 'sin')
828 r11 = conf.CheckLibWithHeader('%s', 'math.h', 'c')
829 r12 = conf.CheckLibWithHeader('%s', 'hopefullynoheader2.h', 'c')
830 r13 = conf.CheckLibWithHeader('hopefullynolib2', 'math.h', 'c')
831 env = conf.Finish()
832 """ % (lib, lib, lib))
833
834     expected_read_str = """\
835 Checking for C function printf()... yes
836 Checking for C function noFunctionCall()... no
837 Checking for C type int... yes
838 Checking for C type noType... no
839 Checking for C header file stdio.h... yes
840 Checking for C header file hopefullynoc-header.h... no
841 Checking for C++ header file vector... yes
842 Checking for C++ header file hopefullynocxx-header.h... no
843 Checking for sin() in C library %(lib)s... yes
844 Checking for sin() in C library hopefullynolib... no
845 Checking for main() in C library %(lib)s... yes
846 Checking for main() in C library %(lib)s... no
847 Checking for main() in C library hopefullynolib2... no
848 """ % {'lib' : lib}
849
850     expected_build_str = """\
851 scons: Configure: creating config.h
852 """
853     
854     expected_stdout = test.wrap_stdout(build_str=expected_build_str,
855                                        read_str=expected_read_str)
856
857     expected_config_h = string.replace("""#ifndef CONFIG_H_SEEN
858 #define CONFIG_H_SEEN
859
860 #define HAVE_PRINTF
861 /* #undef HAVE_NOFUNCTIONCALL */
862 #define HAVE_INT
863 /* #undef HAVE_NOTYPE */
864 #define HAVE_STDIO_H
865 /* #undef HAVE_HOPEFULLYNOC_HEADER_H */
866 #define HAVE_VECTOR
867 /* #undef HAVE_HOPEFULLYNOCXX_HEADER_H */
868 #define HAVE_%(LIB)s
869 /* #undef HAVE_LIBHOPEFULLYNOLIB */
870 #define HAVE_%(LIB)s
871 /* #undef HAVE_%(LIB)s */
872 /* #undef HAVE_LIBHOPEFULLYNOLIB2 */
873
874 #endif /* CONFIG_H_SEEN */
875 """ % {'LIB' : "LIB" + string.upper(lib) }, "\n", os.linesep)
876
877     test.run(chdir=work_dir, stdout=expected_stdout)
878     config_h = test.read(test.workpath(work_dir, 'config.h'))
879     if expected_config_h != config_h:
880         print "Unexpected config.h"
881         print "Expected: "
882         print "---------------------------------------------------------"
883         print repr(expected_config_h)
884         print "---------------------------------------------------------"
885         print "Found: "
886         print "---------------------------------------------------------"
887         print repr(config_h)
888         print "---------------------------------------------------------"
889         print "Stdio: "
890         print "---------------------------------------------------------"
891         print test.stdout()
892         print "---------------------------------------------------------"
893         test.fail_test()
894
895     expected_read_str = re.sub(r'\b((yes)|(no))\b',
896                                r'(cached) \1',
897                                expected_read_str)
898     expected_build_str = "scons: `.' is up to date.\n"
899     expected_stdout = test.wrap_stdout(build_str=expected_build_str,
900                                        read_str=expected_read_str)
901     #expected_stdout = string.replace(expected_stdout, "\n", os.linesep)
902     test.run(chdir=work_dir, stdout=expected_stdout)    
903     config_h = test.read(test.workpath(work_dir, 'config.h'))    
904     if expected_config_h != config_h:
905         print "Unexpected config.h"
906         print "Expected: "
907         print "---------------------------------------------------------"
908         print repr(expected_config_h)
909         print "---------------------------------------------------------"
910         print "Found: "
911         print "---------------------------------------------------------"
912         print repr(config_h)
913         print "---------------------------------------------------------"
914         print "Stdio: "
915         print "---------------------------------------------------------"
916         print test.stdout()
917         print "---------------------------------------------------------"
918         test.fail_test()
919
920 finally:
921     pass
922     #os.system( 'find . -type f -exec ls -l {} \;' )
923     #print "-------------config.log------------------"
924     #print test.read( test.workpath(work_dir, 'config.log'))
925     #print "-------------build/config.log------------"
926     #print test.read( test.workpath('build/config.log' ))
927
928
929 test.pass_test()