2 import SCons.Script.SConscript
11 # ARGH ... Why do they put a '+' in the module name ????????
12 SCons.Tool.cplusplus=getattr(__import__('SCons.Tool.c++', globals(), locals(), []).Tool, 'c++')
22 if line.startswith('COMPILE_FAIL(') and ')' in line:
23 name = line.split('(',1)[-1].split(')',1)[0]
25 elif line.startswith('}') and name and start:
26 tests[name] = (start, linenr)
29 def CompileCheck(target, source, env):
30 tests = scanTests(file(source[0].abspath))
32 cenv.Append( CPPDEFINES = [ 'COMPILE_CHECK' ] )
33 out = tempfile.TemporaryFile()
34 cenv['SPAWN'] = lambda sh, escape, cmd, args, env, pspawn=cenv['PSPAWN'], out=out: \
35 pspawn(sh, escape, cmd, args, env, out, out)
36 SCons.Script.Action('$CXXCOM').execute(target, source, cenv)
41 for error in result.splitlines():
42 elts = error.split(':',2)
43 if len(elts) != 3 : continue
44 filename, line, message = elts
45 if not os.path.exists(filename) : continue
47 except ValueError : continue
48 message = message.strip()
50 if delay_name and not message.startswith('instantiated from '):
51 print "Passed test '%s': %s" % (delay_name, message)
55 filename = os.path.abspath(filename)
56 if filename != source[0].abspath : continue
58 for name,lines in tests.iteritems():
59 if line >= lines[0] and line <= lines[1]:
61 if message.startswith('instantiated from '):
64 print "Passed test '%s': %s" % (name, message)
66 print "Passed test '%s': <unknown message ??>" % delay_name
67 failedTests = set(tests.iterkeys()) - set(passedTests.iterkeys())
69 for test in failedTests:
70 print "Test '%s' FAILED" % test
72 print "*** %d tests FAILED" % len(failedTests)
73 if os.path.exists(target[0].abspath):
74 os.unlink(target[0].abspath)
76 file(target[0].abspath,"w").write(result)
79 CompileCheck = SCons.Script.Action(CompileCheck)
81 def BoostUnitTest(env, target=None, source=None, **kw):
84 target = env.arg2nodes(target)[0]
85 source = env.arg2nodes(source)
87 binnode = target.dir.File('.' + target.name + '.bin')
88 stampnode = target.dir.File('.' + target.name + '.stamp')
90 bin = env.Program(binnode, source,
91 LIBS = env['LIBS'] + [ '$TEST_EXTRA_LIBS' ],
92 _LIBFLAGS = ' -Wl,-Bstatic -l$BOOSTTESTLIB -Wl,-Bdynamic ' + env['_LIBFLAGS'],
95 stamp = env.Command(stampnode, bin,
96 [ './$SOURCE $BOOSTTESTARGS', SCons.Script.Touch('$TARGET')],
99 alias = env.Command(env.File(target), stamp, [ env.NopAction() ] )
101 compileTests = [ src for src in source
102 if src.suffix in SCons.Tool.cplusplus.CXXSuffixes \
104 and 'COMPILE_CHECK' in file(str(src)).read() ]
106 env.Depends(alias, env.CompileCheck(source = compileTests))
108 _ALL_TESTS.append(alias)
112 def FindAllBoostUnitTests(env, target, source):
116 def NopAction(env, target, source):
117 def nop(target, source, env) : return None
118 def nopstr(target, source, env) : return ''
119 return env.Action(nop, nopstr)
121 ConfTest = CustomTests.ConfTest()
124 def CheckBoostVersion(context,fail=False,min=None,max=None):
125 """Check for boost includes.
127 Will place the boost version number (BOOST_LIB_VERSION) into the
128 BOOST_VERSION environment variable.
132 min/max compare boost version against given range.
134 fail if fail is set to True, the build will be terminated,
135 when no valid boost includes are found."""
137 msg = ' in range %s to %s' % (min,max)
139 msg = ' at least %s' % min
141 msg = ' at most %s' % max
144 context.Message( "Checking boost version%s... " % msg )
145 ret = context.TryRun("#include <boost/version.hpp>\n"
146 "#include <iostream>\n"
147 "int main(int, char **) { std::cout << BOOST_LIB_VERSION << std::endl; }",
151 msg = "no boost includes found"
152 context.env.Replace( BOOST_VERSION = None )
154 context.env.Replace( BOOST_VERSION = ret )
157 try: version = map(int,ret.split('_'))
159 msg = "[%s] invalid version syntax" % ret
162 if min : ret = ret and (version>=map(int,min.split('_')))
163 if max : ret = ret and (version<=map(int,max.split('_')))
164 msg = '[%s] %s' % (msg, ret and "yes" or "no")
166 if fail and not ret : context.env.Fail('No valid boost includes found')
170 def CheckBoostVariants(context, *variants):
171 if not variants : variants = ('','mt')
173 if context.env['BOOST_VARIANT'] is not None:
174 useVariant = context.env['BOOST_VARIANT']
176 _env = context.env.Clone()
177 for variant in variants:
178 if variant : variantStr = "'%s'" % variant
179 else : variantStr = "default"
180 context.Message( "Checking boost %s variant... " % variantStr )
181 context.env.Replace( BOOST_VARIANT=variant )
182 context.env.Append( _LIBFLAGS = ' -Wl,-Bstatic -l$BOOSTTESTLIB -Wl,-Bdynamic' )
183 ret = context.TryLink("#define BOOST_AUTO_TEST_MAIN\n"
184 "#include <boost/test/auto_unit_test.hpp>\n"
185 "#include <boost/test/test_tools.hpp>\n"
186 "BOOST_AUTO_TEST_CASE(test) { BOOST_CHECK(true); }\n",
188 context.Result( ret )
189 if ret and useVariant is None:
192 context.env.Replace(**_env.Dictionary())
193 if useVariant is not None and not context.env.GetOption('no_progress'):
194 print "Using %s boost variant." % (
195 useVariant and "'%s'" % useVariant or "default")
196 context.env.Replace( BOOST_VARIANT = useVariant )
201 BOOST_VARIANT = None,
202 _BOOST_VARIANT = '${BOOST_VARIANT and "-" or None}$BOOST_VARIANT',
204 BOOSTTESTLIB = 'boost_unit_test_framework$_BOOST_VARIANT',
205 BOOSTREGEXLIB = 'boost_regex$_BOOST_VARIANT',
206 BOOSTFSLIB = 'boost_filesystem$_BOOST_VARIANT',
207 BOOSTIOSTREAMSLIB = 'boost_iostreams$_BOOST_VARIANT',
208 BOOSTSIGNALSLIB = 'boost_signals$_BOOST_VARIANT',
210 BOOSTTESTARGS = [ '--build_info=yes', '--log_level=test_suite' ],
213 CUSTOM_TESTS = ConfTest.tests,
216 env['BUILDERS']['BoostUnitTest'] = BoostUnitTest
217 env['BUILDERS']['FindAllBoostUnitTests'] = FindAllBoostUnitTests
218 env['BUILDERS']['CompileCheck'] = env.Builder(
219 action = CompileCheck,
222 source_scanner = SCons.Scanner.C.CScanner(),
225 env['BUILDERS']['NopAction'] = NopAction