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> | # Eryn Wells <eryn@erynwells.me> | ||||||
| 
 | 
 | ||||||
| import os | import logging | ||||||
| 
 |  | ||||||
| import erw |  | ||||||
| 
 | 
 | ||||||
|  | setup_logging() | ||||||
| 
 | 
 | ||||||
| BUILD_CMDS = get_bool_argument(ARGUMENTS.get('BUILD_CMDS', False)) | BUILD_CMDS = get_bool_argument(ARGUMENTS.get('BUILD_CMDS', False)) | ||||||
| MODE = ARGUMENTS.get('MODE', None) | 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']): | for mode in (MODE.split(',') if MODE else ['debug']): | ||||||
|     try: |     env = Environment.for_mode(mode) | ||||||
|         env = modes[mode] |     env.process_lib_dirs() | ||||||
|     except KeyError: |     env.process_src() | ||||||
|         print 'Skipping invalid mode: {}'.format(mode) |     env.process_tests() | ||||||
|         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) |  | ||||||
|  |  | ||||||
|  | @ -1,18 +1,8 @@ | ||||||
| # SConscript | # SConscript | ||||||
| # vim: set ft=python: | # 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> | # Eryn Wells <eryn@erynwells.me> | ||||||
| 
 | 
 | ||||||
| import os.path | Library('gtest', [ | ||||||
| 
 |  | ||||||
| Import('env') |  | ||||||
| env.Append(CPPPATH=[Dir('include').srcnode()]) |  | ||||||
| 
 |  | ||||||
| files = [ |  | ||||||
|     'gtest-all.cc', |     'gtest-all.cc', | ||||||
|     'gtest-death-test.cc', |     'gtest-death-test.cc', | ||||||
|     'gtest-filepath.cc', |     'gtest-filepath.cc', | ||||||
|  | @ -21,7 +11,5 @@ files = [ | ||||||
|     'gtest-test-part.cc', |     'gtest-test-part.cc', | ||||||
|     'gtest-typed-test.cc', |     'gtest-typed-test.cc', | ||||||
|     'gtest.cc', |     'gtest.cc', | ||||||
| ] |     'gtest_main.cc' | ||||||
| 
 | ]) | ||||||
| gtest = env.Library('gtest', files) |  | ||||||
| Return('gtest') |  | ||||||
|  |  | ||||||
|  | @ -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 | # site_init.py | ||||||
| # Eryn Wells <eryn@erynwells.me> | # 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): | 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 |         kwargs['variant_dir'] = out_dir | ||||||
|     return env.SConscript(sconscript, {'env': env}, **kwargs) |     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 | # Argument utils | ||||||
| # | # | ||||||
|  | @ -28,3 +43,204 @@ def get_bool_argument(arg): | ||||||
|     except ValueError: |     except ValueError: | ||||||
|         pass |         pass | ||||||
|     return str(arg).lower() != 'false' |     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