Commit 43faf533 authored by Christoph Groth's avatar Christoph Groth
Browse files

rewrite of setup.py

The code should be easier to understand.  Configuration through a site.cfg file
is supported.
parent cc39c612
......@@ -11,3 +11,4 @@ MANIFEST
/doc/source/images/*.png
/doc/source/images/*.pdf
/doc/source/images/.*_flag
/build.conf
......@@ -4,8 +4,12 @@
include MANIFEST.in
include TODO.txt
# We explicitly include both pyx and c files, so that both are shipped in
# source tarballs independently of whether "setup.py sdist" is run with
# --no-cython or not.
recursive-include kwant *.pyx
recursive-include kwant *.pxd
recursive-include kwant *.c
recursive-include kwant *.h
recursive-include kwant test_*.py
......
......@@ -25,7 +25,10 @@ The prerequisites are
- Some incarnation of `LAPACK <http://www.netlib.org/lapack/>`_.
optional (needed for plotting and the examples):
Recommended:
- `MUMPS <http://graal.ens-lyon.fr/MUMPS/>`_ will in many cases speed up kwant
several times and reduce the memory footprint.
- `pycairo <http://cairographics.org/pycairo/>`_
......@@ -54,7 +57,7 @@ be sure to tell python where to find it. This can be done by setting the
export PYTHONPATH=$HOME/lib/python
You can make this setting permanent by adding this line to your the file
You can make this setting permanent by adding this line to the file
``.bashrc`` in your home directory.
To check successful installation try executing some scripts in the ``examples``
......@@ -107,9 +110,7 @@ Some conventions to keep in mind:
<http://www.python.org/dev/peps/pep-0257/>`_.
Several modules are written in `Cython <http://cython.org/>`_ (.pyx file name
extension). You will need Cython 0.18 if you want to modify them. (If Cython
0.18 is not released yet, try the bleeding-edge version.) Turn on
cythonization by passing the option ``--run-cython`` to setup.py.
extension). You will need Cython 0.17.1 if you want to modify them.
Tests
......
Roughly in order of importance. -*-org-*-
* Document site.cfg
* Document the usage of tinyarray
Tinyarray is a dependency now. Should we include it in kwant?
......
#!/usr/bin/env python
import sys, subprocess, os
CONFIG_FILE = 'build.conf'
STATIC_VERSION_FILE = 'kwant/_static_version.py'
REQUIRED_CYTHON_VERSION = (0, 17, 1)
MUMPS_DEBIAN_PACKAGE = 'libmumps-scotch-dev'
NO_CYTHON_OPTION = '--no-cython'
import sys
import os
import subprocess
import ConfigParser
from distutils.core import setup
from distutils.extension import Extension
import numpy as np
from distutils.errors import DistutilsError, CCompilerError
import numpy
try:
import Cython
except:
cython_version = ()
else:
cython_version = tuple(
int(n) for n in Cython.__version__.split('-')[0].split('.'))
run_cython = '--run-cython' in sys.argv
if run_cython:
sys.argv.remove('--run-cython')
try:
sys.argv.remove(NO_CYTHON_OPTION)
cythonize = False
except ValueError:
cythonize = True
if cythonize and cython_version:
from Cython.Distutils import build_ext
cmdclass = {'build_ext': build_ext}
else:
cmdclass = {}
from distutils.command.build_ext import build_ext
class kwant_build_ext(build_ext):
def run(self):
try:
build_ext.run(self)
except (DistutilsError, CCompilerError):
print >>sys.stderr, \
"""{0}
The compilation of kwant has failed. Please examine the error message
above and consult the installation instructions in README.txt.
You might have to customize {1}.
{0}
Build configuration was:
{2}
{0}""".format('*' * 70, CONFIG_FILE, build_summary)
raise
print '**************** Build summary ****************'
print build_summary
# This is an exact copy of the function from kwant/version.py. We can't import
# it here (because kwant is not yet built when this scipt is run), so we just
......@@ -40,9 +81,11 @@ def get_version_from_git():
version += '-dirty'
return version
def get_static_version():
"""Return the version as recorded inside kwant."""
try:
with open('kwant/_static_version.py') as f:
with open(STATIC_VERSION_FILE) as f:
contents = f.read()
assert contents[:11] == "version = '"
assert contents[-2:] == "'\n"
......@@ -50,99 +93,195 @@ def get_static_version():
except:
return None
git_version = get_version_from_git()
static_version = get_static_version()
if git_version is not None:
version = git_version
if static_version != git_version:
with open('kwant/_static_version.py', 'w') as f:
f.write("version = '%s'\n" % version)
elif static_version is not None:
version = static_version
else:
version = 'unknown'
# List of tuples (args, keywords) to be passed to Extension, possibly after
# replacing ".pyx" with ".c" if Cython is not to be used.
extensions = [ # (["kwant.graph.scotch", ["kwant/graph/scotch.pyx"]],
# {"libraries" : ["scotch", "scotcherr"]}),
(["kwant._system", ["kwant/_system.pyx"]],
{"include_dirs" : ["kwant/graph"]}),
(["kwant.graph.core", ["kwant/graph/core.pyx"]],
{"depends" : ["kwant/graph/core.pxd", "kwant/graph/defs.h",
"kwant/graph/defs.pxd"]}),
(["kwant.graph.utils", ["kwant/graph/utils.pyx"]],
{"depends" : ["kwant/graph/defs.h", "kwant/graph/defs.pxd",
"kwant/graph/core.pxd"]}),
(["kwant.graph.slicer", ["kwant/graph/slicer.pyx",
"kwant/graph/c_slicer/partitioner.cc",
"kwant/graph/c_slicer/slicer.cc"]],
{"depends" : ["kwant/graph/defs.h", "kwant/graph/defs.pxd",
"kwant/graph/core.pxd",
"kwant/graph/c_slicer.pxd",
"kwant/graph/c_slicer/bucket_list.h",
"kwant/graph/c_slicer/graphwrap.h",
"kwant/graph/c_slicer/partitioner.h",
"kwant/graph/c_slicer/slicer.h"]}),
(["kwant.linalg.lapack", ["kwant/linalg/lapack.pyx"]],
{"libraries" : ["lapack", "blas"],
"depends" : ["kwant/linalg/f_lapack.pxd"]}),
(["kwant.linalg._mumps", ["kwant/linalg/_mumps.pyx"]],
{"libraries" : ["zmumps", "mumps_common", "pord",
"metis", "mpiseq", "lapack", "blas",
"gfortran"],
"depends" : ["kwant/linalg/cmumps.pxd"]}) ]
ext_modules = []
for args, keywords in extensions:
if not run_cython:
if 'language' in keywords:
if keywords['language'] == 'c':
ext = '.c'
elif keywords['language'] == 'c++':
ext = '.cpp'
def version():
"""Determine the version of kwant. Return it and save it in a file."""
git_version = get_version_from_git()
static_version = get_static_version()
if git_version is not None:
version = git_version
if static_version != git_version:
with open(STATIC_VERSION_FILE, 'w') as f:
f.write("version = '%s'\n" % version)
elif static_version is not None:
version = static_version
else:
version = 'unknown'
return version
def debian_mumps():
"""Return the configuration for debian-provided MUMPS if it is available,
or an empty dictionary otherwise."""
try:
p = subprocess.Popen(
['dpkg-query', '-W', '-f=${Status}', MUMPS_DEBIAN_PACKAGE],
stdout=subprocess.PIPE)
except OSError:
pass
else:
if p.wait() == 0 and p.communicate()[0] == 'install ok installed':
return {'libraries': ['zmumps_scotch', 'mumps_common_scotch',
'pord', 'mpiseq_scotch', 'gfortran']}
return {}
def extensions():
"""Return a list of tuples (args, kwrds) to be passed to
Extension. possibly after replacing ".pyx" with ".c" if Cython is not to be
used."""
global build_summary
build_summary = []
#### Add components of kwant without external compile-time dependencies.
result = [
(['kwant._system', ['kwant/_system.pyx']],
{'include_dirs': ['kwant/graph']}),
(['kwant.graph.core', ['kwant/graph/core.pyx']],
{'depends': ['kwant/graph/core.pxd', 'kwant/graph/defs.h',
'kwant/graph/defs.pxd']}),
(['kwant.graph.utils', ['kwant/graph/utils.pyx']],
{'depends': ['kwant/graph/defs.h', 'kwant/graph/defs.pxd',
'kwant/graph/core.pxd']}),
(['kwant.graph.slicer', ['kwant/graph/slicer.pyx',
'kwant/graph/c_slicer/partitioner.cc',
'kwant/graph/c_slicer/slicer.cc']],
{'depends': ['kwant/graph/defs.h', 'kwant/graph/defs.pxd',
'kwant/graph/core.pxd',
'kwant/graph/c_slicer.pxd',
'kwant/graph/c_slicer/bucket_list.h',
'kwant/graph/c_slicer/graphwrap.h',
'kwant/graph/c_slicer/partitioner.h',
'kwant/graph/c_slicer/slicer.h']})]
#### Add components of kwant with external compile-time dependencies.
config = ConfigParser.ConfigParser()
try:
with open(CONFIG_FILE) as f:
config.readfp(f)
except IOError:
with open(CONFIG_FILE, 'w') as f:
f.write('# Created by setup.py - feel free to modify.\n')
kwrds_by_section = {}
for section in config.sections():
kwrds_by_section[section] = kwrds = {}
for name, value in config.items(section):
kwrds[name] = value.split()
# Setup LAPACK.
lapack = kwrds_by_section.get('lapack')
if lapack:
build_summary.append('User-configured LAPACK and BLAS')
else:
lapack = {'libraries': ['lapack', 'blas']}
build_summary.append('Default LAPACK and BLAS')
kwrds = lapack.copy()
kwrds.setdefault('depends', []).extend(
[CONFIG_FILE, 'kwant/linalg/f_lapack.pxd'])
result.append((['kwant.linalg.lapack', ['kwant/linalg/lapack.pyx']],
kwrds))
# Setup MUMPS.
kwrds = kwrds_by_section.get('mumps')
if kwrds:
build_summary.append('User-configured MUMPS')
else:
kwrds = debian_mumps()
if kwrds:
build_summary.append(
'MUMPS from package {0}'.format(MUMPS_DEBIAN_PACKAGE))
if kwrds:
for name, value in lapack.iteritems():
kwrds.setdefault(name, []).extend(value)
kwrds.setdefault('depends', []).extend(
[CONFIG_FILE, 'kwant/linalg/cmumps.pxd'])
result.append((['kwant.linalg._mumps', ['kwant/linalg/_mumps.pyx']],
kwrds))
else:
build_summary.append('No MUMPS support')
build_summary = '\n'.join(build_summary)
return result
def ext_modules(extensions):
"""Prepare the ext_modules argument for distutils' setup."""
result = []
for args, kwrds in extensions:
if not cythonize or not cython_version:
if 'language' in kwrds:
if kwrds['language'] == 'c':
ext = '.c'
elif kwrds['language'] == 'c++':
ext = '.cpp'
else:
print >>sys.stderr, 'Unknown language'
exit(1)
else:
print >>sys.stderr, 'Unknown language'
ext = '.c'
pyx_files = []
cythonized_files = []
sources = []
for f in args[1]:
if f[-4:] == '.pyx':
pyx_files.append(f)
f = f[:-4] + ext
cythonized_files.append(f)
sources.append(f)
args[1] = sources
try:
cythonized_oldest = min(os.stat(f).st_mtime
for f in cythonized_files)
except OSError:
print >>sys.stderr, \
"Error: Cython-generated file {0} is missing.".format(f)
if cythonize:
print >>sys.stderr, "Install Cython so it can be made" \
" or use a source distribution of kwant."
else:
print >>sys.stderr, "Run setup.py without", \
NO_CYTHON_OPTION
exit(1)
for f in pyx_files + kwrds.get('depends', []):
if os.stat(f).st_mtime > cythonized_oldest:
msg = "Warning: {0} is newer than its source file, "
if cythonize:
msg += "but Cython is not installed."
else:
msg += "but Cython is not to be run."
print >>sys.stderr, msg.format(f)
result.append(Extension(*args, **kwrds))
return result
def main():
if cythonize and cython_version < REQUIRED_CYTHON_VERSION:
msg = 'Warning: Cython {0} is required but '
if cython_version:
msg += 'only {1} is present.'
else:
ext = '.c'
pyx_files = []
cythonized_files = []
sources = []
for f in args[1]:
if f[-4:] == '.pyx':
pyx_files.append(f)
f = f[:-4] + ext
cythonized_files.append(f)
sources.append(f)
args[1] = sources
msg += 'it is not installed.'
print >>sys.stderr, msg.format(
'.'.join(str(e) for e in REQUIRED_CYTHON_VERSION),
'.'.join(str(e) for e in cython_version))
try:
cythonized_oldest = min(os.stat(f).st_mtime
for f in cythonized_files)
except OSError:
msg = "{0} is missing. Run `./setup.py --run-cython build'."
print >>sys.stderr, msg.format(f)
exit(1)
for f in pyx_files + keywords.get('depends', []):
if os.stat(f).st_mtime > cythonized_oldest:
msg = "{0} has been modified. " \
"Run `./setup.py --run-cython build'."
print >>sys.stderr, msg.format(f)
exit(1)
setup(name='kwant',
version=version(),
author='A. R. Akhmerov, C. W. Groth, X. Waintal, M. Wimmer',
author_email='christoph.groth@cea.fr',
description="A package for numerical "
"quantum transport calculations.",
license="not to be distributed",
packages=["kwant", "kwant.graph", "kwant.linalg", "kwant.physics",
"kwant.solvers"],
cmdclass={'build_ext': kwant_build_ext},
ext_modules=ext_modules(extensions()),
include_dirs=[numpy.get_include()])
ext_modules.append(Extension(*args, **keywords))
include_dirs = [np.get_include()]
setup(name='kwant',
version=version,
author='A. R. Akhmerov, C. W. Groth, X. Waintal, M. Wimmer',
author_email='cwg@falma.de',
description="A package for numerical quantum transport calculations.",
license="not to be distributed",
packages=["kwant", "kwant.graph", "kwant.linalg", "kwant.physics",
"kwant.solvers"],
cmdclass=cmdclass,
ext_modules=ext_modules,
include_dirs = include_dirs)
if __name__ == '__main__':
main()
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment