| 
									
										
										
										
											2014-01-30 14:08:11 -08:00
										 |  |  | # SConstruct | 
					
						
							|  |  |  | # vim: set ft=python: | 
					
						
							|  |  |  | # | 
					
						
							| 
									
										
										
										
											2014-01-30 15:42:25 -08:00
										 |  |  | # Toplevel Scons build script. This should be mostly complete and generic enough | 
					
						
							|  |  |  | # for most builds. | 
					
						
							| 
									
										
										
										
											2014-01-30 14:08:11 -08:00
										 |  |  | # | 
					
						
							|  |  |  | # Eryn Wells <eryn@erynwells.me> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # DEFAULT CONFIGURATION VALUES | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-01-30 20:43:09 -08:00
										 |  |  | # Settings for the default toolchain binaries. Setting these overrides the | 
					
						
							|  |  |  | # defaults, provided your the given binary exists. | 
					
						
							| 
									
										
										
										
											2014-01-30 20:36:38 -08:00
										 |  |  | CC = None | 
					
						
							|  |  |  | CXX = None | 
					
						
							|  |  |  | AS = None | 
					
						
							| 
									
										
										
										
											2014-01-30 20:43:09 -08:00
										 |  |  | LINK = None | 
					
						
							| 
									
										
										
										
											2014-01-30 20:36:38 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | # Same as above but for default CFLAGS. These are appended to both CFLAGS and | 
					
						
							|  |  |  | # CXXFLAGS. | 
					
						
							|  |  |  | CFLAGS = '-Wall -Wextra -pedantic' | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-01-30 14:08:11 -08:00
										 |  |  | # Enabling debugging does the following things: | 
					
						
							|  |  |  | #   1. Turns on debugging symbols | 
					
						
							|  |  |  | #   2. Turns off all optimization | 
					
						
							|  |  |  | #   3. Sets the DEBUG define | 
					
						
							|  |  |  | DEBUG = True | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-01-30 15:42:25 -08:00
										 |  |  | # Show build commands ("cc [args] -o [out] [file]", etc). If this is False, show | 
					
						
							| 
									
										
										
										
											2014-01-30 14:08:11 -08:00
										 |  |  | # some nice messages for each step of the build. | 
					
						
							|  |  |  | BUILD_CMDS = False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # BUILD STUFF BELOW HERE | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-01-30 15:09:28 -08:00
										 |  |  | import os | 
					
						
							| 
									
										
										
										
											2014-01-30 14:08:11 -08:00
										 |  |  | import os.path | 
					
						
							| 
									
										
										
										
											2014-01-30 21:01:20 -08:00
										 |  |  | import SCons.Errors | 
					
						
							| 
									
										
										
										
											2014-01-30 14:08:11 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-01-30 15:09:28 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | def which(program): | 
					
						
							|  |  |  |     def is_executable(path): | 
					
						
							|  |  |  |         return os.path.exists(path) and os.access(path, os.X_OK) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     path, name = os.path.split(program) | 
					
						
							|  |  |  |     if path: | 
					
						
							|  |  |  |         if is_executable(program): | 
					
						
							|  |  |  |             return program | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         pathext = [''] + os.environ.get('PATHEXT', '').split(os.pathsep) | 
					
						
							|  |  |  |         for path in os.environ.get('PATH', '').split(os.pathsep): | 
					
						
							|  |  |  |             exe = os.path.join(path, program) | 
					
						
							|  |  |  |             for ext in pathext: | 
					
						
							|  |  |  |                 candidate = exe + ext | 
					
						
							|  |  |  |                 if is_executable(candidate): | 
					
						
							|  |  |  |                     return candidate | 
					
						
							|  |  |  |     return None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def get_bool_argument(arg): | 
					
						
							|  |  |  |     try: | 
					
						
							|  |  |  |         return bool(int(arg)) | 
					
						
							|  |  |  |     except ValueError: | 
					
						
							|  |  |  |         pass | 
					
						
							|  |  |  |     if arg in ('False', 'FALSE', 'false', ''): | 
					
						
							|  |  |  |         return False | 
					
						
							|  |  |  |     return True | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-01-30 21:01:20 -08:00
										 |  |  | def set_toolchain_binary(env, var, user_binary, binaries=()): | 
					
						
							|  |  |  |     if user_binary and which(user_binary): | 
					
						
							|  |  |  |         env[var] = user_binary | 
					
						
							|  |  |  |         return | 
					
						
							|  |  |  |     for c in binaries: | 
					
						
							|  |  |  |         if which(c): | 
					
						
							|  |  |  |             env[var] = c | 
					
						
							|  |  |  |             break | 
					
						
							| 
									
										
										
										
											2014-01-30 20:36:38 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | common_env = Environment() | 
					
						
							| 
									
										
										
										
											2014-01-30 21:01:20 -08:00
										 |  |  | set_toolchain_binary(common_env, 'CC', CC, ('clang', 'gcc')) | 
					
						
							|  |  |  | set_toolchain_binary(common_env, 'CXX', CXX, ('clang++', 'g++')) | 
					
						
							|  |  |  | set_toolchain_binary(common_env, 'AS', AS) | 
					
						
							|  |  |  | set_toolchain_binary(common_env, 'LINK', LINK) | 
					
						
							| 
									
										
										
										
											2014-01-30 20:36:38 -08:00
										 |  |  | common_env.Append(CFLAGS='{} -std=c99'.format(CFLAGS)) | 
					
						
							|  |  |  | common_env.Append(CXXFLAGS='{} -std=c++11'.format(CFLAGS)) | 
					
						
							| 
									
										
										
										
											2014-01-30 14:08:11 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | BUILD_CMDS = get_bool_argument(ARGUMENTS.get('BUILD_CMDS', BUILD_CMDS)) | 
					
						
							|  |  |  | if not BUILD_CMDS: | 
					
						
							|  |  |  |     def generate_comstr(action): | 
					
						
							| 
									
										
										
										
											2014-02-27 21:57:20 -08:00
										 |  |  |         return '{:>25}: $TARGET'.format(action) | 
					
						
							| 
									
										
										
										
											2014-01-30 15:42:25 -08:00
										 |  |  |     common_env['ASCOMSTR'] = generate_comstr('Assembling') | 
					
						
							|  |  |  |     common_env['CCCOMSTR'] = generate_comstr('Building (C)') | 
					
						
							| 
									
										
										
										
											2014-02-27 21:57:20 -08:00
										 |  |  |     common_env['SHCCCOMSTR'] = generate_comstr('Building (C, Shared)') | 
					
						
							| 
									
										
										
										
											2014-01-30 15:42:25 -08:00
										 |  |  |     common_env['CXXCOMSTR'] = generate_comstr('Building (C++)') | 
					
						
							| 
									
										
										
										
											2014-02-27 21:57:20 -08:00
										 |  |  |     common_env['SHCXXCOMSTR'] = generate_comstr('Building (C++, Shared)') | 
					
						
							| 
									
										
										
										
											2014-01-30 15:42:25 -08:00
										 |  |  |     common_env['LINKCOMSTR'] = generate_comstr('Linking') | 
					
						
							| 
									
										
										
										
											2014-02-27 21:57:20 -08:00
										 |  |  |     common_env['SHLINKCOMSTR'] = generate_comstr('Linking (Shared)') | 
					
						
							| 
									
										
										
										
											2014-01-30 15:42:25 -08:00
										 |  |  |     common_env['ARCOMSTR'] = generate_comstr('Archiving') | 
					
						
							| 
									
										
										
										
											2014-01-30 14:08:11 -08:00
										 |  |  |     common_env['RANLIBCOMSTR'] = generate_comstr('Indexing') | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-01-30 15:09:28 -08:00
										 |  |  | src_dir = Dir('#src') | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-01-31 08:42:41 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | def create_env(variant_dir, appends=None): | 
					
						
							|  |  |  |     env = common_env.Clone() | 
					
						
							|  |  |  |     env.VariantDir(variant_dir, src_dir, duplicate=0) | 
					
						
							|  |  |  |     env.Clean('.', variant_dir) | 
					
						
							|  |  |  |     for k, v in appends.iteritems(): | 
					
						
							|  |  |  |         if k.startswith('='): | 
					
						
							|  |  |  |             env[k[1:]] = v | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             env.Append(**{k: v}) | 
					
						
							|  |  |  |     return env | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-01-30 14:08:11 -08:00
										 |  |  | debug_cflags = ' -O0 -g' | 
					
						
							| 
									
										
										
										
											2014-01-31 08:42:41 -08:00
										 |  |  | debug_env = create_env(os.path.join('build', 'debug'), { | 
					
						
							|  |  |  |     'CPPDEFINES': ['DEBUG'], | 
					
						
							|  |  |  |     'CFLAGS': debug_cflags, | 
					
						
							|  |  |  |     'CXXFLAGS': debug_cflags, | 
					
						
							|  |  |  | }) | 
					
						
							| 
									
										
										
										
											2014-01-30 14:08:11 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-01-30 15:42:25 -08:00
										 |  |  | release_cflags = ' -O2' | 
					
						
							| 
									
										
										
										
											2014-01-31 08:42:41 -08:00
										 |  |  | release_env = create_env(os.path.join('build', 'release'), { | 
					
						
							|  |  |  |     'CPPDEFINES': ['RELEASE'], | 
					
						
							|  |  |  |     'CFLAGS': release_cflags, | 
					
						
							|  |  |  |     'CXXFLAGS': release_cflags, | 
					
						
							|  |  |  | }) | 
					
						
							| 
									
										
										
										
											2014-01-30 14:08:11 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-01-31 08:27:37 -08:00
										 |  |  | modes = { | 
					
						
							|  |  |  |     'debug': debug_env, | 
					
						
							|  |  |  |     'release': release_env, | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | mode = ARGUMENTS.get('MODE', None) | 
					
						
							|  |  |  | if mode: | 
					
						
							|  |  |  |     # If MODE=foo is specified, build only that mode. | 
					
						
							|  |  |  |     try: | 
					
						
							|  |  |  |         env = modes[mode] | 
					
						
							|  |  |  |     except KeyError: | 
					
						
							|  |  |  |         raise SCons.Errors.UserError('Invalid mode: {}'.format(mode)) | 
					
						
							| 
									
										
										
										
											2014-01-30 15:09:28 -08:00
										 |  |  |     env.SConscript(os.path.join('build', mode, 'SConscript'), {'env': env}) | 
					
						
							| 
									
										
										
										
											2014-01-31 08:27:37 -08:00
										 |  |  | else: | 
					
						
							|  |  |  |     # Build all modes. | 
					
						
							| 
									
										
										
										
											2014-01-31 08:42:41 -08:00
										 |  |  |     for mode, env in modes.iteritems(): | 
					
						
							| 
									
										
										
										
											2014-01-31 08:27:37 -08:00
										 |  |  |         env.SConscript(os.path.join('build', mode, 'SConscript'), {'env': env}) |