Mercurial > parpg-core
comparison SConstruct @ 5:33684971cdb1
Replaced the shell script launcher with a cross-platform C executable.
* Replaced the Unix-only shell script launcher with a cross-platform compiled executable written in C.
* Added several new configuration variables to the SConsctruct script which allows the user to specify where their Python site-packages and executable are located;
* Cleaned up the SConstruct script and made it easier to grok.
author | M. George Hansen <technopolitica@gmail.com> |
---|---|
date | Tue, 17 May 2011 14:18:25 -0700 |
parents | e2a8e3805b04 |
children | dd4ed4945411 |
comparison
equal
deleted
inserted
replaced
4:20c2b7a42c63 | 5:33684971cdb1 |
---|---|
2 import os | 2 import os |
3 import platform | 3 import platform |
4 import compileall | 4 import compileall |
5 import fnmatch | 5 import fnmatch |
6 from collections import Sequence | 6 from collections import Sequence |
7 from types import StringType | |
7 from multiprocessing import cpu_count | 8 from multiprocessing import cpu_count |
8 | 9 |
9 def InstallChmod(env, dest, source, mode): | 10 def InstallChmod(env, dest, source, mode): |
10 targets = env.Install(dest, source) | 11 targets = env.Install(dest, source) |
11 for target in targets: | 12 for target in targets: |
49 file_path = os.path.join(dir_path, file_name) | 50 file_path = os.path.join(dir_path, file_name) |
50 env.Clean(path, file_path) | 51 env.Clean(path, file_path) |
51 source_file_path = file_path.rstrip('oc') | 52 source_file_path = file_path.rstrip('oc') |
52 env.Depends(file_path, source_file_path) | 53 env.Depends(file_path, source_file_path) |
53 | 54 |
54 if not isinstance(source, Sequence): | 55 if not isinstance(source, Sequence) or isinstance(source, StringType): |
55 source = [source] | 56 source = [source] |
56 for dir in source: | 57 for dir in source: |
57 _remove_compiled_modules(str(dir)) | 58 _remove_compiled_modules(str(dir)) |
58 if compile: | 59 if compile: |
59 compileall.compile_dir(str(dir), ddir=str(dest), force=True) | 60 compileall.compile_dir(str(dir), ddir=str(dest), force=True) |
79 AddOption( | 80 AddOption( |
80 '--no-compile', | 81 '--no-compile', |
81 dest='compile', | 82 dest='compile', |
82 action='store_false', | 83 action='store_false', |
83 default=True, | 84 default=True, |
84 help='don\'t compile any Python modules into .pyc files', | 85 help='don\'t compile any Python modules into .pyc files before installing', |
85 ) | 86 ) |
86 SetOption('num_jobs', cpu_count()) | 87 SetOption('num_jobs', cpu_count()) |
87 | 88 |
88 def is_abs_path(key, val, env): | 89 def is_abs_path(key, val, env): |
89 if not os.path.isabs(val): | 90 if not os.path.isabs(val): |
113 dist_name, dist_version, dist_id = \ | 114 dist_name, dist_version, dist_id = \ |
114 platform.linux_distribution(full_distribution_name=False) | 115 platform.linux_distribution(full_distribution_name=False) |
115 if dist_name in ['debian', 'Ubuntu']: | 116 if dist_name in ['debian', 'Ubuntu']: |
116 # Debian uses dist-packages instead of site-packages for Python | 117 # Debian uses dist-packages instead of site-packages for Python |
117 # versions > 2.5. | 118 # versions > 2.5. |
118 PY_LIB_DIR_DEFAULT = '$EXEC_PREFIX/lib/python$PY_VERSION_SHORT/' \ | 119 PY_PACKAGES_DIR_DEFAULT = '$EXEC_PREFIX/lib/python$PY_VERSION_SHORT/' \ |
119 'dist-packages' | 120 'dist-packages' |
120 else: | 121 else: |
121 PY_LIB_DIR_DEFAULT = '$EXEC_PREFIX/lib/python$PY_VERSION_SHORT/' \ | 122 PY_PACKAGES_DIR_DEFAULT = '$EXEC_PREFIX/lib/python$PY_VERSION_SHORT/' \ |
122 'site-packages' | 123 'site-packages' |
124 PY_HEADERS_DIR_DEFAULT = '/usr/include/python$PY_VERSION_SHORT' | |
125 PY_LIB_DIR_DEFAULT = '/usr/lib' | |
126 PY_LIB_NAME = 'python$PY_VERSION_SHORT' | |
123 elif platform_name == 'Windows': | 127 elif platform_name == 'Windows': |
124 try: | 128 try: |
125 PREFIX_DEFAULT = os.environ['ProgramFiles'] + r'\$PROGRAM_NAME' | 129 PREFIX_DEFAULT = os.environ['PROGRAMFILES'] + r'\$PROGRAM_NAME' |
126 except KeyError: | 130 except KeyError: |
127 PREFIX_DEFAULT = '' | 131 PREFIX_DEFAULT = '' |
128 error_message = '%ProgramFiles% environmental variable is not ' \ | 132 error_message = '%PROGRAMFILES% environmental variable is not ' \ |
129 'set, unable to determine path to Program Files ' \ | 133 'set, unable to determine path to Program Files ' \ |
130 'folder (use --prefix to override)' | 134 'folder' |
131 raise SConfWarning(error_message) | 135 raise SConfWarning(error_message) |
132 BIN_DIR_DEFAULT = '$EXEC_PREFIX' | 136 BIN_DIR_DEFAULT = '$EXEC_PREFIX' |
133 DATA_ROOT_DIR_DEFAULT = '$PREFIX/data' | 137 DATA_ROOT_DIR_DEFAULT = '$PREFIX/data' |
134 SYS_CONF_DIR_DEFAULT = '$PREFIX/config' | 138 SYS_CONF_DIR_DEFAULT = '$PREFIX/config' |
135 INCLUDE_DIR_DEFAULT = '$PREFIX/include' | 139 INCLUDE_DIR_DEFAULT = '$PREFIX/include' |
136 DOC_DIR_DEFAULT = '$PREFIX/doc/' | 140 DOC_DIR_DEFAULT = '$PREFIX/doc/' |
137 LIB_DIR_DEFAULT = '$EXEC_PREFIX/lib' | 141 LIB_DIR_DEFAULT = '$EXEC_PREFIX/lib' |
138 PY_LIB_DIR_DEFAULT = '$EXEC_PREFIX/lib' | 142 PY_LIB_DIR_DEFAULT = '$EXEC_PREFIX/lib' |
143 # FIXME M. George Hansen 2011-05-12: Does sys.prefix include the | |
144 # PythonX.Y part on Windows? | |
145 python_prefix = sys.prefix | |
139 if GetOption('stand_alone'): | 146 if GetOption('stand_alone'): |
140 PY_LIB_DIR_DEFAULT = '$PREFIX/lib' | 147 PY_PACKAGES_DIR_DEFAULT = '$PREFIX/lib' |
141 else: | 148 else: |
142 python_prefix = sys.prefix | 149 PY_PACKAGES_DIR_DEFAULT = \ |
143 # FIXME M. George Hansen 2011-05-12: Does sys.prefix include the | |
144 # PythonX.Y part on Windows? | |
145 PY_LIB_DIR_DEFAULT = \ | |
146 os.path.join(python_prefix, 'Lib', 'site-packages') | 150 os.path.join(python_prefix, 'Lib', 'site-packages') |
151 PY_HEADERS_DIR_DEFAULT = os.path.join(python_prefix, 'include') | |
152 try: | |
153 PY_LIB_DIR_DEFAULT = os.environ['SYSTEMROOT'] | |
154 except KeyError: | |
155 PY_LIB_DIR_DEFAULT = '' | |
156 error_message = '%SYSTEMROOT% environmental variable is not set, ' \ | |
157 'unable to determine path to Windows system folder' | |
158 raise SConfWarning(error_message) | |
159 PY_LIB_NAME = 'python$PY_VERSION_MAJOR$PY_VERSION_MINOR' | |
147 | 160 |
148 # Platform-independant variables: | 161 # Platform-independant variables: |
149 variables.AddVariables( | 162 variables.AddVariables( |
150 PathVariable( | 163 PathVariable( |
151 'PREFIX', | 164 'PREFIX', |
206 'files should be installed', | 219 'files should be installed', |
207 LIB_DIR_DEFAULT, | 220 LIB_DIR_DEFAULT, |
208 is_abs_path, | 221 is_abs_path, |
209 ), | 222 ), |
210 PathVariable( | 223 PathVariable( |
211 'PY_LIB_DIR', | 224 'PY_PACKAGES_DIR', |
212 'directory where pure Python modules and packages should be installed', | 225 'directory where pure Python modules and packages should be installed', |
213 PY_LIB_DIR_DEFAULT, | 226 PY_PACKAGES_DIR_DEFAULT, |
214 is_abs_path, | 227 is_abs_path, |
215 ), | 228 ), |
216 PathVariable( | 229 PathVariable( |
217 'INCLUDE_DIR', | 230 'INCLUDE_DIR', |
218 'directory where C/C++ header files should be installed', | 231 'directory where C/C++ header files should be installed', |
219 INCLUDE_DIR_DEFAULT, | 232 INCLUDE_DIR_DEFAULT, |
220 is_abs_path, | 233 is_abs_path, |
221 ), | 234 ), |
235 PathVariable( | |
236 'PY_HEADERS_DIR', | |
237 'directory where Python.h can be found', | |
238 PY_HEADERS_DIR_DEFAULT, | |
239 ), | |
240 PathVariable( | |
241 'PY_LIB_DIR', | |
242 'directory where the Python shared library can be found', | |
243 PY_LIB_DIR_DEFAULT, | |
244 ), | |
245 BoolVariable( | |
246 'DEBUG', | |
247 'if True, compile the program launcher executable with debugging ' | |
248 'symbols', | |
249 False, | |
250 ), | |
222 ) | 251 ) |
223 | 252 |
224 platform_name = platform.system() | 253 platform_name = platform.system() |
225 python_version_tuple = platform.python_version_tuple() | 254 python_version_tuple = platform.python_version_tuple() |
226 | 255 |
227 environment = Environment( | 256 environment = Environment( |
228 tools=['default', 'textfile', 'packaging'], | 257 tools=['default', 'cc', 'textfile', 'packaging'], |
229 variables=variables, | 258 variables=variables, |
230 PROJECT_NAME='parpg', | 259 PROJECT_NAME='parpg', |
231 PROJECT_VERSION_MAJOR=0, | 260 PROJECT_VERSION_MAJOR=0, |
232 PROJECT_VERSION_MINOR=2, | 261 PROJECT_VERSION_MINOR=2, |
233 PROJECT_VERSION_PATCH=0, | 262 PROJECT_VERSION_PATCH=0, |
234 PROJECT_VERSION_SHORT='$PROJECT_VERSION_MAJOR.$PROJECT_VERSION_MAJOR', | 263 PROJECT_VERSION_SHORT='${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MAJOR}', |
235 PROJECT_VERSION_LONG='$PROJECT_VERSION_MAJOR.$PROJECT_VERSION_MINOR.' | 264 PROJECT_VERSION_LONG='${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.' |
236 '$PROJECT_VERSION_PATCH', | 265 '${PROJECT_VERSION_PATCH}', |
237 PYTHON=sys.executable, | 266 PYTHON=sys.executable, |
238 PY_VERSION_SHORT='.'.join(python_version_tuple[:-1]), | 267 PY_VERSION_MAJOR=python_version_tuple[0], |
239 PY_VERSION_LONG='.'.join(python_version_tuple), | 268 PY_VERSION_MINOR=python_version_tuple[1], |
269 PY_VERSION_PATCH=python_version_tuple[2], | |
270 PY_VERSION_SHORT='${PY_VERSION_MAJOR}.${PY_VERSION_MINOR}', | |
271 PY_VERSION_LONG='${PY_VERSION_MAJOR}.${PY_VERSION_MINOR}.' | |
272 '${PY_VERSION_PATCH}', | |
273 PY_LIB_NAME=PY_LIB_NAME, | |
240 PY_PACKAGES=[], | 274 PY_PACKAGES=[], |
241 CONFIG_FILES=[], | 275 CONFIG_FILES=[], |
242 DATA_FILES=[], | 276 DATA_FILES=[], |
243 EXECUTABLES=[], | 277 EXECUTABLES=[], |
244 ) | 278 ) |
279 if environment['DEBUG']: | |
280 environment.AppendUnique(CCFLAGS=['-gdwarf-2', '-g3']) | |
281 | |
245 Help(variables.GenerateHelpText(environment)) | 282 Help(variables.GenerateHelpText(environment)) |
246 | 283 |
247 config_dict = [('@{0}@'.format(key), environment.Dictionary()[key]) for key in | 284 config_dict = [('@{0}@'.format(key), environment.Dictionary()[key]) for key in |
248 ('PREFIX', 'LIB_DIR', 'PY_LIB_DIR', 'BIN_DIR', 'SYS_CONF_DIR', | 285 ('PREFIX', 'LIB_DIR', 'PY_PACKAGES_DIR', 'BIN_DIR', |
249 'DATA_DIR', 'PYTHON')] | 286 'SYS_CONF_DIR', 'DATA_DIR', 'PYTHON')] |
250 | 287 |
251 environment['PY_PACKAGES'] += [ | 288 install_py_packages = environment.InstallPyPackages( |
252 Dir('src/parpg'), | 289 '$PY_PACKAGES_DIR', |
253 ] | 290 'src/parpg', |
254 config_file_template = File('system.cfg.in') | |
255 subst_config_file = environment.Substfile(config_file_template, | |
256 SUBST_DICT=config_dict) | |
257 environment['CONFIG_FILES'] += [subst_config_file] | |
258 environment['DATA_FILES'] += Glob('data/*') | |
259 # TODO M. George Hansen 2011-05-12: Implement windows executable. | |
260 executable_template = File('bin/unix/parpg.in') | |
261 subst_executable = environment.Substfile(executable_template, | |
262 SUBST_DICT=config_dict) | |
263 environment['EXECUTABLES'] += [subst_executable] | |
264 | |
265 sources = environment.InstallPyPackages( | |
266 '$PY_LIB_DIR', | |
267 environment['PY_PACKAGES'], | |
268 compile=GetOption('compile'), | 291 compile=GetOption('compile'), |
269 ) | 292 ) |
270 config_files = environment.InstallChmod( | 293 |
294 subst_config_file = environment.Substfile( | |
295 'system.cfg.in', | |
296 SUBST_DICT=config_dict | |
297 ) | |
298 install_config_files = environment.InstallChmod( | |
271 '$SYS_CONF_DIR', | 299 '$SYS_CONF_DIR', |
272 environment['CONFIG_FILES'], | 300 subst_config_file, |
273 mode=0755, | 301 mode=0755 |
274 ) | 302 ) |
275 Requires(config_files, subst_config_file) | 303 Requires(install_config_files, subst_config_file) |
276 data_files = environment.InstallReadOnly( | 304 |
305 install_data = environment.InstallReadOnly( | |
277 '$DATA_DIR', | 306 '$DATA_DIR', |
278 environment['DATA_FILES'], | 307 Glob('data/*'), |
279 ) | 308 ) |
280 executables = environment.InstallExecutable( | 309 |
310 executable_source = environment.Substfile( | |
311 'bin/parpg.c.in', | |
312 SUBST_DICT=config_dict, | |
313 ) | |
314 build_executable = environment.Program( | |
315 executable_source, | |
316 LIBS=['$PY_LIB_NAME'], | |
317 LIBPATH='$PY_LIB_DIR', | |
318 CPPPATH=['$PY_HEADERS_DIR'], | |
319 ) | |
320 # FIXME M. George Hansen 2011-05-17: Should the executable target be hard-coded | |
321 # like this? | |
322 install_executable = environment.InstallExecutable( | |
281 '$BIN_DIR', | 323 '$BIN_DIR', |
282 environment['EXECUTABLES'], | 324 'bin/parpg', |
283 ) | 325 ) |
284 Requires(executables, subst_executable) | |
285 | 326 |
286 # TODO M. George Hansen 2011-05-12: Implement package builder. | 327 # TODO M. George Hansen 2011-05-12: Implement package builder. |
287 #package = environment.Package( | 328 #package = environment.Package( |
288 # NAME='parpg', | 329 # NAME='parpg', |
289 # VERSION='0.2.0', | 330 # VERSION='0.2.0', |
292 # SUMMARY='', | 333 # SUMMARY='', |
293 # DESCRIPTION='', | 334 # DESCRIPTION='', |
294 # X_RPM_GROUP='Application/parpg', | 335 # X_RPM_GROUP='Application/parpg', |
295 #) | 336 #) |
296 | 337 |
297 Default([sources, config_files, data_files, executables]) | 338 build = Alias('build', [build_executable]) |
298 Alias('install', [sources, config_files, data_files, executables]) | 339 install = Alias('install', [build, install_executable, install_py_packages, |
340 install_config_files, install_data]) | |
341 | |
342 Default(install) |