xref: /petsc/src/binding/petsc4py/conf/confpetsc.py (revision 56478d3069f08f375747706ae602e4856d1971c9)
1f46a955bSLisandro Dalcin# --------------------------------------------------------------------
2f46a955bSLisandro Dalcin
3f46a955bSLisandro Dalcinimport re
4f46a955bSLisandro Dalcinimport os
5f46a955bSLisandro Dalcinimport sys
6f46a955bSLisandro Dalcinimport glob
7f46a955bSLisandro Dalcinimport copy
8f46a955bSLisandro Dalcinimport warnings
9f46a955bSLisandro Dalcin
10f46a955bSLisandro Dalcintry:
11f46a955bSLisandro Dalcin    from cStringIO import StringIO
12f46a955bSLisandro Dalcinexcept ImportError:
13f46a955bSLisandro Dalcin    from io import StringIO
14f46a955bSLisandro Dalcin
15f46a955bSLisandro Dalcintry:
16f46a955bSLisandro Dalcin    import setuptools
17f46a955bSLisandro Dalcinexcept ImportError:
18f46a955bSLisandro Dalcin    setuptools = None
19f46a955bSLisandro Dalcin
20f46a955bSLisandro Dalcinif setuptools:
21f46a955bSLisandro Dalcin    from setuptools import setup as _setup
22f46a955bSLisandro Dalcin    from setuptools import Extension as _Extension
23f46a955bSLisandro Dalcin    from setuptools import Command
24f46a955bSLisandro Dalcinelse:
25f46a955bSLisandro Dalcin    from distutils.core import setup as _setup
26f46a955bSLisandro Dalcin    from distutils.core import Extension as _Extension
27f46a955bSLisandro Dalcin    from distutils.core import Command
28f46a955bSLisandro Dalcin
29f46a955bSLisandro Dalcindef import_command(cmd):
30f46a955bSLisandro Dalcin    try:
31f46a955bSLisandro Dalcin        from importlib import import_module
32f46a955bSLisandro Dalcin    except ImportError:
33f46a955bSLisandro Dalcin        def import_module(n):
34f46a955bSLisandro Dalcin            return __import__(n, fromlist=[None])
35f46a955bSLisandro Dalcin    try:
36f46a955bSLisandro Dalcin        if not setuptools: raise ImportError
37f46a955bSLisandro Dalcin        mod = import_module('setuptools.command.' + cmd)
38f46a955bSLisandro Dalcin        return getattr(mod, cmd)
39f46a955bSLisandro Dalcin    except ImportError:
40f46a955bSLisandro Dalcin        mod = import_module('distutils.command.' + cmd)
41f46a955bSLisandro Dalcin        return getattr(mod, cmd)
42f46a955bSLisandro Dalcin
43f46a955bSLisandro Dalcin_config    = import_command('config')
44f46a955bSLisandro Dalcin_build     = import_command('build')
45f46a955bSLisandro Dalcin_build_ext = import_command('build_ext')
46f46a955bSLisandro Dalcin_install   = import_command('install')
47f46a955bSLisandro Dalcin
48f46a955bSLisandro Dalcinfrom distutils import log
49f46a955bSLisandro Dalcinfrom distutils import sysconfig
50f46a955bSLisandro Dalcinfrom distutils.util import execute
51f46a955bSLisandro Dalcinfrom distutils.util import split_quoted
52f46a955bSLisandro Dalcinfrom distutils.errors import DistutilsError
53f46a955bSLisandro Dalcin
54f46a955bSLisandro Dalcintry:
55*56478d30SPierre Jolivet    from setuptools import modified
56f46a955bSLisandro Dalcinexcept ImportError:
57*56478d30SPierre Jolivet  try:
58*56478d30SPierre Jolivet      from setuptools import dep_util as modified
59*56478d30SPierre Jolivet  except ImportError:
60*56478d30SPierre Jolivet      from distutils import dep_util as modified
61f46a955bSLisandro Dalcin
62f46a955bSLisandro Dalcintry:
63f46a955bSLisandro Dalcin    from packaging.version import Version
64f46a955bSLisandro Dalcinexcept ImportError:
65f46a955bSLisandro Dalcin    try:
66f46a955bSLisandro Dalcin        from setuptools.extern.packaging.version import Version
67f46a955bSLisandro Dalcin    except ImportError:
68f46a955bSLisandro Dalcin        from distutils.version import StrictVersion as Version
69f46a955bSLisandro Dalcin
70f46a955bSLisandro Dalcin# --------------------------------------------------------------------
71f46a955bSLisandro Dalcin
72f46a955bSLisandro Dalcin# Cython
73f46a955bSLisandro Dalcin
74b12f50ebSLisandro DalcinCYTHON = '3.0.0'
75f46a955bSLisandro Dalcin
76f46a955bSLisandro Dalcindef cython_req():
77f46a955bSLisandro Dalcin    return CYTHON
78f46a955bSLisandro Dalcin
79f46a955bSLisandro Dalcindef cython_chk(VERSION, verbose=True):
80f46a955bSLisandro Dalcin    #
81f46a955bSLisandro Dalcin    def warn(message):
82f46a955bSLisandro Dalcin        if not verbose: return
83f46a955bSLisandro Dalcin        ruler, ws, nl = "*"*80, " " ,"\n"
84f46a955bSLisandro Dalcin        pyexe = sys.executable
85f46a955bSLisandro Dalcin        advise = "$ %s -m pip install --upgrade cython" % pyexe
86f46a955bSLisandro Dalcin        def printer(*s): sys.stderr.write(" ".join(s)+"\n")
87f46a955bSLisandro Dalcin        printer(ruler, nl)
88f46a955bSLisandro Dalcin        printer(ws, message, nl)
89f46a955bSLisandro Dalcin        printer(ws, ws, advise, nl)
90f46a955bSLisandro Dalcin        printer(ruler)
91f46a955bSLisandro Dalcin    #
92f46a955bSLisandro Dalcin    try:
93f46a955bSLisandro Dalcin        import Cython
94f46a955bSLisandro Dalcin    except ImportError:
95f46a955bSLisandro Dalcin        warn("You need Cython to generate C source files.")
96f46a955bSLisandro Dalcin        return False
97f46a955bSLisandro Dalcin    #
98f46a955bSLisandro Dalcin    CYTHON_VERSION = Cython.__version__
99f46a955bSLisandro Dalcin    m = re.match(r"(\d+\.\d+(?:\.\d+)?).*", CYTHON_VERSION)
100f46a955bSLisandro Dalcin    if not m:
101f46a955bSLisandro Dalcin        warn("Cannot parse Cython version string {0!r}"
102f46a955bSLisandro Dalcin             .format(CYTHON_VERSION))
103f46a955bSLisandro Dalcin        return False
104f46a955bSLisandro Dalcin    REQUIRED = Version(VERSION)
105f46a955bSLisandro Dalcin    PROVIDED = Version(m.groups()[0])
106b12f50ebSLisandro Dalcin    if PROVIDED < REQUIRED:
107b12f50ebSLisandro Dalcin        warn("You need Cython >= {0} (you have version {1})"
108f46a955bSLisandro Dalcin             .format(VERSION, CYTHON_VERSION))
109f46a955bSLisandro Dalcin        return False
110f46a955bSLisandro Dalcin    #
111f46a955bSLisandro Dalcin    if verbose:
112f46a955bSLisandro Dalcin        log.info("using Cython %s" % CYTHON_VERSION)
113f46a955bSLisandro Dalcin    return True
114f46a955bSLisandro Dalcin
115f46a955bSLisandro Dalcindef cython_run(
116f46a955bSLisandro Dalcin    source, target=None,
117f46a955bSLisandro Dalcin    depends=(), includes=(),
118f46a955bSLisandro Dalcin    workdir=None, force=False,
119f46a955bSLisandro Dalcin    VERSION="0.0",
120f46a955bSLisandro Dalcin):
121f46a955bSLisandro Dalcin    if target is None:
122f46a955bSLisandro Dalcin        target = os.path.splitext(source)[0]+'.c'
123f46a955bSLisandro Dalcin    cwd = os.getcwd()
124f46a955bSLisandro Dalcin    try:
125f46a955bSLisandro Dalcin        if workdir:
126f46a955bSLisandro Dalcin            os.chdir(workdir)
127f46a955bSLisandro Dalcin        alldeps = [source]
128f46a955bSLisandro Dalcin        for dep in depends:
129f46a955bSLisandro Dalcin            alldeps += glob.glob(dep)
130*56478d30SPierre Jolivet        if not (force or modified.newer_group(alldeps, target)):
131f46a955bSLisandro Dalcin            log.debug("skipping '%s' -> '%s' (up-to-date)",
132f46a955bSLisandro Dalcin                      source, target)
133f46a955bSLisandro Dalcin            return
134f46a955bSLisandro Dalcin    finally:
135f46a955bSLisandro Dalcin        os.chdir(cwd)
13680e0d92bSLisandro Dalcin    require = 'Cython >= %s' % VERSION
137f46a955bSLisandro Dalcin    if setuptools and not cython_chk(VERSION, verbose=False):
138f46a955bSLisandro Dalcin        if sys.modules.get('Cython'):
139f46a955bSLisandro Dalcin            removed = getattr(sys.modules['Cython'], '__version__', '')
140f46a955bSLisandro Dalcin            log.info("removing Cython %s from sys.modules" % removed)
141f46a955bSLisandro Dalcin            pkgname = re.compile(r'cython(\.|$)', re.IGNORECASE)
142f46a955bSLisandro Dalcin            for modname in list(sys.modules.keys()):
143f46a955bSLisandro Dalcin                if pkgname.match(modname):
144f46a955bSLisandro Dalcin                    del sys.modules[modname]
145f46a955bSLisandro Dalcin        try:
146f46a955bSLisandro Dalcin            install_setup_requires = setuptools._install_setup_requires
147f46a955bSLisandro Dalcin            with warnings.catch_warnings():
148f46a955bSLisandro Dalcin                if hasattr(setuptools, 'SetuptoolsDeprecationWarning'):
149f46a955bSLisandro Dalcin                    category = setuptools.SetuptoolsDeprecationWarning
150f46a955bSLisandro Dalcin                    warnings.simplefilter('ignore', category)
151f46a955bSLisandro Dalcin                log.info("fetching build requirement '%s'" % require)
152f46a955bSLisandro Dalcin                install_setup_requires(dict(setup_requires=[require]))
153f46a955bSLisandro Dalcin        except Exception:
154f46a955bSLisandro Dalcin            log.info("failed to fetch build requirement '%s'" % require)
155f46a955bSLisandro Dalcin    if not cython_chk(VERSION):
156f46a955bSLisandro Dalcin        raise DistutilsError("unsatisfied build requirement '%s'" % require)
157f46a955bSLisandro Dalcin    #
158f46a955bSLisandro Dalcin    log.info("cythonizing '%s' -> '%s'", source, target)
159f46a955bSLisandro Dalcin    from cythonize import cythonize
160f46a955bSLisandro Dalcin    args = []
161f46a955bSLisandro Dalcin    if workdir:
162f46a955bSLisandro Dalcin        args += ['--working', workdir]
163f46a955bSLisandro Dalcin    args += [source]
164f46a955bSLisandro Dalcin    if target:
165f46a955bSLisandro Dalcin        args += ['--output-file', target]
166f46a955bSLisandro Dalcin    err = cythonize(args)
167f46a955bSLisandro Dalcin    if err:
168f46a955bSLisandro Dalcin        raise DistutilsError(
169f46a955bSLisandro Dalcin            "Cython failure: '%s' -> '%s'" % (source, target)
170f46a955bSLisandro Dalcin        )
171f46a955bSLisandro Dalcin
172f46a955bSLisandro Dalcin
173f46a955bSLisandro Dalcin# --------------------------------------------------------------------
174f46a955bSLisandro Dalcin
175f46a955bSLisandro Dalcindef fix_config_vars(names, values):
176f46a955bSLisandro Dalcin    values = list(values)
177f46a955bSLisandro Dalcin    if 'CONDA_BUILD' in os.environ:
178f46a955bSLisandro Dalcin        return values
179f46a955bSLisandro Dalcin    if sys.platform == 'darwin':
180f46a955bSLisandro Dalcin        if 'ARCHFLAGS' in os.environ:
181f46a955bSLisandro Dalcin            ARCHFLAGS = os.environ['ARCHFLAGS']
182f46a955bSLisandro Dalcin            for i, flag in enumerate(list(values)):
1838acd7bfaSLisandro Dalcin                flag, count = re.subn(r'-arch\s+\w+', ' ', str(flag))
184f46a955bSLisandro Dalcin                if count and ARCHFLAGS:
185f46a955bSLisandro Dalcin                    flag = flag + ' ' + ARCHFLAGS
186f46a955bSLisandro Dalcin                values[i] = flag
187f46a955bSLisandro Dalcin        if 'SDKROOT' in os.environ:
188f46a955bSLisandro Dalcin            SDKROOT = os.environ['SDKROOT']
189f46a955bSLisandro Dalcin            for i, flag in enumerate(list(values)):
1908acd7bfaSLisandro Dalcin                flag, count = re.subn(r'-isysroot [^ \t]*', ' ', str(flag))
191f46a955bSLisandro Dalcin                if count and SDKROOT:
192f46a955bSLisandro Dalcin                    flag = flag + ' ' + '-isysroot ' + SDKROOT
193f46a955bSLisandro Dalcin                values[i] = flag
194f46a955bSLisandro Dalcin    return values
195f46a955bSLisandro Dalcin
196f46a955bSLisandro Dalcindef get_config_vars(*names):
197f46a955bSLisandro Dalcin    # Core Python configuration
198f46a955bSLisandro Dalcin    values = sysconfig.get_config_vars(*names)
199f46a955bSLisandro Dalcin    # Do any distutils flags fixup right now
200f46a955bSLisandro Dalcin    values = fix_config_vars(names, values)
201f46a955bSLisandro Dalcin    return values
202f46a955bSLisandro Dalcin
203f46a955bSLisandro Dalcinfrom distutils.unixccompiler import UnixCCompiler
204f46a955bSLisandro Dalcinrpath_option_orig = UnixCCompiler.runtime_library_dir_option
205f46a955bSLisandro Dalcindef rpath_option(compiler, dir):
206f46a955bSLisandro Dalcin    option = rpath_option_orig(compiler, dir)
207f46a955bSLisandro Dalcin    if sys.platform[:5] == 'linux':
208f46a955bSLisandro Dalcin        if option.startswith('-R'):
209f46a955bSLisandro Dalcin            option =  option.replace('-R', '-Wl,-rpath,', 1)
210f46a955bSLisandro Dalcin        elif option.startswith('-Wl,-R'):
211f46a955bSLisandro Dalcin            option =  option.replace('-Wl,-R', '-Wl,-rpath,', 1)
212f46a955bSLisandro Dalcin    return option
213f46a955bSLisandro DalcinUnixCCompiler.runtime_library_dir_option = rpath_option
214f46a955bSLisandro Dalcin
215f46a955bSLisandro Dalcin# --------------------------------------------------------------------
216f46a955bSLisandro Dalcin
217f46a955bSLisandro Dalcinclass PetscConfig:
218f46a955bSLisandro Dalcin
219f46a955bSLisandro Dalcin    def __init__(self, petsc_dir, petsc_arch, dest_dir=None):
220f46a955bSLisandro Dalcin        if dest_dir is None:
221f46a955bSLisandro Dalcin            dest_dir = os.environ.get('DESTDIR')
222f46a955bSLisandro Dalcin        self.configdict = { }
223f46a955bSLisandro Dalcin        if not petsc_dir:
224f46a955bSLisandro Dalcin            raise DistutilsError("PETSc not found")
225f46a955bSLisandro Dalcin        if not os.path.isdir(petsc_dir):
226f46a955bSLisandro Dalcin            raise DistutilsError("invalid PETSC_DIR: %s" % petsc_dir)
227f46a955bSLisandro Dalcin        self.version    = self._get_petsc_version(petsc_dir)
228f46a955bSLisandro Dalcin        self.configdict = self._get_petsc_config(petsc_dir, petsc_arch)
229f46a955bSLisandro Dalcin        self.PETSC_DIR  = self['PETSC_DIR']
230f46a955bSLisandro Dalcin        self.PETSC_ARCH = self['PETSC_ARCH']
231f46a955bSLisandro Dalcin        self.DESTDIR = dest_dir
232f46a955bSLisandro Dalcin        language_map = {'CONLY':'c', 'CXXONLY':'c++'}
233f46a955bSLisandro Dalcin        self.language = language_map[self['PETSC_LANGUAGE']]
234f46a955bSLisandro Dalcin
235f46a955bSLisandro Dalcin    def __getitem__(self, item):
236f46a955bSLisandro Dalcin        return self.configdict[item]
237f46a955bSLisandro Dalcin
238f46a955bSLisandro Dalcin    def get(self, item, default=None):
239f46a955bSLisandro Dalcin        return self.configdict.get(item, default)
240f46a955bSLisandro Dalcin
241f46a955bSLisandro Dalcin    def configure(self, extension, compiler=None):
242f46a955bSLisandro Dalcin        self.configure_extension(extension)
243f46a955bSLisandro Dalcin        if compiler is not None:
244f46a955bSLisandro Dalcin            self.configure_compiler(compiler)
245f46a955bSLisandro Dalcin
246f46a955bSLisandro Dalcin    def _get_petsc_version(self, petsc_dir):
247f46a955bSLisandro Dalcin        import re
248f46a955bSLisandro Dalcin        version_re = {
249f46a955bSLisandro Dalcin            'major'  : re.compile(r"#define\s+PETSC_VERSION_MAJOR\s+(\d+)"),
250f46a955bSLisandro Dalcin            'minor'  : re.compile(r"#define\s+PETSC_VERSION_MINOR\s+(\d+)"),
251f46a955bSLisandro Dalcin            'micro'  : re.compile(r"#define\s+PETSC_VERSION_SUBMINOR\s+(\d+)"),
252f46a955bSLisandro Dalcin            'release': re.compile(r"#define\s+PETSC_VERSION_RELEASE\s+(-*\d+)"),
253f46a955bSLisandro Dalcin            }
254f46a955bSLisandro Dalcin        petscversion_h = os.path.join(petsc_dir, 'include', 'petscversion.h')
255f46a955bSLisandro Dalcin        with open(petscversion_h, 'rt') as f: data = f.read()
256f46a955bSLisandro Dalcin        major = int(version_re['major'].search(data).groups()[0])
257f46a955bSLisandro Dalcin        minor = int(version_re['minor'].search(data).groups()[0])
258f46a955bSLisandro Dalcin        micro = int(version_re['micro'].search(data).groups()[0])
259f46a955bSLisandro Dalcin        release = int(version_re['release'].search(data).groups()[0])
260f46a955bSLisandro Dalcin        return  (major, minor, micro), (release == 1)
261f46a955bSLisandro Dalcin
262f46a955bSLisandro Dalcin    def _get_petsc_config(self, petsc_dir, petsc_arch):
263f46a955bSLisandro Dalcin        from os.path import join, isdir, exists
264f46a955bSLisandro Dalcin        PETSC_DIR  = petsc_dir
265f46a955bSLisandro Dalcin        PETSC_ARCH = petsc_arch
266f46a955bSLisandro Dalcin        #
267f46a955bSLisandro Dalcin        confdir = join('lib', 'petsc', 'conf')
268f46a955bSLisandro Dalcin        if not (PETSC_ARCH and isdir(join(PETSC_DIR, PETSC_ARCH))):
269f46a955bSLisandro Dalcin            petscvars = join(PETSC_DIR, confdir, 'petscvariables')
270f46a955bSLisandro Dalcin            PETSC_ARCH = makefile(open(petscvars, 'rt')).get('PETSC_ARCH')
271f46a955bSLisandro Dalcin        if not (PETSC_ARCH and isdir(join(PETSC_DIR, PETSC_ARCH))):
272f46a955bSLisandro Dalcin            PETSC_ARCH = ''
273f46a955bSLisandro Dalcin        #
274f46a955bSLisandro Dalcin        variables = join(PETSC_DIR, confdir, 'variables')
275f46a955bSLisandro Dalcin        if not exists(variables):
276f46a955bSLisandro Dalcin            variables  = join(PETSC_DIR, PETSC_ARCH, confdir, 'variables')
277f46a955bSLisandro Dalcin        petscvariables = join(PETSC_DIR, PETSC_ARCH, confdir, 'petscvariables')
278f46a955bSLisandro Dalcin        #
279f46a955bSLisandro Dalcin        with open(variables) as f:
280f46a955bSLisandro Dalcin            contents = f.read()
281f46a955bSLisandro Dalcin        with open(petscvariables) as f:
282f46a955bSLisandro Dalcin            contents += f.read()
283f46a955bSLisandro Dalcin        #
284f46a955bSLisandro Dalcin        confstr  = 'PETSC_DIR  = %s\n' % PETSC_DIR
285f46a955bSLisandro Dalcin        confstr += 'PETSC_ARCH = %s\n' % PETSC_ARCH
286f46a955bSLisandro Dalcin        confstr += contents
287f46a955bSLisandro Dalcin        confdict = makefile(StringIO(confstr))
288f46a955bSLisandro Dalcin        return confdict
289f46a955bSLisandro Dalcin
290ec81f945SPierre Jolivet    def _configure_ext(self, ext, dct, append=False):
291f46a955bSLisandro Dalcin        extdict = ext.__dict__
292f46a955bSLisandro Dalcin        for key, values in dct.items():
293f46a955bSLisandro Dalcin            if key in extdict:
294f46a955bSLisandro Dalcin                for value in values:
295f46a955bSLisandro Dalcin                    if value not in extdict[key]:
296ec81f945SPierre Jolivet                        if not append:
297f46a955bSLisandro Dalcin                            extdict[key].insert(0, value)
298f46a955bSLisandro Dalcin                        else:
299f46a955bSLisandro Dalcin                            extdict[key].append(value)
300f46a955bSLisandro Dalcin
301f46a955bSLisandro Dalcin    def configure_extension(self, extension):
302f46a955bSLisandro Dalcin        # includes and libraries
303f46a955bSLisandro Dalcin        # paths in PETSc config files point to final installation location, but
304f46a955bSLisandro Dalcin        # we might be building against PETSc in staging location (DESTDIR) when
305f46a955bSLisandro Dalcin        # DESTDIR is set, so append DESTDIR (if nonempty) to those paths
306f46a955bSLisandro Dalcin        petsc_inc = flaglist(prepend_to_flags(self.DESTDIR, self['PETSC_CC_INCLUDES']))
307f46a955bSLisandro Dalcin        lib_flags = prepend_to_flags(self.DESTDIR, '-L%s %s' % \
308f46a955bSLisandro Dalcin                (self['PETSC_LIB_DIR'], self['PETSC_LIB_BASIC']))
309f46a955bSLisandro Dalcin        petsc_lib = flaglist(lib_flags)
310f46a955bSLisandro Dalcin        # runtime_library_dirs is not supported on Windows
311f46a955bSLisandro Dalcin        if sys.platform != 'win32':
312f46a955bSLisandro Dalcin            # if DESTDIR is set, then we're building against PETSc in a staging
313f46a955bSLisandro Dalcin            # directory, but rpath needs to point to final install directory.
314f46a955bSLisandro Dalcin            rpath = strip_prefix(self.DESTDIR, self['PETSC_LIB_DIR'])
315f46a955bSLisandro Dalcin            petsc_lib['runtime_library_dirs'].append(rpath)
316f46a955bSLisandro Dalcin
317f46a955bSLisandro Dalcin        # Link in extra libraries on static builds
318f46a955bSLisandro Dalcin        if self['BUILDSHAREDLIB'] != 'yes':
319f46a955bSLisandro Dalcin            petsc_ext_lib = split_quoted(self['PETSC_EXTERNAL_LIB_BASIC'])
320f46a955bSLisandro Dalcin            petsc_lib['extra_link_args'].extend(petsc_ext_lib)
321ec81f945SPierre Jolivet        self._configure_ext(extension, petsc_inc, append=True)
322f46a955bSLisandro Dalcin        self._configure_ext(extension, petsc_lib)
323f46a955bSLisandro Dalcin
324f46a955bSLisandro Dalcin    def configure_compiler(self, compiler):
325f46a955bSLisandro Dalcin        if compiler.compiler_type != 'unix': return
326f46a955bSLisandro Dalcin        getenv = os.environ.get
327f46a955bSLisandro Dalcin        # distutils C/C++ compiler
328f46a955bSLisandro Dalcin        (cc, cflags, ccshared, cxx) = get_config_vars(
329f46a955bSLisandro Dalcin            'CC', 'CFLAGS',  'CCSHARED', 'CXX')
330f46a955bSLisandro Dalcin        ccshared = getenv('CCSHARED', ccshared or '')
331f46a955bSLisandro Dalcin        cflags = getenv('CFLAGS', cflags or '')
332f46a955bSLisandro Dalcin        cflags = cflags.replace('-Wstrict-prototypes', '')
333f46a955bSLisandro Dalcin        # distutils linker
334f46a955bSLisandro Dalcin        (ldflags, ldshared, so_ext) = get_config_vars(
335f46a955bSLisandro Dalcin            'LDFLAGS', 'LDSHARED', 'SO')
336f46a955bSLisandro Dalcin        ld = cc
337f46a955bSLisandro Dalcin        ldshared = getenv('LDSHARED', ldshared)
338f46a955bSLisandro Dalcin        ldflags = getenv('LDFLAGS', cflags + ' ' + (ldflags or ''))
339f46a955bSLisandro Dalcin        ldcmd = split_quoted(ld) + split_quoted(ldflags)
340e35c6634SSatish Balay        ldshared = [flg for flg in split_quoted(ldshared) if flg not in ldcmd and (flg.find('/lib/spack/env')<0)]
341f46a955bSLisandro Dalcin        ldshared = str.join(' ', ldshared)
342f46a955bSLisandro Dalcin        #
343f46a955bSLisandro Dalcin        def get_flags(cmd):
344f46a955bSLisandro Dalcin            if not cmd: return ''
345f46a955bSLisandro Dalcin            cmd = split_quoted(cmd)
346f46a955bSLisandro Dalcin            if os.path.basename(cmd[0]) == 'xcrun':
347f46a955bSLisandro Dalcin                del cmd[0]
348f46a955bSLisandro Dalcin                while True:
349f46a955bSLisandro Dalcin                    if cmd[0] == '-sdk':
350f46a955bSLisandro Dalcin                        del cmd[0:2]
351f46a955bSLisandro Dalcin                        continue
352f46a955bSLisandro Dalcin                    if cmd[0] == '-log':
353f46a955bSLisandro Dalcin                        del cmd[0]
354f46a955bSLisandro Dalcin                        continue
355f46a955bSLisandro Dalcin                    break
356f46a955bSLisandro Dalcin            return ' '.join(cmd[1:])
357f46a955bSLisandro Dalcin        # PETSc C compiler
358f46a955bSLisandro Dalcin        PCC = self['PCC']
359f46a955bSLisandro Dalcin        PCC_FLAGS = get_flags(cc) + ' ' + self['PCC_FLAGS']
360f46a955bSLisandro Dalcin        PCC_FLAGS = PCC_FLAGS.replace('-fvisibility=hidden', '')
361f46a955bSLisandro Dalcin        PCC = getenv('PCC', PCC) + ' ' +  getenv('PCCFLAGS', PCC_FLAGS)
362f46a955bSLisandro Dalcin        PCC_SHARED = str.join(' ', (PCC, ccshared, cflags))
363f46a955bSLisandro Dalcin        # PETSc C++ compiler
364f46a955bSLisandro Dalcin        PCXX = PCC if self.language == 'c++' else self.get('CXX', cxx)
365f46a955bSLisandro Dalcin        # PETSc linker
366f46a955bSLisandro Dalcin        PLD = self['PCC_LINKER']
367f46a955bSLisandro Dalcin        PLD_FLAGS = get_flags(ld) + ' ' + self['PCC_LINKER_FLAGS']
368f46a955bSLisandro Dalcin        PLD_FLAGS = PLD_FLAGS.replace('-fvisibility=hidden', '')
369f46a955bSLisandro Dalcin        PLD = getenv('PLD', PLD) + ' ' + getenv('PLDFLAGS', PLD_FLAGS)
370f46a955bSLisandro Dalcin        PLD_SHARED = str.join(' ', (PLD, ldshared, ldflags))
371f46a955bSLisandro Dalcin        #
372f46a955bSLisandro Dalcin        compiler.set_executables(
373f46a955bSLisandro Dalcin            compiler     = PCC,
374f46a955bSLisandro Dalcin            compiler_cxx = PCXX,
375f46a955bSLisandro Dalcin            linker_exe   = PLD,
376f46a955bSLisandro Dalcin            compiler_so  = PCC_SHARED,
377f46a955bSLisandro Dalcin            linker_so    = PLD_SHARED,
378f46a955bSLisandro Dalcin            )
379f46a955bSLisandro Dalcin        compiler.shared_lib_extension = so_ext
380f46a955bSLisandro Dalcin        #
381f46a955bSLisandro Dalcin        if sys.platform == 'darwin':
382f46a955bSLisandro Dalcin            for attr in ('preprocessor',
383f46a955bSLisandro Dalcin                         'compiler', 'compiler_cxx', 'compiler_so',
384f46a955bSLisandro Dalcin                         'linker_so', 'linker_exe'):
385f46a955bSLisandro Dalcin                compiler_cmd = getattr(compiler, attr, [])
386f46a955bSLisandro Dalcin                while '-mno-fused-madd' in compiler_cmd:
387f46a955bSLisandro Dalcin                    compiler_cmd.remove('-mno-fused-madd')
388f46a955bSLisandro Dalcin
389f46a955bSLisandro Dalcin    def log_info(self):
390f46a955bSLisandro Dalcin        PETSC_DIR  = self['PETSC_DIR']
391f46a955bSLisandro Dalcin        PETSC_ARCH = self['PETSC_ARCH']
392f46a955bSLisandro Dalcin        version = ".".join([str(i) for i in self.version[0]])
393f46a955bSLisandro Dalcin        release = ("development", "release")[self.version[1]]
394f46a955bSLisandro Dalcin        version_info = version + ' ' + release
395f46a955bSLisandro Dalcin        integer_size = '%s-bit' % self['PETSC_INDEX_SIZE']
396f46a955bSLisandro Dalcin        scalar_type  = self['PETSC_SCALAR']
397f46a955bSLisandro Dalcin        precision    = self['PETSC_PRECISION']
398f46a955bSLisandro Dalcin        language     = self['PETSC_LANGUAGE']
399f46a955bSLisandro Dalcin        compiler     = self['PCC']
400f46a955bSLisandro Dalcin        linker       = self['PCC_LINKER']
401f46a955bSLisandro Dalcin        log.info('PETSC_DIR:    %s' % PETSC_DIR )
402f46a955bSLisandro Dalcin        log.info('PETSC_ARCH:   %s' % PETSC_ARCH )
403f46a955bSLisandro Dalcin        log.info('version:      %s' % version_info)
404f46a955bSLisandro Dalcin        log.info('integer-size: %s' % integer_size)
405f46a955bSLisandro Dalcin        log.info('scalar-type:  %s' % scalar_type)
406f46a955bSLisandro Dalcin        log.info('precision:    %s' % precision)
407f46a955bSLisandro Dalcin        log.info('language:     %s' % language)
408f46a955bSLisandro Dalcin        log.info('compiler:     %s' % compiler)
409f46a955bSLisandro Dalcin        log.info('linker:       %s' % linker)
410f46a955bSLisandro Dalcin
411f46a955bSLisandro Dalcin# --------------------------------------------------------------------
412f46a955bSLisandro Dalcin
413f46a955bSLisandro Dalcinclass Extension(_Extension):
414f46a955bSLisandro Dalcin    pass
415f46a955bSLisandro Dalcin
416f46a955bSLisandro Dalcin# --------------------------------------------------------------------
417f46a955bSLisandro Dalcin
418f46a955bSLisandro Dalcincmd_petsc_opts = [
419f46a955bSLisandro Dalcin    ('petsc-dir=', None,
420f46a955bSLisandro Dalcin     "define PETSC_DIR, overriding environmental variables"),
421f46a955bSLisandro Dalcin    ('petsc-arch=', None,
422f46a955bSLisandro Dalcin     "define PETSC_ARCH, overriding environmental variables"),
423f46a955bSLisandro Dalcin    ]
424f46a955bSLisandro Dalcin
425f46a955bSLisandro Dalcin
426f46a955bSLisandro Dalcinclass config(_config):
427f46a955bSLisandro Dalcin
428f46a955bSLisandro Dalcin    Configure = PetscConfig
429f46a955bSLisandro Dalcin
430f46a955bSLisandro Dalcin    user_options = _config.user_options + cmd_petsc_opts
431f46a955bSLisandro Dalcin
432f46a955bSLisandro Dalcin    def initialize_options(self):
433f46a955bSLisandro Dalcin        _config.initialize_options(self)
434f46a955bSLisandro Dalcin        self.petsc_dir  = None
435f46a955bSLisandro Dalcin        self.petsc_arch = None
436f46a955bSLisandro Dalcin
437f46a955bSLisandro Dalcin    def get_config_arch(self, arch):
438f46a955bSLisandro Dalcin        return config.Configure(self.petsc_dir, arch)
439f46a955bSLisandro Dalcin
440f46a955bSLisandro Dalcin    def run(self):
441f46a955bSLisandro Dalcin        _config.run(self)
442f46a955bSLisandro Dalcin        self.petsc_dir = config.get_petsc_dir(self.petsc_dir)
443f46a955bSLisandro Dalcin        if self.petsc_dir is None: return
444f46a955bSLisandro Dalcin        petsc_arch = config.get_petsc_arch(self.petsc_dir, self.petsc_arch)
445f46a955bSLisandro Dalcin        log.info('-' * 70)
446f46a955bSLisandro Dalcin        log.info('PETSC_DIR:   %s' % self.petsc_dir)
447f46a955bSLisandro Dalcin        arch_list = petsc_arch
448f46a955bSLisandro Dalcin        if not arch_list :
449f46a955bSLisandro Dalcin            arch_list = [ None ]
450f46a955bSLisandro Dalcin        for arch in arch_list:
451f46a955bSLisandro Dalcin            conf = self.get_config_arch(arch)
452f46a955bSLisandro Dalcin            archname    = conf.PETSC_ARCH or conf['PETSC_ARCH']
453f46a955bSLisandro Dalcin            scalar_type = conf['PETSC_SCALAR']
454f46a955bSLisandro Dalcin            precision   = conf['PETSC_PRECISION']
455f46a955bSLisandro Dalcin            language    = conf['PETSC_LANGUAGE']
456f46a955bSLisandro Dalcin            compiler    = conf['PCC']
457f46a955bSLisandro Dalcin            linker      = conf['PCC_LINKER']
458f46a955bSLisandro Dalcin            log.info('-'*70)
459f46a955bSLisandro Dalcin            log.info('PETSC_ARCH:  %s' % archname)
460f46a955bSLisandro Dalcin            log.info(' * scalar-type: %s' % scalar_type)
461f46a955bSLisandro Dalcin            log.info(' * precision:   %s' % precision)
462f46a955bSLisandro Dalcin            log.info(' * language:    %s' % language)
463f46a955bSLisandro Dalcin            log.info(' * compiler:    %s' % compiler)
464f46a955bSLisandro Dalcin            log.info(' * linker:      %s' % linker)
465f46a955bSLisandro Dalcin        log.info('-' * 70)
466f46a955bSLisandro Dalcin
467f46a955bSLisandro Dalcin    #@staticmethod
468f46a955bSLisandro Dalcin    def get_petsc_dir(petsc_dir):
469f46a955bSLisandro Dalcin        if not petsc_dir: return None
470f46a955bSLisandro Dalcin        petsc_dir = os.path.expandvars(petsc_dir)
471f46a955bSLisandro Dalcin        if not petsc_dir or '$PETSC_DIR' in petsc_dir:
472f46a955bSLisandro Dalcin            try:
473f46a955bSLisandro Dalcin                import petsc
474f46a955bSLisandro Dalcin                petsc_dir = petsc.get_petsc_dir()
475f46a955bSLisandro Dalcin            except ImportError:
476f46a955bSLisandro Dalcin                log.warn("PETSC_DIR not specified")
477f46a955bSLisandro Dalcin                return None
478f46a955bSLisandro Dalcin        petsc_dir = os.path.expanduser(petsc_dir)
479f46a955bSLisandro Dalcin        petsc_dir = os.path.abspath(petsc_dir)
480f46a955bSLisandro Dalcin        return config.chk_petsc_dir(petsc_dir)
481f46a955bSLisandro Dalcin    get_petsc_dir = staticmethod(get_petsc_dir)
482f46a955bSLisandro Dalcin
483f46a955bSLisandro Dalcin    #@staticmethod
484f46a955bSLisandro Dalcin    def chk_petsc_dir(petsc_dir):
485f46a955bSLisandro Dalcin        if not os.path.isdir(petsc_dir):
486f46a955bSLisandro Dalcin            log.error('invalid PETSC_DIR: %s (ignored)' % petsc_dir)
487f46a955bSLisandro Dalcin            return None
488f46a955bSLisandro Dalcin        return petsc_dir
489f46a955bSLisandro Dalcin    chk_petsc_dir = staticmethod(chk_petsc_dir)
490f46a955bSLisandro Dalcin
491f46a955bSLisandro Dalcin    #@staticmethod
492f46a955bSLisandro Dalcin    def get_petsc_arch(petsc_dir, petsc_arch):
493f46a955bSLisandro Dalcin        if not petsc_dir: return None
494f46a955bSLisandro Dalcin        petsc_arch = os.path.expandvars(petsc_arch)
495f46a955bSLisandro Dalcin        if (not petsc_arch or '$PETSC_ARCH' in petsc_arch):
496f46a955bSLisandro Dalcin            petsc_arch = ''
497f46a955bSLisandro Dalcin            petsc_conf = os.path.join(petsc_dir, 'lib', 'petsc', 'conf')
498f46a955bSLisandro Dalcin            if os.path.isdir(petsc_conf):
499f46a955bSLisandro Dalcin                petscvariables = os.path.join(petsc_conf, 'petscvariables')
500f46a955bSLisandro Dalcin                if os.path.exists(petscvariables):
501f46a955bSLisandro Dalcin                    conf = makefile(open(petscvariables, 'rt'))
502f46a955bSLisandro Dalcin                    petsc_arch = conf.get('PETSC_ARCH', '')
503f46a955bSLisandro Dalcin        petsc_arch = petsc_arch.split(os.pathsep)
504f46a955bSLisandro Dalcin        petsc_arch = unique(petsc_arch)
505f46a955bSLisandro Dalcin        petsc_arch = [arch for arch in petsc_arch if arch]
506f46a955bSLisandro Dalcin        return config.chk_petsc_arch(petsc_dir, petsc_arch)
507f46a955bSLisandro Dalcin    get_petsc_arch = staticmethod(get_petsc_arch)
508f46a955bSLisandro Dalcin
509f46a955bSLisandro Dalcin    #@staticmethod
510f46a955bSLisandro Dalcin    def chk_petsc_arch(petsc_dir, petsc_arch):
511f46a955bSLisandro Dalcin        valid_archs = []
512f46a955bSLisandro Dalcin        for arch in petsc_arch:
513f46a955bSLisandro Dalcin            arch_path = os.path.join(petsc_dir, arch)
514f46a955bSLisandro Dalcin            if os.path.isdir(arch_path):
515f46a955bSLisandro Dalcin                valid_archs.append(arch)
516f46a955bSLisandro Dalcin            else:
517f46a955bSLisandro Dalcin                log.warn("invalid PETSC_ARCH: %s (ignored)" % arch)
518f46a955bSLisandro Dalcin        return valid_archs
519f46a955bSLisandro Dalcin    chk_petsc_arch = staticmethod(chk_petsc_arch)
520f46a955bSLisandro Dalcin
521f46a955bSLisandro Dalcin
522f46a955bSLisandro Dalcinclass build(_build):
523f46a955bSLisandro Dalcin
52455a74a43SLisandro Dalcin    user_options = _build.user_options
52555a74a43SLisandro Dalcin    user_options += [(
52655a74a43SLisandro Dalcin        'inplace',
52755a74a43SLisandro Dalcin        'i',
52855a74a43SLisandro Dalcin        "ignore build-lib and put compiled extensions into the source "
52955a74a43SLisandro Dalcin        "directory alongside your pure Python modules",
53055a74a43SLisandro Dalcin    )]
53155a74a43SLisandro Dalcin    user_options += cmd_petsc_opts
53255a74a43SLisandro Dalcin
53355a74a43SLisandro Dalcin    boolean_options = _build.boolean_options
53455a74a43SLisandro Dalcin    boolean_options += ['inplace']
535f46a955bSLisandro Dalcin
536f46a955bSLisandro Dalcin    def initialize_options(self):
537f46a955bSLisandro Dalcin        _build.initialize_options(self)
53855a74a43SLisandro Dalcin        self.inplace = None
539f46a955bSLisandro Dalcin        self.petsc_dir  = None
540f46a955bSLisandro Dalcin        self.petsc_arch = None
541f46a955bSLisandro Dalcin
542f46a955bSLisandro Dalcin    def finalize_options(self):
543f46a955bSLisandro Dalcin        _build.finalize_options(self)
54455a74a43SLisandro Dalcin        if self.inplace is None:
54555a74a43SLisandro Dalcin            self.inplace = False
546f46a955bSLisandro Dalcin        self.set_undefined_options('config',
547f46a955bSLisandro Dalcin                                   ('petsc_dir',  'petsc_dir'),
548f46a955bSLisandro Dalcin                                   ('petsc_arch', 'petsc_arch'))
549f46a955bSLisandro Dalcin        self.petsc_dir  = config.get_petsc_dir(self.petsc_dir)
550f46a955bSLisandro Dalcin        self.petsc_arch = config.get_petsc_arch(self.petsc_dir,
551f46a955bSLisandro Dalcin                                                self.petsc_arch)
552f46a955bSLisandro Dalcin
553f46a955bSLisandro Dalcin    sub_commands = \
554f46a955bSLisandro Dalcin        [('build_src', lambda *args: True)] + \
555f46a955bSLisandro Dalcin        _build.sub_commands
556f46a955bSLisandro Dalcin
557f46a955bSLisandro Dalcin
558f46a955bSLisandro Dalcinclass build_src(Command):
559f46a955bSLisandro Dalcin    description = "build C sources from Cython files"
560f46a955bSLisandro Dalcin
561f46a955bSLisandro Dalcin    user_options = [
562f46a955bSLisandro Dalcin        ('force', 'f',
563f46a955bSLisandro Dalcin         "forcibly build everything (ignore file timestamps)"),
564f46a955bSLisandro Dalcin        ]
565f46a955bSLisandro Dalcin
566f46a955bSLisandro Dalcin    boolean_options = ['force']
567f46a955bSLisandro Dalcin
568f46a955bSLisandro Dalcin    def initialize_options(self):
569f46a955bSLisandro Dalcin        self.force = False
570f46a955bSLisandro Dalcin
571f46a955bSLisandro Dalcin    def finalize_options(self):
572f46a955bSLisandro Dalcin        self.set_undefined_options('build',
573f46a955bSLisandro Dalcin                                   ('force', 'force'),
574f46a955bSLisandro Dalcin                                   )
575f46a955bSLisandro Dalcin
576f46a955bSLisandro Dalcin    def run(self):
577f46a955bSLisandro Dalcin        sources = getattr(self, 'sources', [])
578f46a955bSLisandro Dalcin        for source in sources:
579f46a955bSLisandro Dalcin            cython_run(
580f46a955bSLisandro Dalcin                force=self.force,
581f46a955bSLisandro Dalcin                VERSION=cython_req(),
582f46a955bSLisandro Dalcin                **source
583f46a955bSLisandro Dalcin            )
584f46a955bSLisandro Dalcin
585f46a955bSLisandro Dalcin
586f46a955bSLisandro Dalcinclass build_ext(_build_ext):
587f46a955bSLisandro Dalcin
588f46a955bSLisandro Dalcin    user_options = _build_ext.user_options + cmd_petsc_opts
589f46a955bSLisandro Dalcin
590f46a955bSLisandro Dalcin    def initialize_options(self):
591f46a955bSLisandro Dalcin        _build_ext.initialize_options(self)
59255a74a43SLisandro Dalcin        self.inplace = None
593f46a955bSLisandro Dalcin        self.petsc_dir  = None
594f46a955bSLisandro Dalcin        self.petsc_arch = None
595f46a955bSLisandro Dalcin        self._outputs = []
596f46a955bSLisandro Dalcin
597f46a955bSLisandro Dalcin    def finalize_options(self):
598f46a955bSLisandro Dalcin        _build_ext.finalize_options(self)
59955a74a43SLisandro Dalcin        self.set_undefined_options('build', ('inplace', 'inplace'))
600f46a955bSLisandro Dalcin        self.set_undefined_options('build',
601f46a955bSLisandro Dalcin                                   ('petsc_dir',  'petsc_dir'),
602f46a955bSLisandro Dalcin                                   ('petsc_arch', 'petsc_arch'))
603f46a955bSLisandro Dalcin        if ((sys.platform.startswith('linux') or
604f46a955bSLisandro Dalcin             sys.platform.startswith('gnu') or
605f46a955bSLisandro Dalcin             sys.platform.startswith('sunos')) and
606f46a955bSLisandro Dalcin            sysconfig.get_config_var('Py_ENABLE_SHARED')):
607f46a955bSLisandro Dalcin            py_version = sysconfig.get_python_version()
608f46a955bSLisandro Dalcin            bad_pylib_dir = os.path.join(sys.prefix, "lib",
609f46a955bSLisandro Dalcin                                         "python" + py_version,
610f46a955bSLisandro Dalcin                                         "config")
611f46a955bSLisandro Dalcin            try:
612f46a955bSLisandro Dalcin                self.library_dirs.remove(bad_pylib_dir)
613f46a955bSLisandro Dalcin            except ValueError:
614f46a955bSLisandro Dalcin                pass
615f46a955bSLisandro Dalcin            pylib_dir = sysconfig.get_config_var("LIBDIR")
616f46a955bSLisandro Dalcin            if pylib_dir not in self.library_dirs:
617f46a955bSLisandro Dalcin                self.library_dirs.append(pylib_dir)
618f46a955bSLisandro Dalcin            if pylib_dir not in self.rpath:
619f46a955bSLisandro Dalcin                self.rpath.append(pylib_dir)
620f46a955bSLisandro Dalcin            if sys.exec_prefix == '/usr':
621f46a955bSLisandro Dalcin                self.library_dirs.remove(pylib_dir)
622f46a955bSLisandro Dalcin                self.rpath.remove(pylib_dir)
623f46a955bSLisandro Dalcin
624f46a955bSLisandro Dalcin    def _copy_ext(self, ext):
625f46a955bSLisandro Dalcin        extclass = ext.__class__
626f46a955bSLisandro Dalcin        fullname = self.get_ext_fullname(ext.name)
627f46a955bSLisandro Dalcin        modpath = str.split(fullname, '.')
628f46a955bSLisandro Dalcin        pkgpath = os.path.join('', *modpath[0:-1])
629f46a955bSLisandro Dalcin        name = modpath[-1]
630f46a955bSLisandro Dalcin        sources = list(ext.sources)
631f46a955bSLisandro Dalcin        newext = extclass(name, sources)
632f46a955bSLisandro Dalcin        newext.__dict__.update(copy.deepcopy(ext.__dict__))
633f46a955bSLisandro Dalcin        newext.name = name
634f46a955bSLisandro Dalcin        return pkgpath, newext
635f46a955bSLisandro Dalcin
636f46a955bSLisandro Dalcin    def _build_ext_arch(self, ext, pkgpath, arch):
637f46a955bSLisandro Dalcin        build_temp = self.build_temp
638f46a955bSLisandro Dalcin        build_lib  = self.build_lib
639f46a955bSLisandro Dalcin        try:
640f46a955bSLisandro Dalcin            self.build_temp = os.path.join(build_temp, arch)
641f46a955bSLisandro Dalcin            self.build_lib  = os.path.join(build_lib, pkgpath, arch)
642f46a955bSLisandro Dalcin            _build_ext.build_extension(self, ext)
643f46a955bSLisandro Dalcin        finally:
644f46a955bSLisandro Dalcin            self.build_temp = build_temp
645f46a955bSLisandro Dalcin            self.build_lib  = build_lib
646f46a955bSLisandro Dalcin
647f46a955bSLisandro Dalcin    def get_config_arch(self, arch):
648f46a955bSLisandro Dalcin        return config.Configure(self.petsc_dir, arch)
649f46a955bSLisandro Dalcin
650f46a955bSLisandro Dalcin    def build_extension(self, ext):
651f46a955bSLisandro Dalcin        if not isinstance(ext, Extension):
652f46a955bSLisandro Dalcin            return _build_ext.build_extension(self, ext)
653f46a955bSLisandro Dalcin        petsc_arch = self.petsc_arch
654f46a955bSLisandro Dalcin        if not petsc_arch:
655f46a955bSLisandro Dalcin            petsc_arch = [ None ]
656f46a955bSLisandro Dalcin        for arch in petsc_arch:
657f46a955bSLisandro Dalcin            config = self.get_config_arch(arch)
658f46a955bSLisandro Dalcin            ARCH = arch or config['PETSC_ARCH']
659f46a955bSLisandro Dalcin            if ARCH not in self.PETSC_ARCH_LIST:
660f46a955bSLisandro Dalcin                self.PETSC_ARCH_LIST.append(ARCH)
661f46a955bSLisandro Dalcin            self.DESTDIR = config.DESTDIR
662f46a955bSLisandro Dalcin            ext.language = config.language
663f46a955bSLisandro Dalcin            config.log_info()
664f46a955bSLisandro Dalcin            pkgpath, newext = self._copy_ext(ext)
665f46a955bSLisandro Dalcin            config.configure(newext, self.compiler)
666f46a955bSLisandro Dalcin            self._build_ext_arch(newext, pkgpath, ARCH)
667f46a955bSLisandro Dalcin
668f46a955bSLisandro Dalcin    def run(self):
669f46a955bSLisandro Dalcin        self.build_sources()
670f46a955bSLisandro Dalcin        _build_ext.run(self)
671f46a955bSLisandro Dalcin
672f46a955bSLisandro Dalcin    def build_sources(self):
673f46a955bSLisandro Dalcin        if 'build_src' in self.distribution.cmdclass:
674f46a955bSLisandro Dalcin            self.run_command('build_src')
675f46a955bSLisandro Dalcin
676f46a955bSLisandro Dalcin    def build_extensions(self, *args, **kargs):
677f46a955bSLisandro Dalcin        self.PETSC_ARCH_LIST = []
678f46a955bSLisandro Dalcin        _build_ext.build_extensions(self, *args,**kargs)
679f46a955bSLisandro Dalcin        if not self.PETSC_ARCH_LIST: return
680f46a955bSLisandro Dalcin        self.build_configuration(self.PETSC_ARCH_LIST)
681f46a955bSLisandro Dalcin
682f46a955bSLisandro Dalcin    def build_configuration(self, arch_list):
683f46a955bSLisandro Dalcin        #
684f46a955bSLisandro Dalcin        template, variables = self.get_config_data(arch_list)
685f46a955bSLisandro Dalcin        config_data = template % variables
686f46a955bSLisandro Dalcin        #
687f46a955bSLisandro Dalcin        build_lib   = self.build_lib
688f46a955bSLisandro Dalcin        dist_name   = self.distribution.get_name()
689f46a955bSLisandro Dalcin        config_file = os.path.join(build_lib, dist_name, 'lib',
690f46a955bSLisandro Dalcin                                   dist_name.replace('4py', '') + '.cfg')
691f46a955bSLisandro Dalcin        #
692f46a955bSLisandro Dalcin        def write_file(filename, data):
693f46a955bSLisandro Dalcin            with open(filename, 'w') as fh:
694f46a955bSLisandro Dalcin                fh.write(config_data)
695f46a955bSLisandro Dalcin        execute(write_file, (config_file, config_data),
696f46a955bSLisandro Dalcin                msg='writing %s' % config_file,
697f46a955bSLisandro Dalcin                verbose=self.verbose, dry_run=self.dry_run)
698f46a955bSLisandro Dalcin
699f46a955bSLisandro Dalcin    def get_config_data(self, arch_list):
700f46a955bSLisandro Dalcin        DESTDIR = self.DESTDIR
701f46a955bSLisandro Dalcin        template = "\n".join([
702f46a955bSLisandro Dalcin            "PETSC_DIR  = %(PETSC_DIR)s",
703f46a955bSLisandro Dalcin            "PETSC_ARCH = %(PETSC_ARCH)s",
704f46a955bSLisandro Dalcin        ]) + "\n"
705f46a955bSLisandro Dalcin        variables = {
706f46a955bSLisandro Dalcin            'PETSC_DIR'  : strip_prefix(DESTDIR, self.petsc_dir),
707f46a955bSLisandro Dalcin            'PETSC_ARCH' : os.path.pathsep.join(arch_list),
708f46a955bSLisandro Dalcin        }
709f46a955bSLisandro Dalcin        return template, variables
710f46a955bSLisandro Dalcin
711f46a955bSLisandro Dalcin    def copy_extensions_to_source(self):
712f46a955bSLisandro Dalcin        build_py = self.get_finalized_command('build_py')
713f46a955bSLisandro Dalcin        for ext in self.extensions:
714f46a955bSLisandro Dalcin            inp_file, reg_file = self._get_inplace_equivalent(build_py, ext)
715f46a955bSLisandro Dalcin
716f46a955bSLisandro Dalcin            arch_list = ['']
717f46a955bSLisandro Dalcin            if isinstance(ext, Extension) and self.petsc_arch:
718f46a955bSLisandro Dalcin                arch_list = self.petsc_arch[:]
719f46a955bSLisandro Dalcin
720f46a955bSLisandro Dalcin            file_pairs = []
721f46a955bSLisandro Dalcin            inp_head, inp_tail = os.path.split(inp_file)
722f46a955bSLisandro Dalcin            reg_head, reg_tail = os.path.split(reg_file)
723f46a955bSLisandro Dalcin            for arch in arch_list:
724f46a955bSLisandro Dalcin                inp_file = os.path.join(inp_head, arch, inp_tail)
725f46a955bSLisandro Dalcin                reg_file = os.path.join(reg_head, arch, reg_tail)
726f46a955bSLisandro Dalcin                file_pairs.append((inp_file, reg_file))
727f46a955bSLisandro Dalcin
728f46a955bSLisandro Dalcin            for inp_file, reg_file in file_pairs:
729f46a955bSLisandro Dalcin                if os.path.exists(reg_file) or not ext.optional:
730f46a955bSLisandro Dalcin                    dest_dir, _ = os.path.split(inp_file)
731f46a955bSLisandro Dalcin                    self.mkpath(dest_dir)
732f46a955bSLisandro Dalcin                    self.copy_file(reg_file, inp_file, level=self.verbose)
733f46a955bSLisandro Dalcin
734f46a955bSLisandro Dalcin    def get_outputs(self):
735f46a955bSLisandro Dalcin        self.check_extensions_list(self.extensions)
736f46a955bSLisandro Dalcin        outputs = []
737f46a955bSLisandro Dalcin        for ext in self.extensions:
738f46a955bSLisandro Dalcin            fullname = self.get_ext_fullname(ext.name)
739f46a955bSLisandro Dalcin            filename = self.get_ext_filename(fullname)
740f46a955bSLisandro Dalcin            if isinstance(ext, Extension) and self.petsc_arch:
741f46a955bSLisandro Dalcin                head, tail = os.path.split(filename)
742f46a955bSLisandro Dalcin                for arch in self.petsc_arch:
743f46a955bSLisandro Dalcin                    outfile = os.path.join(self.build_lib, head, arch, tail)
744f46a955bSLisandro Dalcin                    outputs.append(outfile)
745f46a955bSLisandro Dalcin            else:
746f46a955bSLisandro Dalcin                outfile = os.path.join(self.build_lib, filename)
747f46a955bSLisandro Dalcin                outputs.append(outfile)
748f46a955bSLisandro Dalcin        outputs = list(set(outputs))
749f46a955bSLisandro Dalcin        return outputs
750f46a955bSLisandro Dalcin
751f46a955bSLisandro Dalcin
752f46a955bSLisandro Dalcinclass install(_install):
753f46a955bSLisandro Dalcin
754f46a955bSLisandro Dalcin    def initialize_options(self):
755f46a955bSLisandro Dalcin        with warnings.catch_warnings():
756f46a955bSLisandro Dalcin            if setuptools:
757f46a955bSLisandro Dalcin                if hasattr(setuptools, 'SetuptoolsDeprecationWarning'):
758f46a955bSLisandro Dalcin                    category = setuptools.SetuptoolsDeprecationWarning
759f46a955bSLisandro Dalcin                    warnings.simplefilter('ignore', category)
760f46a955bSLisandro Dalcin            _install.initialize_options(self)
761f46a955bSLisandro Dalcin        self.old_and_unmanageable = True
762f46a955bSLisandro Dalcin
763f46a955bSLisandro Dalcin
764f46a955bSLisandro Dalcincmdclass_list = [
765f46a955bSLisandro Dalcin    config,
766f46a955bSLisandro Dalcin    build,
767f46a955bSLisandro Dalcin    build_src,
768f46a955bSLisandro Dalcin    build_ext,
769f46a955bSLisandro Dalcin    install,
770f46a955bSLisandro Dalcin]
771f46a955bSLisandro Dalcin
772f46a955bSLisandro Dalcin# --------------------------------------------------------------------
773f46a955bSLisandro Dalcin
774f46a955bSLisandro Dalcindef setup(**attrs):
775f46a955bSLisandro Dalcin    cmdclass = attrs.setdefault('cmdclass', {})
776f46a955bSLisandro Dalcin    for cmd in cmdclass_list:
777f46a955bSLisandro Dalcin        cmdclass.setdefault(cmd.__name__, cmd)
778f46a955bSLisandro Dalcin    build_src.sources = attrs.pop('cython_sources', None)
779f46a955bSLisandro Dalcin    use_setup_requires = False  # handle Cython requirement ourselves
780f46a955bSLisandro Dalcin    if setuptools and build_src.sources and use_setup_requires:
781f46a955bSLisandro Dalcin        version = cython_req()
782f46a955bSLisandro Dalcin        if not cython_chk(version, verbose=False):
783f46a955bSLisandro Dalcin            reqs = attrs.setdefault('setup_requires', [])
784223a8ff9SLisandro Dalcin            reqs += ['Cython=='+version]
785f46a955bSLisandro Dalcin    return _setup(**attrs)
786f46a955bSLisandro Dalcin
787f46a955bSLisandro Dalcin# --------------------------------------------------------------------
788f46a955bSLisandro Dalcin
789f46a955bSLisandro Dalcinif setuptools:
790f46a955bSLisandro Dalcin    try:
791f46a955bSLisandro Dalcin        from setuptools.command import egg_info as mod_egg_info
792f46a955bSLisandro Dalcin        _FileList = mod_egg_info.FileList
793f46a955bSLisandro Dalcin        class FileList(_FileList):
794f46a955bSLisandro Dalcin            def process_template_line(self, line):
795f46a955bSLisandro Dalcin                level = log.set_threshold(log.ERROR)
796f46a955bSLisandro Dalcin                try:
797f46a955bSLisandro Dalcin                    _FileList.process_template_line(self, line)
798f46a955bSLisandro Dalcin                finally:
799f46a955bSLisandro Dalcin                    log.set_threshold(level)
800f46a955bSLisandro Dalcin        mod_egg_info.FileList = FileList
801f46a955bSLisandro Dalcin    except (ImportError, AttributeError):
802f46a955bSLisandro Dalcin        pass
803f46a955bSLisandro Dalcin
804f46a955bSLisandro Dalcin# --------------------------------------------------------------------
805f46a955bSLisandro Dalcin
806f46a955bSLisandro Dalcindef append(seq, item):
807f46a955bSLisandro Dalcin    if item not in seq:
808f46a955bSLisandro Dalcin        seq.append(item)
809f46a955bSLisandro Dalcin
810f46a955bSLisandro Dalcindef append_dict(conf, dct):
811f46a955bSLisandro Dalcin    for key, values in dct.items():
812f46a955bSLisandro Dalcin        if key in conf:
813f46a955bSLisandro Dalcin            for value in values:
814f46a955bSLisandro Dalcin                if value not in conf[key]:
815f46a955bSLisandro Dalcin                    conf[key].append(value)
816f46a955bSLisandro Dalcindef unique(seq):
817f46a955bSLisandro Dalcin    res = []
818f46a955bSLisandro Dalcin    for item in seq:
819f46a955bSLisandro Dalcin        if item not in res:
820f46a955bSLisandro Dalcin            res.append(item)
821f46a955bSLisandro Dalcin    return res
822f46a955bSLisandro Dalcin
823f46a955bSLisandro Dalcindef flaglist(flags):
824f46a955bSLisandro Dalcin
825f46a955bSLisandro Dalcin    conf = {
826f46a955bSLisandro Dalcin        'define_macros'       : [],
827f46a955bSLisandro Dalcin        'undef_macros'        : [],
828f46a955bSLisandro Dalcin        'include_dirs'        : [],
829f46a955bSLisandro Dalcin
830f46a955bSLisandro Dalcin        'libraries'           : [],
831f46a955bSLisandro Dalcin        'library_dirs'        : [],
832f46a955bSLisandro Dalcin        'runtime_library_dirs': [],
833f46a955bSLisandro Dalcin
834f46a955bSLisandro Dalcin        'extra_compile_args'  : [],
835f46a955bSLisandro Dalcin        'extra_link_args'     : [],
836f46a955bSLisandro Dalcin        }
837f46a955bSLisandro Dalcin
838f46a955bSLisandro Dalcin    if type(flags) is str:
839f46a955bSLisandro Dalcin        flags = flags.split()
840f46a955bSLisandro Dalcin
841f46a955bSLisandro Dalcin    switch = '-Wl,'
842f46a955bSLisandro Dalcin    newflags = []
843f46a955bSLisandro Dalcin    linkopts = []
844f46a955bSLisandro Dalcin    for f in flags:
845f46a955bSLisandro Dalcin        if f.startswith(switch):
846f46a955bSLisandro Dalcin            if len(f) > 4:
847f46a955bSLisandro Dalcin                append(linkopts, f[4:])
848f46a955bSLisandro Dalcin        else:
849f46a955bSLisandro Dalcin            append(newflags, f)
850f46a955bSLisandro Dalcin    if linkopts:
851f46a955bSLisandro Dalcin        newflags.append(switch + ','.join(linkopts))
852f46a955bSLisandro Dalcin    flags = newflags
853f46a955bSLisandro Dalcin
854f46a955bSLisandro Dalcin    append_next_word = None
855f46a955bSLisandro Dalcin
856f46a955bSLisandro Dalcin    for word in flags:
857f46a955bSLisandro Dalcin
858f46a955bSLisandro Dalcin        if append_next_word is not None:
859f46a955bSLisandro Dalcin            append(append_next_word, word)
860f46a955bSLisandro Dalcin            append_next_word = None
861f46a955bSLisandro Dalcin            continue
862f46a955bSLisandro Dalcin
863f46a955bSLisandro Dalcin        switch, value = word[0:2], word[2:]
864f46a955bSLisandro Dalcin
865f46a955bSLisandro Dalcin        if switch == "-I":
866f46a955bSLisandro Dalcin            append(conf['include_dirs'], value)
867f46a955bSLisandro Dalcin        elif switch == "-D":
868f46a955bSLisandro Dalcin            try:
869f46a955bSLisandro Dalcin                idx = value.index("=")
870f46a955bSLisandro Dalcin                macro = (value[:idx], value[idx+1:])
871f46a955bSLisandro Dalcin            except ValueError:
872f46a955bSLisandro Dalcin                macro = (value, None)
873f46a955bSLisandro Dalcin            append(conf['define_macros'], macro)
874f46a955bSLisandro Dalcin        elif switch == "-U":
875f46a955bSLisandro Dalcin            append(conf['undef_macros'], value)
876f46a955bSLisandro Dalcin        elif switch == "-l":
877f46a955bSLisandro Dalcin            append(conf['libraries'], value)
878f46a955bSLisandro Dalcin        elif switch == "-L":
879f46a955bSLisandro Dalcin            append(conf['library_dirs'], value)
880f46a955bSLisandro Dalcin        elif switch == "-R":
881f46a955bSLisandro Dalcin            append(conf['runtime_library_dirs'], value)
882f46a955bSLisandro Dalcin        elif word.startswith("-Wl"):
883f46a955bSLisandro Dalcin            linkopts = word.split(',')
884f46a955bSLisandro Dalcin            append_dict(conf, flaglist(linkopts[1:]))
885f46a955bSLisandro Dalcin        elif word == "-rpath":
886f46a955bSLisandro Dalcin            append_next_word = conf['runtime_library_dirs']
887f46a955bSLisandro Dalcin        elif word == "-Xlinker":
888f46a955bSLisandro Dalcin            append_next_word = conf['extra_link_args']
889f46a955bSLisandro Dalcin        else:
890f46a955bSLisandro Dalcin            #log.warn("unrecognized flag '%s'" % word)
891f46a955bSLisandro Dalcin            pass
892f46a955bSLisandro Dalcin    return conf
893f46a955bSLisandro Dalcin
894f46a955bSLisandro Dalcindef prepend_to_flags(path, flags):
895f46a955bSLisandro Dalcin    """Prepend a path to compiler flags with absolute paths"""
896f46a955bSLisandro Dalcin    if not path:
897f46a955bSLisandro Dalcin        return flags
898f46a955bSLisandro Dalcin    def append_path(m):
899f46a955bSLisandro Dalcin        switch = m.group(1)
900f46a955bSLisandro Dalcin        open_quote = m.group(4)
901f46a955bSLisandro Dalcin        old_path = m.group(5)
902f46a955bSLisandro Dalcin        close_quote = m.group(6)
903f46a955bSLisandro Dalcin        if os.path.isabs(old_path):
904f46a955bSLisandro Dalcin            moded_path = os.path.normpath(path + os.path.sep + old_path)
905f46a955bSLisandro Dalcin            return switch + open_quote + moded_path + close_quote
906f46a955bSLisandro Dalcin        return m.group(0)
907f46a955bSLisandro Dalcin    return re.sub(r'((^|\s+)(-I|-L))(\s*["\']?)(\S+)(["\']?)',
908f46a955bSLisandro Dalcin            append_path, flags)
909f46a955bSLisandro Dalcin
910f46a955bSLisandro Dalcindef strip_prefix(prefix, string):
911f46a955bSLisandro Dalcin    if not prefix:
912f46a955bSLisandro Dalcin        return string
913f46a955bSLisandro Dalcin    return re.sub(r'^' + prefix, '', string)
914f46a955bSLisandro Dalcin
915f46a955bSLisandro Dalcin# --------------------------------------------------------------------
916f46a955bSLisandro Dalcin
917f46a955bSLisandro Dalcinfrom distutils.text_file import TextFile
918f46a955bSLisandro Dalcin
919f46a955bSLisandro Dalcin# Regexes needed for parsing Makefile-like syntaxes
920f46a955bSLisandro Dalcinimport re as _re
9218acd7bfaSLisandro Dalcin_variable_rx = _re.compile(r"([a-zA-Z][a-zA-Z0-9_]+)\s*=\s*(.*)")
922f46a955bSLisandro Dalcin_findvar1_rx = _re.compile(r"\$\(([A-Za-z][A-Za-z0-9_]*)\)")
923f46a955bSLisandro Dalcin_findvar2_rx = _re.compile(r"\${([A-Za-z][A-Za-z0-9_]*)}")
924f46a955bSLisandro Dalcin
925f46a955bSLisandro Dalcindef makefile(fileobj, dct=None):
926f46a955bSLisandro Dalcin    """Parse a Makefile-style file.
927f46a955bSLisandro Dalcin
928f46a955bSLisandro Dalcin    A dictionary containing name/value pairs is returned.  If an
929f46a955bSLisandro Dalcin    optional dictionary is passed in as the second argument, it is
930f46a955bSLisandro Dalcin    used instead of a new dictionary.
931f46a955bSLisandro Dalcin    """
932f46a955bSLisandro Dalcin    fp = TextFile(file=fileobj,
933f46a955bSLisandro Dalcin                  strip_comments=1,
934f46a955bSLisandro Dalcin                  skip_blanks=1,
935f46a955bSLisandro Dalcin                  join_lines=1)
936f46a955bSLisandro Dalcin
937f46a955bSLisandro Dalcin    if dct is None:
938f46a955bSLisandro Dalcin        dct = {}
939f46a955bSLisandro Dalcin    done = {}
940f46a955bSLisandro Dalcin    notdone = {}
941f46a955bSLisandro Dalcin
942f46a955bSLisandro Dalcin    while 1:
943f46a955bSLisandro Dalcin        line = fp.readline()
944f46a955bSLisandro Dalcin        if line is None: # eof
945f46a955bSLisandro Dalcin            break
946f46a955bSLisandro Dalcin        m = _variable_rx.match(line)
947f46a955bSLisandro Dalcin        if m:
948f46a955bSLisandro Dalcin            n, v = m.group(1, 2)
949f46a955bSLisandro Dalcin            v = str.strip(v)
950f46a955bSLisandro Dalcin            if "$" in v:
951f46a955bSLisandro Dalcin                notdone[n] = v
952f46a955bSLisandro Dalcin            else:
953f46a955bSLisandro Dalcin                try: v = int(v)
954f46a955bSLisandro Dalcin                except ValueError: pass
955f46a955bSLisandro Dalcin                done[n] = v
956f46a955bSLisandro Dalcin                try: del notdone[n]
957f46a955bSLisandro Dalcin                except KeyError: pass
958f46a955bSLisandro Dalcin    fp.close()
959f46a955bSLisandro Dalcin
960f46a955bSLisandro Dalcin    # do variable interpolation here
961f46a955bSLisandro Dalcin    while notdone:
962f46a955bSLisandro Dalcin        for name in list(notdone.keys()):
963f46a955bSLisandro Dalcin            value = notdone[name]
964f46a955bSLisandro Dalcin            m = _findvar1_rx.search(value) or _findvar2_rx.search(value)
965f46a955bSLisandro Dalcin            if m:
966f46a955bSLisandro Dalcin                n = m.group(1)
967f46a955bSLisandro Dalcin                found = True
968f46a955bSLisandro Dalcin                if n in done:
969f46a955bSLisandro Dalcin                    item = str(done[n])
970f46a955bSLisandro Dalcin                elif n in notdone:
971f46a955bSLisandro Dalcin                    # get it on a subsequent round
972f46a955bSLisandro Dalcin                    found = False
973f46a955bSLisandro Dalcin                else:
974f46a955bSLisandro Dalcin                    done[n] = item = ""
975f46a955bSLisandro Dalcin                if found:
976f46a955bSLisandro Dalcin                    after = value[m.end():]
977f46a955bSLisandro Dalcin                    value = value[:m.start()] + item + after
978f46a955bSLisandro Dalcin                    if "$" in after:
979f46a955bSLisandro Dalcin                        notdone[name] = value
980f46a955bSLisandro Dalcin                    else:
981f46a955bSLisandro Dalcin                        try: value = int(value)
982f46a955bSLisandro Dalcin                        except ValueError:
983f46a955bSLisandro Dalcin                            done[name] = str.strip(value)
984f46a955bSLisandro Dalcin                        else:
985f46a955bSLisandro Dalcin                            done[name] = value
986f46a955bSLisandro Dalcin                        del notdone[name]
987f46a955bSLisandro Dalcin            else:
988f46a955bSLisandro Dalcin                # bogus variable reference;
989f46a955bSLisandro Dalcin                # just drop it since we can't deal
990f46a955bSLisandro Dalcin                del notdone[name]
991f46a955bSLisandro Dalcin    # save the results in the global dictionary
992f46a955bSLisandro Dalcin    dct.update(done)
993f46a955bSLisandro Dalcin    return dct
994f46a955bSLisandro Dalcin
995f46a955bSLisandro Dalcin# --------------------------------------------------------------------
996