BuildScripts.py :  » XML » 4Suite » 4Suite-XML-1.0.2 » Ft » Lib » DistExt » Python Open Source

Home
Python Open Source
1.3.1.2 Python
2.Ajax
3.Aspect Oriented
4.Blog
5.Build
6.Business Application
7.Chart Report
8.Content Management Systems
9.Cryptographic
10.Database
11.Development
12.Editor
13.Email
14.ERP
15.Game 2D 3D
16.GIS
17.GUI
18.IDE
19.Installer
20.IRC
21.Issue Tracker
22.Language Interface
23.Log
24.Math
25.Media Sound Audio
26.Mobile
27.Network
28.Parser
29.PDF
30.Project Management
31.RSS
32.Search
33.Security
34.Template Engines
35.Test
36.UML
37.USB Serial
38.Web Frameworks
39.Web Server
40.Web Services
41.Web Unit
42.Wiki
43.Windows
44.XML
Python Open Source » XML » 4Suite 
4Suite » 4Suite XML 1.0.2 » Ft » Lib » DistExt » BuildScripts.py
import os
import sys
import time
from distutils import spawn,sysconfig,util
from distutils.ccompiler import new_compiler,show_compilers
from distutils.core import Command
from distutils.dep_util import newer_group

from Ft.Lib import ImportUtil
from Ft.Lib.DistExt import Util,ImageHlp
from Ft.Lib.DistExt.Structures import Script,Executable

SHELL_SCRIPT_BODY = """#!%(executable)s
# %(name)s script generated by %(command)s on %(timestamp)s.
# DO NOT EDIT THIS FILE!

import %(module)s
status = %(module)s.%(function)s()
raise SystemExit(status)
"""

class ScriptInfo(ImageHlp.Struct):
    """
    Representation of the SCRIPT_INFO resource in the stub executable.
    """
    __fields__ = [
        (ImageHlp.Dword, 'Signature'),
        (ImageHlp.Word, 'MajorPythonVersion'),
        (ImageHlp.Word, 'MinorPythonVersion'),
        (ImageHlp.Word, 'Subsystem'),
        (ImageHlp.Word, 'Characteristics'),
        (ImageHlp.Word, 'ScriptAddress'),
        (ImageHlp.Word, 'ScriptSize'),
        ]

class BuildScripts(Command):

    command_name = 'build_scripts'

    description = "\"build\" scripts"

    user_options = [
        ('build-dir=', 'd', "directory to \"build\" (copy) to"),
        ('build-temp=', 't',
         "directory for temporary files (build by-products)"),
        ('force', 'f', "forcibly build everything (ignore file timestamps"),
        ('debug', 'g', "compile/link with debugging information"),
        ('compiler=', 'c', "specify the compiler type"),
        ]

    help_options = [
        ('help-compiler', None,
         "list available compilers", show_compilers),
        ]

    boolean_options = ['force', 'debug']

    def initialize_options(self):
        self.build_dir = None
        self.build_temp = None
        self.force = None
        self.debug = None
        self.compiler = None
        return

    def finalize_options(self):
        undefined_temp = self.build_temp is None
        self.set_undefined_options('build',
                                   ('build_scripts', 'build_dir'),
                                   ('build_temp', 'build_temp'),
                                   ('compiler', 'compiler'),
                                   ('debug', 'debug'),
                                   ('force', 'force'))
        if undefined_temp:
            self.build_temp = os.path.join(self.build_temp, 'scripts')

        self.scripts = self.distribution.scripts or []

        # Get the linker arguments for building executables
        if os.name == 'posix':
            args = sysconfig.get_config_vars('LDFLAGS', 'LINKFORSHARED')
            self.link_preargs = ' '.join(args).split()

            args = sysconfig.get_config_vars('LIBS', 'MODLIBS', 'SYSLIBS',
                                             'LDLAST')
            self.link_postargs = ' '.join(args).split()
        else:
            self.link_preargs = []
            self.link_postargs = []

        # Get the extension for executables
        self.exe_extension = sysconfig.get_config_var('EXE') or ''
        if self.debug and os.name == 'nt':
            self.exe_extension = '_d' + self.exe_extension
        return

    def run(self):
        """
        Create the proper script for the current platform.
        """
        if not self.scripts:
            return

        # Ensure the destination directory exists.
        self.mkpath(self.build_dir)

        # Build the "plain" (pure-Python) scripts.
        self.build_scripts([ script for script in self.scripts
                             if isinstance(script, Script) ])

        # Build the executable (compiled) scripts.
        self.build_executables([ script for script in self.scripts
                                 if isinstance(script, Executable) ])
        return

    # -- worker functions ---------------------------------------------

    def build_scripts(self, scripts):
        for script in scripts:
            self.build_script(script)
        return

    def build_script(self, script):
        """
        Builds a CommandLineApp script.
        On POSIX systems, this is a generated shell script.  For Windows,
        it is a compiled executable with the generated file appended to the
        end of the stub.
        """
        # Get the destination filename
        outfile = self.get_script_filename(script)

        # Determine if the script needs to be built
        command_mtime = ImportUtil.GetLastModified(__name__)
        if os.name == 'nt':
            stub_mtime = ImportUtil.GetResourceLastModified(__name__,
                                                            'stubmain.exe')
            command_mtime = max(command_mtime, stub_mtime)
        try:
            target_mtime = os.stat(outfile).st_mtime
        except OSError:
            target_mtime = -1
        if not (self.force or command_mtime > target_mtime):
            self.announce("skipping '%s' script (up-to-date)" % script.name)
            return
        else:
            self.announce("building '%s' script" % (script.name), 2)

        repl = {'executable' : self.get_python_executable(),
                'command' : self.get_command_name(),
                'timestamp' : time.asctime(),
                'toplevel' : script.module.split('.', 1)[0],
                }
        repl.update(vars(script))
        script_body = SHELL_SCRIPT_BODY % repl

        if self.dry_run:
            # Don't actually create the script
            pass
        elif os.name == 'nt':
            # Populate the ScriptInfo structure
            script_info = ScriptInfo()
            script_info.Signature = 0x00005446  # "FT\0\0"
            script_info.MajorPythonVersion = sys.version_info[0]
            script_info.MinorPythonVersion = sys.version_info[1]
            script_info.Subsystem = 0x0003;     # CUI
            if self.debug:
                script_info.Characteristics |= 0x0001
            stub_bytes = ImportUtil.GetResourceString(__name__, 'stubmain.exe')
            script_info.ScriptAddress = len(stub_bytes)
            script_info.ScriptSize = len(script_body)

            # Write the script executable
            f = open(outfile, 'w+b')
            try:
                f.write(stub_bytes)
                f.write(script_body)
                ImageHlp.UpdateResource(f, ImageHlp.RT_RCDATA, 1, script_info)
                ImageHlp.SetSubsystem(f, ImageHlp.IMAGE_SUBSYSTEM_WINDOWS_CUI)
            finally:
                f.close()
        else:
            # Create the file with execute permissions set
            fd = os.open(outfile, os.O_WRONLY|os.O_CREAT|os.O_TRUNC, 0755)
            try:
                os.write(fd, script_body)
            finally:
                os.close(fd)
        return

    def build_executables(self, executables):
        if not executables:
            return

        # Create the compiler for compiling the executables.
        self._prep_compiler()

        for executable in executables:
            self.build_executable(executable)
        return

    def build_executable(self, executable):
        """
        Builds a compiled executable.
        For all systems, the executable is created in the same fashion as
        the Python interpreter executable.
        """
        outfile = self.get_script_filename(executable)

        all_sources = self._prep_build(script)
        sources = []
        for source, includes in all_sources:
            sources.append(source)
            sources.extend(includes)

        if not (self.force or newer_group(sources, outfile, 'newer')):
            self.announce("skipping '%s' executable (up-to-date)" %
                          executable.name)
            return
        else:
            self.announce("building '%s' executable" % executable.name)

        output_dir = os.path.join(self.build_temp, executable.name)

        macros = executable.define_macros[:]
        for undef in executable.undef_macros:
            macros.append((undef,))

        objects = []
        for source, includes in all_sources:
            if not self.force:
                # Recompile if the includes or source are newer than the
                # resulting object files.
                objs = self.compiler.object_filenames([source], 1, output_dir)

                # Recompile if any of the inputs are newer than the object
                inputs = [source] + includes
                force = 0
                for filename in objs:
                    force = force or newer_group(inputs, filename, 'newer')
                self.compiler.force = force

            objs = self.compiler.compile(
                [source],
                output_dir=output_dir,
                macros=macros,
                include_dirs=executable.include_dirs,
                debug=self.debug,
                extra_postargs=executable.extra_compile_args)
            objects.extend(objs)

        # Reset the force flag on the compiler
        self.compiler.force = self.force

        # Now link the object files together into a "shared object" --
        # of course, first we have to figure out all the other things
        # that go into the mix.
        if os.name == 'nt' and self.debug:
            executable = executable.name + '_d'
        else:
            executable = executable.name

        if executable.extra_objects:
            objects.extend(executable.extra_objects)

        # On Windows, non-MSVC compilers need some help finding python
        # libs. This logic comes from distutils/command/build_ext.py.
        libraries = executable.libraries
        if sys.platform == "win32":
            from distutils.msvccompiler import MSVCCompiler
            if not isinstance(self.compiler, MSVCCompiler):
                template = "python%d%d"
                if self.debug:
                    template = template + "_d"
                pythonlib = (template % ((sys.hexversion >> 24),
                                         (sys.hexversion >> 16) & 0xff))
                libraries += [pythonlib]

        self.compiler.link_executable(
            objects, executable,
            libraries=libraries,
            library_dirs=executable.library_dirs,
            runtime_library_dirs=executable.runtime_library_dirs,
            extra_preargs=self.link_preargs,
            extra_postargs=self.link_postargs + executable.extra_link_args,
            debug=self.debug,
            build_temp=self.build_temp)
        return

    # -- utility functions --------------------------------------------

    def get_python_executable(self):
        if os.name == 'nt':
            executable = sys.executable
        else:
            executable = spawn.find_executable('env')
            if executable is None:
                # No 'env' executable found; use the interpreter directly
                executable = sys.executable
            else:
                # Use the python found runtime (via env)
                executable += ' python'
        return executable

    def get_script_filename(self, script):
        """
        Convert the name of a script into the name of the file which it
        will be run from.
        """
        # All Windows scripts are executables
        if os.name == 'nt' or isinstance(script, Executable):
            script_name = script.name + self.exe_extension
        else:
            script_name = script.name
        return os.path.join(self.build_dir, script_name)

    # -- helper functions ---------------------------------------------

    def _prep_compiler(self):
        # Setup the CCompiler object that we'll use to do all the
        # compiling and linking
        self.compiler = new_compiler(compiler=self.compiler,
                                     verbose=self.verbose,
                                     dry_run=self.dry_run,
                                     force=self.force)
        sysconfig.customize_compiler(self.compiler)

        # If we were asked to build any C/C++ libraries, make sure that the
        # directory where we put them is in the library search path for
        # linking executables.
        if self.distribution.has_c_libraries():
            build_clib = self.get_finalized_command('build_clib')
            self.compiler.set_libraries(build_clib.get_library_names())
            self.compiler.add_library_dir(build_clib.build_clib)

        # Make sure Python's include directories (for Python.h, pyconfig.h,
        # etc.) are in the include search path.
        py_include = sysconfig.get_python_inc()
        plat_py_include = sysconfig.get_python_inc(plat_specific=1)
        self.compiler.add_include_dir(py_include)
        if plat_py_include != py_include:
            include_dirs.append(plat_py_include)

        if os.name == 'posix':
            # Add the Python archive library
            ldlibrary = sysconfig.get_config_var('BLDLIBRARY')
            # MacOSX with frameworks doesn't link against a library
            if ldlibrary:
                # Get the location of the library file
                for d in sysconfig.get_config_vars('LIBDIR', 'LIBP', 'LIBPL'):
                    library = os.path.join(d, ldlibrary)
                    if os.path.exists(library):
                        self.compiler.add_link_object(library)
                        break
        elif os.name == 'nt':
            # Add Python's library directory
            lib_dir = os.path.join(sys.exec_prefix, 'libs')
            self.compiler.add_library_dir(lib_dir)
        return

    def _prep_build(self, script):
        # This should really exist in the CCompiler class, but
        # that would required overriding all compilers.
        result = []
        for source in script.sources:
            source = util.convert_path(source)
            includes = Util.FindIncludes(source, script.include_dirs)
            result.append((source, includes))
        return result

    # -- external interfaces ------------------------------------------

    def get_outputs(self):
        return [ self.get_script_filename(script) for script in self.scripts ]

    def get_source_files(self):
        filenames = []
        for script in self.scripts:
            if isinstance(script, Executable):
                for source, includes in self._prep_build(script):
                    filenames.append(source)
                    filenames.extend(includes)
        return filenames
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.