[h5py] 335/455: Overhaul setup.py
Ghislain Vaillant
ghisvail-guest at moszumanska.debian.org
Thu Jul 2 18:19:48 UTC 2015
This is an automated email from the git hooks/post-receive script.
ghisvail-guest pushed a commit to annotated tag 1.3.0
in repository h5py.
commit 5fb64fa4d82255097b9f714969a175dc779a1d8a
Author: andrewcollette <andrew.collette at gmail.com>
Date: Sun Dec 20 01:23:05 2009 +0000
Overhaul setup.py
---
setup.py | 306 +++++++++++++++++++++++++++++++++++++++++----------------------
1 file changed, 198 insertions(+), 108 deletions(-)
diff --git a/setup.py b/setup.py
index 046f9f0..4ebcedc 100644
--- a/setup.py
+++ b/setup.py
@@ -12,6 +12,8 @@
#
#-
+from __future__ import with_statement
+
"""
Setup script for the h5py package.
@@ -33,6 +35,7 @@ SRC_PATH = 'h5py' # Name of directory with .pyx files
USE_DISTUTILS = False
+# --- Helper functions --------------------------------------------------------
def version_check(vers, required):
""" Compare versions between two "."-separated strings. """
@@ -56,6 +59,24 @@ def debug(instring):
def localpath(*args):
return op.abspath(reduce(op.join, (op.dirname(__file__),)+args))
+from contextlib import contextmanager
+ at contextmanager
+def tempdir(*args):
+ """ Create a temp dir and clean it up afterwards. """
+ path = localpath(*args)
+ try:
+ shutil.rmtree(path)
+ except Exception:
+ pass
+ os.mkdir(path)
+ try:
+ yield
+ finally:
+ try:
+ shutil.rmtree(path)
+ except Exception:
+ pass
+
MODULES = ['h5', 'h5e', 'h5f', 'h5g', 'h5s', 'h5t', 'h5d', 'h5a', 'h5p', 'h5z',
'h5i', 'h5r', 'h5fd', 'utils', 'h5o', 'h5l', '_conv', '_proxy']
@@ -81,9 +102,6 @@ for arg in sys.argv[:]:
sys.argv.remove(arg)
DEBUG = True
-if not (sys.version_info[0:2] >= (2,5)):
- fatal("At least Python 2.5 is required to install h5py")
-
try:
import numpy
if numpy.version.version < MIN_NUMPY:
@@ -116,120 +134,206 @@ from distutils.cmd import Command
# --- Compiler and library config ---------------------------------------------
-class GlobalOpts:
+class GlobalSettings(object):
- def __init__(self):
+ """
+ Repository for all settings which are fixed when the script is run.
+ This includes the following:
- # Environment variables are the only way to communicate this
- # information if we're building with easy_install
- hdf5 = os.environ.get("HDF5_DIR", None)
- if hdf5 == '': hdf5 = None
- if hdf5 is not None:
+ * Any custom path to HDF5
+ * Any custom API level
+ * Compiler settings for extension modules
+ """
+
+ api_string = {'16': (1,6), '18': (1,8)}
+
+ def get_environment_args(self):
+ """ Look for options in environment vars """
+ hdf5 = os.environ.get("HDF5_DIR", '')
+ if hdf5 != '':
debug("Found environ var HDF5_DIR=%s" % hdf5)
+ else:
+ hdf5 = None
- api = os.environ.get("HDF5_API", None)
- if api == '': api = None
- if api is not None:
+ api = os.environ.get("HDF5_API", '')
+ if api != '':
debug("Found environ var HDF5_API=%s" % api)
-
- # The output of the "configure" command is preferred
+ try:
+ api = self.api_string[api]
+ except KeyError:
+ fatal("API level must be one of %s" % ", ".join(self.api_string))
+ else:
+ api = None
+
+ return hdf5, api
+
+ def get_commandline_args(self):
+ """ Look for global options in the command line """
+ hdf5 = api = None
+ for arg in sys.argv[:]:
+ if arg.find('--hdf5=') == 0:
+ hdf5 = arg.split('=')[-1]
+ if hdf5.lower() == 'default':
+ hdf5 = False # This means "explicitly forget"
+ sys.argv.remove(arg)
+ if arg.find('--api=') == 0:
+ api = arg.split('=')[-1]
+ if api.lower() == 'default':
+ api = False
+ else:
+ try:
+ api = self.api_string[api]
+ except KeyError:
+ fatal("API level must be 16 or 18")
+ sys.argv.remove(arg)
+
+ # We save command line args to a pickle file so that the user doesn't
+ # have to keep specifying them for the different distutils commands.
+ if (hdf5 or api) or (hdf5 is False or api is False):
+ self.save_pickle_args(hdf5 if hdf5 is not False else None,
+ api if api is not False else None)
+ hdf5 = hdf5 if hdf5 else None
+ api = api if api else None
+
+ return hdf5, api
+
+ def get_pickle_args(self):
+ """ Look for options stored in the pickle file """
+ import pickle
+ hdf5 = api = None
try:
f = open(localpath('buildconf.pickle'),'r')
- hdf5_pkl, api_pkl = pickle.load(f)
+ hdf5, api = pickle.load(f)
f.close()
except Exception:
pass
- else:
- if hdf5_pkl is not None:
- hdf5 = hdf5_pkl
- debug("Loaded HDF5 dir %s from pickle file" % hdf5)
- if api_pkl is not None:
- api = api_pkl
- debug("Loaded API %s from pickle file" % api)
-
- if hdf5 is not None and not op.isdir(hdf5):
- fatal('Invalid HDF5 path "%s"' % hdf5)
+ return hdf5, api
- if api is not None:
- try:
- api = int(api)
- if api not in (16,18):
- raise Exception
- except Exception:
- fatal('Invalid API version "%s" (legal values are 16,18)' % api)
-
- self.hdf5 = hdf5
- self.api = api
+ def save_pickle_args(self, hdf5, api):
+ """ Save options to the pickle file """
+ import pickle
+ f = open(localpath('buildconf.pickle'),'w')
+ pickle.dump((hdf5, api), f)
+ f.close()
+
+ def __init__(self):
- def get_api_version(self):
- """ Get the active HDF5 version, from the command line or by
- trying to run showconfig.
- """
- if self.api is not None:
- debug("User specified API version %s" % self.api)
- return self.api
+ # --- Handle custom dirs and API levels for HDF5 ----------------------
- if self.hdf5 is not None:
- cmd = reduce(op.join, (self.hdf5, 'bin', 'h5cc'))+" -showconfig"
- else:
- cmd = "h5cc -showconfig"
- output = commands.getoutput(cmd)
- l = output.find("HDF5 Version")
+ eargs = self.get_environment_args()
+ cargs = self.get_commandline_args()
+ pargs = self.get_pickle_args()
- if l > 0:
- if output[l:l+30].find('1.8') > 0:
- debug("Autodetected HDF5 1.8")
- return 18
- elif output[l:l+30].find('1.6') > 0:
- debug("Autodetected HDF5 1.6")
- return 16
+ # Commandline args have first priority, followed by pickle args and
+ # finally by environment args
+ hdf5 = cargs[0]
+ if hdf5 is None: hdf5 = pargs[0]
+ if hdf5 is None: hdf5 = eargs[0]
- debug("Autodetect FAILED; output is:\n\n%s\n" % output)
- warn("Can't determine HDF5 version, assuming 1.6 (use --api= to override)")
- return 16
+ api = cargs[1]
+ if api is None: api = pargs[1]
+ if api is None: api = eargs[1]
-class ExtensionCreator(object):
+ if hdf5 is not None and not op.isdir(hdf5):
+ fatal('Invalid HDF5 path "%s"' % hdf5)
- """ Figures out what include/library dirs are appropriate, and
- serves as a factory for Extension instances.
+ self.hdf5 = hdf5
+ self.api = api
- Note this is a purely C-oriented process; it doesn't know or
- care about Cython.
- """
+ # --- Extension settings ----------------------------------------------
- def __init__(self, hdf5_loc=None):
if sys.platform == 'win32':
- if hdf5_loc is None:
+ if hdf5 is None:
warn("On Windows, HDF5 directory must be specified.")
- hdf5_loc = '.'
+ hdf5 = '.'
self.libraries = ['hdf5dll18']
self.include_dirs = [numpy.get_include(),
- op.join(hdf5_loc, 'include'),
+ op.join(hdf5, 'include'),
localpath('lzf'),
localpath('win_include')]
self.library_dirs = [op.join(hdf5_loc, 'dll')]
self.runtime_dirs = []
self.extra_compile_args = ['/DH5_USE_16_API', '/D_HDF5USEDLL_']
- self.extra_link_args = []
else:
self.libraries = ['hdf5']
- if hdf5_loc is None:
+ if hdf5 is None:
self.include_dirs = [numpy.get_include()]
self.library_dirs = []
if sys.platform == 'darwin':
self.include_dirs += ['/opt/local/include']
self.library_dirs += ['/opt/local/lib']
else:
- self.include_dirs = [numpy.get_include(), op.join(hdf5_loc, 'include')]
- self.library_dirs = [op.join(hdf5_loc, 'lib')]
+ self.include_dirs = [numpy.get_include(), op.join(hdf5, 'include')]
+ self.library_dirs = [op.join(hdf5, 'lib')]
self.include_dirs += [localpath('lzf')]
self.runtime_dirs = self.library_dirs
self.extra_compile_args = ['-DH5_USE_16_API', '-Wno-unused', '-Wno-uninitialized']
- self.extra_link_args = []
+ def check_hdf5(self):
+
+ if hasattr(self, '_vers_cache'):
+ return self._vers_cache
+
+ from distutils import ccompiler
+ from distutils.core import CompileError, LinkError
+ import commands
+
+ cc = ccompiler.new_compiler()
+ cc.libraries = self.libraries
+ cc.include_dirs = self.include_dirs
+ cc.library_dirs = self.library_dirs
+ cc.runtime_library_dirs = self.runtime_dirs
+
+ with tempdir('detect'):
+
+ f = open(localpath('detect', 'h5vers.c'),'w')
+ f.write(
+r"""\
+#include <stdio.h>
+#include "hdf5.h"
+
+int main(){
+ unsigned int main, minor, release;
+ H5get_libversion(&main, &minor, &release);
+ fprintf(stdout, "%d.%d.%d\n", main, minor, release);
+ return 0;
+}
+""")
+ f.close()
+ try:
+ objs = cc.compile([localpath('detect','h5vers.c')], extra_preargs=self.extra_compile_args)
+ except CompileError:
+ fatal("Can't find your installation of HDF5. Use the --hdf5 option to manually specify the path.")
+ try:
+ cc.link_executable(objs, localpath('detect','h5vers'))
+ except LinkError:
+ fatal("Can't link against HDF5.")
+ status, output = commands.getstatusoutput(localpath('detect', 'h5vers'))
+ if status:
+ fatal("Error running HDF5 version detection script")
+ vmaj, vmin, vrel = (int(v) for v in output.split('.'))
+ self._vers_cache = (vmaj, vmin, vrel)
+ return (vmaj, vmin, vrel)
+
+ def print_config(self):
+ """ Print a summary of the configuration to stdout """
+
+ vers = self.check_hdf5()
+
+ print "\nSummary of the h5py configuration"
+ print "---------------------------------"
+ print "Installed HDF5 version: %d.%d.%d" % vers
+ print "Path to HDF5 installation: %s" % \
+ (self.hdf5 if self.hdf5 is not None else "default")
+ if self.api is None:
+ print "API compatibility level: default (%d.%d)" % vers[0:2]
+ else:
+ print "API compatibility level: %d.%d (manually set)" % self.api
+
+
def create_extension(self, name, extra_src=None):
""" Create a distutils Extension object for the given module. A list
of C source files to be included in the compilation can also be
@@ -244,24 +348,20 @@ class ExtensionCreator(object):
libraries = self.libraries,
library_dirs = self.library_dirs,
runtime_library_dirs = self.runtime_dirs,
- extra_compile_args = self.extra_compile_args,
- extra_link_args = self.extra_link_args)
+ extra_compile_args = self.extra_compile_args)
-GLOBALOPTS = GlobalOpts()
-
-creator = ExtensionCreator(GLOBALOPTS.hdf5)
-EXTENSIONS = [creator.create_extension(x, EXTRA_SRC.get(x, None)) for x in MODULES]
+SETTINGS = GlobalSettings()
+EXTENSIONS = [SETTINGS.create_extension(x, EXTRA_SRC.get(x, None)) for x in MODULES]
# --- Custom extensions for distutils -----------------------------------------
class configure(Command):
- description = "Set options for your HDF5 installation"
+ description = "Display and check ssettings for h5py build"
user_options = [('hdf5=', '5', 'Path to HDF5'),
- ('api=', 'a', 'API version ("16" or "18")'),
- ('show', 's', 'Print existing config (don\'t set anything)')]
+ ('api=', 'a', 'API version ("16" or "18")')]
boolean_options = ['show']
@@ -274,26 +374,8 @@ class configure(Command):
pass
def run(self):
- if self.show:
- try:
- f = open('buildconf.pickle','r')
- hdf5, api = pickle.load(f)
- except Exception:
- hdf5 = api = None
- print "HDF5 path: %s\nAPI setting: %s" % (hdf5, api)
- return
- if self.hdf5 is not None:
- if op.isdir(self.hdf5):
- self.hdf5 = op.abspath(self.hdf5)
- else:
- fatal("Invalid HDF5 path: %s" % self.hdf5)
- if self.api is not None and self.api not in ('16','18'):
- fatal("Invalid API level %s (must be 16 or 18)" % self.api)
-
- f = open('buildconf.pickle','w')
- pickle.dump((self.hdf5, self.api), f)
- f.close()
+ SETTINGS.print_config()
class cython(Command):
@@ -393,16 +475,23 @@ DEF H5PY_18API = %(API_18)d # 1.8.X API available
cythonize(18)
class hbuild_ext(build_ext):
-
+
def run(self):
- api = GLOBALOPTS.get_api_version()
-
- if GLOBALOPTS.hdf5 is None:
- autostr = "(path not specified)"
+ # First check if we can find HDF5
+ vers = SETTINGS.check_hdf5()
+
+ # Used as a part of the path to the correct Cython build
+ if SETTINGS.api is not None:
+ api = 10*SETTINGS.api[0] + SETTINGS.api[1]
else:
- autostr = "(located at %s)" % GLOBALOPTS.hdf5
+ api = 10*vers[0] + vers[1]
+ if SETTINGS.hdf5 is None:
+ autostr = "(path not specified)"
+ else:
+ autostr = "(located at %s)" % SETTINGS.hdf5
+
print "Building for HDF5 %s.%s %s" % (divmod(api,10) + (autostr,))
def identical(src, dst):
@@ -435,6 +524,7 @@ class hbuild_ext(build_ext):
build_ext.run(self)
+ SETTINGS.print_config()
class cleaner(clean):
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/h5py.git
More information about the debian-science-commits
mailing list