Mercurial > parpg-core
view SConstruct @ 17:15107282d9eb
Redefined SYSCONFDIR installation path variable so that it appends APPNAME.
* Although this deviates from GNU standards this relatively minor change makes it easier to write paths that are portable to Windows.
author | M. George Hansen <technopolitica@gmail.com> |
---|---|
date | Thu, 09 Jun 2011 21:40:51 -1000 |
parents | d60f1dab8469 |
children | de378945b839 |
line wrap: on
line source
import sys import os import platform import compileall import fnmatch from copy import copy from collections import Sequence from types import StringType from multiprocessing import cpu_count from SCons.Util import is_Sequence, is_Dict from SCons.Tool.install import copyFunc #def recursive_glob(topdir_path, include_pattern='*', exclude_pattern=''): # """ # Locate all files matching supplied filename pattern in and below # supplied root directory. # """ # for dir_path, subdir_names, file_names in \ # os.walk(os.path.abspath(topdir_path)): # for file_name in fnmatch.filter(file_names, include_pattern): # if not fnmatch.fnmatch(file_name, exclude_pattern): # file_path = os.path.join(dir_path, file_name) # yield File(file_path) # for subdir_name in copy(subdir_names): # if not fnmatch.fnmatch(subdir_name, include_pattern) or \ # fnmatch.fnmatch(subdir_name, exclude_pattern): # subdir_names.remove(subdir_name) # else: # subdir_path = os.path.join(dir_path, subdir_name) def InstallChmod(env, dest, source, mode): targets = env.Install(dest, source) for target in targets: env.AddPostAction(target, Chmod(target, mode)) return targets def InstallExecutable(env, dest, source): return env.InstallChmod(dest, source, mode=0755) def InstallReadOnly(env, dest, source): if not isinstance(source, Sequence): source = [source] targets = [] for entry in map(Entry, source): entry.disambiguate() if entry.isdir(): target = env.InstallChmod(dest, entry, mode=0755) elif entry.isfile(): target = env.InstallChmod(dest, entry, mode=0644) else: # Something really weird happened and entry is not a Dir or a # File... (Note: Yes this can happen!) error_message = \ 'expected entry to be a Dir or a File, but got {0!r}' raise ValueError(error_message.format(entry)) targets.append(target) return targets def SubstfileEscape(env, *args, **kwargs): subst_dict = kwargs.get('SUBST_DICT') or env.get('SUBST_DICT') escape_sequences = kwargs.get('ESCAPE_SEQUENCES') or env.get('ESCAPE_SEQUENCES') if subst_dict is not None and escape_sequences is not None: if not is_Dict(subst_dict) and is_Sequence(subst_dict): subst_dict = dict(subst_dict) else: error_message = 'SUBST_DICT must be dict or sequence' raise SCons.Errors.UserError(error_message) escaped_subst_dict = {} for key, value in subst_dict.items(): escaped_value = value for seq, escaped_seq in escape_sequences.items(): escaped_value = escaped_value.replace(seq, escaped_seq) escaped_subst_dict[key] = escaped_value kwargs['SUBST_DICT'] = escaped_subst_dict target = env.Substfile(*args, **kwargs) return target AddMethod(Environment, InstallChmod) AddMethod(Environment, InstallExecutable) AddMethod(Environment, InstallReadOnly) AddMethod(Environment, SubstfileEscape) EnsurePythonVersion(2, 6) AddOption( '--stand-alone', dest='stand_alone', action='store_true', default=False, help='install the entire program under installation prefix instead of in ' 'various system folders' ) AddOption( '--no-compile', dest='compile', action='store_false', default=True, help='don\'t compile any Python modules into .pyc files before installing', ) SetOption('num_jobs', cpu_count()) def is_abs_path(key, val, env): if not os.path.isabs(val): error_message = '${key} must be an absolute path' raise ValueError(error_message.format(key=key)) env[key] = os.path.normpath(val) variables = Variables() # NOTE M. George Hansen 2011-05-13: Path variables are based on the GNU # standards as defined at http://www.gnu.org/prep/standards/html_node/Directory-Variables.html # Platform-specific variable defaults. # FIXME M. George Hansen 2011-05-12: Define the MacOS-specific # environmental variables (and check version...) platform_name = platform.system() if platform_name in ['Linux', 'MacOS']: if GetOption('stand_alone'): PREFIX_DEFAULT = '/opt' else: PREFIX_DEFAULT = '/usr/local' BIN_DIR_DEFAULT = '$EXEC_PREFIX/bin' DATA_ROOT_DIR_DEFAULT = '$PREFIX/share/$PROJECT_NAME' SYS_CONF_DIR_DEFAULT = '$PREFIX/etc/$PROJECT_NAME' INCLUDE_DIR_DEFAULT = '$PREFIX/include/$PROJECT_NAME' DOC_DIR_DEFAULT = '$DATA_ROOT_DIR/doc/$PROJECT_NAME' LIB_DIR_DEFAULT = '$EXEC_PREFIX/lib' dist_name, dist_version, dist_id = \ platform.linux_distribution(full_distribution_name=False) if dist_name in ['debian', 'Ubuntu']: # Debian uses dist-packages instead of site-packages for Python # versions > 2.5. PY_PACKAGES_DIR_DEFAULT = '$EXEC_PREFIX/lib/python$PY_VERSION_SHORT/' \ 'dist-packages' else: PY_PACKAGES_DIR_DEFAULT = '$EXEC_PREFIX/lib/python$PY_VERSION_SHORT/' \ 'site-packages' PY_HEADERS_DIR_DEFAULT = '/usr/include/python$PY_VERSION_SHORT' PY_LIB_DIR_DEFAULT = '/usr/lib' PY_LIB_NAME = 'python$PY_VERSION_SHORT' elif platform_name == 'Windows': try: PREFIX_DEFAULT = os.environ['PROGRAMFILES'] + r'\$PROGRAM_NAME' except KeyError: PREFIX_DEFAULT = '' error_message = '%PROGRAMFILES% environmental variable is not ' \ 'set, unable to determine path to Program Files ' \ 'folder' raise SConfWarning(error_message) BIN_DIR_DEFAULT = '$EXEC_PREFIX' DATA_ROOT_DIR_DEFAULT = '$PREFIX/data' SYS_CONF_DIR_DEFAULT = '$PREFIX/config' INCLUDE_DIR_DEFAULT = '$PREFIX/include' DOC_DIR_DEFAULT = '$PREFIX/doc/' LIB_DIR_DEFAULT = '$EXEC_PREFIX/lib' # FIXME M. George Hansen 2011-05-12: Does sys.prefix include the # PythonX.Y part on Windows? python_prefix = sys.prefix if GetOption('stand_alone'): PY_PACKAGES_DIR_DEFAULT = '$PREFIX/lib' else: PY_PACKAGES_DIR_DEFAULT = \ os.path.join(python_prefix, 'Lib', 'site-packages') PY_HEADERS_DIR_DEFAULT = os.path.join(python_prefix, 'include') PY_LIB_DIR_DEFAULT = os.path.join(python_prefix, 'libs') PY_LIB_NAME = 'python$PY_VERSION_MAJOR$PY_VERSION_MINOR' # Platform-independant variables: variables.AddVariables( PathVariable( 'PREFIX', 'directory under which most or all of the program components should ' 'be installed', PREFIX_DEFAULT, is_abs_path, ), PathVariable( 'EXEC_PREFIX', 'directory under which machine-specific compiled libraries and ' 'objects should be installed', '$PREFIX', is_abs_path, ), PathVariable( 'BIN_DIR', 'directory where program executables should be installed', BIN_DIR_DEFAULT, is_abs_path, ), PathVariable( 'DATA_ROOT_DIR', 'directory under which read-only, architecture-independant data files ' 'should be installed', DATA_ROOT_DIR_DEFAULT, is_abs_path, ), PathVariable( 'DATA_DIR', 'directory where read-only, architecture-independant data files ' 'should be installed', '$DATA_ROOT_DIR', is_abs_path, ), PathVariable( 'SYS_CONF_DIR', 'directory where read-only, machine-specific data files should be ' 'installed', SYS_CONF_DIR_DEFAULT, is_abs_path, ), PathVariable( 'INCLUDE_DIR', 'directory where C/C++ header files should be installed', INCLUDE_DIR_DEFAULT, is_abs_path, ), PathVariable( 'DOC_DIR', 'directory where program documentation should be installed', DOC_DIR_DEFAULT, is_abs_path, ), PathVariable( 'LIB_DIR', 'directory where platform-dependant, compiled library and object ' 'files should be installed', LIB_DIR_DEFAULT, is_abs_path, ), PathVariable( 'PY_PACKAGES_DIR', 'directory where pure Python modules and packages should be installed', PY_PACKAGES_DIR_DEFAULT, is_abs_path, ), PathVariable( 'PY_HEADERS_DIR', 'directory where Python.h can be found', PY_HEADERS_DIR_DEFAULT, ), PathVariable( 'PY_LIB_DIR', 'directory where the Python shared library can be found', PY_LIB_DIR_DEFAULT, ), BoolVariable( 'DEBUG', 'if True, compile the program launcher executable with debugging ' 'symbols', False, ), ) python_version_tuple = platform.python_version_tuple() environment = Environment( tools=['default', 'cpython', 'textfile', 'packaging'], variables=variables, PROJECT_NAME='parpg', PROJECT_VERSION_MAJOR=0, PROJECT_VERSION_MINOR=2, PROJECT_VERSION_PATCH=0, PROJECT_VERSION_SHORT='${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MAJOR}', PROJECT_VERSION_LONG='${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.' '${PROJECT_VERSION_PATCH}', PYTHON=sys.executable, PY_VERSION_MAJOR=python_version_tuple[0], PY_VERSION_MINOR=python_version_tuple[1], PY_VERSION_PATCH=python_version_tuple[2], PY_VERSION_SHORT='${PY_VERSION_MAJOR}.${PY_VERSION_MINOR}', PY_VERSION_LONG='${PY_VERSION_MAJOR}.${PY_VERSION_MINOR}.' '${PY_VERSION_PATCH}', PY_LIB_NAME=PY_LIB_NAME, BUILD_DIR=Dir('build'), ) if environment['DEBUG']: if platform_name == 'Windows': environment['CCPDBFLAGS'] = '/Z7 /Od' environment.AppendUnique(LINKFLAGS='/DEBUG') else: environment.AppendUnique(CCFLAGS=['-gdwarf-2', '-g3']) Help(variables.GenerateHelpText(environment)) local_config_dict = { '@PREFIX@': '${BUILD_DIR.abspath}', '@LIB_DIR@': '${BUILD_DIR.abspath}', '@PY_PACKAGES_DIR@': '${BUILD_DIR.abspath}', '@BIN_DIR@': '${BUILD_DIR.abspath}', '@SYS_CONF_DIR@': '${BUILD_DIR.abspath}', '@DATA_DIR@': '${BUILD_DIR.abspath}/data', '@PYTHON@': '$PYTHON', } system_config_dict = [('@{0}@'.format(key), environment.Dictionary()[key]) for key in ('PREFIX', 'LIB_DIR', 'PY_PACKAGES_DIR', 'BIN_DIR', 'SYS_CONF_DIR', 'DATA_DIR', 'PYTHON')] build_py_packages = environment.Install( '$BUILD_DIR', 'src/parpg', ) #build_py_packages = environment.InstallPython( # '$BUILD_DIR/parpg', # py_sources, # PYTHON_COMPILE=GetOption('compile'), #) py_packages = environment.InstallPython( '$PY_PACKAGES_DIR', build_py_packages, PYTHON_COMPILE=GetOption('compile'), ) data_subdirs = Glob('data/*') build_data = environment.Install( '$BUILD_DIR/data', data_subdirs, ) # FIXME M. George Hansen 2011-06-05: Chmod should make dirs 0755 and files # 0644. #environment.AddPostAction(build_data, Chmod(build_data, 0755)) data = environment.Install( '$DATA_DIR', build_data, ) build_config_file = environment.Substfile( '$BUILD_DIR/parpg.cfg', 'parpg.cfg.in', SUBST_DICT=local_config_dict, ) environment.AddPostAction(build_config_file, Chmod(build_config_file, 0644)) config_file = environment.Substfile( '$SYS_CONF_DIR/parpg.cfg', 'parpg.cfg.in', SUBST_DICT=system_config_dict, ) environment.AddPostAction(config_file, Chmod(config_file, 0644)) if platform_name == 'Windows': launcher_source = 'parpg.bat' launcher_name = 'parpg.bat' else: launcher_source = 'parpg.sh' launcher_name = 'parpg' # FIXME M. George Hansen 2011-05-20: Do any other sequences need to be escaped? build_launcher = environment.SubstfileEscape( '$BUILD_DIR/$LAUNCHER_SOURCE', 'bin/${LAUNCHER_SOURCE}.in', LAUNCHER_SOURCE=launcher_source, LAUNCHER_NAME=launcher_name, SUBST_DICT=system_config_dict, ESCAPE_SEQUENCES={'\\': r'\\\\', '"': r'\\"'}, ) environment.AddPostAction(build_launcher, Chmod(build_launcher, 0755)) launcher = environment.InstallAs( '$BIN_DIR/$LAUNCHER_NAME', build_launcher, ) # TODO M. George Hansen 2011-05-12: Implement package builder. #package = environment.Package( # NAME='parpg', # VERSION='0.2.0', # PACKAGEVERSION=0, # LICENSE='gpl', # SUMMARY='', # DESCRIPTION='', # X_RPM_GROUP='Application/parpg', #) build = Alias( 'build', [build_launcher, build_config_file, build_py_packages, build_data], ) install = Alias( 'install', [build, launcher, config_file, py_packages, data], ) Default(build)