diff SConstruct @ 11:4706e0194af3

Various improvements to the build process including support for self-contained builds. * Note that despite all of these changes PARPG still does not run because asset paths are not standardized, * Modified the SCons script so that by default running `scons` with no arguments creates a self-contained "build" under a build subdirectory to make in-source testing easier. To install PARPG, use `scons install` instead. * Got rid of the binary launcher and replaced it with a shell script for unix and a batch script for Windows (batch script is untested). The binary turned out to be too much trouble to maintain. * Modified the parpg.settings module and parpg.main entry script so that PARPG searches through several default search paths for configuration file(s). PARPG thus no longer crashes if it can't find a configuration file in any particular search path, but will crash it if can't find any configuration files. * Paths supplied to parpg.main are now appended as search paths for the configuration file(s). * Changed the default configuration file name to "parpg.cfg" to simplify searches. * Created the site_scons directory tree where SCons extensions and tools should be placed. * Created a new SCons builder, CopyRecurse, which can copy only certain files and folders from a directory tree using filters (files and folders that start with a leading dot "." e.g. ".svn" are ignored by default). * Added the CPython SCons tool (stands for Compile-Python - I didn't name it!), which provides the InstallPython builder for pre-compiling python sources before they are installed. However, it is currently broken and only installs the python sources.
author M. George Hansen <technopolitica@gmail.com>
date Tue, 31 May 2011 02:46:20 -0700
parents dd4ed4945411
children d60f1dab8469
line wrap: on
line diff
--- a/SConstruct	Wed Jun 01 00:45:27 2011 -0700
+++ b/SConstruct	Tue May 31 02:46:20 2011 -0700
@@ -3,11 +3,31 @@
 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)
@@ -37,33 +57,6 @@
         targets.append(target)
     return targets
 
-def InstallPyPackages(env, dest, source, compile=True):
-    # Remove all existing *.pyc and *.pyo files for a sanitary install
-    # environment.
-    def _remove_compiled_modules(path):
-        for dir_path, dir_names, file_names in os.walk(path):
-            for file_name in fnmatch.filter(file_names, '*.py[co]'):
-                file_path = os.path.join(dir_path, file_name)
-                os.remove(file_path)
-    
-    def _add_targets(path):
-         for dir_path, dir_names, file_names in os.walk(path):
-            for file_name in fnmatch.filter(file_names, '*.py[co]'):
-                file_path = os.path.join(dir_path, file_name)
-                env.Clean(path, file_path)
-                source_file_path = file_path.rstrip('oc')
-                env.Depends(file_path, source_file_path)
-
-    if not isinstance(source, Sequence) or isinstance(source, StringType):
-        source = [source]
-    for dir in source:
-        _remove_compiled_modules(str(dir))
-        if compile:
-            compileall.compile_dir(str(dir), ddir=str(dest), force=True)
-            _add_targets(str(dir))
-    targets = env.InstallReadOnly(dest, source)
-    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')
@@ -87,7 +80,6 @@
 AddMethod(Environment, InstallChmod)
 AddMethod(Environment, InstallExecutable)
 AddMethod(Environment, InstallReadOnly)
-AddMethod(Environment, InstallPyPackages)
 AddMethod(Environment, SubstfileEscape)
 
 EnsurePythonVersion(2, 6)
@@ -269,7 +261,7 @@
 python_version_tuple = platform.python_version_tuple()
 
 environment = Environment(
-    tools=['default', 'textfile', 'packaging'],
+    tools=['default', 'cpython', 'copyrecurse', 'textfile', 'packaging'],
     variables=variables,
     PROJECT_NAME='parpg',
     PROJECT_VERSION_MAJOR=0,
@@ -286,10 +278,7 @@
     PY_VERSION_LONG='${PY_VERSION_MAJOR}.${PY_VERSION_MINOR}.'
                     '${PY_VERSION_PATCH}',
     PY_LIB_NAME=PY_LIB_NAME,
-    PY_PACKAGES=[],
-    CONFIG_FILES=[],
-    DATA_FILES=[],
-    EXECUTABLES=[],
+    BUILD_DIR='build',
 )
 if environment['DEBUG']:
     if platform_name == 'Windows':
@@ -304,49 +293,56 @@
                ('PREFIX', 'LIB_DIR', 'PY_PACKAGES_DIR', 'BIN_DIR',
                 'SYS_CONF_DIR', 'DATA_DIR', 'PYTHON')]
 
-install_py_packages = environment.InstallPyPackages(
+copy_py_packages = environment.Install(
+    '$BUILD_DIR',
+    'src/parpg',
+)
+install_py_packages = environment.InstallPython(
     '$PY_PACKAGES_DIR',
-    'src/parpg',
-    compile=GetOption('compile'),
+    copy_py_packages,
+    PYTHON_COMPILE=GetOption('compile'),
+)
+
+copy_data = environment.CopyRecurse(
+    '$BUILD_DIR',
+    'data',
 )
 
 subst_config_file = environment.Substfile(
-    'system.cfg.in',
-    SUBST_DICT=config_dict
+    '$BUILD_DIR/parpg.cfg',
+    'parpg.cfg.in',
+    SUBST_DICT=config_dict,
 )
 install_config_files = environment.InstallChmod(
     '$SYS_CONF_DIR',
     subst_config_file,
-    mode=0755
+    mode=0755,
 )
 Requires(install_config_files, subst_config_file)
 
-install_data = environment.InstallReadOnly(
-    '$DATA_DIR',
-    Glob('data/*'),
-)
-
-# FIXME M. George Hansen 2011-05-20: Do any other sequences need to be escaped
-#     in a C string?
-executable_source = environment.SubstfileEscape(
-    'bin/parpg.c.in',
+if platform_name == 'Windows':
+    launcher_name = 'parpg.bat'
+else:
+    launcher_name = 'parpg.sh'
+# FIXME M. George Hansen 2011-05-20: Do any other sequences need to be escaped?
+launcher = environment.SubstfileEscape(
+    'build/$LAUNCHER_NAME',
+    'bin/${LAUNCHER_NAME}.in',
+    LAUNCHER_NAME=launcher_name,
     SUBST_DICT=config_dict,
     ESCAPE_SEQUENCES={'\\': r'\\\\', '"': r'\\"'},
 )
-build_executable = environment.Program(
-    executable_source,
-    LIBS=['$PY_LIB_NAME'],
-    LIBPATH='$PY_LIB_DIR',
-    CPPPATH=['$PY_HEADERS_DIR'],
-)
-# Clean up any files created by the MSVC compiler on Windows.
 if platform_name == 'Windows':
-    environment.Clean(build_executable, 'bin/parpg.ilk')
-    environment.Clean(build_executable, 'bin/parpg.pdb')
-install_executable = environment.InstallExecutable(
-    '$BIN_DIR',
-    build_executable,
-)
+    install_launcher = environment.InstallExecutable(
+        '$BIN_DIR',
+        launcher,
+    )
+else:
+    # Remove the .sh suffix, since it isn't needed on unix platforms.
+    install_launcher = environment.InstallAs(
+        '$BIN_DIR/parpg',
+        launcher,
+    )
 
 # TODO M. George Hansen 2011-05-12: Implement package builder.
 #package = environment.Package(
@@ -359,8 +355,9 @@
 #    X_RPM_GROUP='Application/parpg',
 #)
 
-build = Alias('build', [build_executable])
-install = Alias('install', [build, install_executable, install_py_packages,
-                install_config_files, install_data])
+build = Alias('build', [launcher, subst_config_file, copy_py_packages,
+                        copy_data])
+install = Alias('install', [build, install_launcher, install_py_packages,
+                install_config_files])
 
-Default(install)
+Default(build)