]> git.saurik.com Git - wxWidgets.git/blobdiff - wxPython/my_distutils.py
compilation fix (for !PCH)
[wxWidgets.git] / wxPython / my_distutils.py
index 47da51b1d7dec21f7d71f60a0a28e5858b122c7e..f1603f4f5f6d0673f65157de73181c0cd656fb74 100644 (file)
@@ -2,6 +2,7 @@
 import sys, os, string
 
 from distutils.msvccompiler import MSVCCompiler
+from distutils.bcppcompiler import BCPPCompiler
 
 from distutils.errors import \
      DistutilsExecError, DistutilsPlatformError, \
@@ -13,6 +14,24 @@ from distutils.ccompiler import \
 
 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
@@ -53,15 +72,15 @@ class MyMSVCCompiler(MSVCCompiler):
                 self.mkpath (os.path.dirname (obj))
 
                 if ext in self._c_extensions:
-                    input_opt = "/Tc" + src
+                    input_opt = "/Tc" + os.path.abspath(src)    ### RPD
                 elif ext in self._cpp_extensions:
-                    input_opt = "/Tp" + src
+                    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 only
+                        self.spawn ([self.rc] + pp_opts +         ### RPD changed this line
                                     [output_opt] + [input_opt])
                     except DistutilsExecError, msg:
                         raise CompileError, msg
@@ -115,12 +134,98 @@ class MyMSVCCompiler(MSVCCompiler):
 
 
 
+from distutils.file_util import write_file
+class MyBCPPCompiler(BCPPCompiler):
+
     ##------------------------------------------------------------
-    ## Now override the link() method to change where the import
-    ## library is placed.  Hopefully distutils will be updated
-    ## someday to make this configurable...
+    ## 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,
@@ -135,6 +240,9 @@ class MyMSVCCompiler(MSVCCompiler):
               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)
@@ -143,52 +251,98 @@ class MyMSVCCompiler(MSVCCompiler):
             self.warn ("I don't know what to do with 'runtime_library_dirs': "
                        + str (runtime_library_dirs))
 
-        lib_opts = gen_lib_options (self,
-                                    library_dirs, runtime_library_dirs,
-                                    libraries)
         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:
-                    ldflags = self.ldflags_shared_debug[1:]
+                    ld_args = self.ldflags_exe_debug[:]
                 else:
-                    ldflags = self.ldflags_shared[1:]
+                    ld_args = self.ldflags_exe[:]
             else:
+                startup_obj = 'c0d32'
                 if debug:
-                    ldflags = self.ldflags_shared_debug
+                    ld_args = self.ldflags_shared_debug[:]
                 else:
-                    ldflags = self.ldflags_shared
-
-            export_opts = []
-            for sym in (export_symbols or []):
-                export_opts.append("/EXPORT:" + sym)
+                    ld_args = self.ldflags_shared[:]
 
-            ld_args = (ldflags + lib_opts + export_opts +
-                       objects + ['/OUT:' + output_filename])
 
-            # The MSVC linker generates .lib and .exp files, which cannot be
-            # suppressed by any linker switches. The .lib files may even be
-            # needed! Make sure they are generated in the temporary build
-            # directory. Since they have different names for debug and release
-            # builds, they can go into the same directory.
-            if export_symbols is not None:
-                (dll_name, dll_ext) = os.path.splitext(
-                    os.path.basename(output_filename))
+            # 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)
 
-                ## The old code
-                ##implib_file = os.path.join(
-                ##    os.path.dirname(objects[0]),
-                ##    self.library_filename(dll_name))
+            # some default libraries
+            ld_args.append ('import32')
+            ld_args.append ('cw32mti') ### mt->mti (as in wx2)
 
-                ## The new
-                implib_file = os.path.join('build', 'ilib',
-                                           self.library_filename(dll_name))
-                self.mkpath(os.path.dirname(implib_file))
+            # def file for export symbols
+            ld_args.extend([',',def_file])
+            # add resource files
+            ld_args.append(',')
+            ld_args.extend(resources)
 
-                ld_args.append ('/IMPLIB:' + implib_file)
 
             if extra_preargs:
                 ld_args[:0] = extra_preargs
@@ -213,17 +367,73 @@ class MyMSVCCompiler(MSVCCompiler):
 
 from distutils import ccompiler
 
-ccompiler.default_compiler['nt'] = 'my_msvc'
+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
+
+
 
 
 #----------------------------------------------------------------------
@@ -255,7 +465,7 @@ def run_swig(files, dir, gendir, package, USE_SWIG, force, swig_args, swig_deps=
                 cpp_file = string.join(string.split(cpp_file, '\\'), '/')
                 i_file = string.join(string.split(i_file, '\\'), '/')
 
-                cmd = ['swig'] + swig_args + ['-I'+dir, '-c', '-o', cpp_file, i_file]
+                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