[Numpy-svn] r3795 - in branches/distutils-revamp: . command fcompiler

numpy-svn at scipy.org numpy-svn at scipy.org
Mon May 21 09:15:52 EDT 2007


Author: cookedm
Date: 2007-05-21 08:15:45 -0500 (Mon, 21 May 2007)
New Revision: 3795

Modified:
   branches/distutils-revamp/
   branches/distutils-revamp/ccompiler.py
   branches/distutils-revamp/command/build.py
   branches/distutils-revamp/command/build_clib.py
   branches/distutils-revamp/command/build_ext.py
   branches/distutils-revamp/command/build_src.py
   branches/distutils-revamp/command/config.py
   branches/distutils-revamp/command/config_compiler.py
   branches/distutils-revamp/core.py
   branches/distutils-revamp/fcompiler/__init__.py
   branches/distutils-revamp/misc_util.py
   branches/distutils-revamp/system_info.py
Log:
[distutils-revamp] Merged revisions 3769-3794 via svnmerge from 
http://svn.scipy.org/svn/numpy/trunk/numpy/distutils

........
  r3775 | pearu | 2007-05-18 10:32:33 -0400 (Fri, 18 May 2007) | 1 line
  
  build_src: introduced --swig and other related options (as in std distutils build_ext command), use --f2py-opts instead of --f2pyflags, improved error messages.
........
  r3776 | pearu | 2007-05-18 12:41:44 -0400 (Fri, 18 May 2007) | 1 line
  
  Extension modules and libraries are built with suitable compilers/linkers. Improved failure handling.
........
  r3779 | pearu | 2007-05-18 13:33:15 -0400 (Fri, 18 May 2007) | 1 line
  
  Fixed warnings on language changes.
........
  r3780 | pearu | 2007-05-18 16:17:48 -0400 (Fri, 18 May 2007) | 1 line
  
  unify config_fc, build_clib, build_ext commands --fcompiler options so that --fcompiler can be specified only once in a command line
........
  r3781 | pearu | 2007-05-18 16:41:10 -0400 (Fri, 18 May 2007) | 1 line
  
  added config to --fcompiler option unification method. introduced config_cc for unifying --compiler options.
........
  r3782 | pearu | 2007-05-18 16:49:09 -0400 (Fri, 18 May 2007) | 1 line
  
  Added --help-fcompiler option to build_ext command.
........
  r3783 | pearu | 2007-05-18 17:00:17 -0400 (Fri, 18 May 2007) | 1 line
  
  show less messages in --help-fcompiler
........
  r3784 | pearu | 2007-05-18 17:25:23 -0400 (Fri, 18 May 2007) | 1 line
  
  Added --fcompiler,--help-fcompiler options to build command parallel to --compiler,--help-compiler options.
........
  r3785 | pearu | 2007-05-18 17:33:07 -0400 (Fri, 18 May 2007) | 1 line
  
  Add descriptions to config_fc and config_cc commands.
........
  r3786 | pearu | 2007-05-19 05:54:00 -0400 (Sat, 19 May 2007) | 1 line
  
  Fix for win32 platform.
........
  r3787 | pearu | 2007-05-19 06:23:16 -0400 (Sat, 19 May 2007) | 1 line
  
  Fix fcompiler/compiler unification warning.
........
  r3788 | pearu | 2007-05-19 11:20:48 -0400 (Sat, 19 May 2007) | 1 line
  
  Fix atlas version detection when using MSVC compiler
........
  r3789 | pearu | 2007-05-19 11:21:41 -0400 (Sat, 19 May 2007) | 1 line
  
  Fix typo.
........
  r3790 | pearu | 2007-05-19 11:24:20 -0400 (Sat, 19 May 2007) | 1 line
  
  More typo fixes.
........
  r3791 | pearu | 2007-05-19 13:01:39 -0400 (Sat, 19 May 2007) | 1 line
  
  win32: fix install when build has been carried out earlier.
........
  r3792 | pearu | 2007-05-19 15:44:42 -0400 (Sat, 19 May 2007) | 1 line
  
  Clean up and completed (hopefully) MSVC support.
........
  r3794 | cookedm | 2007-05-21 09:01:20 -0400 (Mon, 21 May 2007) | 1 line
  
  minor cleanups in numpy.distutils (style mostly)
........



Property changes on: branches/distutils-revamp
___________________________________________________________________
Name: svnmerge-integrated
   - /branches/distutils-revamp:1-2756 /trunk/numpy/distutils:1-3768
   + /branches/distutils-revamp:1-2756 /trunk/numpy/distutils:1-3794

Modified: branches/distutils-revamp/ccompiler.py
===================================================================
--- branches/distutils-revamp/ccompiler.py	2007-05-21 13:01:20 UTC (rev 3794)
+++ branches/distutils-revamp/ccompiler.py	2007-05-21 13:15:45 UTC (rev 3795)
@@ -288,6 +288,7 @@
 replace_method(CCompiler, 'get_version', CCompiler_get_version)
 
 def CCompiler_cxx_compiler(self):
+    if self.compiler_type=='msvc': return self
     cxx = copy(self)
     cxx.compiler_so = [cxx.compiler_cxx[0]] + cxx.compiler_so[1:]
     if sys.platform.startswith('aix') and 'ld_so_aix' in cxx.linker_so[0]:

Modified: branches/distutils-revamp/command/build.py
===================================================================
--- branches/distutils-revamp/command/build.py	2007-05-21 13:01:20 UTC (rev 3794)
+++ branches/distutils-revamp/command/build.py	2007-05-21 13:15:45 UTC (rev 3795)
@@ -2,13 +2,29 @@
 import sys
 from distutils.command.build import build as old_build
 from distutils.util import get_platform
+from numpy.distutils.command.config_compiler import show_fortran_compilers
 
 class build(old_build):
 
-    sub_commands = [('config_fc',     lambda *args: 1),
+    sub_commands = [('config_cc',     lambda *args: True),
+                    ('config_fc',     lambda *args: True),
                     ('build_src',     old_build.has_ext_modules),
                     ] + old_build.sub_commands
 
+    user_options = old_build.user_options + [
+        ('fcompiler=', None,
+         "specify the Fortran compiler type"),
+        ]
+
+    help_options = old_build.help_options + [
+        ('help-fcompiler',None, "list available Fortran compilers",
+         show_fortran_compilers),
+        ]
+
+    def initialize_options(self):
+        old_build.initialize_options(self)
+        self.fcompiler = None
+
     def finalize_options(self):
         build_scripts = self.build_scripts
         old_build.finalize_options(self)

Modified: branches/distutils-revamp/command/build_clib.py
===================================================================
--- branches/distutils-revamp/command/build_clib.py	2007-05-21 13:01:20 UTC (rev 3794)
+++ branches/distutils-revamp/command/build_clib.py	2007-05-21 13:15:45 UTC (rev 3795)
@@ -1,19 +1,15 @@
 """ Modified version of build_clib that handles fortran source files.
 """
 
+import os
 from distutils.command.build_clib import build_clib as old_build_clib
-from distutils.errors import DistutilsSetupError
+from distutils.errors import DistutilsSetupError, DistutilsError
 
 from numpy.distutils import log
 from distutils.dep_util import newer_group
 from numpy.distutils.misc_util import filter_sources, has_f_sources,\
      has_cxx_sources, all_strings, get_lib_source_files, is_sequence
 
-try:
-    set
-except NameError:
-    from sets import Set as set
-
 # Fix Python distutils bug sf #1718574:
 _l = old_build_clib.user_options
 for _i in range(len(_l)):
@@ -33,46 +29,32 @@
     def initialize_options(self):
         old_build_clib.initialize_options(self)
         self.fcompiler = None
+        return
 
-    def finalize_options(self):
-        old_build_clib.finalize_options(self)
-        self._languages = None
-        self.set_undefined_options('config_fc',
-                                   ('fcompiler', 'fcompiler'))
-        # we set this to the appropiate Fortran compiler object
-        # (f77 or f90) in the .run() method
-        self._fcompiler = None
-
-    def languages(self):
-        """Return a set of language names used in this library.
-        Valid language names are 'c', 'f77', and 'f90'.
-        """
-        if self._languages is None:
-            languages = set()
-            for (lib_name, build_info) in self.libraries:
-                l = build_info.get('language',None)
-                if l:
-                    languages.add(l)
-            self._languages = languages
-        return self._languages
-
     def have_f_sources(self):
-        l = self.languages()
-        return 'f90' in l or 'f77' in l
+        for (lib_name, build_info) in self.libraries:
+            if has_f_sources(build_info.get('sources',[])):
+                return True
+        return False
 
     def have_cxx_sources(self):
-        l = self.languages()
-        return 'c++' in l
+        for (lib_name, build_info) in self.libraries:
+            if has_cxx_sources(build_info.get('sources',[])):
+                return True
+        return False
 
     def run(self):
         if not self.libraries:
             return
 
         # Make sure that library sources are complete.
-        self.run_command('build_src')
+        languages = []
+        for (lib_name, build_info) in self.libraries:
+            if not all_strings(build_info.get('sources',[])):
+                self.run_command('build_src')
+            l = build_info.get('language',None)
+            if l and l not in languages: languages.append(l)
 
-        languages = self.languages()
-
         from distutils.ccompiler import new_compiler
         self.compiler = new_compiler(compiler=self.compiler,
                                      dry_run=self.dry_run,
@@ -88,17 +70,20 @@
         self.compiler.show_customization()
 
         if self.have_f_sources():
-            if 'f90' in languages:
-                fc = self.fcompiler.f90()
-            else:
-                fc = self.fcompiler.f77()
+            from numpy.distutils.fcompiler import new_fcompiler
+            self.fcompiler = new_fcompiler(compiler=self.fcompiler,
+                                           verbose=self.verbose,
+                                           dry_run=self.dry_run,
+                                           force=self.force,
+                                           requiref90='f90' in languages)
+            self.fcompiler.customize(self.distribution)
+
             libraries = self.libraries
             self.libraries = None
-            fc.customize_cmd(self)
+            self.fcompiler.customize_cmd(self)
             self.libraries = libraries
 
-            fc.show_customization()
-            self._fcompiler = fc
+            self.fcompiler.show_customization()
 
         self.build_libraries(self.libraries)
 
@@ -110,10 +95,10 @@
         return filenames
 
     def build_libraries(self, libraries):
-        fcompiler = self._fcompiler
-        compiler = self.compiler
-
         for (lib_name, build_info) in libraries:
+            # default compilers
+            compiler = self.compiler
+            fcompiler = self.fcompiler
 
             sources = build_info.get('sources')
             if sources is None or not is_sequence(sources):
@@ -123,9 +108,21 @@
                        "a list of source filenames") % lib_name
             sources = list(sources)
 
+            c_sources, cxx_sources, f_sources, fmodule_sources \
+                       = filter_sources(sources)
+            requiref90 = not not fmodule_sources or \
+                         build_info.get('language','c')=='f90'
+
+            # save source type information so that build_ext can use it.
+            source_languages = []
+            if c_sources: source_languages.append('c')
+            if cxx_sources: source_languages.append('c++')
+            if requiref90: source_languages.append('f90')
+            elif f_sources: source_languages.append('f77')
+            build_info['source_languages'] = source_languages
+
             lib_file = compiler.library_filename(lib_name,
                                                  output_dir=self.build_clib)
-
             depends = sources + build_info.get('depends',[])
             if not (self.force or newer_group(depends, lib_file, 'newer')):
                 log.debug("skipping '%s' library (up-to-date)", lib_name)
@@ -133,34 +130,42 @@
             else:
                 log.info("building '%s' library", lib_name)
 
-
             config_fc = build_info.get('config_fc',{})
             if fcompiler is not None and config_fc:
                 log.info('using additional config_fc from setup script '\
                          'for fortran compiler: %s' \
                          % (config_fc,))
+                from numpy.distutils.fcompiler import new_fcompiler
+                fcompiler = new_fcompiler(compiler=fcompiler.compiler_type,
+                                          verbose=self.verbose,
+                                          dry_run=self.dry_run,
+                                          force=self.force,
+                                          requiref90=requiref90)
                 dist = self.distribution
                 base_config_fc = dist.get_option_dict('config_fc').copy()
                 base_config_fc.update(config_fc)
                 fcompiler.customize(base_config_fc)
 
+            # check availability of Fortran compilers
+            if (f_sources or fmodule_sources) and fcompiler is None:
+                raise DistutilsError, "library %s has Fortran sources"\
+                      " but no Fortran compiler found" % (lib_name)
+
             macros = build_info.get('macros')
             include_dirs = build_info.get('include_dirs')
             extra_postargs = build_info.get('extra_compiler_args') or []
 
-            c_sources, cxx_sources, f_sources, fmodule_sources \
-                       = filter_sources(sources)
+            # where compiled F90 module files are:
+            module_dirs = build_info.get('module_dirs') or []
+            module_build_dir = os.path.dirname(lib_file)
+            if requiref90: self.mkpath(module_build_dir)
 
-            if self.compiler.compiler_type=='msvc':
+            if compiler.compiler_type=='msvc':
                 # this hack works around the msvc compiler attributes
                 # problem, msvc uses its own convention :(
                 c_sources += cxx_sources
                 cxx_sources = []
 
-            if fmodule_sources:
-                print 'XXX: Fortran 90 module support not implemented or tested'
-                f_sources.extend(fmodule_sources)
-
             objects = []
             if c_sources:
                 log.info("compiling C sources")
@@ -182,20 +187,61 @@
                                                    extra_postargs=extra_postargs)
                 objects.extend(cxx_objects)
 
-            if f_sources:
-                log.info("compiling Fortran sources")
-                f_objects = fcompiler.compile(f_sources,
-                                              output_dir=self.build_temp,
-                                              macros=macros,
-                                              include_dirs=include_dirs,
-                                              debug=self.debug,
-                                              extra_postargs=[])
-                objects.extend(f_objects)
+            if f_sources or fmodule_sources:
+                extra_postargs = []
+                f_objects = []
 
-            self.compiler.create_static_lib(objects, lib_name,
-                                            output_dir=self.build_clib,
-                                            debug=self.debug)
+                if requiref90:
+                    if fcompiler.module_dir_switch is None:
+                        existing_modules = glob('*.mod')
+                    extra_postargs += fcompiler.module_options(\
+                        module_dirs,module_build_dir)
 
+                if fmodule_sources:
+                    log.info("compiling Fortran 90 module sources")
+                    f_objects += fcompiler.compile(fmodule_sources,
+                                                   output_dir=self.build_temp,
+                                                   macros=macros,
+                                                   include_dirs=include_dirs,
+                                                   debug=self.debug,
+                                                   extra_postargs=extra_postargs)
+
+                if requiref90 and self.fcompiler.module_dir_switch is None:
+                    # move new compiled F90 module files to module_build_dir
+                    for f in glob('*.mod'):
+                        if f in existing_modules:
+                            continue
+                        t = os.path.join(module_build_dir, f)
+                        if os.path.abspath(f)==os.path.abspath(t):
+                            continue
+                        if os.path.isfile(t):
+                            os.remove(t)
+                        try:
+                            self.move_file(f, module_build_dir)
+                        except DistutilsFileError:
+                            log.warn('failed to move %r to %r' \
+                                     % (f, module_build_dir))
+
+                if f_sources:
+                    log.info("compiling Fortran sources")
+                    f_objects += fcompiler.compile(f_sources,
+                                                   output_dir=self.build_temp,
+                                                   macros=macros,
+                                                   include_dirs=include_dirs,
+                                                   debug=self.debug,
+                                                   extra_postargs=extra_postargs)
+            else:
+                f_objects = []
+
+            objects.extend(f_objects)
+
+            # assume that default linker is suitable for
+            # linking Fortran object files
+            compiler.create_static_lib(objects, lib_name,
+                                       output_dir=self.build_clib,
+                                       debug=self.debug)
+
+            # fix library dependencies
             clib_libraries = build_info.get('libraries',[])
             for lname, binfo in libraries:
                 if lname in clib_libraries:

Modified: branches/distutils-revamp/command/build_ext.py
===================================================================
--- branches/distutils-revamp/command/build_ext.py	2007-05-21 13:01:20 UTC (rev 3794)
+++ branches/distutils-revamp/command/build_ext.py	2007-05-21 13:15:45 UTC (rev 3795)
@@ -2,26 +2,28 @@
 """
 
 import os
-import string
 import sys
 from glob import glob
 
 from distutils.dep_util import newer_group
 from distutils.command.build_ext import build_ext as old_build_ext
-from distutils.errors import DistutilsFileError, DistutilsSetupError
+from distutils.errors import DistutilsFileError, DistutilsSetupError,\
+     DistutilsError
 from distutils.file_util import copy_file
 
 from numpy.distutils import log
 from numpy.distutils.exec_command import exec_command
 from numpy.distutils.system_info import combine_paths
 from numpy.distutils.misc_util import filter_sources, has_f_sources, \
-     has_cxx_sources, get_ext_source_files, all_strings, \
+     has_cxx_sources, get_ext_source_files, \
      get_numpy_include_dirs, is_sequence
+from numpy.distutils.command.config_compiler import show_fortran_compilers
 
+try:
+    set
+except NameError:
+    from sets import Set as set
 
-def ext_language(ext):
-    return getattr(ext, 'language', 'c')
-
 class build_ext (old_build_ext):
 
     description = "build C/C++/F extensions (compile/link to build directory)"
@@ -31,6 +33,11 @@
          "specify the Fortran compiler type"),
         ]
 
+    help_options = old_build_ext.help_options + [
+        ('help-fcompiler',None, "list available Fortran compilers",
+         show_fortran_compilers),
+        ]
+
     def initialize_options(self):
         old_build_ext.initialize_options(self)
         self.fcompiler = None
@@ -40,45 +47,7 @@
         old_build_ext.finalize_options(self)
         if incl_dirs is not None:
             self.include_dirs.extend(self.distribution.include_dirs or [])
-        self.set_undefined_options('config_fc',
-                                   ('fcompiler', 'fcompiler'))
-        self._fcompiler = None
 
-    def initialize_fcompiler(self, build_clib):
-        # Determine if Fortran compiler is needed.
-        requiref77 = requiref90 = False
-        if build_clib:
-            lang = build_clib.languages()
-            requiref77 = 'f77' in lang
-            requiref90 = 'f90' in lang
-        else:
-            for ext in self.extensions:
-                language = ext_language(ext)
-                if language == 'f77':
-                    requiref77 = True
-                elif language == 'f90':
-                    requiref90 = True
-                elif has_f_sources(ext.sources):
-                    # because we don't know any better, assume F77
-                    requiref77 = True
-
-        if not (requiref77 or requiref90):
-            return
-
-        if requiref90:
-            self.fcompiler.need_f90()
-        if requiref77:
-            self.fcompiler.need_f77()
-
-        fc = self.fcompiler.fortran(requiref90)
-        if fc.get_version():
-            fc.customize_cmd(self)
-            fc.show_customization()
-        else:
-            self.warn('fcompiler=%s is not available.' % (
-                fc.compiler_type,))
-        self._fcompiler = fc
-
     def run(self):
         if not self.extensions:
             return
@@ -86,10 +55,6 @@
         # Make sure that extension sources are complete.
         self.run_command('build_src')
 
-        # Not including C libraries to the list of
-        # extension libraries automatically to prevent
-        # bogus linking commands. Extensions must
-        # explicitly specify the C libraries that they use.
         if self.distribution.has_c_libraries():
             self.run_command('build_clib')
             build_clib = self.get_finalized_command('build_clib')
@@ -97,96 +62,163 @@
         else:
             build_clib = None
 
-        # Determine if C++ compiler is needed.
-        need_cxx_compiler = False
-        for ext in self.extensions:
-            if has_cxx_sources(ext.sources):
-                need_cxx_compiler = True
-                break
-            if getattr(ext,'language','c') == 'c++':
-                need_cxx_compiler = True
-                break
+        # Not including C libraries to the list of
+        # extension libraries automatically to prevent
+        # bogus linking commands. Extensions must
+        # explicitly specify the C libraries that they use.
 
         from distutils.ccompiler import new_compiler
-        self.compiler = new_compiler(compiler=self.compiler,
+        from numpy.distutils.fcompiler import new_fcompiler
+
+        compiler_type = self.compiler
+        # Initialize C compiler:
+        self.compiler = new_compiler(compiler=compiler_type,
                                      verbose=self.verbose,
                                      dry_run=self.dry_run,
                                      force=self.force)
-        self.compiler.customize(self.distribution,need_cxx=need_cxx_compiler)
+        self.compiler.customize(self.distribution)
         self.compiler.customize_cmd(self)
         self.compiler.show_customization()
 
-        self.initialize_fcompiler(build_clib)
+        # Create mapping of libraries built by build_clib:
+        clibs = {}
+        if build_clib is not None:
+            for libname,build_info in build_clib.libraries or []:
+                if clibs.has_key(libname):
+                    log.warn('library %r defined more than once,'\
+                             ' overwriting build_info %r with %r.' \
+                             % (libname, clibs[libname], build_info))
+                clibs[libname] = build_info
+        # .. and distribution libraries:
+        for libname,build_info in self.distribution.libraries or []:
+            if clibs.has_key(libname):
+                # build_clib libraries have a precedence before distribution ones
+                continue
+            clibs[libname] = build_info
 
-        # Build extensions
-        self.build_extensions()
+        # Determine if C++/Fortran 77/Fortran 90 compilers are needed.
+        # Update extension libraries, library_dirs, and macros.
+        all_languages = set()
+        for ext in self.extensions:
+            ext_languages = set()
+            c_libs = []
+            c_lib_dirs = []
+            macros = []
+            for libname in ext.libraries:
+                if clibs.has_key(libname):
+                    binfo = clibs[libname]
+                    c_libs += binfo.get('libraries',[])
+                    c_lib_dirs += binfo.get('library_dirs',[])
+                    for m in binfo.get('macros',[]):
+                        if m not in macros:
+                            macros.append(m)
+                for l in clibs.get(libname,{}).get('source_languages',[]):
+                    ext_languages.add(l)
+            if c_libs:
+                new_c_libs = ext.libraries + c_libs
+                log.info('updating extension %r libraries from %r to %r'
+                         % (ext.name, ext.libraries, new_c_libs))
+                ext.libraries = new_c_libs
+                ext.library_dirs = ext.library_dirs + c_lib_dirs
+            if macros:
+                log.info('extending extension %r defined_macros with %r'
+                         % (ext.name, macros))
+                ext.define_macros = ext.define_macros + macros
 
-    def swig_sources(self, sources):
-        # Do nothing. Swig sources have beed handled in build_src command.
-        return sources
+            # determine extension languages
+            if has_f_sources(ext.sources):
+                ext_languages.add('f77')
+            if has_cxx_sources(ext.sources):
+                ext_languages.add('c++')
+            l = ext.language or self.compiler.detect_language(ext.sources)
+            if l:
+                ext_languages.add(l)
+            # reset language attribute for choosing proper linker
+            if 'c++' in ext_languages:
+                ext_language = 'c++'
+            elif 'f90' in ext_languages:
+                ext_language = 'f90'
+            elif 'f77' in ext_languages:
+                ext_language = 'f77'
+            else:
+                ext_language = 'c' # default
+            if l and l != ext_language and ext.language:
+                log.warn('resetting extension %r language from %r to %r.' %
+                         (ext.name,l,ext_language))
+            ext.language = ext_language
+            # global language
+            all_languages.update(ext_languages)
 
-    def get_fortran_objects(self, ext, f_sources, fmodule_sources,
-                            macros, include_dirs):
-        if not f_sources and not fmodule_sources:
-            return None, []
+        need_f90_compiler = 'f90' in all_languages
+        need_f77_compiler = 'f77' in all_languages
+        need_cxx_compiler = 'c++' in all_languages
 
-        fcompiler = self._fcompiler
+        # Initialize C++ compiler:
+        if need_cxx_compiler:
+            self._cxx_compiler = new_compiler(compiler=compiler_type,
+                                             verbose=self.verbose,
+                                             dry_run=self.dry_run,
+                                             force=self.force)
+            compiler = self._cxx_compiler
+            compiler.customize(self.distribution,need_cxx=need_cxx_compiler)
+            compiler.customize_cmd(self)
+            compiler.show_customization()
+            self._cxx_compiler = compiler.cxx_compiler()
+        else:
+            self._cxx_compiler = None
 
-        extra_postargs = []
-        module_dirs = ext.module_dirs[:]
+        # Initialize Fortran 77 compiler:
+        if need_f77_compiler:
+            self._f77_compiler = new_fcompiler(compiler=self.fcompiler,
+                                               verbose=self.verbose,
+                                               dry_run=self.dry_run,
+                                               force=self.force,
+                                               requiref90=False)
+            fcompiler = self._f77_compiler
+            if fcompiler.get_version():
+                fcompiler.customize(self.distribution)
+                fcompiler.customize_cmd(self)
+                fcompiler.show_customization()
+            else:
+                self.warn('f77_compiler=%s is not available.' %
+                          (fcompiler.compiler_type))
+                self._f77_compiler = None
+        else:
+            self._f77_compiler = None
 
-        macros = []
+        # Initialize Fortran 90 compiler:
+        if need_f90_compiler:
+            self._f90_compiler = new_fcompiler(compiler=self.fcompiler,
+                                               verbose=self.verbose,
+                                               dry_run=self.dry_run,
+                                               force=self.force,
+                                               requiref90=True)
+            fcompiler = self._f90_compiler
+            if fcompiler.get_version():
+                fcompiler.customize(self.distribution)
+                fcompiler.customize_cmd(self)
+                fcompiler.show_customization()
+            else:
+                self.warn('f90_compiler=%s is not available.' %
+                          (fcompiler.compiler_type))
+                self._f90_compiler = None
+        else:
+            self._f90_compiler = None
 
-        if fmodule_sources:
-            module_build_dir = os.path.join(
-                self.build_temp,os.path.dirname(
-                self.get_ext_filename(fullname)))
+        # Build extensions
+        self.build_extensions()
 
-            self.mkpath(module_build_dir)
-            if fcompiler.module_dir_switch is None:
-                existing_modules = glob('*.mod')
-            extra_postargs += fcompiler.module_options(\
-                module_dirs,module_build_dir)
+    def swig_sources(self, sources):
+        # Do nothing. Swig sources have beed handled in build_src command.
+        return sources
 
-        f_objects = []
-        if fmodule_sources:
-            log.info("compiling Fortran 90 module sources")
-            f_objects = fcompiler.compile(fmodule_sources,
-                                          output_dir=self.build_temp,
-                                          macros=macros,
-                                          include_dirs=include_dirs,
-                                          debug=self.debug,
-                                          extra_postargs=extra_postargs,
-                                          depends=ext.depends)
-
-        if fmodule_sources and fcompiler.module_dir_switch is None:
-            for f in glob('*.mod'):
-                if f in existing_modules:
-                    continue
-                try:
-                    self.move_file(f, module_build_dir)
-                except DistutilsFileError:  # already exists in destination
-                    os.remove(f)
-
-        if f_sources:
-            log.info("compiling Fortran sources")
-            f_objects += fcompiler.compile(f_sources,
-                                           output_dir=self.build_temp,
-                                           macros=macros,
-                                           include_dirs=include_dirs,
-                                           debug=self.debug,
-                                           extra_postargs=extra_postargs,
-                                           depends=ext.depends)
-
-        return fcompiler, f_objects
-
     def build_extension(self, ext):
         sources = ext.sources
         if sources is None or not is_sequence(sources):
-            raise DistutilsSetupError, \
-                  ("in 'ext_modules' option (extension '%s'), " +
-                   "'sources' must be present and must be " +
-                   "a list of source filenames") % ext.name
+            raise DistutilsSetupError(
+                ("in 'ext_modules' option (extension '%s'), " +
+                 "'sources' must be present and must be " +
+                 "a list of source filenames") % ext.name)
         sources = list(sources)
 
         if not sources:
@@ -194,10 +226,9 @@
 
         fullname = self.get_ext_fullname(ext.name)
         if self.inplace:
-            modpath = string.split(fullname, '.')
-            package = string.join(modpath[0:-1], '.')
+            modpath = fullname.split('.')
+            package = '.'.join(modpath[0:-1])
             base = modpath[-1]
-
             build_py = self.get_finalized_command('build_py')
             package_dir = build_py.get_package_dir(package)
             ext_filename = os.path.join(package_dir,
@@ -218,17 +249,11 @@
         for undef in ext.undef_macros:
             macros.append((undef,))
 
-        clib_libraries = []
-        clib_library_dirs = []
-        if self.distribution.libraries:
-            for libname,build_info in self.distribution.libraries:
-                if libname in ext.libraries:
-                    macros.extend(build_info.get('macros',[]))
-                    clib_libraries.extend(build_info.get('libraries',[]))
-                    clib_library_dirs.extend(build_info.get('library_dirs',[]))
-
         c_sources, cxx_sources, f_sources, fmodule_sources = \
                    filter_sources(ext.sources)
+
+
+
         if self.compiler.compiler_type=='msvc':
             if cxx_sources:
                 # Needed to compile kiva.agg._agg extension.
@@ -238,7 +263,29 @@
             c_sources += cxx_sources
             cxx_sources = []
 
+        # Set Fortran/C++ compilers for compilation and linking.
+        if ext.language=='f90':
+            fcompiler = self._f90_compiler
+        elif ext.language=='f77':
+            fcompiler = self._f77_compiler
+        else: # in case ext.language is c++, for instance
+            fcompiler = self._f90_compiler or self._f77_compiler
+        cxx_compiler = self._cxx_compiler
 
+        # check for the availability of required compilers
+        if cxx_sources and cxx_compiler is None:
+            raise DistutilsError, "extension %r has C++ sources" \
+                  "but no C++ compiler found" % (ext.name)
+        if (f_sources or fmodule_sources) and fcompiler is None:
+            raise DistutilsError, "extension %r has Fortran sources " \
+                  "but no Fortran compiler found" % (ext.name)
+        if ext.language in ['f77','f90'] and fcompiler is None:
+            self.warn("extension %r has Fortran libraries " \
+                  "but no Fortran linker found, using default linker" % (ext.name))
+        if ext.language=='c++' and cxx_compiler is None:
+            self.warn("extension %r has C++ libraries " \
+                  "but no C++ linker found, using default linker" % (ext.name))
+
         kws = {'depends':ext.depends}
         output_dir = self.build_temp
 
@@ -254,11 +301,9 @@
                                               debug=self.debug,
                                               extra_postargs=extra_args,
                                               **kws)
+
         if cxx_sources:
             log.info("compiling C++ sources")
-
-            cxx_compiler = self.compiler.cxx_compiler()
-
             c_objects += cxx_compiler.compile(cxx_sources,
                                               output_dir=output_dir,
                                               macros=macros,
@@ -267,80 +312,117 @@
                                               extra_postargs=extra_args,
                                               **kws)
 
-        fcompiler, f_objects = self.get_fortran_objects(ext,
-                                                        f_sources,
-                                                        fmodule_sources,
-                                                        macros, include_dirs)
+        extra_postargs = []
+        f_objects = []
+        if fmodule_sources:
+            log.info("compiling Fortran 90 module sources")
+            module_dirs = ext.module_dirs[:]
+            module_build_dir = os.path.join(
+                self.build_temp,os.path.dirname(
+                    self.get_ext_filename(fullname)))
 
+            self.mkpath(module_build_dir)
+            if fcompiler.module_dir_switch is None:
+                existing_modules = glob('*.mod')
+            extra_postargs += fcompiler.module_options(
+                module_dirs,module_build_dir)
+            f_objects += fcompiler.compile(fmodule_sources,
+                                           output_dir=self.build_temp,
+                                           macros=macros,
+                                           include_dirs=include_dirs,
+                                           debug=self.debug,
+                                           extra_postargs=extra_postargs,
+                                           depends=ext.depends)
+
+            if fcompiler.module_dir_switch is None:
+                for f in glob('*.mod'):
+                    if f in existing_modules:
+                        continue
+                    t = os.path.join(module_build_dir, f)
+                    if os.path.abspath(f)==os.path.abspath(t):
+                        continue
+                    if os.path.isfile(t):
+                        os.remove(t)
+                    try:
+                        self.move_file(f, module_build_dir)
+                    except DistutilsFileError:
+                        log.warn('failed to move %r to %r' %
+                                 (f, module_build_dir))
+        if f_sources:
+            log.info("compiling Fortran sources")
+            f_objects += fcompiler.compile(f_sources,
+                                           output_dir=self.build_temp,
+                                           macros=macros,
+                                           include_dirs=include_dirs,
+                                           debug=self.debug,
+                                           extra_postargs=extra_postargs,
+                                           depends=ext.depends)
+
         objects = c_objects + f_objects
 
         if ext.extra_objects:
             objects.extend(ext.extra_objects)
         extra_args = ext.extra_link_args or []
+        libraries = self.get_libraries(ext)[:]
+        library_dirs = ext.library_dirs[:]
 
         linker = self.compiler.link_shared_object
-
-        use_fortran_linker = getattr(ext,'language','c') in ['f77','f90']
-        c_libraries = []
-        c_library_dirs = []
-        if not use_fortran_linker and self.distribution.has_c_libraries():
-            build_clib = self.get_finalized_command('build_clib')
-            f_libs = []
-            for (lib_name, build_info) in build_clib.libraries:
-                if has_f_sources(build_info.get('sources',[])):
-                    f_libs.append(lib_name)
-                if lib_name in ext.libraries:
-                    # XXX: how to determine if c_libraries contain
-                    # fortran compiled sources?
-                    c_libraries.extend(build_info.get('libraries',[]))
-                    c_library_dirs.extend(build_info.get('library_dirs',[]))
-            for l in ext.libraries:
-                if l in f_libs:
-                    use_fortran_linker = True
-                    fcompiler = self.fcompiler.fortran()
-                    break
-
-        if use_fortran_linker and not fcompiler:
-            fcompiler = self.fcompiler.fortran()
-
         # Always use system linker when using MSVC compiler.
-        if self.compiler.compiler_type=='msvc' and use_fortran_linker:
-            self._libs_with_msvc_and_fortran(c_libraries, c_library_dirs)
-            use_fortran_linker = False
-
-        if use_fortran_linker:
-            if cxx_sources:
-                # XXX: Which linker should be used, Fortran or C++?
-                log.warn('mixing Fortran and C++ is untested')
+        if self.compiler.compiler_type=='msvc':
+            # expand libraries with fcompiler libraries as we are
+            # not using fcompiler linker
+            self._libs_with_msvc_and_fortran(fcompiler, libraries, library_dirs)
+        elif ext.language in ['f77','f90'] and fcompiler is not None:
             linker = fcompiler.link_shared_object
-            language = ext.language or fcompiler.detect_language(f_sources)
-        else:
-            linker = self.compiler.link_shared_object
-            if sys.version[:3]>='2.3':
-                language = ext.language or self.compiler.detect_language(sources)
-            else:
-                language = ext.language
-            if cxx_sources:
-                linker = self.compiler.cxx_compiler().link_shared_object
+        if ext.language=='c++' and cxx_compiler is not None:
+            linker = cxx_compiler.link_shared_object
 
         if sys.version[:3]>='2.3':
-            kws = {'target_lang':language}
+            kws = {'target_lang':ext.language}
         else:
             kws = {}
 
         linker(objects, ext_filename,
-               libraries=self.get_libraries(ext) + c_libraries + clib_libraries,
-               library_dirs=ext.library_dirs+c_library_dirs+clib_library_dirs,
+               libraries=libraries,
+               library_dirs=library_dirs,
                runtime_library_dirs=ext.runtime_library_dirs,
                extra_postargs=extra_args,
                export_symbols=self.get_export_symbols(ext),
                debug=self.debug,
                build_temp=self.build_temp,**kws)
 
-    def _libs_with_msvc_and_fortran(self, c_libraries, c_library_dirs):
+    def _libs_with_msvc_and_fortran(self, fcompiler, c_libraries,
+                                    c_library_dirs):
+        if fcompiler is None: return
+
+        for libname in c_libraries:
+            if libname.startswith('msvc'): continue
+            fileexists = False
+            for libdir in c_library_dirs or []:
+                libfile = os.path.join(libdir,'%s.lib' % (libname))
+                if os.path.isfile(libfile):
+                    fileexists = True
+                    break
+            if fileexists: continue
+            # make g77-compiled static libs available to MSVC
+            fileexists = False
+            for libdir in c_library_dirs:
+                libfile = os.path.join(libdir,'lib%s.a' % (libname))
+                if os.path.isfile(libfile):
+                    # copy libname.a file to name.lib so that MSVC linker
+                    # can find it
+                    libfile2 = os.path.join(self.build_temp, libname + '.lib')
+                    copy_file(libfile, libfile2)
+                    if self.build_temp not in c_library_dirs:
+                        c_library_dirs.append(self.build_temp)
+                    fileexists = True
+                    break
+            if fileexists: continue
+            log.warn('could not find library %r in directories %s'
+                     % (libname, c_library_dirs))
+
         # Always use system linker when using MSVC compiler.
         f_lib_dirs = []
-        fcompiler = self.fcompiler.fortran()
         for dir in fcompiler.library_dirs:
             # correct path when compiling in Cygwin but with normal Win
             # Python
@@ -352,17 +434,16 @@
         c_library_dirs.extend(f_lib_dirs)
 
         # make g77-compiled static libs available to MSVC
-        lib_added = False
         for lib in fcompiler.libraries:
-            if not lib.startswith('msvcr'):
+            if not lib.startswith('msvc'):
                 c_libraries.append(lib)
                 p = combine_paths(f_lib_dirs, 'lib' + lib + '.a')
                 if p:
                     dst_name = os.path.join(self.build_temp, lib + '.lib')
-                    copy_file(p[0], dst_name)
-                    if not lib_added:
+                    if not os.path.isfile(dst_name):
+                        copy_file(p[0], dst_name)
+                    if self.build_temp not in c_library_dirs:
                         c_library_dirs.append(self.build_temp)
-                        lib_added = True
 
     def get_source_files (self):
         self.check_extensions_list(self.extensions)

Modified: branches/distutils-revamp/command/build_src.py
===================================================================
--- branches/distutils-revamp/command/build_src.py	2007-05-21 13:01:20 UTC (rev 3794)
+++ branches/distutils-revamp/command/build_src.py	2007-05-21 13:15:45 UTC (rev 3795)
@@ -8,6 +8,7 @@
 from distutils.command import build_ext
 from distutils.dep_util import newer_group, newer
 from distutils.util import get_platform
+from distutils.errors import DistutilsError, DistutilsSetupError
 
 try:
     from Pyrex.Compiler import Main
@@ -23,6 +24,7 @@
      appendpath, is_string, is_sequence
 from numpy.distutils.from_template import process_file as process_f_file
 from numpy.distutils.conv_template import process_file as process_c_file
+from numpy.distutils.exec_command import splitcmdline
 
 class build_src(build_ext.build_ext):
 
@@ -30,8 +32,12 @@
 
     user_options = [
         ('build-src=', 'd', "directory to \"build\" sources to"),
-        ('f2pyflags=', None, "additonal flags to f2py"),
-        ('swigflags=', None, "additional flags to swig"),
+        ('f2py-opts=', None, "list of f2py command line options"),
+        ('swig=', None, "path to the SWIG executable"),
+        ('swig-opts=', None, "list of SWIG command line options"),
+        ('swig-cpp', None, "make SWIG create C++ files (default is autodetected from sources)"),
+        ('f2pyflags=', None, "additional flags to f2py (use --f2py-opts= instead)"), # obsolete
+        ('swigflags=', None, "additional flags to swig (use --swig-opts= instead)"), # obsolete
         ('force', 'f', "forcibly build everything (ignore file timestamps)"),
         ('inplace', 'i',
          "ignore build-lib and put compiled extensions into the source " +
@@ -53,8 +59,12 @@
         self.force = None
         self.inplace = None
         self.package_dir = None
-        self.f2pyflags = None
-        self.swigflags = None
+        self.f2pyflags = None # obsolete
+        self.f2py_opts = None
+        self.swigflags = None # obsolete
+        self.swig_opts = None
+        self.swig_cpp = None
+        self.swig = None
 
     def finalize_options(self):
         self.set_undefined_options('build',
@@ -71,23 +81,49 @@
         if self.build_src is None:
             plat_specifier = ".%s-%s" % (get_platform(), sys.version[0:3])
             self.build_src = os.path.join(self.build_base, 'src'+plat_specifier)
-        if self.inplace is None:
-            build_ext = self.get_finalized_command('build_ext')
-            self.inplace = build_ext.inplace
 
         # py_modules_dict is used in build_py.find_package_modules
         self.py_modules_dict = {}
 
-        if self.f2pyflags is None:
-            self.f2pyflags = []
+        if self.f2pyflags:
+            if self.f2py_opts:
+                log.warn('ignoring --f2pyflags as --f2py-opts already used')
+            else:
+                self.f2py_opts = self.f2pyflags
+            self.f2pyflags = None
+        if self.f2py_opts is None:
+            self.f2py_opts = []
         else:
-            self.f2pyflags = self.f2pyflags.split() # XXX spaces??
+            self.f2py_opts = splitcmdline(self.f2py_opts)
 
-        if self.swigflags is None:
-            self.swigflags = []
+        if self.swigflags:
+            if self.swig_opts:
+                log.warn('ignoring --swigflags as --swig-opts already used')
+            else:
+                self.swig_opts = self.swigflags
+            self.swigflags = None
+
+        if self.swig_opts is None: 
+            self.swig_opts = []
         else:
-            self.swigflags = self.swigflags.split() # XXX spaces??
+            self.swig_opts = splitcmdline(self.swig_opts)
 
+        # use options from build_ext command
+        build_ext = self.get_finalized_command('build_ext')
+        if self.inplace is None:
+            self.inplace = build_ext.inplace
+        if self.swig_cpp is None:
+            self.swig_cpp = build_ext.swig_cpp
+        for c in ['swig','swig_opt']:
+            o = '--'+c.replace('_','-')
+            v = getattr(build_ext,c,None) 
+            if v:
+                if getattr(self,c):
+                    log.warn('both build_src and build_ext define %s option' % (o))
+                else:
+                    log.info('using "%s=%s" option from build_ext command' % (o,v))
+                    setattr(self, c, v)
+
     def run(self):
         if not (self.extensions or self.libraries):
             return
@@ -144,7 +180,7 @@
                 filenames = get_data_files((d,files))
                 new_data_files.append((d, filenames))
             else:
-                raise
+                raise TypeError(repr(data))
         self.data_files[:] = new_data_files
 
     def build_py_modules_sources(self):
@@ -354,16 +390,14 @@
                             output_file=target_file)
                         pyrex_result = Main.compile(source, options=options)
                         if pyrex_result.num_errors != 0:
-                            raise RuntimeError("%d errors in Pyrex compile" %
-                                               pyrex_result.num_errors)
+                            raise DistutilsError,"%d errors while compiling %r with Pyrex" \
+                                  % (pyrex_result.num_errors, source)
                     elif os.path.isfile(target_file):
-                        log.warn("Pyrex needed to compile %s but not available."\
-                                 " Using old target %s"\
+                        log.warn("Pyrex required for compiling %r but not available,"\
+                                 " using old target %r"\
                                  % (source, target_file))
                     else:
-                        raise SystemError,"Non-existing target %r. "\
-                              "Perhaps you need to install Pyrex."\
-                              % (target_file)
+                        raise DistutilsError,"Pyrex required for compiling %r but not available" % (source)
                 new_sources.append(target_file)
             else:
                 new_sources.append(source)
@@ -388,9 +422,9 @@
                 if os.path.isfile(source):
                     name = get_f2py_modulename(source)
                     if name != ext_name:
-                        raise ValueError('mismatch of extension names: %s '
-                                         'provides %r but expected %r' % (
-                                          source, name, ext_name))
+                        raise DistutilsSetupError('mismatch of extension names: %s '
+                                                  'provides %r but expected %r' % (
+                            source, name, ext_name))
                     target_file = os.path.join(target_dir,name+'module.c')
                 else:
                     log.debug('  source %s does not exist: skipping f2py\'ing.' \
@@ -399,16 +433,16 @@
                     skip_f2py = 1
                     target_file = os.path.join(target_dir,name+'module.c')
                     if not os.path.isfile(target_file):
-                        log.debug('  target %s does not exist:\n   '\
-                                  'Assuming %smodule.c was generated with '\
-                                  '"build_src --inplace" command.' \
-                                  % (target_file, name))
+                        log.warn('  target %s does not exist:\n   '\
+                                 'Assuming %smodule.c was generated with '\
+                                 '"build_src --inplace" command.' \
+                                 % (target_file, name))
                         target_dir = os.path.dirname(base)
                         target_file = os.path.join(target_dir,name+'module.c')
                         if not os.path.isfile(target_file):
-                            raise ValueError("%r missing" % (target_file,))
-                        log.debug('   Yes! Using %s as up-to-date target.' \
-                                  % (target_file))
+                            raise DistutilsSetupError("%r missing" % (target_file,))
+                        log.info('   Yes! Using %r as up-to-date target.' \
+                                 % (target_file))
                 target_dirs.append(target_dir)
                 f2py_sources.append(source)
                 f2py_targets[source] = target_file
@@ -423,7 +457,7 @@
 
         map(self.mkpath, target_dirs)
 
-        f2py_options = extension.f2py_options + self.f2pyflags
+        f2py_options = extension.f2py_options + self.f2py_opts
 
         if self.distribution.libraries:
             for name,build_info in self.distribution.libraries:
@@ -434,7 +468,7 @@
 
         if f2py_sources:
             if len(f2py_sources) != 1:
-                raise ValueError(
+                raise DistutilsSetupError(
                     'only one .pyf file is allowed per extension module but got'\
                     ' more: %r' % (f2py_sources,))
             source = f2py_sources[0]
@@ -472,7 +506,7 @@
                           % (target_file))
 
         if not os.path.isfile(target_file):
-            raise ValueError("%r missing" % (target_file,))
+            raise DistutilsError("f2py target file %r not generated" % (target_file,))
 
         target_c = os.path.join(self.build_src,'fortranobject.c')
         target_h = os.path.join(self.build_src,'fortranobject.h')
@@ -494,9 +528,9 @@
                 self.copy_file(source_h,target_h)
         else:
             if not os.path.isfile(target_c):
-                raise ValueError("%r missing" % (target_c,))
+                raise DistutilsSetupError("f2py target_c file %r not found" % (target_c,))
             if not os.path.isfile(target_h):
-                raise ValueError("%r missing" % (target_h,))
+                raise DistutilsSetupError("f2py target_h file %r not found" % (target_h,))
 
         for name_ext in ['-f2pywrappers.f','-f2pywrappers2.f90']:
             filename = os.path.join(target_dir,ext_name + name_ext)
@@ -516,8 +550,12 @@
         target_dirs = []
         py_files = []     # swig generated .py files
         target_ext = '.c'
-        typ = None
-        is_cpp = 0
+        if self.swig_cpp:
+            typ = 'c++'
+            is_cpp = True
+        else:
+            typ = None
+            is_cpp = False
         skip_swig = 0
         ext_name = extension.name.split('.')[-1]
 
@@ -533,35 +571,43 @@
                 if os.path.isfile(source):
                     name = get_swig_modulename(source)
                     if name != ext_name[1:]:
-                        raise ValueError(
+                        raise DistutilsSetupError(
                             'mismatch of extension names: %s provides %r'
                             ' but expected %r' % (source, name, ext_name[1:]))
                     if typ is None:
                         typ = get_swig_target(source)
                         is_cpp = typ=='c++'
-                        if is_cpp:
-                            target_ext = '.cpp'
+                        if is_cpp: target_ext = '.cpp'
                     else:
-                        assert typ == get_swig_target(source), repr(typ)
+                        typ2 = get_swig_target(source)
+                        if typ!=typ2:
+                            log.warn('expected %r but source %r defines %r swig target' \
+                                     % (typ, source, typ2))
+                            if typ2=='c++':
+                                log.warn('resetting swig target to c++ (some targets may have .c extension)')
+                                is_cpp = True
+                                target_ext = '.cpp'
+                            else:
+                                log.warn('assuming that %r has c++ swig target' % (source))
                     target_file = os.path.join(target_dir,'%s_wrap%s' \
                                                % (name, target_ext))
                 else:
-                    log.debug('  source %s does not exist: skipping swig\'ing.' \
+                    log.warn('  source %s does not exist: skipping swig\'ing.' \
                              % (source))
                     name = ext_name[1:]
                     skip_swig = 1
                     target_file = _find_swig_target(target_dir, name)
                     if not os.path.isfile(target_file):
-                        log.debug('  target %s does not exist:\n   '\
-                                  'Assuming %s_wrap.{c,cpp} was generated with '\
-                                  '"build_src --inplace" command.' \
+                        log.warn('  target %s does not exist:\n   '\
+                                 'Assuming %s_wrap.{c,cpp} was generated with '\
+                                 '"build_src --inplace" command.' \
                                  % (target_file, name))
                         target_dir = os.path.dirname(base)
                         target_file = _find_swig_target(target_dir, name)
                         if not os.path.isfile(target_file):
-                            raise ValueError("%r missing" % (target_file,))
-                        log.debug('   Yes! Using %s as up-to-date target.' \
-                                  % (target_file))
+                            raise DistutilsSetupError("%r missing" % (target_file,))
+                        log.warn('   Yes! Using %r as up-to-date target.' \
+                                 % (target_file))
                 target_dirs.append(target_dir)
                 new_sources.append(target_file)
                 py_files.append(os.path.join(py_target_dir, name+'.py'))
@@ -577,7 +623,7 @@
             return new_sources + py_files
 
         map(self.mkpath, target_dirs)
-        swig = self.find_swig()
+        swig = self.swig or self.find_swig()
         swig_cmd = [swig, "-python"]
         if is_cpp:
             swig_cmd.append('-c++')
@@ -589,7 +635,7 @@
             if self.force or newer_group(depends, target, 'newer'):
                 log.info("%s: %s" % (os.path.basename(swig) \
                                      + (is_cpp and '++' or ''), source))
-                self.spawn(swig_cmd + self.swigflags \
+                self.spawn(swig_cmd + self.swig_opts \
                            + ["-o", target, '-outdir', py_target_dir, source])
             else:
                 log.debug("  skipping '%s' swig interface (up-to-date)" \

Modified: branches/distutils-revamp/command/config.py
===================================================================
--- branches/distutils-revamp/command/config.py	2007-05-21 13:01:20 UTC (rev 3794)
+++ branches/distutils-revamp/command/config.py	2007-05-21 13:15:45 UTC (rev 3795)
@@ -3,56 +3,41 @@
 # compilers (they must define linker_exe first).
 # Pearu Peterson
 
-import os, signal, copy
+import os, signal
 from distutils.command.config import config as old_config
 from distutils.command.config import LANG_EXT
 from distutils import log
+from distutils.file_util import copy_file
 from numpy.distutils.exec_command import exec_command
-from numpy.distutils.fcompiler import FCompiler, new_fcompiler
 
 LANG_EXT['f77'] = '.f'
 LANG_EXT['f90'] = '.f90'
 
 class config(old_config):
     old_config.user_options += [
-        ('fcompiler=', None,
-         "specify the Fortran compiler type"),
+        ('fcompiler=', None, "specify the Fortran compiler type"),
         ]
 
     def initialize_options(self):
         self.fcompiler = None
         old_config.initialize_options(self)
 
-    def finalize_options(self):
-        old_config.finalize_options(self)
-        f = self.distribution.get_command_obj('config_fc')
-        self.set_undefined_options('config_fc',
-                                   ('fcompiler', 'fcompiler'))
-        self._fcompiler = None
-
-    def run(self):
-        self._check_compiler()
-
-    def _check_compiler(self):
+    def _check_compiler (self):
         old_config._check_compiler(self)
+        from numpy.distutils.fcompiler import FCompiler, new_fcompiler
+        if not isinstance(self.fcompiler, FCompiler):
+            self.fcompiler = new_fcompiler(compiler=self.fcompiler,
+                                           dry_run=self.dry_run, force=1)
+            self.fcompiler.customize(self.distribution)
+            self.fcompiler.customize_cmd(self)
+            self.fcompiler.show_customization()
 
-    def get_fcompiler(self):
-        if self._fcompiler is None:
-            fc = self.fcompiler.fortran()
-            fc.force = 1
-            fc.dry_run = self.dry_run
-            fc.customize(self.distribution)
-            fc.customize_cmd(self)
-            fc.show_customization()
-            self._fcompiler = fc
-        return self._fcompiler
-
-    def _wrap_method(self, mth, lang, args):
+    def _wrap_method(self,mth,lang,args):
         from distutils.ccompiler import CompileError
         from distutils.errors import DistutilsExecError
         save_compiler = self.compiler
-        if lang in ('f77', 'f90'):
-            self.compiler = self.get_fcompiler()
+        if lang in ['f77','f90']:
+            self.compiler = self.fcompiler
         try:
             ret = mth(*((self,)+args))
         except (DistutilsExecError,CompileError),msg:
@@ -68,6 +53,47 @@
     def _link (self, body,
                headers, include_dirs,
                libraries, library_dirs, lang):
+        if self.compiler.compiler_type=='msvc':
+            libraries = (libraries or [])[:]
+            library_dirs = (library_dirs or [])[:]
+            if lang in ['f77','f90']:
+                lang = 'c' # always use system linker when using MSVC compiler
+                if self.fcompiler:
+                    for d in self.fcompiler.library_dirs or []:
+                        # correct path when compiling in Cygwin but with
+                        # normal Win Python
+                        if d.startswith('/usr/lib'):
+                            s,o = exec_command(['cygpath', '-w', d],
+                                               use_tee=False)
+                            if not s: d = o
+                        library_dirs.append(d)
+                    for libname in self.fcompiler.libraries or []:
+                        if libname not in libraries:
+                            libraries.append(libname)
+            for libname in libraries:
+                if libname.startswith('msvc'): continue
+                fileexists = False
+                for libdir in library_dirs or []:
+                    libfile = os.path.join(libdir,'%s.lib' % (libname))
+                    if os.path.isfile(libfile):
+                        fileexists = True
+                        break
+                if fileexists: continue
+                # make g77-compiled static libs available to MSVC
+                fileexists = False
+                for libdir in library_dirs:
+                    libfile = os.path.join(libdir,'lib%s.a' % (libname))
+                    if os.path.isfile(libfile):
+                        # copy libname.a file to name.lib so that MSVC linker
+                        # can find it
+                        libfile2 = os.path.join(libdir,'%s.lib' % (libname))
+                        copy_file(libfile, libfile2)
+                        self.temp_files.append(libfile2)
+                        fileexists = True
+                        break
+                if fileexists: continue
+                log.warn('could not find library %r in directories %s' \
+                         % (libname, library_dirs))
         return self._wrap_method(old_config._link,lang,
                                  (body, headers, include_dirs,
                                   libraries, library_dirs, lang))

Modified: branches/distutils-revamp/command/config_compiler.py
===================================================================
--- branches/distutils-revamp/command/config_compiler.py	2007-05-21 13:01:20 UTC (rev 3794)
+++ branches/distutils-revamp/command/config_compiler.py	2007-05-21 13:15:45 UTC (rev 3795)
@@ -1,81 +1,18 @@
 import sys
-import copy
-import distutils.core
 from distutils.core import Command
-from distutils.errors import DistutilsSetupError
-from distutils import log
-from numpy.distutils.fcompiler import show_fcompilers, new_fcompiler
+from numpy.distutils import log
 
-#XXX: Implement confic_cc for enhancing C/C++ compiler options.
 #XXX: Linker flags
 
 def show_fortran_compilers(_cache=[]):
     # Using cache to prevent infinite recursion
-    if _cache:
-        return
+    if _cache: return
     _cache.append(1)
-    show_fcompilers()
+    from numpy.distutils.fcompiler import show_fcompilers
+    import distutils.core
+    dist = distutils.core._setup_distribution
+    show_fcompilers(dist)
 
-class FCompilerProxy(object):
-    """
-    A layer of indirection to simplify choosing the correct Fortran compiler.
-
-    If need_f90(), f90(), or fortran(requiref90=True) is called at any time,
-    a Fortran 90 compiler is found and used for *all* Fortran sources,
-    including Fortran 77 sources.
-    """
-    #XXX The ability to use a separate F77 compiler is likely not
-    # necessary: of all the compilers we support, only the 'gnu'
-    # compiler (g77) doesn't support F90, and everything else supports
-    # both.
-
-    def __init__(self, compiler_type, distribution):
-        self._fcompiler = None
-        self._have_f77 = None
-        self._have_f90 = None
-        self._compiler_type = compiler_type
-        self.distribution = distribution
-
-    def _set_fcompiler(self, requiref90=False):
-        fc = new_fcompiler(compiler=self._compiler_type,
-                           dry_run=self.distribution.dry_run,
-                           verbose=self.distribution.verbose,
-                           requiref90=requiref90)
-        if fc is None:
-            raise DistutilsSetupError("could not find a Fortran compiler")
-        fc.customize(self.distribution)
-        self._fcompiler = fc
-        self._have_f77 = fc.compiler_f77 is not None
-        if requiref90:
-            self._have_f90 = fc.compiler_f90 is not None
-        log.info('%s (%s)' % (fc.description, fc.get_version()))
-
-    def need_f77(self):
-        if self._fcompiler is None:
-            self._set_fcompiler(requiref90=False)
-        if not self._have_f77:
-            raise DistutilsSetupError("could not find a Fortran 77 compiler")
-
-    def need_f90(self):
-        if self._fcompiler is None or self._have_f90 is None:
-            self._set_fcompiler(requiref90=True)
-        if not self._have_f90:
-            raise DistutilsSetupError("could not find a Fortran 90 compiler")
-
-    def f77(self):
-        self.need_f77()
-        return copy.copy(self._fcompiler)
-
-    def f90(self):
-        self.need_f90()
-        return copy.copy(self._fcompiler)
-
-    def fortran(self, requiref90=False):
-        if requiref90:
-            return self.f90()
-        else:
-            return self.f77()
-
 class config_fc(Command):
     """ Distutils command to hold user specified options
     to Fortran compilers.
@@ -83,24 +20,19 @@
     config_fc command is used by the FCompiler.customize() method.
     """
 
+    description = "specify Fortran 77/Fortran 90 compiler information"
+
     user_options = [
         ('fcompiler=',None,"specify Fortran compiler type"),
         ('f77exec=', None, "specify F77 compiler command"),
         ('f90exec=', None, "specify F90 compiler command"),
         ('f77flags=',None,"specify F77 compiler flags"),
         ('f90flags=',None,"specify F90 compiler flags"),
-        ('ldshared=',None,"shared-library linker command"),
-        ('ld=',None,"static library linker command"),
-        ('ar=',None,"archiver command (ar)"),
-        ('ranlib=',None,"ranlib command"),
         ('opt=',None,"specify optimization flags"),
         ('arch=',None,"specify architecture specific optimization flags"),
         ('debug','g',"compile with debugging information"),
         ('noopt',None,"compile without optimization"),
         ('noarch',None,"compile without arch-dependent optimization"),
-        ('fflags=',None,"extra flags for Fortran compiler"),
-        ('ldflags=',None,"linker flags"),
-        ('arflags=',None,"flags for ar"),
         ]
 
     help_options = [
@@ -116,21 +48,77 @@
         self.f90exec = None
         self.f77flags = None
         self.f90flags = None
-        self.ldshared = None
-        self.ld = None
-        self.ar = None
-        self.ranlib = None
         self.opt = None
         self.arch = None
         self.debug = None
         self.noopt = None
         self.noarch = None
-        self.fflags = None
-        self.ldflags = None
-        self.arflags = None
 
     def finalize_options(self):
-        self.fcompiler = FCompilerProxy(self.fcompiler, self.distribution)
+        log.info('unifing config_fc, config, build_clib, build_ext, build commands --fcompiler options')
+        build_clib = self.get_finalized_command('build_clib')
+        build_ext = self.get_finalized_command('build_ext')
+        config = self.get_finalized_command('config')
+        build = self.get_finalized_command('build')
+        cmd_list = [self, config, build_clib, build_ext, build]
+        for a in ['fcompiler']:
+            l = []
+            for c in cmd_list:
+                v = getattr(c,a)
+                if v is not None:
+                    if not isinstance(v, str): v = v.compiler_type
+                    if v not in l: l.append(v)
+            if not l: v1 = None
+            else: v1 = l[0]
+            if len(l)>1:
+                log.warn('  commands have different --%s options: %s'\
+                         ', using first in list as default' % (a, l))
+            if v1:
+                for c in cmd_list:
+                    if getattr(c,a) is None: setattr(c, a, v1)
 
     def run(self):
-        pass
+        # Do nothing.
+        return
+
+class config_cc(Command):
+    """ Distutils command to hold user specified options
+    to C/C++ compilers.
+    """
+
+    description = "specify C/C++ compiler information"
+
+    user_options = [
+        ('compiler=',None,"specify C/C++ compiler type"),
+        ]
+
+    def initialize_options(self):
+        self.compiler = None
+
+    def finalize_options(self):
+        log.info('unifing config_cc, config, build_clib, build_ext, build commands --compiler options')
+        build_clib = self.get_finalized_command('build_clib')
+        build_ext = self.get_finalized_command('build_ext')
+        config = self.get_finalized_command('config')
+        build = self.get_finalized_command('build')
+        cmd_list = [self, config, build_clib, build_ext, build]
+        for a in ['compiler']:
+            l = []
+            for c in cmd_list:
+                v = getattr(c,a)
+                if v is not None:
+                    if not isinstance(v, str): v = v.compiler_type
+                    if v not in l: l.append(v)
+            if not l: v1 = None
+            else: v1 = l[0]
+            if len(l)>1:
+                log.warn('  commands have different --%s options: %s'\
+                         ', using first in list as default' % (a, l))
+            if v1:
+                for c in cmd_list:
+                    if getattr(c,a) is None: setattr(c, a, v1)
+        return
+
+    def run(self):
+        # Do nothing.
+        return

Modified: branches/distutils-revamp/core.py
===================================================================
--- branches/distutils-revamp/core.py	2007-05-21 13:01:20 UTC (rev 3794)
+++ branches/distutils-revamp/core.py	2007-05-21 13:15:45 UTC (rev 3795)
@@ -39,6 +39,7 @@
 numpy_cmdclass = {'build':            build.build,
                   'build_src':        build_src.build_src,
                   'build_scripts':    build_scripts.build_scripts,
+                  'config_cc':        config_compiler.config_cc,
                   'config_fc':        config_compiler.config_fc,
                   'config':           config.config,
                   'build_ext':        build_ext.build_ext,

Modified: branches/distutils-revamp/fcompiler/__init__.py
===================================================================
--- branches/distutils-revamp/fcompiler/__init__.py	2007-05-21 13:01:20 UTC (rev 3794)
+++ branches/distutils-revamp/fcompiler/__init__.py	2007-05-21 13:15:45 UTC (rev 3795)
@@ -770,7 +770,6 @@
         dist.cmdclass['config_fc'] = config_fc
         dist.parse_config_files()
         dist.parse_command_line()
-
     compilers = []
     compilers_na = []
     compilers_ni = []
@@ -779,12 +778,14 @@
     platform_compilers = available_fcompilers_for_platform()
     for compiler in platform_compilers:
         v = None
+        log.set_verbosity(-2)
         try:
             c = new_fcompiler(compiler=compiler, verbose=dist.verbose)
             c.customize(dist)
             v = c.get_version()
         except (DistutilsModuleError, CompilerNotFound):
             pass
+
         if v is None:
             compilers_na.append(("fcompiler="+compiler, None,
                               fcompiler_class[compiler][2]))

Modified: branches/distutils-revamp/misc_util.py
===================================================================
--- branches/distutils-revamp/misc_util.py	2007-05-21 13:01:20 UTC (rev 3794)
+++ branches/distutils-revamp/misc_util.py	2007-05-21 13:15:45 UTC (rev 3795)
@@ -309,8 +309,9 @@
         return [seq]
 
 def get_language(sources):
+    # not used in numpy/scipy packages, use build_ext.detect_language instead
     """ Determine language value (c,f77,f90) from sources """
-    language = 'c'
+    language = None
     for source in sources:
         if isinstance(source, str):
             if f90_ext_match(source):
@@ -1020,11 +1021,7 @@
         ext_args = copy.copy(kw)
         ext_args['name'] = dot_join(self.name,name)
         ext_args['sources'] = sources
-
-        language = ext_args.get('language',None)
-        if language is None:
-            ext_args['language'] = get_language(sources)
-
+        
         if ext_args.has_key('extra_info'):
             extra_info = ext_args['extra_info']
             del ext_args['extra_info']
@@ -1089,10 +1086,6 @@
         name = name #+ '__OF__' + self.name
         build_info['sources'] = sources
 
-        language = build_info.get('language',None)
-        if language is None:
-            build_info['language'] = get_language(sources)
-
         self._fix_paths_dict(build_info)
 
         self.libraries.append((name,build_info))

Modified: branches/distutils-revamp/system_info.py
===================================================================
--- branches/distutils-revamp/system_info.py	2007-05-21 13:01:20 UTC (rev 3794)
+++ branches/distutils-revamp/system_info.py	2007-05-21 13:15:45 UTC (rev 3795)
@@ -1107,7 +1107,7 @@
         self.set_info(**info)
 
 atlas_version_c_text = r'''
-/* This file is generated from numpy_distutils/system_info.py */
+/* This file is generated from numpy/distutils/system_info.py */
 void ATL_buildinfo(void);
 int main(void) {
   ATL_buildinfo();




More information about the Numpy-svn mailing list