xref: /petsc/setup.py (revision 6e200cf138d7208212dabd38e5aa8adb86863e7f)
1#!/usr/bin/env python
2
3"""
4TAO: Toolkit for Advanced Optimization
5======================================
6
7The Toolkit for Advanced Optimization (TAO) is aimed at the solution
8of large-scale optimization problems on high-performance
9architectures. Its main goals are portability, performance, scalable
10parallelism, and an interface independent of the architecture. TAO is
11suitable for both single-processor and massively-parallel
12architectures.
13
14.. tip::
15
16  You can also install `tao-dev`_ with::
17
18    $ pip install petsc==dev tao==dev
19
20  .. _tao-dev: http://bitbucket.org/sarich/tao-devel/
21               get/tip.tar.gz#egg=tao-dev
22"""
23
24import sys, os
25from distutils.core import setup
26from distutils.util import get_platform
27from distutils.spawn import find_executable
28from distutils.command.build import build as _build
29if 'setuptools' in sys.modules:
30    from setuptools.command.install import install as _install
31else:
32    from distutils.command.install import install as _install
33from distutils.command.sdist import sdist as _sdist
34from distutils import log
35
36init_py = """\
37# Author:  TAO Team
38# Contact: tao-comments@mcs.anl.gov
39
40def get_tao_dir():
41    import os
42    return os.path.dirname(__file__)
43
44def get_config():
45    conf = {}
46    conf['TAO_DIR'] = get_tao_dir()
47    return conf
48"""
49
50metadata = {
51    'provides' : ['tao'],
52    'requires' : [],
53}
54
55def bootstrap():
56    from os.path import join, isdir, abspath
57    # Set TAO_DIR
58    TAO_DIR  = abspath(os.getcwd())
59    os.environ['TAO_DIR']  = TAO_DIR
60    # Check PETSC_DIR/PETSC_ARCH
61    PETSC_DIR  = os.environ.get('PETSC_DIR',  "")
62    PETSC_ARCH = os.environ.get('PETSC_ARCH', "")
63    if not (PETSC_DIR and isdir(PETSC_DIR)):
64        PETSC_DIR = None
65        try: del os.environ['PETSC_DIR']
66        except KeyError: pass
67        PETSC_ARCH = None
68        try: del os.environ['PETSC_ARCH']
69        except KeyError: pass
70    elif not isdir(join(PETSC_DIR, PETSC_ARCH)):
71        PETSC_ARCH = None
72        try: del os.environ['PETSC_ARCH']
73        except KeyError: pass
74    # Generate package __init__.py file
75    from distutils.dir_util import mkpath
76    pkgdir = os.path.join(TAO_DIR, 'pypi')
77    pkgfile = os.path.join(pkgdir, '__init__.py')
78    if not os.path.exists(pkgdir): mkpath(pkgdir)
79    fh = open(pkgfile, 'wt')
80    fh.write(init_py)
81    fh.close()
82    if ('setuptools' in sys.modules):
83        metadata['zip_safe'] = False
84        if not PETSC_DIR:
85            metadata['install_requires']= ['petsc>=3.3,<3.4']
86
87def get_petsc_dir():
88    PETSC_DIR = os.environ.get('PETSC_DIR')
89    if PETSC_DIR: return PETSC_DIR
90    try:
91        import petsc
92        PETSC_DIR = petsc.get_petsc_dir()
93    except ImportError:
94        log.warn("PETSC_DIR not specified")
95        PETSC_DIR = os.path.join(os.path.sep, 'usr', 'local', 'petsc')
96    return PETSC_DIR
97
98def get_petsc_arch():
99    PETSC_ARCH = os.environ.get('PETSC_ARCH') or ''
100    return PETSC_ARCH
101
102def config(dry_run=False):
103    log.info('TAO: configure')
104    if dry_run: return
105    # Run TAO configure
106    os.environ['PETSC_DIR'] = get_petsc_dir()
107    status = 0#os.system("./configure")
108    if status != 0: raise RuntimeError(status)
109
110def build(dry_run=False):
111    log.info('TAO: build')
112    if dry_run: return
113    # Run TAO build
114    status = os.system(" ".join((
115            find_executable('make'),
116            'PETSC_DIR='+get_petsc_dir(),
117            'PETSC_ARCH='+get_petsc_arch(),
118            'all',
119            )))
120    if status != 0: raise RuntimeError
121
122def install(dest_dir, prefix=None, dry_run=False):
123    log.info('TAO: install')
124    if dry_run: return
125    TAO_DIR = os.environ['TAO_DIR']
126    PETSC_ARCH = get_petsc_arch()
127    # Run TAO install (python)
128    from distutils.file_util import copy_file
129    from distutils.dir_util import copy_tree
130    copy_tree(os.path.join(TAO_DIR,  'include'),
131              os.path.join(dest_dir, 'include'))
132    copy_tree(os.path.join(TAO_DIR,  'conf'),
133              os.path.join(dest_dir, 'conf'))
134    copy_tree(os.path.join(TAO_DIR, PETSC_ARCH, 'lib'),
135              os.path.join(dest_dir, 'lib'))
136    # remove bad files
137    badfiles = [os.path.join(dest_dir, 'conf', 'install.py')]
138    for dirname, _, filenames in os.walk(
139        os.path.join(dest_dir, 'include')):
140        badfiles += [os.path.join(dirname, f)
141                     for f in filenames
142                     if f.endswith('.html')]
143    for filename in badfiles:
144        fullpath = os.path.join(dirname, filename)
145        try:
146            os.remove(fullpath)
147            log.info("removing %s", fullpath)
148        except:
149            pass
150
151class context:
152    def __init__(self):
153        self.sys_argv = sys.argv[:]
154        self.wdir = os.getcwd()
155    def enter(self):
156        del sys.argv[1:]
157        pdir = os.environ['TAO_DIR']
158        os.chdir(pdir)
159        return self
160    def exit(self):
161        sys.argv[:] = self.sys_argv
162        os.chdir(self.wdir)
163
164class cmd_build(_build):
165
166    def initialize_options(self):
167        _build.initialize_options(self)
168        PETSC_ARCH = get_petsc_arch()
169        self.build_base = os.path.join(PETSC_ARCH, 'build-python')
170
171    def run(self):
172        _build.run(self)
173        ctx = context().enter()
174        try:
175            config(self.dry_run)
176            build(self.dry_run)
177        finally:
178            ctx.exit()
179
180class cmd_install(_install):
181
182    def initialize_options(self):
183        _install.initialize_options(self)
184        self.optimize = 1
185
186    def run(self):
187        root_dir = self.install_platlib
188        dest_dir = os.path.join(root_dir, 'tao')
189        bdist_base = self.get_finalized_command('bdist').bdist_base
190        if dest_dir.startswith(bdist_base):
191            prefix = dest_dir[len(bdist_base)+1:]
192            prefix = prefix[prefix.index(os.path.sep):]
193        else:
194            prefix = dest_dir
195        dest_dir = os.path.abspath(dest_dir)
196        prefix   = os.path.abspath(prefix)
197        #
198        _install.run(self)
199        ctx = context().enter()
200        try:
201            install(dest_dir, prefix, self.dry_run)
202        finally:
203            ctx.exit()
204
205manifest_in = """\
206include makefile LICENSE
207
208recursive-include include *
209recursive-include src *
210recursive-include conf *
211
212recursive-exclude include *.html
213recursive-exclude src *.html
214recursive-exclude src/*/examples/* *.*
215recursive-exclude pypi *.*
216"""
217
218class cmd_sdist(_sdist):
219
220    def initialize_options(self):
221        _sdist.initialize_options(self)
222        self.force_manifest = 1
223        self.template = os.path.join('pypi', 'manifest.in')
224        # Generate manifest.in file
225        from distutils.dir_util import mkpath
226        TAO_DIR = os.environ['TAO_DIR']
227        pkgdir = os.path.join(TAO_DIR, 'pypi')
228        if not os.path.exists(pkgdir): mkpath(pkgdir)
229        template = self.template
230        fh = open(template, 'wt')
231        fh.write(manifest_in)
232        fh.close()
233
234def version():
235    import re
236    version_re = {
237        'major'  : re.compile(r"#define\s+TAO_VERSION_MAJOR\s+(\d+)"),
238        'minor'  : re.compile(r"#define\s+TAO_VERSION_MINOR\s+(\d+)"),
239        'micro'  : re.compile(r"#define\s+TAO_VERSION_SUBMINOR\s+(\d+)"),
240        'patch'  : re.compile(r"#define\s+TAO_VERSION_PATCH\s+(\d+)"),
241        'release': re.compile(r"#define\s+TAO_VERSION_RELEASE\s+(\d+)"),
242        }
243    taoversion_h = os.path.join('include','tao_version.h')
244    data = open(taoversion_h, 'rt').read()
245    major = int(version_re['major'].search(data).groups()[0])
246    minor = int(version_re['minor'].search(data).groups()[0])
247    micro = int(version_re['micro'].search(data).groups()[0])
248    patch = int(version_re['patch'].search(data).groups()[0])
249    release = int(version_re['release'].search(data).groups()[0])
250    if release:
251        v = "%d.%d" % (major, minor)
252        if micro > 0:
253            v += ".%d" % micro
254        if patch > 0:
255            v += ".%d" % patch
256    else:
257        v = "%d.%d.dev%d" % (major, minor+1, 0)
258    return v
259
260def tarball():
261    VERSION = version()
262    if '.dev' in VERSION:
263        return None
264    bits = VERSION.split('.')
265    if len(bits) == 2: bits.append('0')
266    TAO_VERSION = '.'.join(bits[:-1]) + '-p' + bits[-1]
267    return ('http://www.mcs.anl.gov/research/projects/tao/download/'
268            'tao-%s.tar.gz#egg=tao-%s' % (TAO_VERSION, VERSION))
269
270description = __doc__.split('\n')[1:-1]; del description[1:3]
271classifiers = """
272License :: OSI Approved
273Operating System :: POSIX
274Intended Audience :: Developers
275Intended Audience :: Science/Research
276Programming Language :: C
277Programming Language :: C++
278Programming Language :: Fortran
279Programming Language :: Python
280Topic :: Scientific/Engineering
281Topic :: Software Development :: Libraries
282"""
283
284bootstrap()
285print tarball()
286setup(name='tao',
287      version=version(),
288      description=description.pop(0),
289      long_description='\n'.join(description),
290      classifiers= classifiers.split('\n')[1:-1],
291      keywords = ['TAO', 'PETSc', 'MPI'],
292      platforms=['POSIX'],
293      license='TAO',
294
295      url='http://www.mcs.anl.gov/tao/',
296      download_url=tarball(),
297
298      author='TAO Team',
299      author_email='tao-comments@mcs.anl.gov',
300      maintainer='Lisandro Dalcin',
301      maintainer_email='dalcinl@gmail.com',
302
303      packages = ['tao'],
304      package_dir = {'tao': 'pypi'},
305      cmdclass={
306        'build': cmd_build,
307        'install': cmd_install,
308        'sdist': cmd_sdist,
309        },
310      **metadata)
311