[Distutils] Duelling SWIG patches

Greg Ward gward@python.net
Wed, 21 Jun 2000 21:39:08 -0400


Well, I was inspired by Thomas' patch for SWIG support to come up with
my own patch.  Here it is: completely untested, so I haven't checked it
in yet.  (I don't have SWIG installed at home, so I figured I'd let
someone Out There who actually uses it test this for me.  Remember:
laziness is a virtue!)

Note that Thomas' patch was Windows/C++-centric; mine tries to be
OS-agnostic, but is C-centric.  Is it possible to tell from a SWIG .i
file whether it is destined to be C or C++?  I can't think of a good way
to do it, but then my knowledge if SWIG is roughly epsilon.  (Out of
curiosity, I took the manual home and read it about three years ago.  It 
struck me as being *way* to easy, and I wanted to write Perl extensions
like a *real* man.  Ahh, the folly of youth...)

Here's da patch:

===================================================================
RCS file: /cvsroot/python/distutils/distutils/command/build_ext.py,v
retrieving revision 1.43
diff -u -r1.43 build_ext.py
--- build_ext.py	2000/06/17 23:04:31	1.43
+++ build_ext.py	2000/06/22 01:30:49
@@ -367,12 +367,13 @@
 	    else:
         	self.announce ("building '%s' extension" % ext.name)
 
-            # First step: compile the source code to object files.  This
-            # drops the object files in the current directory, regardless
-            # of where the source is (may be a bad thing, but that's how a
-            # Makefile.pre.in-based system does it, so at least there's a
-            # precedent!)
+            # First, scan the sources for SWIG definition files (.i), run
+            # SWIG on 'em to create .c files, and modify the sources list
+            # accordingly.
+            sources = self.swig_sources(sources)
 
+            # Next, compile the source code to object files.
+
             # XXX not honouring 'define_macros' or 'undef_macros' -- the
             # CCompiler API needs to change to accomodate this, and I
             # want to do one thing at a time!
@@ -428,6 +429,74 @@
 
     # build_extensions ()
 
+
+    def swig_sources (self, sources):
+
+        """Walk the list of source files in 'sources', looking for SWIG
+        interface (.i) files.  Run SWIG on all that are found, and
+        return a modified 'sources' list with SWIG source files replaced
+        by the generated C (or C++) files.
+        """
+
+        new_sources = []
+        swig_sources = []
+        swig_targets = {}
+
+        # XXX this drops generated C files into the source tree, which
+        # is fine for developers who want to distribute the generated
+        # source -- but there should be an option to put SWIG output in
+        # the temp dir.
+
+        for source in sources:
+            (base, ext) = os.path.splitext(source)
+            if ext in self.swig_ext():
+                new_sources.append(base + ".c") # umm, what if it's C++?
+                swig_files.append(source)
+                swig_targets[source] = new_sources[-1]
+            else:
+                new_sources.append(source)
+
+        if not swig_files:
+            return new_sources
+
+        swig = self.find_swig()
+        swig_cmd = [swig, "-python", "-dnone", "-ISWIG"] # again, C++?!?
+
+        for source in swig_sources:
+            self.announce ("swigging %s to %s" % (src, obj))
+            self.spawn(swig_cmd + ["-o", swig_targets[source], source])
+
+        return new_sources
+
+    # swig_sources ()
+
+    def find_swig (self):
+        """Return the name of the SWIG executable.  On Unix, this is
+        just "swig" -- it should be in the PATH.  Tries a bit harder on
+        Windows.
+        """
+
+        if os.name == "posix":
+            return "swig"
+        elif os.name == "nt":
+
+            # Look for SWIG in its standard installation directory on
+            # Windows (or so I presume!).  If we find it there, great;
+            # if not, act like Unix and assume it's in the PATH.
+            for vers in ("1.3", "1.2", "1.1"):
+                fn = os.path.join("c:\\swig%s" % vers, "swig.exe")
+                if os.path.isfile (fn):
+                    return fn
+            else:
+                return "swig.exe"
+
+        else:
+            raise DistutilsPlatformError, \
+                  ("I don't know how to find (much less run) SWIG "
+                   "on platform '%s'") % os.name
+
+    # find_swig ()
+    
 
     # -- Hooks ---------------------------------------------------------
 
========================================================================

        Greg
-- 
Greg Ward - Unix geek                                   gward@python.net
http://starship.python.net/~gward/
All right, you degenerates!  I want this place evacuated in 20 seconds!