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