Redo the _whooollleee_ build system
Following the tutorials on http://www.ostricher.com/tag/scons/, I rebuilt the build system so that SConscript files are *much* easier to write.
This commit is contained in:
		
							parent
							
								
									10b650c9a4
								
							
						
					
					
						commit
						c56cc557f8
					
				
					 6 changed files with 335 additions and 146 deletions
				
			
		
							
								
								
									
										56
									
								
								SConstruct
									
										
									
									
									
								
							
							
						
						
									
										56
									
								
								SConstruct
									
										
									
									
									
								
							|  | @ -6,59 +6,15 @@ | |||
| # | ||||
| # Eryn Wells <eryn@erynwells.me> | ||||
| 
 | ||||
| import os | ||||
| 
 | ||||
| import erw | ||||
| import logging | ||||
| 
 | ||||
| setup_logging() | ||||
| 
 | ||||
| BUILD_CMDS = get_bool_argument(ARGUMENTS.get('BUILD_CMDS', False)) | ||||
| MODE = ARGUMENTS.get('MODE', None) | ||||
| 
 | ||||
| BUILD_DIR = Dir('#build') | ||||
| LIB_DIR = Dir('#lib') | ||||
| SRC_DIR = Dir('#src') | ||||
| TEST_DIR = Dir('#test') | ||||
| 
 | ||||
| 
 | ||||
| modes = { | ||||
|     'debug': erw.DebugEnvironment(succinct=not BUILD_CMDS), | ||||
|     'beta': erw.BetaEnvironment(succinct=not BUILD_CMDS), | ||||
|     'release': erw.ReleaseEnvironment(succinct=not BUILD_CMDS), | ||||
| } | ||||
| 
 | ||||
| for mode in (MODE.split(',') if MODE else ['debug']): | ||||
|     try: | ||||
|         env = modes[mode] | ||||
|     except KeyError: | ||||
|         print 'Skipping invalid mode: {}'.format(mode) | ||||
|         break | ||||
| 
 | ||||
|     out_dir = BUILD_DIR.Dir(env['NAME']) | ||||
| 
 | ||||
|     # Allow same directory includes. | ||||
|     env.Append(CPPPATH=['.']) | ||||
| 
 | ||||
|     # Process all lib dirs. | ||||
|     env['AVAILABLE_LIBS'] = {} | ||||
|     for lib in os.listdir(LIB_DIR.abspath): | ||||
|         lib_dir = LIB_DIR.Dir(lib) | ||||
|         if not lib_dir.isdir(): | ||||
|             print 'Skipping {} in lib directory: is not a directory'.format(lib) | ||||
|             continue | ||||
|         lib_out_dir = out_dir.Dir('lib').Dir(lib) | ||||
|         output = do_sconscript(env, LIB_DIR.Dir(lib), lib_out_dir) | ||||
|         if not output: | ||||
|             print "Lib {} didn't return any object".format(lib) | ||||
|         env['AVAILABLE_LIBS'][lib] = output | ||||
|         env.Append(LIBPATH=[lib_out_dir]) | ||||
| 
 | ||||
|     # Get source files. | ||||
|     src_out_dir = out_dir.Dir('src') | ||||
|     do_sconscript(env, SRC_DIR, src_out_dir) | ||||
|     env.Append(LIBPATH=[src_out_dir], | ||||
|                CPPPATH=[SRC_DIR]) | ||||
| 
 | ||||
|     # Get test binaries. | ||||
|     test = do_sconscript(env, TEST_DIR, out_dir.Dir('test')) | ||||
|     run_tests = env.Alias('test', [test], '{} --gtest_color=yes'.format(test[0].path)) | ||||
|     env.AlwaysBuild(run_tests) | ||||
|     env = Environment.for_mode(mode) | ||||
|     env.process_lib_dirs() | ||||
|     env.process_src() | ||||
|     env.process_tests() | ||||
|  |  | |||
|  | @ -1,18 +1,8 @@ | |||
| # SConscript | ||||
| # vim: set ft=python: | ||||
| # | ||||
| # Build file for the gtest library. This file also serves as an example for how | ||||
| # to build libraries for inclusion with my SCons environment. Libraries should | ||||
| # return a build object. | ||||
| # | ||||
| # Eryn Wells <eryn@erynwells.me> | ||||
| 
 | ||||
| import os.path | ||||
| 
 | ||||
| Import('env') | ||||
| env.Append(CPPPATH=[Dir('include').srcnode()]) | ||||
| 
 | ||||
| files = [ | ||||
| Library('gtest', [ | ||||
|     'gtest-all.cc', | ||||
|     'gtest-death-test.cc', | ||||
|     'gtest-filepath.cc', | ||||
|  | @ -21,7 +11,5 @@ files = [ | |||
|     'gtest-test-part.cc', | ||||
|     'gtest-typed-test.cc', | ||||
|     'gtest.cc', | ||||
| ] | ||||
| 
 | ||||
| gtest = env.Library('gtest', files) | ||||
| Return('gtest') | ||||
|     'gtest_main.cc' | ||||
| ]) | ||||
|  |  | |||
|  | @ -1,81 +0,0 @@ | |||
| # erw.py | ||||
| # Eryn Wells <eryn@erynwells.me> | ||||
| 
 | ||||
| import sys | ||||
| 
 | ||||
| import SCons.Environment | ||||
| 
 | ||||
| import paths | ||||
| 
 | ||||
| # | ||||
| # Environments | ||||
| # | ||||
| 
 | ||||
| class Environment(SCons.Environment.Environment): | ||||
|     ''' | ||||
|     Default SCons environment for building things. | ||||
|     ''' | ||||
| 
 | ||||
|     def __init__(self, name, modern=True, paranoid=True, colorful=True, succinct=True, **kwargs): | ||||
|         super(Environment, self).__init__(**kwargs) | ||||
| 
 | ||||
|         self['NAME'] = name | ||||
| 
 | ||||
|         if 'CC' not in kwargs: | ||||
|             self['CC'] = self.Detect(['clang', 'gcc']) | ||||
|         if 'CXX' not in kwargs: | ||||
|             self['CXX'] = self.Detect(['clang++', 'g++']) | ||||
|         if 'LINK' not in kwargs: | ||||
|             self['LINK'] = self.Detect(['clang++', 'clang', 'ld']) | ||||
| 
 | ||||
|         # Modern C/C++ | ||||
|         if modern: | ||||
|             self.Append(CFLAGS=['-std=c99']) | ||||
|             self.Append(CXXFLAGS=['-std=c++11']) | ||||
| 
 | ||||
|         # Paranoid C/C++ | ||||
|         if paranoid: | ||||
|             self.Append(CCFLAGS=['-Wall', '-Wextra', '-pedantic']) | ||||
| 
 | ||||
|         # Colorful C/C++ | ||||
|         if colorful and sys.stdout.isatty(): | ||||
|             if 'clang' in self['CC'] or 'clang' in self['CXX']: | ||||
|                 self.Append(CCFLAGS=['-fcolor-diagnostics']) | ||||
| 
 | ||||
|         self['ARCOMSTR'] = self._comstr('Archiving', succinct) | ||||
|         self['ASCOMSTR'] = self._comstr('Assembling', succinct) | ||||
|         self['ASPPCOMSTR'] = self._comstr('Assembling', succinct) | ||||
|         self['CCCOMSTR'] = self._comstr('Building (C)', succinct) | ||||
|         self['CXXCOMSTR'] = self._comstr('Building (C++)', succinct) | ||||
|         self['LINKCOMSTR'] = self._comstr('Linking', succinct) | ||||
|         self['RANLIBCOMSTR'] = self._comstr('Indexing', succinct) | ||||
|         self['SHCCCOMSTR'] = self._comstr('Building (C, Shared)', succinct) | ||||
|         self['SHCXXCOMSTR'] = self._comstr('Building (C++, Shared)', succinct) | ||||
|         self['SHLINKCOMSTR'] = self._comstr('Linking (Shared)', succinct) | ||||
| 
 | ||||
|     def _comstr(self, action, succinct=True): | ||||
|         if succinct: | ||||
|             return '{:>25}: $TARGET'.format(action) | ||||
|         else: | ||||
|             return '  [{:^6}] $TARGET'.format(action) | ||||
| 
 | ||||
| 
 | ||||
| class DebugEnvironment(Environment): | ||||
|     def __init__(self, name='debug', **kwargs): | ||||
|         super(DebugEnvironment, self).__init__(name, **kwargs) | ||||
|         self.Append(CPPDEFINES=['DEBUG']) | ||||
|         self.Append(CCFLAGS=['-O0', '-g']) | ||||
| 
 | ||||
| 
 | ||||
| class BetaEnvironment(Environment): | ||||
|     def __init__(self, name='beta', **kwargs): | ||||
|         super(BetaEnvironment, self).__init__(name, **kwargs) | ||||
|         self.Append(CPPDEFINES=['DEBUG']) | ||||
|         self.Append(CCFLAGS=['-O3', '-g']) | ||||
| 
 | ||||
| 
 | ||||
| class ReleaseEnvironment(Environment): | ||||
|     def __init__(self, name='release', **kwargs): | ||||
|         super(ReleaseEnvironment, self).__init__(name, **kwargs) | ||||
|         self.Append(CPPDEFINES=['NDEBUG', 'RELEASE']) | ||||
|         self.Append(CCFLAGS=['-O3']) | ||||
|  | @ -1,6 +1,14 @@ | |||
| # site_init.py | ||||
| # Eryn Wells <eryn@erynwells.me> | ||||
| 
 | ||||
| import logging | ||||
| import os | ||||
| import sys | ||||
| 
 | ||||
| import SCons.Environment | ||||
| import SCons.Errors | ||||
| 
 | ||||
| import paths | ||||
| 
 | ||||
| def do_sconscript(env, src_dir, out_dir=None): | ||||
|     ''' | ||||
|  | @ -13,6 +21,13 @@ def do_sconscript(env, src_dir, out_dir=None): | |||
|         kwargs['variant_dir'] = out_dir | ||||
|     return env.SConscript(sconscript, {'env': env}, **kwargs) | ||||
| 
 | ||||
| 
 | ||||
| def setup_logging(level=logging.DEBUG): | ||||
|     '''Configure global logging for the SCons system.''' | ||||
|     root = logging.getLogger() | ||||
|     root.setLevel(logging.DEBUG) | ||||
|     root.addHandler(logging.StreamHandler()) | ||||
| 
 | ||||
| # | ||||
| # Argument utils | ||||
| # | ||||
|  | @ -28,3 +43,204 @@ def get_bool_argument(arg): | |||
|     except ValueError: | ||||
|         pass | ||||
|     return str(arg).lower() != 'false' | ||||
| 
 | ||||
| # | ||||
| # Builders | ||||
| # | ||||
| 
 | ||||
| def program_builder(env): | ||||
|     original_builder = env.Program | ||||
|     def builder(env, prog_name, sources, *args, **kwargs): | ||||
|         return original_builder(prog_name, sources, *args, **kwargs) | ||||
|     return builder | ||||
| 
 | ||||
| # | ||||
| # Environments | ||||
| # | ||||
| 
 | ||||
| class Environment(SCons.Environment.Environment): | ||||
|     ''' | ||||
|     Default SCons environment for building things. | ||||
|     ''' | ||||
| 
 | ||||
|     @classmethod | ||||
|     def _comstr(cls, action, succinct=True): | ||||
|         if succinct: | ||||
|             return '{:>25}: $TARGET'.format(action) | ||||
|         # Use the default *COMSTR. | ||||
|         return None | ||||
| 
 | ||||
|     @classmethod | ||||
|     def for_mode(cls, mode, name=None, succinct=True): | ||||
|         kwargs = {'succinct': succinct} | ||||
|         if name: | ||||
|             kwargs['name'] = name | ||||
|         mode_lower = mode.lower() | ||||
|         if mode_lower == 'debug': | ||||
|             return DebugEnvironment(**kwargs) | ||||
|         elif mode_lower == 'beta': | ||||
|             return BetaEnvironment(**kwargs) | ||||
|         elif mode_lower == 'release': | ||||
|             return ReleaseEnvironment(**kwargs) | ||||
|         raise SCons.Errors.UserError('Invalid mode: {}'.format(mode)) | ||||
| 
 | ||||
|     def __init__(self, name, modern=True, paranoid=True, colorful=True, succinct=True, **kwargs): | ||||
|         super(Environment, self).__init__(**self._append_custom_tools(kwargs)) | ||||
| 
 | ||||
|         self.SetDefault(NAME=name) | ||||
| 
 | ||||
|         self.SetDefault(LOGGER=logging.getLogger(name)) | ||||
| 
 | ||||
|         self.SetDefault(BUILD_ROOT=self.Dir('#build')) | ||||
|         self.SetDefault(LIB_ROOT=self.Dir('#lib')) | ||||
|         self.SetDefault(SRC_ROOT=self.Dir('#src')) | ||||
|         self.SetDefault(TEST_ROOT=self.Dir('#test')) | ||||
|         self.SetDefault(INCLUDE_ROOT=self.Dir('#include')) | ||||
| 
 | ||||
|         # Allow same directory includes. | ||||
|         self.AppendUnique(CPPPATH=['.']) | ||||
| 
 | ||||
|         self.SetDefault(CC=self.Detect(['clang', 'gcc'])) | ||||
|         self.SetDefault(CXX=self.Detect(['clang++', 'g++'])) | ||||
|         self.SetDefault(LINK=self.Detect(['clang++', 'clang', 'ld'])) | ||||
| 
 | ||||
|         # Modern C/C++ | ||||
|         if modern: | ||||
|             self.AppendUnique(CFLAGS=['-std=c99']) | ||||
|             self.AppendUnique(CXXFLAGS=['-std=c++11']) | ||||
| 
 | ||||
|         # Paranoid C/C++ | ||||
|         if paranoid: | ||||
|             self.AppendUnique(CCFLAGS=['-Wall', '-Wextra', '-pedantic']) | ||||
| 
 | ||||
|         # Colorful C/C++ | ||||
|         if colorful and sys.stdout.isatty(): | ||||
|             if 'clang' in self['CC'] or 'clang' in self['CXX']: | ||||
|                 self.AppendUnique(CCFLAGS=['-fcolor-diagnostics']) | ||||
| 
 | ||||
|         # Pretty printing | ||||
|         self.SetDefault(ARCOMSTR=Environment._comstr('Archiving', succinct)) | ||||
|         self.SetDefault(ASCOMSTR=Environment._comstr('Assembling', succinct)) | ||||
|         self.SetDefault(ASPPCOMSTR=Environment._comstr('Assembling', succinct)) | ||||
|         self.SetDefault(CCCOMSTR=Environment._comstr('Building (C)', succinct)) | ||||
|         self.SetDefault(CXXCOMSTR=Environment._comstr('Building (C++)', succinct)) | ||||
|         self.SetDefault(LINKCOMSTR=Environment._comstr('Linking', succinct)) | ||||
|         self.SetDefault(RANLIBCOMSTR=Environment._comstr('Indexing', succinct)) | ||||
|         self.SetDefault(SHCCCOMSTR=Environment._comstr('Building (C, Shared)', succinct)) | ||||
|         self.SetDefault(SHCXXCOMSTR=Environment._comstr('Building (C++, Shared)', succinct)) | ||||
|         self.SetDefault(SHLINKCOMSTR=Environment._comstr('Linking (Shared)', succinct)) | ||||
| 
 | ||||
|     @property | ||||
|     def build_root(self): | ||||
|         '''Return the build output directory for this environment.''' | ||||
|         return self['BUILD_ROOT'].Dir(self['NAME']) | ||||
| 
 | ||||
|     @property | ||||
|     def lib_root(self): | ||||
|         '''Return the root directory for libraries for this environment.''' | ||||
|         return self['LIB_ROOT'] | ||||
| 
 | ||||
|     @property | ||||
|     def src_root(self): | ||||
|         '''Return the main source root directory for this environment.''' | ||||
|         return self['SRC_ROOT'] | ||||
| 
 | ||||
|     @property | ||||
|     def lib_dirs(self): | ||||
|         for lib in os.listdir(self['LIB_ROOT'].abspath): | ||||
|             lib_dir = self['LIB_ROOT'].Dir(lib) | ||||
|             if not lib_dir.isdir(): | ||||
|                 continue | ||||
|             yield (lib, lib_dir) | ||||
| 
 | ||||
|     # | ||||
|     # Library processing | ||||
|     # | ||||
| 
 | ||||
|     def process_lib_dirs(self): | ||||
|         self.log('Processing libs in #{} ...'.format(self.lib_root.path)) | ||||
|         for name, lib in self.lib_dirs: | ||||
|             self.log('  - {}'.format(name)) | ||||
|             self.LibDir(name) | ||||
| 
 | ||||
|     def process_src(self): | ||||
|         out_dir = self.build_root.Dir('src') | ||||
|         # TODO: Do the thing. | ||||
|         # do_sconscript(env, env.source_root, src_out_dir) | ||||
|         self.Append(CPPPATH=[self.src_root]) | ||||
| 
 | ||||
|     def lib(self, name): | ||||
|         return self['LIBS'].get(name) | ||||
| 
 | ||||
|     def register_lib(self, name, lib): | ||||
|         if name in self['LIBS']: | ||||
|             self.log_error('Library has already been built: {}'.format(name)) | ||||
|         self['LIBS'][name] = lib | ||||
| 
 | ||||
|     # | ||||
|     # Test processing | ||||
|     # | ||||
| 
 | ||||
|     def test_objects(self, name): | ||||
|         self._ensure_test_structure(name) | ||||
|         return self['TESTS'][name]['objects'] | ||||
| 
 | ||||
|     def test_program(self, name): | ||||
|         self._ensure_test_structure(name) | ||||
|         return self['TESTS'][name]['program'] | ||||
| 
 | ||||
|     def register_test_program(self, name, prog): | ||||
|         self._ensure_test_structure(name) | ||||
|         self['TESTS'][name]['program'] = prog | ||||
| 
 | ||||
|     def process_tests(self): | ||||
|         for test, struct in self['TESTS'].iteritems(): | ||||
|             if not struct['program']: | ||||
|                 continue | ||||
|             self.TestRun(test) | ||||
| 
 | ||||
|     def _ensure_test_structure(self, name): | ||||
|         self['TESTS'].setdefault(name, {'program': None, 'objects': []}) | ||||
| 
 | ||||
|     # | ||||
|     # Logging | ||||
|     # | ||||
| 
 | ||||
|     def log(self, msg, *args, **kwargs): | ||||
|         self['LOGGER'].info(msg, *args, **kwargs) | ||||
| 
 | ||||
|     def log_debug(self, msg, *args, **kwargs): | ||||
|         self['LOGGER'].debug(msg, *args, **kwargs) | ||||
| 
 | ||||
|     def log_error(self, msg, *args, **kwargs): | ||||
|         self['LOGGER'].error(msg, *args, **kwargs) | ||||
| 
 | ||||
|     def _append_custom_tools(self, kwargs): | ||||
|         '''Add custom tools to the `kwargs`.''' | ||||
|         tools = kwargs.setdefault('tools', ['default']) | ||||
|         for tool in ['lib', 'test']: | ||||
|             if tool in tools: | ||||
|                 continue | ||||
|             tools.append(tool) | ||||
|         return kwargs | ||||
| 
 | ||||
| 
 | ||||
| class DebugEnvironment(Environment): | ||||
|     def __init__(self, name='debug', **kwargs): | ||||
|         super(DebugEnvironment, self).__init__(name, **kwargs) | ||||
|         self.Append(CPPDEFINES=['DEBUG']) | ||||
|         self.Append(CCFLAGS=['-O0', '-g']) | ||||
| 
 | ||||
| 
 | ||||
| class BetaEnvironment(Environment): | ||||
|     def __init__(self, name='beta', **kwargs): | ||||
|         super(BetaEnvironment, self).__init__(name, **kwargs) | ||||
|         self.Append(CPPDEFINES=['DEBUG']) | ||||
|         self.Append(CCFLAGS=['-O3', '-g']) | ||||
| 
 | ||||
| 
 | ||||
| class ReleaseEnvironment(Environment): | ||||
|     def __init__(self, name='release', **kwargs): | ||||
|         super(ReleaseEnvironment, self).__init__(name, **kwargs) | ||||
|         self.Append(CPPDEFINES=['NDEBUG', 'RELEASE']) | ||||
|         self.Append(CCFLAGS=['-O3']) | ||||
|  |  | |||
							
								
								
									
										59
									
								
								site_scons/site_tools/lib.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								site_scons/site_tools/lib.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,59 @@ | |||
| # lib.py | ||||
| # Eryn Wells <eryn@erynwells.me> | ||||
| 
 | ||||
| ''' | ||||
| SCons builder for a lib directory. | ||||
| ''' | ||||
| 
 | ||||
| import SCons.Errors | ||||
| import SCons.Script | ||||
| 
 | ||||
| 
 | ||||
| def _process_lib_dir(env, lib, src_dir=None, out_dir=None, inc_dir=None): | ||||
|     if not src_dir: | ||||
|         src_dir = env.lib_root.Dir(lib) | ||||
|     if not src_dir.isdir(): | ||||
|         err = 'Invalid library source directory: {}'.format(src_dir) | ||||
|         env.log_error(err) | ||||
|         raise SCons.Errors.UserError(err) | ||||
|     if not out_dir: | ||||
|         out_dir = env.build_root.Dir('lib').Dir(lib) | ||||
|     if not inc_dir: | ||||
|         include_dir = src_dir.Dir('include') | ||||
|         if include_dir.isdir(): | ||||
|             inc_dir = [include_dir] | ||||
|     env.Append(CPPPATH=inc_dir) | ||||
|     exports = {'Library': env.Library, | ||||
|                'StaticLibrary': env.StaticLibrary, | ||||
|                'SharedLibrary': env.SharedLibrary} | ||||
|     SCons.Script._SConscript.GlobalDict.update(exports) | ||||
|     out = env.SConscript(src_dir.File('SConscript'), | ||||
|                          {'env': env.Clone()}, | ||||
|                          variant_dir=out_dir, | ||||
|                          exports=exports) | ||||
|     return out | ||||
| 
 | ||||
| 
 | ||||
| def _build_library(env, lib_func): | ||||
|     original_builder = lib_func | ||||
| 
 | ||||
|     def builder(env, lib_name, sources, *args, **kwargs): | ||||
|         lib = original_builder(lib_name, sources, *args, **kwargs) | ||||
|         env.register_lib(lib_name, lib) | ||||
|         return lib | ||||
| 
 | ||||
|     return builder | ||||
| 
 | ||||
| # | ||||
| # SCons tool interface | ||||
| # | ||||
| 
 | ||||
| def generate(env): | ||||
|     env.SetDefault(LIBS={}) | ||||
|     env.AddMethod(_process_lib_dir, 'LibDir') | ||||
|     env.AddMethod(_build_library(env, env.Library), 'Library') | ||||
|     env.AddMethod(_build_library(env, env.StaticLibrary), 'StaticLibrary') | ||||
|     env.AddMethod(_build_library(env, env.SharedLibrary), 'SharedLibrary') | ||||
| 
 | ||||
| def exists(env): | ||||
|     return True | ||||
							
								
								
									
										51
									
								
								site_scons/site_tools/test.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								site_scons/site_tools/test.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,51 @@ | |||
| # test.py | ||||
| # Eryn Wells <eryn@erynwells.me> | ||||
| 
 | ||||
| ''' | ||||
| Test builder for SCons. Test files are compiled to objects and stored in the  | ||||
| environment. | ||||
| ''' | ||||
| 
 | ||||
| def _process_test_dir(env, dir, program=None): | ||||
|     # TODO: Builder for test directories? | ||||
|     pass | ||||
| 
 | ||||
| 
 | ||||
| def _build_test_object(env, source, program=None): | ||||
|     obj = env.Object(source) | ||||
|     if not program: | ||||
|         program = 'test' | ||||
|     try: | ||||
|         env.test_objects(program).extend(obj) | ||||
|     except TypeError: | ||||
|         env.test_objects(program).append(obj) | ||||
|     return obj | ||||
| 
 | ||||
| 
 | ||||
| def _build_test_program(env, name=None): | ||||
|     if not name: | ||||
|         name = 'test' | ||||
|     prog = env.Program(name, env.test_objects(name), LIBS=[env.lib('gtest')]) | ||||
|     env.register_test_program(name, prog) | ||||
|     return  | ||||
| 
 | ||||
| 
 | ||||
| def _run_tests(env, name=None): | ||||
|     if not name: | ||||
|         name = 'test' | ||||
|     cmd = env.Command(env.test_program(name), None, '$SOURCE --gtest_color=yes') | ||||
|     env.AlwaysBuild(cmd) | ||||
|     return cmd | ||||
| 
 | ||||
| # | ||||
| # SCons tool interface | ||||
| # | ||||
| 
 | ||||
| def generate(env): | ||||
|     env.SetDefault(TESTS={}) | ||||
|     env.AddMethod(_build_test_object, 'Test') | ||||
|     env.AddMethod(_build_test_program, 'TestProgram') | ||||
|     env.AddMethod(_run_tests, 'TestRun') | ||||
| 
 | ||||
| def exists(env): | ||||
|     return 'Object' in env | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue