Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(951)

Side by Side Diff: scons-2.0.1/engine/SCons/SConf.py

Issue 6711079: Added an unmodified copy of SCons to third_party. (Closed) Base URL: svn://svn.chromium.org/native_client/trunk/src/third_party/
Patch Set: '' Created 9 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « scons-2.0.1/engine/SCons/Platform/win32.py ('k') | scons-2.0.1/engine/SCons/SConsign.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Property Changes:
Added: svn:eol-style
+ LF
OLDNEW
(Empty)
1 """SCons.SConf
2
3 Autoconf-like configuration support.
4 """
5
6 #
7 # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 The S Cons Foundation
8 #
9 # Permission is hereby granted, free of charge, to any person obtaining
10 # a copy of this software and associated documentation files (the
11 # "Software"), to deal in the Software without restriction, including
12 # without limitation the rights to use, copy, modify, merge, publish,
13 # distribute, sublicense, and/or sell copies of the Software, and to
14 # permit persons to whom the Software is furnished to do so, subject to
15 # the following conditions:
16 #
17 # The above copyright notice and this permission notice shall be included
18 # in all copies or substantial portions of the Software.
19 #
20 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
21 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
22 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 #
28
29 __revision__ = "src/engine/SCons/SConf.py 5134 2010/08/16 23:02:40 bdeegan"
30
31 import SCons.compat
32
33 import io
34 import os
35 import re
36 import sys
37 import traceback
38
39 import SCons.Action
40 import SCons.Builder
41 import SCons.Errors
42 import SCons.Job
43 import SCons.Node.FS
44 import SCons.Taskmaster
45 import SCons.Util
46 import SCons.Warnings
47 import SCons.Conftest
48
49 from SCons.Debug import Trace
50
51 # Turn off the Conftest error logging
52 SCons.Conftest.LogInputFiles = 0
53 SCons.Conftest.LogErrorMessages = 0
54
55 # Set
56 build_type = None
57 build_types = ['clean', 'help']
58
59 def SetBuildType(type):
60 global build_type
61 build_type = type
62
63 # to be set, if we are in dry-run mode
64 dryrun = 0
65
66 AUTO=0 # use SCons dependency scanning for up-to-date checks
67 FORCE=1 # force all tests to be rebuilt
68 CACHE=2 # force all tests to be taken from cache (raise an error, if necessary)
69 cache_mode = AUTO
70
71 def SetCacheMode(mode):
72 """Set the Configure cache mode. mode must be one of "auto", "force",
73 or "cache"."""
74 global cache_mode
75 if mode == "auto":
76 cache_mode = AUTO
77 elif mode == "force":
78 cache_mode = FORCE
79 elif mode == "cache":
80 cache_mode = CACHE
81 else:
82 raise ValueError("SCons.SConf.SetCacheMode: Unknown mode " + mode)
83
84 progress_display = SCons.Util.display # will be overwritten by SCons.Script
85 def SetProgressDisplay(display):
86 """Set the progress display to use (called from SCons.Script)"""
87 global progress_display
88 progress_display = display
89
90 SConfFS = None
91
92 _ac_build_counter = 0 # incremented, whenever TryBuild is called
93 _ac_config_logs = {} # all config.log files created in this build
94 _ac_config_hs = {} # all config.h files created in this build
95 sconf_global = None # current sconf object
96
97 def _createConfigH(target, source, env):
98 t = open(str(target[0]), "w")
99 defname = re.sub('[^A-Za-z0-9_]', '_', str(target[0]).upper())
100 t.write("""#ifndef %(DEFNAME)s_SEEN
101 #define %(DEFNAME)s_SEEN
102
103 """ % {'DEFNAME' : defname})
104 t.write(source[0].get_contents())
105 t.write("""
106 #endif /* %(DEFNAME)s_SEEN */
107 """ % {'DEFNAME' : defname})
108 t.close()
109
110 def _stringConfigH(target, source, env):
111 return "scons: Configure: creating " + str(target[0])
112
113 def CreateConfigHBuilder(env):
114 """Called just before the building targets phase begins."""
115 if len(_ac_config_hs) == 0:
116 return
117 action = SCons.Action.Action(_createConfigH,
118 _stringConfigH)
119 sconfigHBld = SCons.Builder.Builder(action=action)
120 env.Append( BUILDERS={'SConfigHBuilder':sconfigHBld} )
121 for k in _ac_config_hs.keys():
122 env.SConfigHBuilder(k, env.Value(_ac_config_hs[k]))
123
124 class SConfWarning(SCons.Warnings.Warning):
125 pass
126 SCons.Warnings.enableWarningClass(SConfWarning)
127
128 # some error definitions
129 class SConfError(SCons.Errors.UserError):
130 def __init__(self,msg):
131 SCons.Errors.UserError.__init__(self,msg)
132
133 class ConfigureDryRunError(SConfError):
134 """Raised when a file or directory needs to be updated during a Configure
135 process, but the user requested a dry-run"""
136 def __init__(self,target):
137 if not isinstance(target, SCons.Node.FS.File):
138 msg = 'Cannot create configure directory "%s" within a dry-run.' % s tr(target)
139 else:
140 msg = 'Cannot update configure test "%s" within a dry-run.' % str(ta rget)
141 SConfError.__init__(self,msg)
142
143 class ConfigureCacheError(SConfError):
144 """Raised when a use explicitely requested the cache feature, but the test
145 is run the first time."""
146 def __init__(self,target):
147 SConfError.__init__(self, '"%s" is not yet built and cache is forced.' % str(target))
148
149 # define actions for building text files
150 def _createSource( target, source, env ):
151 fd = open(str(target[0]), "w")
152 fd.write(source[0].get_contents())
153 fd.close()
154 def _stringSource( target, source, env ):
155 return (str(target[0]) + ' <-\n |' +
156 source[0].get_contents().replace( '\n', "\n |" ) )
157
158 class SConfBuildInfo(SCons.Node.FS.FileBuildInfo):
159 """
160 Special build info for targets of configure tests. Additional members
161 are result (did the builder succeed last time?) and string, which
162 contains messages of the original build phase.
163 """
164 result = None # -> 0/None -> no error, != 0 error
165 string = None # the stdout / stderr output when building the target
166
167 def set_build_result(self, result, string):
168 self.result = result
169 self.string = string
170
171
172 class Streamer(object):
173 """
174 'Sniffer' for a file-like writable object. Similar to the unix tool tee.
175 """
176 def __init__(self, orig):
177 self.orig = orig
178 self.s = io.StringIO()
179
180 def write(self, str):
181 if self.orig:
182 self.orig.write(str)
183 self.s.write(str)
184
185 def writelines(self, lines):
186 for l in lines:
187 self.write(l + '\n')
188
189 def getvalue(self):
190 """
191 Return everything written to orig since the Streamer was created.
192 """
193 return self.s.getvalue()
194
195 def flush(self):
196 if self.orig:
197 self.orig.flush()
198 self.s.flush()
199
200
201 class SConfBuildTask(SCons.Taskmaster.AlwaysTask):
202 """
203 This is almost the same as SCons.Script.BuildTask. Handles SConfErrors
204 correctly and knows about the current cache_mode.
205 """
206 def display(self, message):
207 if sconf_global.logstream:
208 sconf_global.logstream.write("scons: Configure: " + message + "\n")
209
210 def display_cached_string(self, bi):
211 """
212 Logs the original builder messages, given the SConfBuildInfo instance
213 bi.
214 """
215 if not isinstance(bi, SConfBuildInfo):
216 SCons.Warnings.warn(SConfWarning,
217 "The stored build information has an unexpected class: %s" % bi.__ class__)
218 else:
219 self.display("The original builder output was:\n" +
220 (" |" + str(bi.string)).replace("\n", "\n |"))
221
222 def failed(self):
223 # check, if the reason was a ConfigureDryRunError or a
224 # ConfigureCacheError and if yes, reraise the exception
225 exc_type = self.exc_info()[0]
226 if issubclass(exc_type, SConfError):
227 raise
228 elif issubclass(exc_type, SCons.Errors.BuildError):
229 # we ignore Build Errors (occurs, when a test doesn't pass)
230 # Clear the exception to prevent the contained traceback
231 # to build a reference cycle.
232 self.exc_clear()
233 else:
234 self.display('Caught exception while building "%s":\n' %
235 self.targets[0])
236 try:
237 excepthook = sys.excepthook
238 except AttributeError:
239 # Earlier versions of Python don't have sys.excepthook...
240 def excepthook(type, value, tb):
241 traceback.print_tb(tb)
242 print type, value
243 excepthook(*self.exc_info())
244 return SCons.Taskmaster.Task.failed(self)
245
246 def collect_node_states(self):
247 # returns (is_up_to_date, cached_error, cachable)
248 # where is_up_to_date is 1, if the node(s) are up_to_date
249 # cached_error is 1, if the node(s) are up_to_date, but the
250 # build will fail
251 # cachable is 0, if some nodes are not in our cache
252 T = 0
253 changed = False
254 cached_error = False
255 cachable = True
256 for t in self.targets:
257 if T: Trace('%s' % (t))
258 bi = t.get_stored_info().binfo
259 if isinstance(bi, SConfBuildInfo):
260 if T: Trace(': SConfBuildInfo')
261 if cache_mode == CACHE:
262 t.set_state(SCons.Node.up_to_date)
263 if T: Trace(': set_state(up_to-date)')
264 else:
265 if T: Trace(': get_state() %s' % t.get_state())
266 if T: Trace(': changed() %s' % t.changed())
267 if (t.get_state() != SCons.Node.up_to_date and t.changed()):
268 changed = True
269 if T: Trace(': changed %s' % changed)
270 cached_error = cached_error or bi.result
271 else:
272 if T: Trace(': else')
273 # the node hasn't been built in a SConf context or doesn't
274 # exist
275 cachable = False
276 changed = ( t.get_state() != SCons.Node.up_to_date )
277 if T: Trace(': changed %s' % changed)
278 if T: Trace('\n')
279 return (not changed, cached_error, cachable)
280
281 def execute(self):
282 if not self.targets[0].has_builder():
283 return
284
285 sconf = sconf_global
286
287 is_up_to_date, cached_error, cachable = self.collect_node_states()
288
289 if cache_mode == CACHE and not cachable:
290 raise ConfigureCacheError(self.targets[0])
291 elif cache_mode == FORCE:
292 is_up_to_date = 0
293
294 if cached_error and is_up_to_date:
295 self.display("Building \"%s\" failed in a previous run and all "
296 "its sources are up to date." % str(self.targets[0]))
297 binfo = self.targets[0].get_stored_info().binfo
298 self.display_cached_string(binfo)
299 raise SCons.Errors.BuildError # will be 'caught' in self.failed
300 elif is_up_to_date:
301 self.display("\"%s\" is up to date." % str(self.targets[0]))
302 binfo = self.targets[0].get_stored_info().binfo
303 self.display_cached_string(binfo)
304 elif dryrun:
305 raise ConfigureDryRunError(self.targets[0])
306 else:
307 # note stdout and stderr are the same here
308 s = sys.stdout = sys.stderr = Streamer(sys.stdout)
309 try:
310 env = self.targets[0].get_build_env()
311 if cache_mode == FORCE:
312 # Set up the Decider() to force rebuilds by saying
313 # that every source has changed. Note that we still
314 # call the environment's underlying source decider so
315 # that the correct .sconsign info will get calculated
316 # and keep the build state consistent.
317 def force_build(dependency, target, prev_ni,
318 env_decider=env.decide_source):
319 env_decider(dependency, target, prev_ni)
320 return True
321 if env.decide_source.func_code is not force_build.func_code:
322 env.Decider(force_build)
323 env['PSTDOUT'] = env['PSTDERR'] = s
324 try:
325 sconf.cached = 0
326 self.targets[0].build()
327 finally:
328 sys.stdout = sys.stderr = env['PSTDOUT'] = \
329 env['PSTDERR'] = sconf.logstream
330 except KeyboardInterrupt:
331 raise
332 except SystemExit:
333 exc_value = sys.exc_info()[1]
334 raise SCons.Errors.ExplicitExit(self.targets[0],exc_value.code)
335 except Exception, e:
336 for t in self.targets:
337 binfo = t.get_binfo()
338 binfo.__class__ = SConfBuildInfo
339 binfo.set_build_result(1, s.getvalue())
340 sconsign_entry = SCons.SConsign.SConsignEntry()
341 sconsign_entry.binfo = binfo
342 #sconsign_entry.ninfo = self.get_ninfo()
343 # We'd like to do this as follows:
344 # t.store_info(binfo)
345 # However, we need to store it as an SConfBuildInfo
346 # object, and store_info() will turn it into a
347 # regular FileNodeInfo if the target is itself a
348 # regular File.
349 sconsign = t.dir.sconsign()
350 sconsign.set_entry(t.name, sconsign_entry)
351 sconsign.merge()
352 raise e
353 else:
354 for t in self.targets:
355 binfo = t.get_binfo()
356 binfo.__class__ = SConfBuildInfo
357 binfo.set_build_result(0, s.getvalue())
358 sconsign_entry = SCons.SConsign.SConsignEntry()
359 sconsign_entry.binfo = binfo
360 #sconsign_entry.ninfo = self.get_ninfo()
361 # We'd like to do this as follows:
362 # t.store_info(binfo)
363 # However, we need to store it as an SConfBuildInfo
364 # object, and store_info() will turn it into a
365 # regular FileNodeInfo if the target is itself a
366 # regular File.
367 sconsign = t.dir.sconsign()
368 sconsign.set_entry(t.name, sconsign_entry)
369 sconsign.merge()
370
371 class SConfBase(object):
372 """This is simply a class to represent a configure context. After
373 creating a SConf object, you can call any tests. After finished with your
374 tests, be sure to call the Finish() method, which returns the modified
375 environment.
376 Some words about caching: In most cases, it is not necessary to cache
377 Test results explicitely. Instead, we use the scons dependency checking
378 mechanism. For example, if one wants to compile a test program
379 (SConf.TryLink), the compiler is only called, if the program dependencies
380 have changed. However, if the program could not be compiled in a former
381 SConf run, we need to explicitely cache this error.
382 """
383
384 def __init__(self, env, custom_tests = {}, conf_dir='$CONFIGUREDIR',
385 log_file='$CONFIGURELOG', config_h = None, _depth = 0):
386 """Constructor. Pass additional tests in the custom_tests-dictinary,
387 e.g. custom_tests={'CheckPrivate':MyPrivateTest}, where MyPrivateTest
388 defines a custom test.
389 Note also the conf_dir and log_file arguments (you may want to
390 build tests in the VariantDir, not in the SourceDir)
391 """
392 global SConfFS
393 if not SConfFS:
394 SConfFS = SCons.Node.FS.default_fs or \
395 SCons.Node.FS.FS(env.fs.pathTop)
396 if sconf_global is not None:
397 raise SCons.Errors.UserError
398 self.env = env
399 if log_file is not None:
400 log_file = SConfFS.File(env.subst(log_file))
401 self.logfile = log_file
402 self.logstream = None
403 self.lastTarget = None
404 self.depth = _depth
405 self.cached = 0 # will be set, if all test results are cached
406
407 # add default tests
408 default_tests = {
409 'CheckCC' : CheckCC,
410 'CheckCXX' : CheckCXX,
411 'CheckSHCC' : CheckSHCC,
412 'CheckSHCXX' : CheckSHCXX,
413 'CheckFunc' : CheckFunc,
414 'CheckType' : CheckType,
415 'CheckTypeSize' : CheckTypeSize,
416 'CheckDeclaration' : CheckDeclaration,
417 'CheckHeader' : CheckHeader,
418 'CheckCHeader' : CheckCHeader,
419 'CheckCXXHeader' : CheckCXXHeader,
420 'CheckLib' : CheckLib,
421 'CheckLibWithHeader' : CheckLibWithHeader,
422 }
423 self.AddTests(default_tests)
424 self.AddTests(custom_tests)
425 self.confdir = SConfFS.Dir(env.subst(conf_dir))
426 if config_h is not None:
427 config_h = SConfFS.File(config_h)
428 self.config_h = config_h
429 self._startup()
430
431 def Finish(self):
432 """Call this method after finished with your tests:
433 env = sconf.Finish()
434 """
435 self._shutdown()
436 return self.env
437
438 def Define(self, name, value = None, comment = None):
439 """
440 Define a pre processor symbol name, with the optional given value in the
441 current config header.
442
443 If value is None (default), then #define name is written. If value is no t
444 none, then #define name value is written.
445
446 comment is a string which will be put as a C comment in the
447 header, to explain the meaning of the value (appropriate C comments /* a nd
448 */ will be put automatically."""
449 lines = []
450 if comment:
451 comment_str = "/* %s */" % comment
452 lines.append(comment_str)
453
454 if value is not None:
455 define_str = "#define %s %s" % (name, value)
456 else:
457 define_str = "#define %s" % name
458 lines.append(define_str)
459 lines.append('')
460
461 self.config_h_text = self.config_h_text + '\n'.join(lines)
462
463 def BuildNodes(self, nodes):
464 """
465 Tries to build the given nodes immediately. Returns 1 on success,
466 0 on error.
467 """
468 if self.logstream is not None:
469 # override stdout / stderr to write in log file
470 oldStdout = sys.stdout
471 sys.stdout = self.logstream
472 oldStderr = sys.stderr
473 sys.stderr = self.logstream
474
475 # the engine assumes the current path is the SConstruct directory ...
476 old_fs_dir = SConfFS.getcwd()
477 old_os_dir = os.getcwd()
478 SConfFS.chdir(SConfFS.Top, change_os_dir=1)
479
480 # Because we take responsibility here for writing out our
481 # own .sconsign info (see SConfBuildTask.execute(), above),
482 # we override the store_info() method with a null place-holder
483 # so we really control how it gets written.
484 for n in nodes:
485 n.store_info = n.do_not_store_info
486
487 ret = 1
488
489 try:
490 # ToDo: use user options for calc
491 save_max_drift = SConfFS.get_max_drift()
492 SConfFS.set_max_drift(0)
493 tm = SCons.Taskmaster.Taskmaster(nodes, SConfBuildTask)
494 # we don't want to build tests in parallel
495 jobs = SCons.Job.Jobs(1, tm )
496 jobs.run()
497 for n in nodes:
498 state = n.get_state()
499 if (state != SCons.Node.executed and
500 state != SCons.Node.up_to_date):
501 # the node could not be built. we return 0 in this case
502 ret = 0
503 finally:
504 SConfFS.set_max_drift(save_max_drift)
505 os.chdir(old_os_dir)
506 SConfFS.chdir(old_fs_dir, change_os_dir=0)
507 if self.logstream is not None:
508 # restore stdout / stderr
509 sys.stdout = oldStdout
510 sys.stderr = oldStderr
511 return ret
512
513 def pspawn_wrapper(self, sh, escape, cmd, args, env):
514 """Wrapper function for handling piped spawns.
515
516 This looks to the calling interface (in Action.py) like a "normal"
517 spawn, but associates the call with the PSPAWN variable from
518 the construction environment and with the streams to which we
519 want the output logged. This gets slid into the construction
520 environment as the SPAWN variable so Action.py doesn't have to
521 know or care whether it's spawning a piped command or not.
522 """
523 return self.pspawn(sh, escape, cmd, args, env, self.logstream, self.logs tream)
524
525
526 def TryBuild(self, builder, text = None, extension = ""):
527 """Low level TryBuild implementation. Normally you don't need to
528 call that - you can use TryCompile / TryLink / TryRun instead
529 """
530 global _ac_build_counter
531
532 # Make sure we have a PSPAWN value, and save the current
533 # SPAWN value.
534 try:
535 self.pspawn = self.env['PSPAWN']
536 except KeyError:
537 raise SCons.Errors.UserError('Missing PSPAWN construction variable.' )
538 try:
539 save_spawn = self.env['SPAWN']
540 except KeyError:
541 raise SCons.Errors.UserError('Missing SPAWN construction variable.')
542
543 nodesToBeBuilt = []
544
545 f = "conftest_" + str(_ac_build_counter)
546 pref = self.env.subst( builder.builder.prefix )
547 suff = self.env.subst( builder.builder.suffix )
548 target = self.confdir.File(pref + f + suff)
549
550 try:
551 # Slide our wrapper into the construction environment as
552 # the SPAWN function.
553 self.env['SPAWN'] = self.pspawn_wrapper
554 sourcetext = self.env.Value(text)
555
556 if text is not None:
557 textFile = self.confdir.File(f + extension)
558 textFileNode = self.env.SConfSourceBuilder(target=textFile,
559 source=sourcetext)
560 nodesToBeBuilt.extend(textFileNode)
561 source = textFileNode
562 else:
563 source = None
564
565 nodes = builder(target = target, source = source)
566 if not SCons.Util.is_List(nodes):
567 nodes = [nodes]
568 nodesToBeBuilt.extend(nodes)
569 result = self.BuildNodes(nodesToBeBuilt)
570
571 finally:
572 self.env['SPAWN'] = save_spawn
573
574 _ac_build_counter = _ac_build_counter + 1
575 if result:
576 self.lastTarget = nodes[0]
577 else:
578 self.lastTarget = None
579
580 return result
581
582 def TryAction(self, action, text = None, extension = ""):
583 """Tries to execute the given action with optional source file
584 contents <text> and optional source file extension <extension>,
585 Returns the status (0 : failed, 1 : ok) and the contents of the
586 output file.
587 """
588 builder = SCons.Builder.Builder(action=action)
589 self.env.Append( BUILDERS = {'SConfActionBuilder' : builder} )
590 ok = self.TryBuild(self.env.SConfActionBuilder, text, extension)
591 del self.env['BUILDERS']['SConfActionBuilder']
592 if ok:
593 outputStr = self.lastTarget.get_contents()
594 return (1, outputStr)
595 return (0, "")
596
597 def TryCompile( self, text, extension):
598 """Compiles the program given in text to an env.Object, using extension
599 as file extension (e.g. '.c'). Returns 1, if compilation was
600 successful, 0 otherwise. The target is saved in self.lastTarget (for
601 further processing).
602 """
603 return self.TryBuild(self.env.Object, text, extension)
604
605 def TryLink( self, text, extension ):
606 """Compiles the program given in text to an executable env.Program,
607 using extension as file extension (e.g. '.c'). Returns 1, if
608 compilation was successful, 0 otherwise. The target is saved in
609 self.lastTarget (for further processing).
610 """
611 return self.TryBuild(self.env.Program, text, extension )
612
613 def TryRun(self, text, extension ):
614 """Compiles and runs the program given in text, using extension
615 as file extension (e.g. '.c'). Returns (1, outputStr) on success,
616 (0, '') otherwise. The target (a file containing the program's stdout)
617 is saved in self.lastTarget (for further processing).
618 """
619 ok = self.TryLink(text, extension)
620 if( ok ):
621 prog = self.lastTarget
622 pname = prog.path
623 output = self.confdir.File(os.path.basename(pname)+'.out')
624 node = self.env.Command(output, prog, [ [ pname, ">", "${TARGET}"] ] )
625 ok = self.BuildNodes(node)
626 if ok:
627 outputStr = output.get_contents()
628 return( 1, outputStr)
629 return (0, "")
630
631 class TestWrapper(object):
632 """A wrapper around Tests (to ensure sanity)"""
633 def __init__(self, test, sconf):
634 self.test = test
635 self.sconf = sconf
636 def __call__(self, *args, **kw):
637 if not self.sconf.active:
638 raise SCons.Errors.UserError
639 context = CheckContext(self.sconf)
640 ret = self.test(context, *args, **kw)
641 if self.sconf.config_h is not None:
642 self.sconf.config_h_text = self.sconf.config_h_text + context.co nfig_h
643 context.Result("error: no result")
644 return ret
645
646 def AddTest(self, test_name, test_instance):
647 """Adds test_class to this SConf instance. It can be called with
648 self.test_name(...)"""
649 setattr(self, test_name, SConfBase.TestWrapper(test_instance, self))
650
651 def AddTests(self, tests):
652 """Adds all the tests given in the tests dictionary to this SConf
653 instance
654 """
655 for name in tests.keys():
656 self.AddTest(name, tests[name])
657
658 def _createDir( self, node ):
659 dirName = str(node)
660 if dryrun:
661 if not os.path.isdir( dirName ):
662 raise ConfigureDryRunError(dirName)
663 else:
664 if not os.path.isdir( dirName ):
665 os.makedirs( dirName )
666 node._exists = 1
667
668 def _startup(self):
669 """Private method. Set up logstream, and set the environment
670 variables necessary for a piped build
671 """
672 global _ac_config_logs
673 global sconf_global
674 global SConfFS
675
676 self.lastEnvFs = self.env.fs
677 self.env.fs = SConfFS
678 self._createDir(self.confdir)
679 self.confdir.up().add_ignore( [self.confdir] )
680
681 if self.logfile is not None and not dryrun:
682 # truncate logfile, if SConf.Configure is called for the first time
683 # in a build
684 if self.logfile in _ac_config_logs:
685 log_mode = "a"
686 else:
687 _ac_config_logs[self.logfile] = None
688 log_mode = "w"
689 fp = open(str(self.logfile), log_mode)
690 self.logstream = SCons.Util.Unbuffered(fp)
691 # logfile may stay in a build directory, so we tell
692 # the build system not to override it with a eventually
693 # existing file with the same name in the source directory
694 self.logfile.dir.add_ignore( [self.logfile] )
695
696 tb = traceback.extract_stack()[-3-self.depth]
697 old_fs_dir = SConfFS.getcwd()
698 SConfFS.chdir(SConfFS.Top, change_os_dir=0)
699 self.logstream.write('file %s,line %d:\n\tConfigure(confdir = %s)\n' %
700 (tb[0], tb[1], str(self.confdir)) )
701 SConfFS.chdir(old_fs_dir)
702 else:
703 self.logstream = None
704 # we use a special builder to create source files from TEXT
705 action = SCons.Action.Action(_createSource,
706 _stringSource)
707 sconfSrcBld = SCons.Builder.Builder(action=action)
708 self.env.Append( BUILDERS={'SConfSourceBuilder':sconfSrcBld} )
709 self.config_h_text = _ac_config_hs.get(self.config_h, "")
710 self.active = 1
711 # only one SConf instance should be active at a time ...
712 sconf_global = self
713
714 def _shutdown(self):
715 """Private method. Reset to non-piped spawn"""
716 global sconf_global, _ac_config_hs
717
718 if not self.active:
719 raise SCons.Errors.UserError("Finish may be called only once!")
720 if self.logstream is not None and not dryrun:
721 self.logstream.write("\n")
722 self.logstream.close()
723 self.logstream = None
724 # remove the SConfSourceBuilder from the environment
725 blds = self.env['BUILDERS']
726 del blds['SConfSourceBuilder']
727 self.env.Replace( BUILDERS=blds )
728 self.active = 0
729 sconf_global = None
730 if not self.config_h is None:
731 _ac_config_hs[self.config_h] = self.config_h_text
732 self.env.fs = self.lastEnvFs
733
734 class CheckContext(object):
735 """Provides a context for configure tests. Defines how a test writes to the
736 screen and log file.
737
738 A typical test is just a callable with an instance of CheckContext as
739 first argument:
740
741 def CheckCustom(context, ...)
742 context.Message('Checking my weird test ... ')
743 ret = myWeirdTestFunction(...)
744 context.Result(ret)
745
746 Often, myWeirdTestFunction will be one of
747 context.TryCompile/context.TryLink/context.TryRun. The results of
748 those are cached, for they are only rebuild, if the dependencies have
749 changed.
750 """
751
752 def __init__(self, sconf):
753 """Constructor. Pass the corresponding SConf instance."""
754 self.sconf = sconf
755 self.did_show_result = 0
756
757 # for Conftest.py:
758 self.vardict = {}
759 self.havedict = {}
760 self.headerfilename = None
761 self.config_h = "" # config_h text will be stored here
762 # we don't regenerate the config.h file after each test. That means,
763 # that tests won't be able to include the config.h file, and so
764 # they can't do an #ifdef HAVE_XXX_H. This shouldn't be a major
765 # issue, though. If it turns out, that we need to include config.h
766 # in tests, we must ensure, that the dependencies are worked out
767 # correctly. Note that we can't use Conftest.py's support for config.h,
768 # cause we will need to specify a builder for the config.h file ...
769
770 def Message(self, text):
771 """Inform about what we are doing right now, e.g.
772 'Checking for SOMETHING ... '
773 """
774 self.Display(text)
775 self.sconf.cached = 1
776 self.did_show_result = 0
777
778 def Result(self, res):
779 """Inform about the result of the test. res may be an integer or a
780 string. In case of an integer, the written text will be 'yes' or 'no'.
781 The result is only displayed when self.did_show_result is not set.
782 """
783 if isinstance(res, (int, bool)):
784 if res:
785 text = "yes"
786 else:
787 text = "no"
788 elif isinstance(res, str):
789 text = res
790 else:
791 raise TypeError("Expected string, int or bool, got " + str(type(res) ))
792
793 if self.did_show_result == 0:
794 # Didn't show result yet, do it now.
795 self.Display(text + "\n")
796 self.did_show_result = 1
797
798 def TryBuild(self, *args, **kw):
799 return self.sconf.TryBuild(*args, **kw)
800
801 def TryAction(self, *args, **kw):
802 return self.sconf.TryAction(*args, **kw)
803
804 def TryCompile(self, *args, **kw):
805 return self.sconf.TryCompile(*args, **kw)
806
807 def TryLink(self, *args, **kw):
808 return self.sconf.TryLink(*args, **kw)
809
810 def TryRun(self, *args, **kw):
811 return self.sconf.TryRun(*args, **kw)
812
813 def __getattr__( self, attr ):
814 if( attr == 'env' ):
815 return self.sconf.env
816 elif( attr == 'lastTarget' ):
817 return self.sconf.lastTarget
818 else:
819 raise AttributeError("CheckContext instance has no attribute '%s'" % attr)
820
821 #### Stuff used by Conftest.py (look there for explanations).
822
823 def BuildProg(self, text, ext):
824 self.sconf.cached = 1
825 # TODO: should use self.vardict for $CC, $CPPFLAGS, etc.
826 return not self.TryBuild(self.env.Program, text, ext)
827
828 def CompileProg(self, text, ext):
829 self.sconf.cached = 1
830 # TODO: should use self.vardict for $CC, $CPPFLAGS, etc.
831 return not self.TryBuild(self.env.Object, text, ext)
832
833 def CompileSharedObject(self, text, ext):
834 self.sconf.cached = 1
835 # TODO: should use self.vardict for $SHCC, $CPPFLAGS, etc.
836 return not self.TryBuild(self.env.SharedObject, text, ext)
837
838 def RunProg(self, text, ext):
839 self.sconf.cached = 1
840 # TODO: should use self.vardict for $CC, $CPPFLAGS, etc.
841 st, out = self.TryRun(text, ext)
842 return not st, out
843
844 def AppendLIBS(self, lib_name_list):
845 oldLIBS = self.env.get( 'LIBS', [] )
846 self.env.Append(LIBS = lib_name_list)
847 return oldLIBS
848
849 def PrependLIBS(self, lib_name_list):
850 oldLIBS = self.env.get( 'LIBS', [] )
851 self.env.Prepend(LIBS = lib_name_list)
852 return oldLIBS
853
854 def SetLIBS(self, val):
855 oldLIBS = self.env.get( 'LIBS', [] )
856 self.env.Replace(LIBS = val)
857 return oldLIBS
858
859 def Display(self, msg):
860 if self.sconf.cached:
861 # We assume that Display is called twice for each test here
862 # once for the Checking for ... message and once for the result.
863 # The self.sconf.cached flag can only be set between those calls
864 msg = "(cached) " + msg
865 self.sconf.cached = 0
866 progress_display(msg, append_newline=0)
867 self.Log("scons: Configure: " + msg + "\n")
868
869 def Log(self, msg):
870 if self.sconf.logstream is not None:
871 self.sconf.logstream.write(msg)
872
873 #### End of stuff used by Conftest.py.
874
875
876 def SConf(*args, **kw):
877 if kw.get(build_type, True):
878 kw['_depth'] = kw.get('_depth', 0) + 1
879 for bt in build_types:
880 try:
881 del kw[bt]
882 except KeyError:
883 pass
884 return SConfBase(*args, **kw)
885 else:
886 return SCons.Util.Null()
887
888
889 def CheckFunc(context, function_name, header = None, language = None):
890 res = SCons.Conftest.CheckFunc(context, function_name, header = header, lang uage = language)
891 context.did_show_result = 1
892 return not res
893
894 def CheckType(context, type_name, includes = "", language = None):
895 res = SCons.Conftest.CheckType(context, type_name,
896 header = includes, language = language)
897 context.did_show_result = 1
898 return not res
899
900 def CheckTypeSize(context, type_name, includes = "", language = None, expect = N one):
901 res = SCons.Conftest.CheckTypeSize(context, type_name,
902 header = includes, language = language,
903 expect = expect)
904 context.did_show_result = 1
905 return res
906
907 def CheckDeclaration(context, declaration, includes = "", language = None):
908 res = SCons.Conftest.CheckDeclaration(context, declaration,
909 includes = includes,
910 language = language)
911 context.did_show_result = 1
912 return not res
913
914 def createIncludesFromHeaders(headers, leaveLast, include_quotes = '""'):
915 # used by CheckHeader and CheckLibWithHeader to produce C - #include
916 # statements from the specified header (list)
917 if not SCons.Util.is_List(headers):
918 headers = [headers]
919 l = []
920 if leaveLast:
921 lastHeader = headers[-1]
922 headers = headers[:-1]
923 else:
924 lastHeader = None
925 for s in headers:
926 l.append("#include %s%s%s\n"
927 % (include_quotes[0], s, include_quotes[1]))
928 return ''.join(l), lastHeader
929
930 def CheckHeader(context, header, include_quotes = '<>', language = None):
931 """
932 A test for a C or C++ header file.
933 """
934 prog_prefix, hdr_to_check = \
935 createIncludesFromHeaders(header, 1, include_quotes)
936 res = SCons.Conftest.CheckHeader(context, hdr_to_check, prog_prefix,
937 language = language,
938 include_quotes = include_quotes)
939 context.did_show_result = 1
940 return not res
941
942 def CheckCC(context):
943 res = SCons.Conftest.CheckCC(context)
944 context.did_show_result = 1
945 return not res
946
947 def CheckCXX(context):
948 res = SCons.Conftest.CheckCXX(context)
949 context.did_show_result = 1
950 return not res
951
952 def CheckSHCC(context):
953 res = SCons.Conftest.CheckSHCC(context)
954 context.did_show_result = 1
955 return not res
956
957 def CheckSHCXX(context):
958 res = SCons.Conftest.CheckSHCXX(context)
959 context.did_show_result = 1
960 return not res
961
962 # Bram: Make this function obsolete? CheckHeader() is more generic.
963
964 def CheckCHeader(context, header, include_quotes = '""'):
965 """
966 A test for a C header file.
967 """
968 return CheckHeader(context, header, include_quotes, language = "C")
969
970
971 # Bram: Make this function obsolete? CheckHeader() is more generic.
972
973 def CheckCXXHeader(context, header, include_quotes = '""'):
974 """
975 A test for a C++ header file.
976 """
977 return CheckHeader(context, header, include_quotes, language = "C++")
978
979
980 def CheckLib(context, library = None, symbol = "main",
981 header = None, language = None, autoadd = 1):
982 """
983 A test for a library. See also CheckLibWithHeader.
984 Note that library may also be None to test whether the given symbol
985 compiles without flags.
986 """
987
988 if library == []:
989 library = [None]
990
991 if not SCons.Util.is_List(library):
992 library = [library]
993
994 # ToDo: accept path for the library
995 res = SCons.Conftest.CheckLib(context, library, symbol, header = header,
996 language = language, autoadd = autoadd)
997 context.did_show_result = 1
998 return not res
999
1000 # XXX
1001 # Bram: Can only include one header and can't use #ifdef HAVE_HEADER_H.
1002
1003 def CheckLibWithHeader(context, libs, header, language,
1004 call = None, autoadd = 1):
1005 # ToDo: accept path for library. Support system header files.
1006 """
1007 Another (more sophisticated) test for a library.
1008 Checks, if library and header is available for language (may be 'C'
1009 or 'CXX'). Call maybe be a valid expression _with_ a trailing ';'.
1010 As in CheckLib, we support library=None, to test if the call compiles
1011 without extra link flags.
1012 """
1013 prog_prefix, dummy = \
1014 createIncludesFromHeaders(header, 0)
1015 if libs == []:
1016 libs = [None]
1017
1018 if not SCons.Util.is_List(libs):
1019 libs = [libs]
1020
1021 res = SCons.Conftest.CheckLib(context, libs, None, prog_prefix,
1022 call = call, language = language, autoadd = autoadd)
1023 context.did_show_result = 1
1024 return not res
1025
1026 # Local Variables:
1027 # tab-width:4
1028 # indent-tabs-mode:nil
1029 # End:
1030 # vim: set expandtab tabstop=4 shiftwidth=4:
OLDNEW
« no previous file with comments | « scons-2.0.1/engine/SCons/Platform/win32.py ('k') | scons-2.0.1/engine/SCons/SConsign.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698