git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/branches/WX_2_4_BRANCH@18755 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
		
			
				
	
	
		
			492 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			492 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
 | 
						|
import sys, os
 | 
						|
 | 
						|
from distutils.msvccompiler import MSVCCompiler
 | 
						|
from distutils.bcppcompiler import BCPPCompiler
 | 
						|
 | 
						|
from distutils.errors import \
 | 
						|
     DistutilsExecError, DistutilsPlatformError, \
 | 
						|
     CompileError, LibError, LinkError
 | 
						|
from distutils.ccompiler import \
 | 
						|
     CCompiler, gen_preprocess_options, gen_lib_options
 | 
						|
 | 
						|
#----------------------------------------------------------------------
 | 
						|
 | 
						|
class MyMSVCCompiler(MSVCCompiler):
 | 
						|
 | 
						|
##     def __init__ (self,
 | 
						|
##                   verbose=0,
 | 
						|
##                   dry_run=0,
 | 
						|
##                   force=0):
 | 
						|
##         MSVCCompiler.__init__(self, verbose, dry_run, force)
 | 
						|
 | 
						|
##         self.compile_options = [ '/nologo',
 | 
						|
##                                  '/Ox',
 | 
						|
##                                  '/MD',
 | 
						|
##                                  '/W3',
 | 
						|
##                                  '/GX',
 | 
						|
##                                  ]
 | 
						|
##         self.compile_options_debug = ['/nologo', '/Od', '/MDd', '/W3', '/GX',
 | 
						|
##                                       '/Z7', '/D_DEBUG']
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
    ##------------------------------------------------------------
 | 
						|
    ## Override the entire compile method just to add flags to the
 | 
						|
    ## RC command.  There should be an easier way to do this from
 | 
						|
    ## distutils directly or in a derived class...
 | 
						|
    ##------------------------------------------------------------
 | 
						|
 | 
						|
    def compile (self,
 | 
						|
                 sources,
 | 
						|
                 output_dir=None,
 | 
						|
                 macros=None,
 | 
						|
                 include_dirs=None,
 | 
						|
                 debug=0,
 | 
						|
                 extra_preargs=None,
 | 
						|
                 extra_postargs=None):
 | 
						|
 | 
						|
        (output_dir, macros, include_dirs) = \
 | 
						|
            self._fix_compile_args (output_dir, macros, include_dirs)
 | 
						|
        (objects, skip_sources) = self._prep_compile (sources, output_dir)
 | 
						|
 | 
						|
        if extra_postargs is None:
 | 
						|
            extra_postargs = []
 | 
						|
 | 
						|
        pp_opts = gen_preprocess_options (macros, include_dirs)
 | 
						|
        compile_opts = extra_preargs or []
 | 
						|
        compile_opts.append ('/c')
 | 
						|
        if debug:
 | 
						|
            compile_opts.extend (self.compile_options_debug)
 | 
						|
        else:
 | 
						|
            compile_opts.extend (self.compile_options)
 | 
						|
 | 
						|
        for i in range (len (sources)):
 | 
						|
            src = sources[i] ; obj = objects[i]
 | 
						|
            ext = (os.path.splitext (src))[1]
 | 
						|
 | 
						|
            if skip_sources[src]:
 | 
						|
                self.announce ("skipping %s (%s up-to-date)" % (src, obj))
 | 
						|
            else:
 | 
						|
                self.mkpath (os.path.dirname (obj))
 | 
						|
 | 
						|
                if ext in self._c_extensions:
 | 
						|
                    input_opt = "/Tc" + os.path.abspath(src)    ### RPD
 | 
						|
                elif ext in self._cpp_extensions:
 | 
						|
                    input_opt = "/Tp" + os.path.abspath(src)    ### RPD
 | 
						|
                elif ext in self._rc_extensions:
 | 
						|
                    # compile .RC to .RES file
 | 
						|
                    input_opt = src
 | 
						|
                    output_opt = "/fo" + obj
 | 
						|
                    try:
 | 
						|
                        self.spawn ([self.rc] + pp_opts +         ### RPD changed this line
 | 
						|
                                    [output_opt] + [input_opt])
 | 
						|
                    except DistutilsExecError, msg:
 | 
						|
                        raise CompileError, msg
 | 
						|
                    continue
 | 
						|
                elif ext in self._mc_extensions:
 | 
						|
 | 
						|
                    # Compile .MC to .RC file to .RES file.
 | 
						|
                    #   * '-h dir' specifies the directory for the
 | 
						|
                    #     generated include file
 | 
						|
                    #   * '-r dir' specifies the target directory of the
 | 
						|
                    #     generated RC file and the binary message resource
 | 
						|
                    #     it includes
 | 
						|
                    #
 | 
						|
                    # For now (since there are no options to change this),
 | 
						|
                    # we use the source-directory for the include file and
 | 
						|
                    # the build directory for the RC file and message
 | 
						|
                    # resources. This works at least for win32all.
 | 
						|
 | 
						|
                    h_dir = os.path.dirname (src)
 | 
						|
                    rc_dir = os.path.dirname (obj)
 | 
						|
                    try:
 | 
						|
                        # first compile .MC to .RC and .H file
 | 
						|
                        self.spawn ([self.mc] +
 | 
						|
                                    ['-h', h_dir, '-r', rc_dir] + [src])
 | 
						|
                        base, _ = os.path.splitext (os.path.basename (src))
 | 
						|
                        rc_file = os.path.join (rc_dir, base + '.rc')
 | 
						|
                        # then compile .RC to .RES file
 | 
						|
                        self.spawn ([self.rc] +
 | 
						|
                                    ["/fo" + obj] + [rc_file])
 | 
						|
 | 
						|
                    except DistutilsExecError, msg:
 | 
						|
                        raise CompileError, msg
 | 
						|
                    continue
 | 
						|
                else:
 | 
						|
                    # how to handle this file?
 | 
						|
                    raise CompileError (
 | 
						|
                        "Don't know how to compile %s to %s" % \
 | 
						|
                        (src, obj))
 | 
						|
 | 
						|
                output_opt = "/Fo" + obj
 | 
						|
                try:
 | 
						|
                    self.spawn ([self.cc] + compile_opts + pp_opts +
 | 
						|
                                [input_opt, output_opt] +
 | 
						|
                                extra_postargs)
 | 
						|
                except DistutilsExecError, msg:
 | 
						|
                    raise CompileError, msg
 | 
						|
 | 
						|
        return objects
 | 
						|
 | 
						|
    # compile ()
 | 
						|
 | 
						|
 | 
						|
 | 
						|
from distutils.file_util import write_file
 | 
						|
class MyBCPPCompiler(BCPPCompiler):
 | 
						|
 | 
						|
    ##------------------------------------------------------------
 | 
						|
    ## Override the entire compile method just to add flags to the
 | 
						|
    ## RC command.  There should be an easier way to do this from
 | 
						|
    ## distutils directly or in a derived class...
 | 
						|
    ##------------------------------------------------------------
 | 
						|
 | 
						|
    def compile (self,
 | 
						|
                 sources,
 | 
						|
                 output_dir=None,
 | 
						|
                 macros=None,
 | 
						|
                 include_dirs=None,
 | 
						|
                 debug=0,
 | 
						|
                 extra_preargs=None,
 | 
						|
                 extra_postargs=None):
 | 
						|
 | 
						|
        (output_dir, macros, include_dirs) = \
 | 
						|
            self._fix_compile_args (output_dir, macros, include_dirs)
 | 
						|
        (objects, skip_sources) = self._prep_compile (sources, output_dir)
 | 
						|
 | 
						|
        if extra_postargs is None:
 | 
						|
            extra_postargs = []
 | 
						|
 | 
						|
        pp_opts = gen_preprocess_options (macros, include_dirs)
 | 
						|
        compile_opts = extra_preargs or []
 | 
						|
        compile_opts.append ('-c')
 | 
						|
        if debug:
 | 
						|
            compile_opts.extend (self.compile_options_debug)
 | 
						|
        else:
 | 
						|
            compile_opts.extend (self.compile_options)
 | 
						|
 | 
						|
        for i in range (len (sources)):
 | 
						|
            src = sources[i] ; obj = objects[i]
 | 
						|
            ext = (os.path.splitext (src))[1]
 | 
						|
 | 
						|
            if skip_sources[src]:
 | 
						|
                self.announce ("skipping %s (%s up-to-date)" % (src, obj))
 | 
						|
            else:
 | 
						|
                src = os.path.normpath(src)
 | 
						|
                obj = os.path.normpath(obj)
 | 
						|
                self.mkpath(os.path.dirname(obj))
 | 
						|
 | 
						|
                if ext == '.res':
 | 
						|
                    # This is already a binary file -- skip it.
 | 
						|
                    continue # the 'for' loop
 | 
						|
                if ext == '.rc':
 | 
						|
                    # This needs to be compiled to a .res file -- do it now.
 | 
						|
                    try:
 | 
						|
                        self.spawn (["brcc32"] + pp_opts + ["-fo"] +
 | 
						|
                                    [obj] + [src]) ### RPD changed this lines only
 | 
						|
                    except DistutilsExecError, msg:
 | 
						|
                        raise CompileError, msg
 | 
						|
                    continue # the 'for' loop
 | 
						|
 | 
						|
                # The next two are both for the real compiler.
 | 
						|
                if ext in self._c_extensions:
 | 
						|
                    input_opt = ""
 | 
						|
                elif ext in self._cpp_extensions:
 | 
						|
                    input_opt = "-P"
 | 
						|
                else:
 | 
						|
                    # Unknown file type -- no extra options.  The compiler
 | 
						|
                    # will probably fail, but let it just in case this is a
 | 
						|
                    # file the compiler recognizes even if we don't.
 | 
						|
                    input_opt = ""
 | 
						|
 | 
						|
                output_opt = "-o" + obj
 | 
						|
 | 
						|
                # Compiler command line syntax is: "bcc32 [options] file(s)".
 | 
						|
                # Note that the source file names must appear at the end of
 | 
						|
                # the command line.
 | 
						|
                try:
 | 
						|
                    self.spawn ([self.cc] + compile_opts + pp_opts +
 | 
						|
                                [input_opt, output_opt] +
 | 
						|
                                extra_postargs + [src])
 | 
						|
                except DistutilsExecError, msg:
 | 
						|
                    raise CompileError, msg
 | 
						|
 | 
						|
        return objects
 | 
						|
 | 
						|
    # compile ()
 | 
						|
 | 
						|
    ####################################################################
 | 
						|
    # Now we need to replace cw32mt library used by default by distutils
 | 
						|
    # with cw32mti library as in wxWindows DLL make file
 | 
						|
    # Othervise we obtain Windows "Core dump" ;-).
 | 
						|
    #
 | 
						|
    #           Evgeny A Cherkashin <eugeneai@icc.ru>
 | 
						|
    #
 | 
						|
    ####################################################################
 | 
						|
 | 
						|
    def link (self,
 | 
						|
              target_desc,
 | 
						|
              objects,
 | 
						|
              output_filename,
 | 
						|
              output_dir=None,
 | 
						|
              libraries=None,
 | 
						|
              library_dirs=None,
 | 
						|
              runtime_library_dirs=None,
 | 
						|
              export_symbols=None,
 | 
						|
              debug=0,
 | 
						|
              extra_preargs=None,
 | 
						|
              extra_postargs=None,
 | 
						|
              build_temp=None):
 | 
						|
 | 
						|
        # XXX this ignores 'build_temp'!  should follow the lead of
 | 
						|
        # msvccompiler.py
 | 
						|
 | 
						|
        (objects, output_dir) = self._fix_object_args (objects, output_dir)
 | 
						|
        (libraries, library_dirs, runtime_library_dirs) = \
 | 
						|
            self._fix_lib_args (libraries, library_dirs, runtime_library_dirs)
 | 
						|
 | 
						|
        if runtime_library_dirs:
 | 
						|
            self.warn ("I don't know what to do with 'runtime_library_dirs': "
 | 
						|
                       + str (runtime_library_dirs))
 | 
						|
 | 
						|
        if output_dir is not None:
 | 
						|
            output_filename = os.path.join (output_dir, output_filename)
 | 
						|
 | 
						|
        if self._need_link (objects, output_filename):
 | 
						|
 | 
						|
            # Figure out linker args based on type of target.
 | 
						|
            if target_desc == CCompiler.EXECUTABLE:
 | 
						|
                startup_obj = 'c0w32'
 | 
						|
                if debug:
 | 
						|
                    ld_args = self.ldflags_exe_debug[:]
 | 
						|
                else:
 | 
						|
                    ld_args = self.ldflags_exe[:]
 | 
						|
            else:
 | 
						|
                startup_obj = 'c0d32'
 | 
						|
                if debug:
 | 
						|
                    ld_args = self.ldflags_shared_debug[:]
 | 
						|
                else:
 | 
						|
                    ld_args = self.ldflags_shared[:]
 | 
						|
 | 
						|
 | 
						|
            # Create a temporary exports file for use by the linker
 | 
						|
            if export_symbols is None:
 | 
						|
                def_file = ''
 | 
						|
            else:
 | 
						|
                head, tail = os.path.split (output_filename)
 | 
						|
                modname, ext = os.path.splitext (tail)
 | 
						|
                temp_dir = os.path.dirname(objects[0]) # preserve tree structure
 | 
						|
                def_file = os.path.join (temp_dir, '%s.def' % modname)
 | 
						|
                contents = ['EXPORTS']
 | 
						|
                for sym in (export_symbols or []):
 | 
						|
                    contents.append('  %s=_%s' % (sym, sym))
 | 
						|
                self.execute(write_file, (def_file, contents),
 | 
						|
                             "writing %s" % def_file)
 | 
						|
 | 
						|
            # Borland C++ has problems with '/' in paths
 | 
						|
            objects2 = map(os.path.normpath, objects)
 | 
						|
            # split objects in .obj and .res files
 | 
						|
            # Borland C++ needs them at different positions in the command line
 | 
						|
            objects = [startup_obj]
 | 
						|
            resources = []
 | 
						|
            for file in objects2:
 | 
						|
                (base, ext) = os.path.splitext(os.path.normcase(file))
 | 
						|
                if ext == '.res':
 | 
						|
                    resources.append(file)
 | 
						|
                else:
 | 
						|
                    objects.append(file)
 | 
						|
 | 
						|
 | 
						|
            for l in library_dirs:
 | 
						|
                ld_args.append("/L%s" % os.path.normpath(l))
 | 
						|
            ld_args.append("/L.") # we sometimes use relative paths
 | 
						|
 | 
						|
            # list of object files
 | 
						|
            ld_args.extend(objects)
 | 
						|
 | 
						|
            # XXX the command-line syntax for Borland C++ is a bit wonky;
 | 
						|
            # certain filenames are jammed together in one big string, but
 | 
						|
            # comma-delimited.  This doesn't mesh too well with the
 | 
						|
            # Unix-centric attitude (with a DOS/Windows quoting hack) of
 | 
						|
            # 'spawn()', so constructing the argument list is a bit
 | 
						|
            # awkward.  Note that doing the obvious thing and jamming all
 | 
						|
            # the filenames and commas into one argument would be wrong,
 | 
						|
            # because 'spawn()' would quote any filenames with spaces in
 | 
						|
            # them.  Arghghh!.  Apparently it works fine as coded...
 | 
						|
 | 
						|
            # name of dll/exe file
 | 
						|
            ld_args.extend([',',output_filename])
 | 
						|
            # no map file and start libraries
 | 
						|
            ld_args.append(',,')
 | 
						|
 | 
						|
            for lib in libraries:
 | 
						|
                # see if we find it and if there is a bcpp specific lib
 | 
						|
                # (xxx_bcpp.lib)
 | 
						|
                libfile = self.find_library_file(library_dirs, lib, debug)
 | 
						|
                if libfile is None:
 | 
						|
                    ld_args.append(lib)
 | 
						|
                    # probably a BCPP internal library -- don't warn
 | 
						|
                    #    self.warn('library %s not found.' % lib)
 | 
						|
                else:
 | 
						|
                    # full name which prefers bcpp_xxx.lib over xxx.lib
 | 
						|
                    ld_args.append(libfile)
 | 
						|
 | 
						|
            # some default libraries
 | 
						|
            ld_args.append ('import32')
 | 
						|
            ld_args.append ('cw32mti')  ### mt->mti (as in wx2)
 | 
						|
 | 
						|
            # def file for export symbols
 | 
						|
            ld_args.extend([',',def_file])
 | 
						|
            # add resource files
 | 
						|
            ld_args.append(',')
 | 
						|
            ld_args.extend(resources)
 | 
						|
 | 
						|
 | 
						|
            if extra_preargs:
 | 
						|
                ld_args[:0] = extra_preargs
 | 
						|
            if extra_postargs:
 | 
						|
                ld_args.extend(extra_postargs)
 | 
						|
 | 
						|
            self.mkpath (os.path.dirname (output_filename))
 | 
						|
            try:
 | 
						|
                self.spawn ([self.linker] + ld_args)
 | 
						|
            except DistutilsExecError, msg:
 | 
						|
                raise LinkError, msg
 | 
						|
 | 
						|
        else:
 | 
						|
            self.announce ("skipping %s (up-to-date)" % output_filename)
 | 
						|
 | 
						|
    # link ()
 | 
						|
 | 
						|
 | 
						|
 | 
						|
#----------------------------------------------------------------------
 | 
						|
# Hack this module and class into the distutils...
 | 
						|
 | 
						|
from distutils import ccompiler
 | 
						|
 | 
						|
if hasattr(ccompiler, "default_compiler"):
 | 
						|
    ccompiler.default_compiler['nt'] = 'my_msvc'
 | 
						|
elif hasattr(ccompiler, "_default_compilers"):
 | 
						|
    lst = list(ccompiler._default_compilers)
 | 
						|
    lst.remove( ('nt', 'msvc') )
 | 
						|
    lst.append( ('nt', 'my_msvc') )
 | 
						|
    ccompiler._default_compilers = tuple(lst)
 | 
						|
 | 
						|
 | 
						|
ccompiler.compiler_class['my_msvc'] = ('my_distutils',
 | 
						|
                                       'MyMSVCCompiler',
 | 
						|
                                       'My MSVC derived class')
 | 
						|
 | 
						|
 | 
						|
ccompiler.compiler_class['my_bcpp'] = ('my_distutils',
 | 
						|
                                       'MyBCPPCompiler',
 | 
						|
                                       'My BCPP derived class')
 | 
						|
 | 
						|
# make it look like it is part of the package...
 | 
						|
import my_distutils
 | 
						|
sys.modules['distutils.my_distutils'] = my_distutils
 | 
						|
 | 
						|
 | 
						|
#----------------------------------------------------------------------
 | 
						|
# More hacking...  Distutils in Python 2.1 changed the strip_dir flag
 | 
						|
# passed to object_filenames to true, which causes problems for us since
 | 
						|
# there are a few duplicate source/object names between some of the
 | 
						|
# extensions in wxPython.  This hack replaces the CCompiler._prep_compile
 | 
						|
# method with this one.
 | 
						|
 | 
						|
from distutils.dep_util import newer_pairwise
 | 
						|
 | 
						|
def _prep_compile (self, sources, output_dir):
 | 
						|
    """Determine the list of object files corresponding to 'sources',
 | 
						|
    and figure out which ones really need to be recompiled.  Return a
 | 
						|
    list of all object files and a dictionary telling which source
 | 
						|
    files can be skipped.
 | 
						|
    """
 | 
						|
    # Get the list of expected output (object) files
 | 
						|
    objects = self.object_filenames (sources,
 | 
						|
                                     strip_dir=0,
 | 
						|
                                     output_dir=output_dir)
 | 
						|
 | 
						|
    if self.force:
 | 
						|
        skip_source = {}            # rebuild everything
 | 
						|
        for source in sources:
 | 
						|
            skip_source[source] = 0
 | 
						|
    else:
 | 
						|
        # Figure out which source files we have to recompile according
 | 
						|
        # to a simplistic check -- we just compare the source and
 | 
						|
        # object file, no deep dependency checking involving header
 | 
						|
        # files.
 | 
						|
        skip_source = {}            # rebuild everything
 | 
						|
        for source in sources:      # no wait, rebuild nothing
 | 
						|
            skip_source[source] = 1
 | 
						|
 | 
						|
        (n_sources, n_objects) = newer_pairwise (sources, objects)
 | 
						|
        for source in n_sources:    # no really, only rebuild what's
 | 
						|
            skip_source[source] = 0 # out-of-date
 | 
						|
 | 
						|
    return (objects, skip_source)
 | 
						|
 | 
						|
# _prep_compile ()
 | 
						|
 | 
						|
CCompiler._prep_compile = _prep_compile
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
#----------------------------------------------------------------------
 | 
						|
# Run SWIG the way I want it done
 | 
						|
 | 
						|
def run_swig(files, dir, gendir, package, USE_SWIG, force, swig_args, swig_deps=[]):
 | 
						|
    from distutils.file_util import copy_file
 | 
						|
    from distutils.dep_util import newer
 | 
						|
    from distutils.spawn import spawn
 | 
						|
 | 
						|
    if not os.path.exists(os.path.join(dir, gendir)):
 | 
						|
        os.mkdir(os.path.join(dir, gendir))
 | 
						|
 | 
						|
    sources = []
 | 
						|
 | 
						|
    for file in files:
 | 
						|
        basefile = os.path.splitext(file)[0]
 | 
						|
        i_file   = os.path.join(dir, file)
 | 
						|
        py_file  = os.path.join(dir, gendir, basefile+'.py')
 | 
						|
        cpp_file = os.path.join(dir, gendir, basefile+'.cpp')
 | 
						|
 | 
						|
        sources.append(cpp_file)
 | 
						|
 | 
						|
        if USE_SWIG:
 | 
						|
            for dep in swig_deps:
 | 
						|
                if newer(dep, py_file) or newer(dep, cpp_file):
 | 
						|
                    force = 1
 | 
						|
                    break
 | 
						|
 | 
						|
            if force or newer(i_file, py_file) or newer(i_file, cpp_file):
 | 
						|
                # we need forward slashes here even on win32
 | 
						|
                cpp_file = '/'.join(cpp_file.split('\\'))
 | 
						|
                i_file = '/'.join(i_file.split('\\'))
 | 
						|
 | 
						|
                cmd = ['./wxSWIG/wxswig'] + swig_args + ['-I'+dir, '-c', '-o', cpp_file, i_file]
 | 
						|
                spawn(cmd, verbose=1)
 | 
						|
 | 
						|
        # copy the generated python file to the package directory
 | 
						|
        copy_file(py_file, package, update=not force, verbose=0)
 | 
						|
 | 
						|
 | 
						|
    return sources
 | 
						|
 | 
						|
 | 
						|
 | 
						|
#----------------------------------------------------------------------
 | 
						|
# Update local copies of wxWindows contrib files
 | 
						|
 | 
						|
 | 
						|
def contrib_copy_tree(src, dest, verbose=0):
 | 
						|
    from distutils.dir_util import mkpath, copy_tree
 | 
						|
 | 
						|
    mkpath(dest, verbose=verbose)
 | 
						|
    copy_tree(src, dest, update=1, verbose=verbose)
 | 
						|
 |