summaryrefslogtreecommitdiff
path: root/scipy/weave/build_tools.py
diff options
context:
space:
mode:
authorTravis Oliphant <oliphant@enthought.com>2006-01-02 08:26:24 +0000
committerTravis Oliphant <oliphant@enthought.com>2006-01-02 08:26:24 +0000
commit4712a37b93832933a46376ee99339f9040ba3670 (patch)
tree8a3de8500925061b0f2368fae2d50159dbea206f /scipy/weave/build_tools.py
parentb5ba0003def4cfa43b29d29df8f085d09609707b (diff)
downloadnumpy-4712a37b93832933a46376ee99339f9040ba3670.tar.gz
Moved weave to scipy
Diffstat (limited to 'scipy/weave/build_tools.py')
-rw-r--r--scipy/weave/build_tools.py613
1 files changed, 0 insertions, 613 deletions
diff --git a/scipy/weave/build_tools.py b/scipy/weave/build_tools.py
deleted file mode 100644
index 05cf229a8..000000000
--- a/scipy/weave/build_tools.py
+++ /dev/null
@@ -1,613 +0,0 @@
-""" Tools for compiling C/C++ code to extension modules
-
- The main function, build_extension(), takes the C/C++ file
- along with some other options and builds a Python extension.
- It uses distutils for most of the heavy lifting.
-
- choose_compiler() is also useful (mainly on windows anyway)
- for trying to determine whether MSVC++ or gcc is available.
- MSVC doesn't handle templates as well, so some of the code emitted
- by the python->C conversions need this info to choose what kind
- of code to create.
-
- The other main thing here is an alternative version of the MingW32
- compiler class. The class makes it possible to build libraries with
- gcc even if the original version of python was built using MSVC. It
- does this by converting a pythonxx.lib file to a libpythonxx.a file.
- Note that you need write access to the pythonxx/lib directory to do this.
-"""
-
-import sys,os,string,time
-import tempfile
-import exceptions
-import commands
-
-import platform_info
-
-# If linker is 'gcc', this will convert it to 'g++'
-# necessary to make sure stdc++ is linked in cross-platform way.
-import distutils.sysconfig
-import distutils.dir_util
-old_init_posix = distutils.sysconfig._init_posix
-
-def _init_posix():
- old_init_posix()
- ld = distutils.sysconfig._config_vars['LDSHARED']
- #distutils.sysconfig._config_vars['LDSHARED'] = ld.replace('gcc','g++')
- # FreeBSD names gcc as cc, so the above find and replace doesn't work.
- # So, assume first entry in ld is the name of the linker -- gcc or cc or
- # whatever. This is a sane assumption, correct?
- # If the linker is gcc, set it to g++
- link_cmds = ld.split()
- if gcc_exists(link_cmds[0]):
- link_cmds[0] = 'g++'
- ld = ' '.join(link_cmds)
-
-
- if (sys.platform == 'darwin'):
- # The Jaguar distributed python 2.2 has -arch i386 in the link line
- # which doesn't seem right. It omits all kinds of warnings, so
- # remove it.
- ld = ld.replace('-arch i386','')
-
- # The following line is a HACK to fix a problem with building the
- # freetype shared library under Mac OS X:
- ld += ' -framework AppKit'
-
- # 2.3a1 on OS X emits a ton of warnings about long double. OPT
- # appears to not have all the needed flags set while CFLAGS does.
- cfg_vars = distutils.sysconfig._config_vars
- cfg_vars['OPT'] = cfg_vars['CFLAGS']
- distutils.sysconfig._config_vars['LDSHARED'] = ld
-
-distutils.sysconfig._init_posix = _init_posix
-# end force g++
-
-
-class CompileError(exceptions.Exception):
- pass
-
-
-def create_extension(module_path, **kw):
- """ Create an Extension that can be buil by setup.py
-
- See build_extension for information on keyword arguments.
- """
- # some (most?) platforms will fail to link C++ correctly
- # unless scipy.distutils is used.
- try:
- from scipy.distutils.core import Extension
- except ImportError:
- from distutils.core import Extension
-
- # this is a screwy trick to get rid of a ton of warnings on Unix
- import distutils.sysconfig
- distutils.sysconfig.get_config_vars()
- if distutils.sysconfig._config_vars.has_key('OPT'):
- flags = distutils.sysconfig._config_vars['OPT']
- flags = flags.replace('-Wall','')
- distutils.sysconfig._config_vars['OPT'] = flags
-
- # get the name of the module and the extension directory it lives in.
- module_dir,cpp_name = os.path.split(os.path.abspath(module_path))
- module_name,ext = os.path.splitext(cpp_name)
-
- # the business end of the function
- sources = kw.get('sources',[])
- kw['sources'] = [module_path] + sources
-
- #--------------------------------------------------------------------
- # added access to environment variable that user can set to specify
- # where python (and other) include files are located. This is
- # very useful on systems where python is installed by the root, but
- # the user has also installed numerous packages in their own
- # location.
- #--------------------------------------------------------------------
- if os.environ.has_key('PYTHONINCLUDE'):
- path_string = os.environ['PYTHONINCLUDE']
- if sys.platform == "win32":
- extra_include_dirs = path_string.split(';')
- else:
- extra_include_dirs = path_string.split(':')
- include_dirs = kw.get('include_dirs',[])
- kw['include_dirs'] = include_dirs + extra_include_dirs
-
- # SunOS specific
- # fix for issue with linking to libstdc++.a. see:
- # http://mail.python.org/pipermail/python-dev/2001-March/013510.html
- platform = sys.platform
- version = sys.version.lower()
- if platform[:5] == 'sunos' and version.find('gcc') != -1:
- extra_link_args = kw.get('extra_link_args',[])
- kw['extra_link_args'] = ['-mimpure-text'] + extra_link_args
-
- ext = Extension(module_name, **kw)
- return ext
-
-def build_extension(module_path,compiler_name = '',build_dir = None,
- temp_dir = None, verbose = 0, **kw):
- """ Build the file given by module_path into a Python extension module.
-
- build_extensions uses distutils to build Python extension modules.
- kw arguments not used are passed on to the distutils extension
- module. Directory settings can handle absoulte settings, but don't
- currently expand '~' or environment variables.
-
- module_path -- the full path name to the c file to compile.
- Something like: /full/path/name/module_name.c
- The name of the c/c++ file should be the same as the
- name of the module (i.e. the initmodule() routine)
- compiler_name -- The name of the compiler to use. On Windows if it
- isn't given, MSVC is used if it exists (is found).
- gcc is used as a second choice. If neither are found,
- the default distutils compiler is used. Acceptable
- names are 'gcc', 'msvc' or any of the compiler names
- shown by distutils.ccompiler.show_compilers()
- build_dir -- The location where the resulting extension module
- should be placed. This location must be writable. If
- it isn't, several default locations are tried. If the
- build_dir is not in the current python path, a warning
- is emitted, and it is added to the end of the path.
- build_dir defaults to the current directory.
- temp_dir -- The location where temporary files (*.o or *.obj)
- from the build are placed. This location must be
- writable. If it isn't, several default locations are
- tried. It defaults to tempfile.gettempdir()
- verbose -- 0, 1, or 2. 0 is as quiet as possible. 1 prints
- minimal information. 2 is noisy.
- **kw -- keyword arguments. These are passed on to the
- distutils extension module. Most of the keywords
- are listed below.
-
- Distutils keywords. These are cut and pasted from Greg Ward's
- distutils.extension.Extension class for convenience:
-
- sources : [string]
- list of source filenames, relative to the distribution root
- (where the setup script lives), in Unix form (slash-separated)
- for portability. Source files may be C, C++, SWIG (.i),
- platform-specific resource files, or whatever else is recognized
- by the "build_ext" command as source for a Python extension.
- Note: The module_path file is always appended to the front of this
- list
- include_dirs : [string]
- list of directories to search for C/C++ header files (in Unix
- form for portability)
- define_macros : [(name : string, value : string|None)]
- list of macros to define; each macro is defined using a 2-tuple,
- where 'value' is either the string to define it to or None to
- define it without a particular value (equivalent of "#define
- FOO" in source or -DFOO on Unix C compiler command line)
- undef_macros : [string]
- list of macros to undefine explicitly
- library_dirs : [string]
- list of directories to search for C/C++ libraries at link time
- libraries : [string]
- list of library names (not filenames or paths) to link against
- runtime_library_dirs : [string]
- list of directories to search for C/C++ libraries at run time
- (for shared extensions, this is when the extension is loaded)
- extra_objects : [string]
- list of extra files to link with (eg. object files not implied
- by 'sources', static library that must be explicitly specified,
- binary resource files, etc.)
- extra_compile_args : [string]
- any extra platform- and compiler-specific information to use
- when compiling the source files in 'sources'. For platforms and
- compilers where "command line" makes sense, this is typically a
- list of command-line arguments, but for other platforms it could
- be anything.
- extra_link_args : [string]
- any extra platform- and compiler-specific information to use
- when linking object files together to create the extension (or
- to create a new static Python interpreter). Similar
- interpretation as for 'extra_compile_args'.
- export_symbols : [string]
- list of symbols to be exported from a shared extension. Not
- used on all platforms, and not generally necessary for Python
- extensions, which typically export exactly one symbol: "init" +
- extension_name.
- """
- success = 0
- try:
- from scipy.distutils.core import setup, Extension
- from scipy.distutils.log import set_verbosity
- set_verbosity(-1)
- except ImportError:
- from distutils.core import setup, Extension
-
- # this is a screwy trick to get rid of a ton of warnings on Unix
- import distutils.sysconfig
- distutils.sysconfig.get_config_vars()
- if distutils.sysconfig._config_vars.has_key('OPT'):
- flags = distutils.sysconfig._config_vars['OPT']
- flags = flags.replace('-Wall','')
- distutils.sysconfig._config_vars['OPT'] = flags
-
- # get the name of the module and the extension directory it lives in.
- module_dir,cpp_name = os.path.split(os.path.abspath(module_path))
- module_name,ext = os.path.splitext(cpp_name)
-
- # configure temp and build directories
- temp_dir = configure_temp_dir(temp_dir)
- build_dir = configure_build_dir(module_dir)
-
- # dag. We keep having to add directories to the path to keep
- # object files separated from each other. gcc2.x and gcc3.x C++
- # object files are not compatible, so we'll stick them in a sub
- # dir based on their version. This will add an md5 check sum
- # of the compiler binary to the directory name to keep objects
- # from different compilers in different locations.
-
- compiler_dir = platform_info.get_compiler_dir(compiler_name)
- temp_dir = os.path.join(temp_dir,compiler_dir)
- distutils.dir_util.mkpath(temp_dir)
-
- compiler_name = choose_compiler(compiler_name)
-
- configure_sys_argv(compiler_name,temp_dir,build_dir)
-
- # the business end of the function
- try:
- if verbose == 1:
- print 'Compiling code...'
-
- # set compiler verboseness 2 or more makes it output results
- if verbose > 1:
- verb = 1
- else:
- verb = 0
-
- t1 = time.time()
- ext = create_extension(module_path,**kw)
- # the switcheroo on SystemExit here is meant to keep command line
- # sessions from exiting when compiles fail.
- builtin = sys.modules['__builtin__']
- old_SysExit = builtin.__dict__['SystemExit']
- builtin.__dict__['SystemExit'] = CompileError
-
- # distutils for MSVC messes with the environment, so we save the
- # current state and restore them afterward.
- import copy
- environ = copy.deepcopy(os.environ)
- try:
- setup(name = module_name, ext_modules = [ext],verbose=verb)
- finally:
- # restore state
- os.environ = environ
- # restore SystemExit
- builtin.__dict__['SystemExit'] = old_SysExit
- t2 = time.time()
-
- if verbose == 1:
- print 'finished compiling (sec): ', t2 - t1
- success = 1
- configure_python_path(build_dir)
- except SyntaxError: #TypeError:
- success = 0
-
- # restore argv after our trick...
- restore_sys_argv()
-
- return success
-
-old_argv = []
-def configure_sys_argv(compiler_name,temp_dir,build_dir):
- # We're gonna play some tricks with argv here to pass info to distutils
- # which is really built for command line use. better way??
- global old_argv
- old_argv = sys.argv[:]
- sys.argv = ['','build_ext','--build-lib', build_dir,
- '--build-temp',temp_dir]
- if compiler_name == 'gcc':
- sys.argv.insert(2,'--compiler='+compiler_name)
- elif compiler_name:
- sys.argv.insert(2,'--compiler='+compiler_name)
-
-def restore_sys_argv():
- sys.argv = old_argv
-
-def configure_python_path(build_dir):
- #make sure the module lives in a directory on the python path.
- python_paths = [os.path.abspath(x) for x in sys.path]
- if os.path.abspath(build_dir) not in python_paths:
- #print "warning: build directory was not part of python path."\
- # " It has been appended to the path."
- sys.path.append(os.path.abspath(build_dir))
-
-def choose_compiler(compiler_name=''):
- """ Try and figure out which compiler is gonna be used on windows.
- On other platforms, it just returns whatever value it is given.
-
- converts 'gcc' to 'mingw32' on win32
- """
- if sys.platform == 'win32':
- if not compiler_name:
- # On Windows, default to MSVC and use gcc if it wasn't found
- # wasn't found. If neither are found, go with whatever
- # the default is for distutils -- and probably fail...
- if msvc_exists():
- compiler_name = 'msvc'
- elif gcc_exists():
- compiler_name = 'mingw32'
- elif compiler_name == 'gcc':
- compiler_name = 'mingw32'
- else:
- # don't know how to force gcc -- look into this.
- if compiler_name == 'gcc':
- compiler_name = 'unix'
- return compiler_name
-
-def gcc_exists(name = 'gcc'):
- """ Test to make sure gcc is found
-
- Does this return correct value on win98???
- """
- result = 0
- cmd = '%s -v' % name
- try:
- w,r=os.popen4(cmd)
- w.close()
- str_result = r.read()
- #print str_result
- if string.find(str_result,'Reading specs') != -1:
- result = 1
- except:
- # This was needed because the msvc compiler messes with
- # the path variable. and will occasionlly mess things up
- # so much that gcc is lost in the path. (Occurs in test
- # scripts)
- result = not os.system(cmd)
- return result
-
-def msvc_exists():
- """ Determine whether MSVC is available on the machine.
- """
- result = 0
- try:
- w,r=os.popen4('cl')
- w.close()
- str_result = r.read()
- #print str_result
- if string.find(str_result,'Microsoft') != -1:
- result = 1
- except:
- #assume we're ok if devstudio exists
- import distutils.msvccompiler
- version = distutils.msvccompiler.get_devstudio_version()
- if version:
- result = 1
- return result
-
-if os.name == 'nt':
- def run_command(command):
- """ not sure how to get exit status on nt. """
- in_pipe,out_pipe = os.popen4(command)
- in_pipe.close()
- text = out_pipe.read()
- return 0, text
-else:
- run_command = commands.getstatusoutput
-
-
-def configure_temp_dir(temp_dir=None):
- if temp_dir is None:
- temp_dir = tempfile.gettempdir()
- elif not os.path.exists(temp_dir) or not os.access(temp_dir,os.W_OK):
- print "warning: specified temp_dir '%s' does not exist " \
- "or is not writable. Using the default temp directory" % \
- temp_dir
- temp_dir = tempfile.gettempdir()
-
- # final check that that directories are writable.
- if not os.access(temp_dir,os.W_OK):
- msg = "Either the temp or build directory wasn't writable. Check" \
- " these locations: '%s'" % temp_dir
- raise ValueError, msg
- return temp_dir
-
-def configure_build_dir(build_dir=None):
- # make sure build_dir exists and is writable
- if build_dir and (not os.path.exists(build_dir) or
- not os.access(build_dir,os.W_OK)):
- print "warning: specified build_dir '%s' does not exist " \
- "or is not writable. Trying default locations" % build_dir
- build_dir = None
-
- if build_dir is None:
- #default to building in the home directory of the given module.
- build_dir = os.curdir
- # if it doesn't work use the current directory. This should always
- # be writable.
- if not os.access(build_dir,os.W_OK):
- print "warning:, neither the module's directory nor the "\
- "current directory are writable. Using the temporary"\
- "directory."
- build_dir = tempfile.gettempdir()
-
- # final check that that directories are writable.
- if not os.access(build_dir,os.W_OK):
- msg = "The build directory wasn't writable. Check" \
- " this location: '%s'" % build_dir
- raise ValueError, msg
-
- return os.path.abspath(build_dir)
-
-if sys.platform == 'win32':
- import distutils.cygwinccompiler
- from distutils.version import StrictVersion
- from distutils.ccompiler import gen_preprocess_options, gen_lib_options
- from distutils.errors import DistutilsExecError, CompileError, UnknownFileError
-
- from distutils.unixccompiler import UnixCCompiler
-
- # the same as cygwin plus some additional parameters
- class Mingw32CCompiler(distutils.cygwinccompiler.CygwinCCompiler):
- """ A modified MingW32 compiler compatible with an MSVC built Python.
-
- """
-
- compiler_type = 'mingw32'
-
- def __init__ (self,
- verbose=0,
- dry_run=0,
- force=0):
-
- distutils.cygwinccompiler.CygwinCCompiler.__init__ (self,
- verbose,dry_run, force)
-
- # we need to support 3.2 which doesn't match the standard
- # get_versions methods regex
- if self.gcc_version is None:
- import re
- out = os.popen('gcc' + ' -dumpversion','r')
- out_string = out.read()
- out.close()
- result = re.search('(\d+\.\d+)',out_string)
- if result:
- self.gcc_version = StrictVersion(result.group(1))
-
- # A real mingw32 doesn't need to specify a different entry point,
- # but cygwin 2.91.57 in no-cygwin-mode needs it.
- if self.gcc_version <= "2.91.57":
- entry_point = '--entry _DllMain@12'
- else:
- entry_point = ''
- if self.linker_dll == 'dllwrap':
- self.linker = 'dllwrap' + ' --driver-name g++'
- elif self.linker_dll == 'gcc':
- self.linker = 'g++'
-
- # **changes: eric jones 4/11/01
- # 1. Check for import library on Windows. Build if it doesn't exist.
- if not import_library_exists():
- build_import_library()
-
- # **changes: eric jones 4/11/01
- # 2. increased optimization and turned off all warnings
- # 3. also added --driver-name g++
- #self.set_executables(compiler='gcc -mno-cygwin -O2 -w',
- # compiler_so='gcc -mno-cygwin -mdll -O2 -w',
- # linker_exe='gcc -mno-cygwin',
- # linker_so='%s --driver-name g++ -mno-cygwin -mdll -static %s'
- # % (self.linker, entry_point))
- if self.gcc_version <= "3.0.0":
- self.set_executables(compiler='gcc -mno-cygwin -O2 -w',
- compiler_so='gcc -mno-cygwin -mdll -O2 -w -Wstrict-prototypes',
- linker_exe='g++ -mno-cygwin',
- linker_so='%s -mno-cygwin -mdll -static %s'
- % (self.linker, entry_point))
- else:
- self.set_executables(compiler='gcc -mno-cygwin -O2 -w',
- compiler_so='gcc -O2 -w -Wstrict-prototypes',
- linker_exe='g++ ',
- linker_so='g++ -shared')
- # added for python2.3 support
- # we can't pass it through set_executables because pre 2.2 would fail
- self.compiler_cxx = ['g++']
-
- # Maybe we should also append -mthreads, but then the finished
- # dlls need another dll (mingwm10.dll see Mingw32 docs)
- # (-mthreads: Support thread-safe exception handling on `Mingw32')
-
- # no additional libraries needed
- self.dll_libraries=[]
-
- # __init__ ()
-
- def link(self,
- target_desc,
- objects,
- output_filename,
- output_dir,
- libraries,
- library_dirs,
- runtime_library_dirs,
- export_symbols=None, # export_symbols, we do this in our def-file
- debug=0,
- extra_preargs=None,
- extra_postargs=None,
- build_temp=None,
- target_lang=None):
- if self.gcc_version < "3.0.0":
- distutils.cygwinccompiler.CygwinCCompiler.link(self,
- target_desc,
- objects,
- output_filename,
- output_dir,
- libraries,
- library_dirs,
- runtime_library_dirs,
- None, # export_symbols, we do this in our def-file
- debug,
- extra_preargs,
- extra_postargs,
- build_temp,
- target_lang)
- else:
- UnixCCompiler.link(self,
- target_desc,
- objects,
- output_filename,
- output_dir,
- libraries,
- library_dirs,
- runtime_library_dirs,
- None, # export_symbols, we do this in our def-file
- debug,
- extra_preargs,
- extra_postargs,
- build_temp,
- target_lang)
-
-
- # On windows platforms, we want to default to mingw32 (gcc)
- # because msvc can't build blitz stuff.
- # We should also check the version of gcc available...
- #distutils.ccompiler._default_compilers['nt'] = 'mingw32'
- #distutils.ccompiler._default_compilers = (('nt', 'mingw32'))
- # reset the Mingw32 compiler in distutils to the one defined above
- distutils.cygwinccompiler.Mingw32CCompiler = Mingw32CCompiler
-
- def import_library_exists():
- """ on windows platforms, make sure a gcc import library exists
- """
- if os.name == 'nt':
- lib_name = "libpython%d%d.a" % tuple(sys.version_info[:2])
- full_path = os.path.join(sys.prefix,'libs',lib_name)
- if not os.path.exists(full_path):
- return 0
- return 1
-
- def build_import_library():
- """ Build the import libraries for Mingw32-gcc on Windows
- """
- from scipy.distutils import lib2def
- #libfile, deffile = parse_cmd()
- #if deffile is None:
- # deffile = sys.stdout
- #else:
- # deffile = open(deffile, 'w')
- lib_name = "python%d%d.lib" % tuple(sys.version_info[:2])
- lib_file = os.path.join(sys.prefix,'libs',lib_name)
- def_name = "python%d%d.def" % tuple(sys.version_info[:2])
- def_file = os.path.join(sys.prefix,'libs',def_name)
- nm_cmd = '%s %s' % (lib2def.DEFAULT_NM, lib_file)
- nm_output = lib2def.getnm(nm_cmd)
- dlist, flist = lib2def.parse_nm(nm_output)
- lib2def.output_def(dlist, flist, lib2def.DEF_HEADER, open(def_file, 'w'))
-
- out_name = "libpython%d%d.a" % tuple(sys.version_info[:2])
- out_file = os.path.join(sys.prefix,'libs',out_name)
- dll_name = "python%d%d.dll" % tuple(sys.version_info[:2])
- args = (dll_name,def_file,out_file)
- cmd = 'dlltool --dllname %s --def %s --output-lib %s' % args
- success = not os.system(cmd)
- # for now, fail silently
- if not success:
- print 'WARNING: failed to build import library for gcc. Linking will fail.'
- #if not success:
- # msg = "Couldn't find import library, and failed to build it."
- # raise DistutilsPlatformError, msg
-