3 Autoconf-like configuration support.
7 # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation
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:
17 # The above copyright notice and this permission notice shall be included
18 # in all copies or substantial portions of the Software.
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.
29 __revision__ = "src/engine/SCons/SConf.py 3842 2008/12/20 22:59:52 scons"
44 import SCons.Taskmaster
49 from SCons.Debug import Trace
51 # Turn off the Conftest error logging
52 SCons.Conftest.LogInputFiles = 0
53 SCons.Conftest.LogErrorMessages = 0
57 build_types = ['clean', 'help']
59 def SetBuildType(type):
63 # to be set, if we are in dry-run mode
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)
71 def SetCacheMode(mode):
72 """Set the Configure cache mode. mode must be one of "auto", "force",
82 raise ValueError, "SCons.SConf.SetCacheMode: Unknown mode " + mode
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
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
97 def _createConfigH(target, source, env):
98 t = open(str(target[0]), "w")
99 defname = re.sub('[^A-Za-z0-9_]', '_', string.upper(str(target[0])))
100 t.write("""#ifndef %(DEFNAME)s_SEEN
101 #define %(DEFNAME)s_SEEN
103 """ % {'DEFNAME' : defname})
104 t.write(source[0].get_contents())
106 #endif /* %(DEFNAME)s_SEEN */
107 """ % {'DEFNAME' : defname})
110 def _stringConfigH(target, source, env):
111 return "scons: Configure: creating " + str(target[0])
113 def CreateConfigHBuilder(env):
114 """Called just before the building targets phase begins."""
115 if len(_ac_config_hs) == 0:
117 action = SCons.Action.Action(_createConfigH,
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]))
124 class SConfWarning(SCons.Warnings.Warning):
126 SCons.Warnings.enableWarningClass(SConfWarning)
128 # some error definitions
129 class SConfError(SCons.Errors.UserError):
130 def __init__(self,msg):
131 SCons.Errors.UserError.__init__(self,msg)
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.' % str(target)
140 msg = 'Cannot update configure test "%s" within a dry-run.' % str(target)
141 SConfError.__init__(self,msg)
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))
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())
154 def _stringSource( target, source, env ):
155 return (str(target[0]) + ' <-\n |' +
156 string.replace( source[0].get_contents(),
159 # python 2.2 introduces types.BooleanType
160 BooleanTypes = [types.IntType]
161 if hasattr(types, 'BooleanType'): BooleanTypes.append(types.BooleanType)
163 class SConfBuildInfo(SCons.Node.FS.FileBuildInfo):
165 Special build info for targets of configure tests. Additional members
166 are result (did the builder succeed last time?) and string, which
167 contains messages of the original build phase.
169 result = None # -> 0/None -> no error, != 0 error
170 string = None # the stdout / stderr output when building the target
172 def set_build_result(self, result, string):
179 'Sniffer' for a file-like writable object. Similar to the unix tool tee.
181 def __init__(self, orig):
183 self.s = StringIO.StringIO()
185 def write(self, str):
190 def writelines(self, lines):
196 Return everything written to orig since the Streamer was created.
198 return self.s.getvalue()
206 class SConfBuildTask(SCons.Taskmaster.Task):
208 This is almost the same as SCons.Script.BuildTask. Handles SConfErrors
209 correctly and knows about the current cache_mode.
211 def display(self, message):
212 if sconf_global.logstream:
213 sconf_global.logstream.write("scons: Configure: " + message + "\n")
215 def display_cached_string(self, bi):
217 Logs the original builder messages, given the SConfBuildInfo instance
220 if not isinstance(bi, SConfBuildInfo):
221 SCons.Warnings.warn(SConfWarning,
222 "The stored build information has an unexpected class: %s" % bi.__class__)
224 self.display("The original builder output was:\n" +
225 string.replace(" |" + str(bi.string),
229 # check, if the reason was a ConfigureDryRunError or a
230 # ConfigureCacheError and if yes, reraise the exception
231 exc_type = self.exc_info()[0]
232 if issubclass(exc_type, SConfError):
234 elif issubclass(exc_type, SCons.Errors.BuildError):
235 # we ignore Build Errors (occurs, when a test doesn't pass)
236 # Clear the exception to prevent the contained traceback
237 # to build a reference cycle.
240 self.display('Caught exception while building "%s":\n' %
243 excepthook = sys.excepthook
244 except AttributeError:
245 # Earlier versions of Python don't have sys.excepthook...
246 def excepthook(type, value, tb):
247 traceback.print_tb(tb)
249 apply(excepthook, self.exc_info())
250 return SCons.Taskmaster.Task.failed(self)
252 def collect_node_states(self):
253 # returns (is_up_to_date, cached_error, cachable)
254 # where is_up_to_date is 1, if the node(s) are up_to_date
255 # cached_error is 1, if the node(s) are up_to_date, but the
257 # cachable is 0, if some nodes are not in our cache
262 for t in self.targets:
263 if T: Trace('%s' % (t))
264 bi = t.get_stored_info().binfo
265 if isinstance(bi, SConfBuildInfo):
266 if T: Trace(': SConfBuildInfo')
267 if cache_mode == CACHE:
268 t.set_state(SCons.Node.up_to_date)
269 if T: Trace(': set_state(up_to-date)')
271 if T: Trace(': get_state() %s' % t.get_state())
272 if T: Trace(': changed() %s' % t.changed())
273 if (t.get_state() != SCons.Node.up_to_date and t.changed()):
275 if T: Trace(': changed %s' % changed)
276 cached_error = cached_error or bi.result
278 if T: Trace(': else')
279 # the node hasn't been built in a SConf context or doesn't
282 changed = ( t.get_state() != SCons.Node.up_to_date )
283 if T: Trace(': changed %s' % changed)
285 return (not changed, cached_error, cachable)
288 if not self.targets[0].has_builder():
293 is_up_to_date, cached_error, cachable = self.collect_node_states()
295 if cache_mode == CACHE and not cachable:
296 raise ConfigureCacheError(self.targets[0])
297 elif cache_mode == FORCE:
300 if cached_error and is_up_to_date:
301 self.display("Building \"%s\" failed in a previous run and all "
302 "its sources are up to date." % str(self.targets[0]))
303 binfo = self.targets[0].get_stored_info().binfo
304 self.display_cached_string(binfo)
305 raise SCons.Errors.BuildError # will be 'caught' in self.failed
307 self.display("\"%s\" is up to date." % str(self.targets[0]))
308 binfo = self.targets[0].get_stored_info().binfo
309 self.display_cached_string(binfo)
311 raise ConfigureDryRunError(self.targets[0])
313 # note stdout and stderr are the same here
314 s = sys.stdout = sys.stderr = Streamer(sys.stdout)
316 env = self.targets[0].get_build_env()
317 env['PSTDOUT'] = env['PSTDERR'] = s
320 self.targets[0].build()
322 sys.stdout = sys.stderr = env['PSTDOUT'] = \
323 env['PSTDERR'] = sconf.logstream
324 except KeyboardInterrupt:
327 exc_value = sys.exc_info()[1]
328 raise SCons.Errors.ExplicitExit(self.targets[0],exc_value.code)
330 for t in self.targets:
331 binfo = t.get_binfo()
332 binfo.__class__ = SConfBuildInfo
333 binfo.set_build_result(1, s.getvalue())
334 sconsign_entry = SCons.SConsign.SConsignEntry()
335 sconsign_entry.binfo = binfo
336 #sconsign_entry.ninfo = self.get_ninfo()
337 # We'd like to do this as follows:
338 # t.store_info(binfo)
339 # However, we need to store it as an SConfBuildInfo
340 # object, and store_info() will turn it into a
341 # regular FileNodeInfo if the target is itself a
343 sconsign = t.dir.sconsign()
344 sconsign.set_entry(t.name, sconsign_entry)
348 for t in self.targets:
349 binfo = t.get_binfo()
350 binfo.__class__ = SConfBuildInfo
351 binfo.set_build_result(0, s.getvalue())
352 sconsign_entry = SCons.SConsign.SConsignEntry()
353 sconsign_entry.binfo = binfo
354 #sconsign_entry.ninfo = self.get_ninfo()
355 # We'd like to do this as follows:
356 # t.store_info(binfo)
357 # However, we need to store it as an SConfBuildInfo
358 # object, and store_info() will turn it into a
359 # regular FileNodeInfo if the target is itself a
361 sconsign = t.dir.sconsign()
362 sconsign.set_entry(t.name, sconsign_entry)
366 """This is simply a class to represent a configure context. After
367 creating a SConf object, you can call any tests. After finished with your
368 tests, be sure to call the Finish() method, which returns the modified
370 Some words about caching: In most cases, it is not necessary to cache
371 Test results explicitely. Instead, we use the scons dependency checking
372 mechanism. For example, if one wants to compile a test program
373 (SConf.TryLink), the compiler is only called, if the program dependencies
374 have changed. However, if the program could not be compiled in a former
375 SConf run, we need to explicitely cache this error.
378 def __init__(self, env, custom_tests = {}, conf_dir='$CONFIGUREDIR',
379 log_file='$CONFIGURELOG', config_h = None, _depth = 0):
380 """Constructor. Pass additional tests in the custom_tests-dictinary,
381 e.g. custom_tests={'CheckPrivate':MyPrivateTest}, where MyPrivateTest
382 defines a custom test.
383 Note also the conf_dir and log_file arguments (you may want to
384 build tests in the VariantDir, not in the SourceDir)
388 SConfFS = SCons.Node.FS.default_fs or \
389 SCons.Node.FS.FS(env.fs.pathTop)
390 if not sconf_global is None:
391 raise (SCons.Errors.UserError,
392 "Only one SConf object may be active at one time")
395 log_file = SConfFS.File(env.subst(log_file))
396 self.logfile = log_file
397 self.logstream = None
398 self.lastTarget = None
400 self.cached = 0 # will be set, if all test results are cached
405 'CheckCXX' : CheckCXX,
406 'CheckSHCC' : CheckSHCC,
407 'CheckSHCXX' : CheckSHCXX,
408 'CheckFunc' : CheckFunc,
409 'CheckType' : CheckType,
410 'CheckTypeSize' : CheckTypeSize,
411 'CheckDeclaration' : CheckDeclaration,
412 'CheckHeader' : CheckHeader,
413 'CheckCHeader' : CheckCHeader,
414 'CheckCXXHeader' : CheckCXXHeader,
415 'CheckLib' : CheckLib,
416 'CheckLibWithHeader' : CheckLibWithHeader,
418 self.AddTests(default_tests)
419 self.AddTests(custom_tests)
420 self.confdir = SConfFS.Dir(env.subst(conf_dir))
421 if not config_h is None:
422 config_h = SConfFS.File(config_h)
423 self.config_h = config_h
427 """Call this method after finished with your tests:
433 def Define(self, name, value = None, comment = None):
435 Define a pre processor symbol name, with the optional given value in the
436 current config header.
438 If value is None (default), then #define name is written. If value is not
439 none, then #define name value is written.
441 comment is a string which will be put as a C comment in the
442 header, to explain the meaning of the value (appropriate C comments /* and
443 */ will be put automatically."""
446 comment_str = "/* %s */" % comment
447 lines.append(comment_str)
449 if value is not None:
450 define_str = "#define %s %s" % (name, value)
452 define_str = "#define %s" % name
453 lines.append(define_str)
456 self.config_h_text = self.config_h_text + string.join(lines, '\n')
458 def BuildNodes(self, nodes):
460 Tries to build the given nodes immediately. Returns 1 on success,
463 if self.logstream != None:
464 # override stdout / stderr to write in log file
465 oldStdout = sys.stdout
466 sys.stdout = self.logstream
467 oldStderr = sys.stderr
468 sys.stderr = self.logstream
470 # the engine assumes the current path is the SConstruct directory ...
471 old_fs_dir = SConfFS.getcwd()
472 old_os_dir = os.getcwd()
473 SConfFS.chdir(SConfFS.Top, change_os_dir=1)
475 # Because we take responsibility here for writing out our
476 # own .sconsign info (see SConfBuildTask.execute(), above),
477 # we override the store_info() method with a null place-holder
478 # so we really control how it gets written.
480 n.store_info = n.do_not_store_info
485 # ToDo: use user options for calc
486 save_max_drift = SConfFS.get_max_drift()
487 SConfFS.set_max_drift(0)
488 tm = SCons.Taskmaster.Taskmaster(nodes, SConfBuildTask)
489 # we don't want to build tests in parallel
490 jobs = SCons.Job.Jobs(1, tm )
493 state = n.get_state()
494 if (state != SCons.Node.executed and
495 state != SCons.Node.up_to_date):
496 # the node could not be built. we return 0 in this case
499 SConfFS.set_max_drift(save_max_drift)
501 SConfFS.chdir(old_fs_dir, change_os_dir=0)
502 if self.logstream != None:
503 # restore stdout / stderr
504 sys.stdout = oldStdout
505 sys.stderr = oldStderr
508 def pspawn_wrapper(self, sh, escape, cmd, args, env):
509 """Wrapper function for handling piped spawns.
511 This looks to the calling interface (in Action.py) like a "normal"
512 spawn, but associates the call with the PSPAWN variable from
513 the construction environment and with the streams to which we
514 want the output logged. This gets slid into the construction
515 environment as the SPAWN variable so Action.py doesn't have to
516 know or care whether it's spawning a piped command or not.
518 return self.pspawn(sh, escape, cmd, args, env, self.logstream, self.logstream)
521 def TryBuild(self, builder, text = None, extension = ""):
522 """Low level TryBuild implementation. Normally you don't need to
523 call that - you can use TryCompile / TryLink / TryRun instead
525 global _ac_build_counter
527 # Make sure we have a PSPAWN value, and save the current
530 self.pspawn = self.env['PSPAWN']
532 raise SCons.Errors.UserError('Missing PSPAWN construction variable.')
534 save_spawn = self.env['SPAWN']
536 raise SCons.Errors.UserError('Missing SPAWN construction variable.')
540 f = "conftest_" + str(_ac_build_counter)
541 pref = self.env.subst( builder.builder.prefix )
542 suff = self.env.subst( builder.builder.suffix )
543 target = self.confdir.File(pref + f + suff)
546 # Slide our wrapper into the construction environment as
547 # the SPAWN function.
548 self.env['SPAWN'] = self.pspawn_wrapper
549 sourcetext = self.env.Value(text)
552 textFile = self.confdir.File(f + extension)
553 textFileNode = self.env.SConfSourceBuilder(target=textFile,
555 nodesToBeBuilt.extend(textFileNode)
556 source = textFileNode
560 nodes = builder(target = target, source = source)
561 if not SCons.Util.is_List(nodes):
563 nodesToBeBuilt.extend(nodes)
564 result = self.BuildNodes(nodesToBeBuilt)
567 self.env['SPAWN'] = save_spawn
569 _ac_build_counter = _ac_build_counter + 1
571 self.lastTarget = nodes[0]
573 self.lastTarget = None
577 def TryAction(self, action, text = None, extension = ""):
578 """Tries to execute the given action with optional source file
579 contents <text> and optional source file extension <extension>,
580 Returns the status (0 : failed, 1 : ok) and the contents of the
583 builder = SCons.Builder.Builder(action=action)
584 self.env.Append( BUILDERS = {'SConfActionBuilder' : builder} )
585 ok = self.TryBuild(self.env.SConfActionBuilder, text, extension)
586 del self.env['BUILDERS']['SConfActionBuilder']
588 outputStr = self.lastTarget.get_contents()
589 return (1, outputStr)
592 def TryCompile( self, text, extension):
593 """Compiles the program given in text to an env.Object, using extension
594 as file extension (e.g. '.c'). Returns 1, if compilation was
595 successful, 0 otherwise. The target is saved in self.lastTarget (for
598 return self.TryBuild(self.env.Object, text, extension)
600 def TryLink( self, text, extension ):
601 """Compiles the program given in text to an executable env.Program,
602 using extension as file extension (e.g. '.c'). Returns 1, if
603 compilation was successful, 0 otherwise. The target is saved in
604 self.lastTarget (for further processing).
606 return self.TryBuild(self.env.Program, text, extension )
608 def TryRun(self, text, extension ):
609 """Compiles and runs the program given in text, using extension
610 as file extension (e.g. '.c'). Returns (1, outputStr) on success,
611 (0, '') otherwise. The target (a file containing the program's stdout)
612 is saved in self.lastTarget (for further processing).
614 ok = self.TryLink(text, extension)
616 prog = self.lastTarget
618 output = SConfFS.File(pname+'.out')
619 node = self.env.Command(output, prog, [ [ pname, ">", "${TARGET}"] ])
620 ok = self.BuildNodes(node)
622 outputStr = output.get_contents()
623 return( 1, outputStr)
627 """A wrapper around Tests (to ensure sanity)"""
628 def __init__(self, test, sconf):
631 def __call__(self, *args, **kw):
632 if not self.sconf.active:
633 raise (SCons.Errors.UserError,
634 "Test called after sconf.Finish()")
635 context = CheckContext(self.sconf)
636 ret = apply(self.test, (context,) + args, kw)
637 if not self.sconf.config_h is None:
638 self.sconf.config_h_text = self.sconf.config_h_text + context.config_h
639 context.Result("error: no result")
642 def AddTest(self, test_name, test_instance):
643 """Adds test_class to this SConf instance. It can be called with
644 self.test_name(...)"""
645 setattr(self, test_name, SConfBase.TestWrapper(test_instance, self))
647 def AddTests(self, tests):
648 """Adds all the tests given in the tests dictionary to this SConf
651 for name in tests.keys():
652 self.AddTest(name, tests[name])
654 def _createDir( self, node ):
657 if not os.path.isdir( dirName ):
658 raise ConfigureDryRunError(dirName)
660 if not os.path.isdir( dirName ):
661 os.makedirs( dirName )
665 """Private method. Set up logstream, and set the environment
666 variables necessary for a piped build
668 global _ac_config_logs
672 self.lastEnvFs = self.env.fs
673 self.env.fs = SConfFS
674 self._createDir(self.confdir)
675 self.confdir.up().add_ignore( [self.confdir] )
677 if self.logfile != None and not dryrun:
678 # truncate logfile, if SConf.Configure is called for the first time
680 if _ac_config_logs.has_key(self.logfile):
683 _ac_config_logs[self.logfile] = None
685 fp = open(str(self.logfile), log_mode)
686 self.logstream = SCons.Util.Unbuffered(fp)
687 # logfile may stay in a build directory, so we tell
688 # the build system not to override it with a eventually
689 # existing file with the same name in the source directory
690 self.logfile.dir.add_ignore( [self.logfile] )
692 tb = traceback.extract_stack()[-3-self.depth]
693 old_fs_dir = SConfFS.getcwd()
694 SConfFS.chdir(SConfFS.Top, change_os_dir=0)
695 self.logstream.write('file %s,line %d:\n\tConfigure(confdir = %s)\n' %
696 (tb[0], tb[1], str(self.confdir)) )
697 SConfFS.chdir(old_fs_dir)
699 self.logstream = None
700 # we use a special builder to create source files from TEXT
701 action = SCons.Action.Action(_createSource,
703 sconfSrcBld = SCons.Builder.Builder(action=action)
704 self.env.Append( BUILDERS={'SConfSourceBuilder':sconfSrcBld} )
705 self.config_h_text = _ac_config_hs.get(self.config_h, "")
707 # only one SConf instance should be active at a time ...
711 """Private method. Reset to non-piped spawn"""
712 global sconf_global, _ac_config_hs
715 raise SCons.Errors.UserError, "Finish may be called only once!"
716 if self.logstream != None and not dryrun:
717 self.logstream.write("\n")
718 self.logstream.close()
719 self.logstream = None
720 # remove the SConfSourceBuilder from the environment
721 blds = self.env['BUILDERS']
722 del blds['SConfSourceBuilder']
723 self.env.Replace( BUILDERS=blds )
726 if not self.config_h is None:
727 _ac_config_hs[self.config_h] = self.config_h_text
728 self.env.fs = self.lastEnvFs
731 """Provides a context for configure tests. Defines how a test writes to the
734 A typical test is just a callable with an instance of CheckContext as
737 def CheckCustom(context, ...)
738 context.Message('Checking my weird test ... ')
739 ret = myWeirdTestFunction(...)
742 Often, myWeirdTestFunction will be one of
743 context.TryCompile/context.TryLink/context.TryRun. The results of
744 those are cached, for they are only rebuild, if the dependencies have
748 def __init__(self, sconf):
749 """Constructor. Pass the corresponding SConf instance."""
751 self.did_show_result = 0
756 self.headerfilename = None
757 self.config_h = "" # config_h text will be stored here
758 # we don't regenerate the config.h file after each test. That means,
759 # that tests won't be able to include the config.h file, and so
760 # they can't do an #ifdef HAVE_XXX_H. This shouldn't be a major
761 # issue, though. If it turns out, that we need to include config.h
762 # in tests, we must ensure, that the dependencies are worked out
763 # correctly. Note that we can't use Conftest.py's support for config.h,
764 # cause we will need to specify a builder for the config.h file ...
766 def Message(self, text):
767 """Inform about what we are doing right now, e.g.
768 'Checking for SOMETHING ... '
771 self.sconf.cached = 1
772 self.did_show_result = 0
774 def Result(self, res):
775 """Inform about the result of the test. res may be an integer or a
776 string. In case of an integer, the written text will be 'ok' or
778 The result is only displayed when self.did_show_result is not set.
780 if type(res) in BooleanTypes:
785 elif type(res) == types.StringType:
788 raise TypeError, "Expected string, int or bool, got " + str(type(res))
790 if self.did_show_result == 0:
791 # Didn't show result yet, do it now.
792 self.Display(text + "\n")
793 self.did_show_result = 1
795 def TryBuild(self, *args, **kw):
796 return apply(self.sconf.TryBuild, args, kw)
798 def TryAction(self, *args, **kw):
799 return apply(self.sconf.TryAction, args, kw)
801 def TryCompile(self, *args, **kw):
802 return apply(self.sconf.TryCompile, args, kw)
804 def TryLink(self, *args, **kw):
805 return apply(self.sconf.TryLink, args, kw)
807 def TryRun(self, *args, **kw):
808 return apply(self.sconf.TryRun, args, kw)
810 def __getattr__( self, attr ):
812 return self.sconf.env
813 elif( attr == 'lastTarget' ):
814 return self.sconf.lastTarget
816 raise AttributeError, "CheckContext instance has no attribute '%s'" % attr
818 #### Stuff used by Conftest.py (look there for explanations).
820 def BuildProg(self, text, ext):
821 self.sconf.cached = 1
822 # TODO: should use self.vardict for $CC, $CPPFLAGS, etc.
823 return not self.TryBuild(self.env.Program, text, ext)
825 def CompileProg(self, text, ext):
826 self.sconf.cached = 1
827 # TODO: should use self.vardict for $CC, $CPPFLAGS, etc.
828 return not self.TryBuild(self.env.Object, text, ext)
830 def CompileSharedObject(self, text, ext):
831 self.sconf.cached = 1
832 # TODO: should use self.vardict for $SHCC, $CPPFLAGS, etc.
833 return not self.TryBuild(self.env.SharedObject, text, ext)
835 def RunProg(self, text, ext):
836 self.sconf.cached = 1
837 # TODO: should use self.vardict for $CC, $CPPFLAGS, etc.
838 st, out = self.TryRun(text, ext)
841 def AppendLIBS(self, lib_name_list):
842 oldLIBS = self.env.get( 'LIBS', [] )
843 self.env.Append(LIBS = lib_name_list)
846 def SetLIBS(self, val):
847 oldLIBS = self.env.get( 'LIBS', [] )
848 self.env.Replace(LIBS = val)
851 def Display(self, msg):
852 if self.sconf.cached:
853 # We assume that Display is called twice for each test here
854 # once for the Checking for ... message and once for the result.
855 # The self.sconf.cached flag can only be set between those calls
856 msg = "(cached) " + msg
857 self.sconf.cached = 0
858 progress_display(msg, append_newline=0)
859 self.Log("scons: Configure: " + msg + "\n")
862 if self.sconf.logstream != None:
863 self.sconf.logstream.write(msg)
865 #### End of stuff used by Conftest.py.
868 def SConf(*args, **kw):
869 if kw.get(build_type, True):
870 kw['_depth'] = kw.get('_depth', 0) + 1
871 for bt in build_types:
876 return apply(SConfBase, args, kw)
878 return SCons.Util.Null()
881 def CheckFunc(context, function_name, header = None, language = None):
882 res = SCons.Conftest.CheckFunc(context, function_name, header = header, language = language)
883 context.did_show_result = 1
886 def CheckType(context, type_name, includes = "", language = None):
887 res = SCons.Conftest.CheckType(context, type_name,
888 header = includes, language = language)
889 context.did_show_result = 1
892 def CheckTypeSize(context, type_name, includes = "", language = None, expect = None):
893 res = SCons.Conftest.CheckTypeSize(context, type_name,
894 header = includes, language = language,
896 context.did_show_result = 1
899 def CheckDeclaration(context, declaration, includes = "", language = None):
900 res = SCons.Conftest.CheckDeclaration(context, declaration,
903 context.did_show_result = 1
906 def createIncludesFromHeaders(headers, leaveLast, include_quotes = '""'):
907 # used by CheckHeader and CheckLibWithHeader to produce C - #include
908 # statements from the specified header (list)
909 if not SCons.Util.is_List(headers):
913 lastHeader = headers[-1]
914 headers = headers[:-1]
918 l.append("#include %s%s%s\n"
919 % (include_quotes[0], s, include_quotes[1]))
920 return string.join(l, ''), lastHeader
922 def CheckHeader(context, header, include_quotes = '<>', language = None):
924 A test for a C or C++ header file.
926 prog_prefix, hdr_to_check = \
927 createIncludesFromHeaders(header, 1, include_quotes)
928 res = SCons.Conftest.CheckHeader(context, hdr_to_check, prog_prefix,
930 include_quotes = include_quotes)
931 context.did_show_result = 1
934 def CheckCC(context):
935 res = SCons.Conftest.CheckCC(context)
938 def CheckCXX(context):
939 res = SCons.Conftest.CheckCXX(context)
942 def CheckSHCC(context):
943 res = SCons.Conftest.CheckSHCC(context)
946 def CheckSHCXX(context):
947 res = SCons.Conftest.CheckSHCXX(context)
950 # Bram: Make this function obsolete? CheckHeader() is more generic.
952 def CheckCHeader(context, header, include_quotes = '""'):
954 A test for a C header file.
956 return CheckHeader(context, header, include_quotes, language = "C")
959 # Bram: Make this function obsolete? CheckHeader() is more generic.
961 def CheckCXXHeader(context, header, include_quotes = '""'):
963 A test for a C++ header file.
965 return CheckHeader(context, header, include_quotes, language = "C++")
968 def CheckLib(context, library = None, symbol = "main",
969 header = None, language = None, autoadd = 1):
971 A test for a library. See also CheckLibWithHeader.
972 Note that library may also be None to test whether the given symbol
973 compiles without flags.
979 if not SCons.Util.is_List(library):
982 # ToDo: accept path for the library
983 res = SCons.Conftest.CheckLib(context, library, symbol, header = header,
984 language = language, autoadd = autoadd)
985 context.did_show_result = 1
989 # Bram: Can only include one header and can't use #ifdef HAVE_HEADER_H.
991 def CheckLibWithHeader(context, libs, header, language,
992 call = None, autoadd = 1):
993 # ToDo: accept path for library. Support system header files.
995 Another (more sophisticated) test for a library.
996 Checks, if library and header is available for language (may be 'C'
997 or 'CXX'). Call maybe be a valid expression _with_ a trailing ';'.
998 As in CheckLib, we support library=None, to test if the call compiles
999 without extra link flags.
1001 prog_prefix, dummy = \
1002 createIncludesFromHeaders(header, 0)
1006 if not SCons.Util.is_List(libs):
1009 res = SCons.Conftest.CheckLib(context, libs, None, prog_prefix,
1010 call = call, language = language, autoadd = autoadd)
1011 context.did_show_result = 1