1f46a955bSLisandro Dalcin# -------------------------------------------------------------------- 2f46a955bSLisandro Dalcin 3*163a2e85Spaul.kuehnerfrom pathlib import Path 4f46a955bSLisandro Dalcinimport re 5f46a955bSLisandro Dalcinimport os 6*163a2e85Spaul.kuehnerimport subprocess 7f46a955bSLisandro Dalcinimport sys 8f46a955bSLisandro Dalcinimport glob 9f46a955bSLisandro Dalcinimport copy 10f46a955bSLisandro Dalcinimport warnings 116f336411SStefano Zampinifrom distutils import log 126f336411SStefano Zampinifrom distutils import sysconfig 136f336411SStefano Zampinifrom distutils.util import execute 146f336411SStefano Zampinifrom distutils.util import split_quoted 156f336411SStefano Zampinifrom distutils.errors import DistutilsError 166f336411SStefano Zampinifrom distutils.text_file import TextFile 176f336411SStefano Zampini 18f46a955bSLisandro Dalcin 19f46a955bSLisandro Dalcintry: 20f46a955bSLisandro Dalcin from cStringIO import StringIO 21f46a955bSLisandro Dalcinexcept ImportError: 22f46a955bSLisandro Dalcin from io import StringIO 23f46a955bSLisandro Dalcin 24f46a955bSLisandro Dalcintry: 25f46a955bSLisandro Dalcin import setuptools 26f46a955bSLisandro Dalcinexcept ImportError: 27f46a955bSLisandro Dalcin setuptools = None 28f46a955bSLisandro Dalcin 29f46a955bSLisandro Dalcinif setuptools: 30f46a955bSLisandro Dalcin from setuptools import setup as _setup 31f46a955bSLisandro Dalcin from setuptools import Extension as _Extension 32f46a955bSLisandro Dalcin from setuptools import Command 33f46a955bSLisandro Dalcinelse: 34f46a955bSLisandro Dalcin from distutils.core import setup as _setup 35f46a955bSLisandro Dalcin from distutils.core import Extension as _Extension 36f46a955bSLisandro Dalcin from distutils.core import Command 37f46a955bSLisandro Dalcin 386f336411SStefano Zampini 39f46a955bSLisandro Dalcindef import_command(cmd): 40f46a955bSLisandro Dalcin try: 41f46a955bSLisandro Dalcin from importlib import import_module 42f46a955bSLisandro Dalcin except ImportError: 436f336411SStefano Zampini 44f46a955bSLisandro Dalcin def import_module(n): 45f46a955bSLisandro Dalcin return __import__(n, fromlist=[None]) 466f336411SStefano Zampini 47f46a955bSLisandro Dalcin try: 486f336411SStefano Zampini if not setuptools: 496f336411SStefano Zampini raise ImportError 50f46a955bSLisandro Dalcin mod = import_module('setuptools.command.' + cmd) 51f46a955bSLisandro Dalcin return getattr(mod, cmd) 52f46a955bSLisandro Dalcin except ImportError: 53f46a955bSLisandro Dalcin mod = import_module('distutils.command.' + cmd) 54f46a955bSLisandro Dalcin return getattr(mod, cmd) 55f46a955bSLisandro Dalcin 566f336411SStefano Zampini 57f46a955bSLisandro Dalcin_config = import_command('config') 58f46a955bSLisandro Dalcin_build = import_command('build') 59f46a955bSLisandro Dalcin_build_ext = import_command('build_ext') 60f46a955bSLisandro Dalcin_install = import_command('install') 61f46a955bSLisandro Dalcin 62f46a955bSLisandro Dalcintry: 6356478d30SPierre Jolivet from setuptools import modified 64f46a955bSLisandro Dalcinexcept ImportError: 6556478d30SPierre Jolivet try: 6656478d30SPierre Jolivet from setuptools import dep_util as modified 6756478d30SPierre Jolivet except ImportError: 6856478d30SPierre Jolivet from distutils import dep_util as modified 69f46a955bSLisandro Dalcin 70f46a955bSLisandro Dalcintry: 71f46a955bSLisandro Dalcin from packaging.version import Version 72f46a955bSLisandro Dalcinexcept ImportError: 73f46a955bSLisandro Dalcin try: 74f46a955bSLisandro Dalcin from setuptools.extern.packaging.version import Version 75f46a955bSLisandro Dalcin except ImportError: 76f46a955bSLisandro Dalcin from distutils.version import StrictVersion as Version 77f46a955bSLisandro Dalcin 78f46a955bSLisandro Dalcin# -------------------------------------------------------------------- 79f46a955bSLisandro Dalcin 80f46a955bSLisandro Dalcin# Cython 81f46a955bSLisandro Dalcin 82b12f50ebSLisandro DalcinCYTHON = '3.0.0' 83f46a955bSLisandro Dalcin 846f336411SStefano Zampini 85f46a955bSLisandro Dalcindef cython_req(): 86f46a955bSLisandro Dalcin return CYTHON 87f46a955bSLisandro Dalcin 886f336411SStefano Zampini 89f46a955bSLisandro Dalcindef cython_chk(VERSION, verbose=True): 90f46a955bSLisandro Dalcin # 91f46a955bSLisandro Dalcin def warn(message): 926f336411SStefano Zampini if not verbose: 936f336411SStefano Zampini return 946f336411SStefano Zampini ruler, ws, nl = '*' * 80, ' ', '\n' 95f46a955bSLisandro Dalcin pyexe = sys.executable 966f336411SStefano Zampini advise = '$ %s -m pip install --upgrade cython' % pyexe 976f336411SStefano Zampini 986f336411SStefano Zampini def printer(*s): 996f336411SStefano Zampini sys.stderr.write(' '.join(s) + '\n') 1006f336411SStefano Zampini 101f46a955bSLisandro Dalcin printer(ruler, nl) 102f46a955bSLisandro Dalcin printer(ws, message, nl) 103f46a955bSLisandro Dalcin printer(ws, ws, advise, nl) 104f46a955bSLisandro Dalcin printer(ruler) 1056f336411SStefano Zampini 106f46a955bSLisandro Dalcin # 107f46a955bSLisandro Dalcin try: 108f46a955bSLisandro Dalcin import Cython 109f46a955bSLisandro Dalcin except ImportError: 1106f336411SStefano Zampini warn('You need Cython to generate C source files.') 111f46a955bSLisandro Dalcin return False 112f46a955bSLisandro Dalcin # 113f46a955bSLisandro Dalcin CYTHON_VERSION = Cython.__version__ 1146f336411SStefano Zampini m = re.match(r'(\d+\.\d+(?:\.\d+)?).*', CYTHON_VERSION) 115f46a955bSLisandro Dalcin if not m: 1166f336411SStefano Zampini warn(f'Cannot parse Cython version string {CYTHON_VERSION!r}') 117f46a955bSLisandro Dalcin return False 118f46a955bSLisandro Dalcin REQUIRED = Version(VERSION) 119f46a955bSLisandro Dalcin PROVIDED = Version(m.groups()[0]) 120b12f50ebSLisandro Dalcin if PROVIDED < REQUIRED: 1216f336411SStefano Zampini warn(f'You need Cython >= {VERSION} (you have version {CYTHON_VERSION})') 122f46a955bSLisandro Dalcin return False 123f46a955bSLisandro Dalcin # 124f46a955bSLisandro Dalcin if verbose: 1256f336411SStefano Zampini log.info('using Cython %s' % CYTHON_VERSION) 126f46a955bSLisandro Dalcin return True 127f46a955bSLisandro Dalcin 1286f336411SStefano Zampini 129f46a955bSLisandro Dalcindef cython_run( 1306f336411SStefano Zampini source, 1316f336411SStefano Zampini target=None, 1326f336411SStefano Zampini depends=(), 1336f336411SStefano Zampini includes=(), 1346f336411SStefano Zampini workdir=None, 1356f336411SStefano Zampini force=False, 1366f336411SStefano Zampini VERSION='0.0', 137f46a955bSLisandro Dalcin): 138f46a955bSLisandro Dalcin if target is None: 139f46a955bSLisandro Dalcin target = os.path.splitext(source)[0] + '.c' 140f46a955bSLisandro Dalcin cwd = os.getcwd() 141f46a955bSLisandro Dalcin try: 142f46a955bSLisandro Dalcin if workdir: 143f46a955bSLisandro Dalcin os.chdir(workdir) 144f46a955bSLisandro Dalcin alldeps = [source] 145f46a955bSLisandro Dalcin for dep in depends: 146f46a955bSLisandro Dalcin alldeps += glob.glob(dep) 14756478d30SPierre Jolivet if not (force or modified.newer_group(alldeps, target)): 1486f336411SStefano Zampini log.debug("skipping '%s' -> '%s' (up-to-date)", source, target) 149f46a955bSLisandro Dalcin return 150f46a955bSLisandro Dalcin finally: 151f46a955bSLisandro Dalcin os.chdir(cwd) 15280e0d92bSLisandro Dalcin require = 'Cython >= %s' % VERSION 153f46a955bSLisandro Dalcin if setuptools and not cython_chk(VERSION, verbose=False): 154f46a955bSLisandro Dalcin if sys.modules.get('Cython'): 155f46a955bSLisandro Dalcin removed = getattr(sys.modules['Cython'], '__version__', '') 1566f336411SStefano Zampini log.info('removing Cython %s from sys.modules' % removed) 157f46a955bSLisandro Dalcin pkgname = re.compile(r'cython(\.|$)', re.IGNORECASE) 158f46a955bSLisandro Dalcin for modname in list(sys.modules.keys()): 159f46a955bSLisandro Dalcin if pkgname.match(modname): 160f46a955bSLisandro Dalcin del sys.modules[modname] 161f46a955bSLisandro Dalcin try: 162f46a955bSLisandro Dalcin install_setup_requires = setuptools._install_setup_requires 163f46a955bSLisandro Dalcin with warnings.catch_warnings(): 164f46a955bSLisandro Dalcin if hasattr(setuptools, 'SetuptoolsDeprecationWarning'): 165f46a955bSLisandro Dalcin category = setuptools.SetuptoolsDeprecationWarning 166f46a955bSLisandro Dalcin warnings.simplefilter('ignore', category) 167f46a955bSLisandro Dalcin log.info("fetching build requirement '%s'" % require) 1686f336411SStefano Zampini install_setup_requires({'setup_requires': [require]}) 169f46a955bSLisandro Dalcin except Exception: 170f46a955bSLisandro Dalcin log.info("failed to fetch build requirement '%s'" % require) 171f46a955bSLisandro Dalcin if not cython_chk(VERSION): 172f46a955bSLisandro Dalcin raise DistutilsError("unsatisfied build requirement '%s'" % require) 173f46a955bSLisandro Dalcin # 174f46a955bSLisandro Dalcin log.info("cythonizing '%s' -> '%s'", source, target) 175f46a955bSLisandro Dalcin from cythonize import cythonize 1766f336411SStefano Zampini 177f46a955bSLisandro Dalcin args = [] 178f46a955bSLisandro Dalcin if workdir: 179f46a955bSLisandro Dalcin args += ['--working', workdir] 180f46a955bSLisandro Dalcin args += [source] 181f46a955bSLisandro Dalcin if target: 182f46a955bSLisandro Dalcin args += ['--output-file', target] 183f46a955bSLisandro Dalcin err = cythonize(args) 184f46a955bSLisandro Dalcin if err: 1856f336411SStefano Zampini raise DistutilsError(f"Cython failure: '{source}' -> '{target}'") 186f46a955bSLisandro Dalcin 187f46a955bSLisandro Dalcin 188f46a955bSLisandro Dalcin# -------------------------------------------------------------------- 189f46a955bSLisandro Dalcin 1906f336411SStefano Zampini 191f46a955bSLisandro Dalcindef fix_config_vars(names, values): 192f46a955bSLisandro Dalcin values = list(values) 193f46a955bSLisandro Dalcin if 'CONDA_BUILD' in os.environ: 194f46a955bSLisandro Dalcin return values 195f46a955bSLisandro Dalcin if sys.platform == 'darwin': 196f46a955bSLisandro Dalcin if 'ARCHFLAGS' in os.environ: 197f46a955bSLisandro Dalcin ARCHFLAGS = os.environ['ARCHFLAGS'] 198f46a955bSLisandro Dalcin for i, flag in enumerate(list(values)): 1998acd7bfaSLisandro Dalcin flag, count = re.subn(r'-arch\s+\w+', ' ', str(flag)) 200f46a955bSLisandro Dalcin if count and ARCHFLAGS: 201f46a955bSLisandro Dalcin flag = flag + ' ' + ARCHFLAGS 202f46a955bSLisandro Dalcin values[i] = flag 203f46a955bSLisandro Dalcin if 'SDKROOT' in os.environ: 204f46a955bSLisandro Dalcin SDKROOT = os.environ['SDKROOT'] 205f46a955bSLisandro Dalcin for i, flag in enumerate(list(values)): 2068acd7bfaSLisandro Dalcin flag, count = re.subn(r'-isysroot [^ \t]*', ' ', str(flag)) 207f46a955bSLisandro Dalcin if count and SDKROOT: 208f46a955bSLisandro Dalcin flag = flag + ' ' + '-isysroot ' + SDKROOT 209f46a955bSLisandro Dalcin values[i] = flag 210f46a955bSLisandro Dalcin return values 211f46a955bSLisandro Dalcin 2126f336411SStefano Zampini 213f46a955bSLisandro Dalcindef get_config_vars(*names): 214f46a955bSLisandro Dalcin # Core Python configuration 215f46a955bSLisandro Dalcin values = sysconfig.get_config_vars(*names) 216f46a955bSLisandro Dalcin # Do any distutils flags fixup right now 2176f336411SStefano Zampini return fix_config_vars(names, values) 2186f336411SStefano Zampini 219f46a955bSLisandro Dalcin 220f46a955bSLisandro Dalcin# -------------------------------------------------------------------- 221f46a955bSLisandro Dalcin 222f46a955bSLisandro Dalcin 2236f336411SStefano Zampiniclass PetscConfig: 224f46a955bSLisandro Dalcin def __init__(self, petsc_dir, petsc_arch, dest_dir=None): 225f46a955bSLisandro Dalcin if dest_dir is None: 226f46a955bSLisandro Dalcin dest_dir = os.environ.get('DESTDIR') 227f46a955bSLisandro Dalcin self.configdict = {} 228f46a955bSLisandro Dalcin if not petsc_dir: 2296f336411SStefano Zampini raise DistutilsError('PETSc not found') 230f46a955bSLisandro Dalcin if not os.path.isdir(petsc_dir): 2316f336411SStefano Zampini raise DistutilsError('invalid PETSC_DIR: %s' % petsc_dir) 232f46a955bSLisandro Dalcin self.version = self._get_petsc_version(petsc_dir) 233f46a955bSLisandro Dalcin self.configdict = self._get_petsc_config(petsc_dir, petsc_arch) 234f46a955bSLisandro Dalcin self.PETSC_DIR = self['PETSC_DIR'] 235f46a955bSLisandro Dalcin self.PETSC_ARCH = self['PETSC_ARCH'] 236f46a955bSLisandro Dalcin self.DESTDIR = dest_dir 237f46a955bSLisandro Dalcin language_map = {'CONLY': 'c', 'CXXONLY': 'c++'} 238f46a955bSLisandro Dalcin self.language = language_map[self['PETSC_LANGUAGE']] 239f46a955bSLisandro Dalcin 240f46a955bSLisandro Dalcin def __getitem__(self, item): 241f46a955bSLisandro Dalcin return self.configdict[item] 242f46a955bSLisandro Dalcin 243f46a955bSLisandro Dalcin def get(self, item, default=None): 244f46a955bSLisandro Dalcin return self.configdict.get(item, default) 245f46a955bSLisandro Dalcin 246f46a955bSLisandro Dalcin def configure(self, extension, compiler=None): 247f46a955bSLisandro Dalcin self.configure_extension(extension) 248f46a955bSLisandro Dalcin if compiler is not None: 249f46a955bSLisandro Dalcin self.configure_compiler(compiler) 250f46a955bSLisandro Dalcin 251f46a955bSLisandro Dalcin def _get_petsc_version(self, petsc_dir): 252f46a955bSLisandro Dalcin import re 2536f336411SStefano Zampini 254f46a955bSLisandro Dalcin version_re = { 2556f336411SStefano Zampini 'major': re.compile(r'#define\s+PETSC_VERSION_MAJOR\s+(\d+)'), 2566f336411SStefano Zampini 'minor': re.compile(r'#define\s+PETSC_VERSION_MINOR\s+(\d+)'), 2576f336411SStefano Zampini 'micro': re.compile(r'#define\s+PETSC_VERSION_SUBMINOR\s+(\d+)'), 2586f336411SStefano Zampini 'release': re.compile(r'#define\s+PETSC_VERSION_RELEASE\s+(-*\d+)'), 259f46a955bSLisandro Dalcin } 260f46a955bSLisandro Dalcin petscversion_h = os.path.join(petsc_dir, 'include', 'petscversion.h') 2616f336411SStefano Zampini with open(petscversion_h, 'rt') as f: 2626f336411SStefano Zampini data = f.read() 263f46a955bSLisandro Dalcin major = int(version_re['major'].search(data).groups()[0]) 264f46a955bSLisandro Dalcin minor = int(version_re['minor'].search(data).groups()[0]) 265f46a955bSLisandro Dalcin micro = int(version_re['micro'].search(data).groups()[0]) 266f46a955bSLisandro Dalcin release = int(version_re['release'].search(data).groups()[0]) 267f46a955bSLisandro Dalcin return (major, minor, micro), (release == 1) 268f46a955bSLisandro Dalcin 269f46a955bSLisandro Dalcin def _get_petsc_config(self, petsc_dir, petsc_arch): 270f46a955bSLisandro Dalcin from os.path import join, isdir, exists 2716f336411SStefano Zampini 272f46a955bSLisandro Dalcin PETSC_DIR = petsc_dir 273f46a955bSLisandro Dalcin PETSC_ARCH = petsc_arch 274f46a955bSLisandro Dalcin # 275f46a955bSLisandro Dalcin confdir = join('lib', 'petsc', 'conf') 276f46a955bSLisandro Dalcin if not (PETSC_ARCH and isdir(join(PETSC_DIR, PETSC_ARCH))): 277f46a955bSLisandro Dalcin petscvars = join(PETSC_DIR, confdir, 'petscvariables') 278f46a955bSLisandro Dalcin PETSC_ARCH = makefile(open(petscvars, 'rt')).get('PETSC_ARCH') 279f46a955bSLisandro Dalcin if not (PETSC_ARCH and isdir(join(PETSC_DIR, PETSC_ARCH))): 280f46a955bSLisandro Dalcin PETSC_ARCH = '' 281f46a955bSLisandro Dalcin # 282f46a955bSLisandro Dalcin variables = join(PETSC_DIR, confdir, 'variables') 283f46a955bSLisandro Dalcin if not exists(variables): 284f46a955bSLisandro Dalcin variables = join(PETSC_DIR, PETSC_ARCH, confdir, 'variables') 285f46a955bSLisandro Dalcin petscvariables = join(PETSC_DIR, PETSC_ARCH, confdir, 'petscvariables') 286f46a955bSLisandro Dalcin # 287f46a955bSLisandro Dalcin with open(variables) as f: 288f46a955bSLisandro Dalcin contents = f.read() 289f46a955bSLisandro Dalcin with open(petscvariables) as f: 290f46a955bSLisandro Dalcin contents += f.read() 291f46a955bSLisandro Dalcin # 292f46a955bSLisandro Dalcin confstr = 'PETSC_DIR = %s\n' % PETSC_DIR 293f46a955bSLisandro Dalcin confstr += 'PETSC_ARCH = %s\n' % PETSC_ARCH 294f46a955bSLisandro Dalcin confstr += contents 2956f336411SStefano Zampini return makefile(StringIO(confstr)) 296f46a955bSLisandro Dalcin 297ec81f945SPierre Jolivet def _configure_ext(self, ext, dct, append=False): 298f46a955bSLisandro Dalcin extdict = ext.__dict__ 299f46a955bSLisandro Dalcin for key, values in dct.items(): 300f46a955bSLisandro Dalcin if key in extdict: 301f46a955bSLisandro Dalcin for value in values: 302f46a955bSLisandro Dalcin if value not in extdict[key]: 303ec81f945SPierre Jolivet if not append: 304f46a955bSLisandro Dalcin extdict[key].insert(0, value) 305f46a955bSLisandro Dalcin else: 306f46a955bSLisandro Dalcin extdict[key].append(value) 307f46a955bSLisandro Dalcin 308f46a955bSLisandro Dalcin def configure_extension(self, extension): 309f46a955bSLisandro Dalcin # includes and libraries 310f46a955bSLisandro Dalcin # paths in PETSc config files point to final installation location, but 311f46a955bSLisandro Dalcin # we might be building against PETSc in staging location (DESTDIR) when 312f46a955bSLisandro Dalcin # DESTDIR is set, so append DESTDIR (if nonempty) to those paths 313f46a955bSLisandro Dalcin petsc_inc = flaglist(prepend_to_flags(self.DESTDIR, self['PETSC_CC_INCLUDES'])) 3146f336411SStefano Zampini lib_flags = prepend_to_flags( 3156f336411SStefano Zampini self.DESTDIR, 3166f336411SStefano Zampini '-L{} {}'.format(self['PETSC_LIB_DIR'], self['PETSC_LIB_BASIC']), 3176f336411SStefano Zampini ) 318f46a955bSLisandro Dalcin petsc_lib = flaglist(lib_flags) 319f46a955bSLisandro Dalcin # runtime_library_dirs is not supported on Windows 320f46a955bSLisandro Dalcin if sys.platform != 'win32': 321f46a955bSLisandro Dalcin # if DESTDIR is set, then we're building against PETSc in a staging 322f46a955bSLisandro Dalcin # directory, but rpath needs to point to final install directory. 323693647e8SLisandro Dalcin rpath = [strip_prefix(self.DESTDIR, self['PETSC_LIB_DIR'])] 324693647e8SLisandro Dalcin if sys.modules.get('petsc') is not None: 325693647e8SLisandro Dalcin if sys.platform == 'darwin': 326693647e8SLisandro Dalcin rpath = ['@loader_path/../../petsc/lib'] 327693647e8SLisandro Dalcin else: 328693647e8SLisandro Dalcin rpath = ['$ORIGIN/../../petsc/lib'] 329693647e8SLisandro Dalcin petsc_lib['runtime_library_dirs'].extend(rpath) 330f46a955bSLisandro Dalcin # Link in extra libraries on static builds 331f46a955bSLisandro Dalcin if self['BUILDSHAREDLIB'] != 'yes': 332f46a955bSLisandro Dalcin petsc_ext_lib = split_quoted(self['PETSC_EXTERNAL_LIB_BASIC']) 333f46a955bSLisandro Dalcin petsc_lib['extra_link_args'].extend(petsc_ext_lib) 334ec81f945SPierre Jolivet self._configure_ext(extension, petsc_inc, append=True) 335f46a955bSLisandro Dalcin self._configure_ext(extension, petsc_lib) 336f46a955bSLisandro Dalcin 337f46a955bSLisandro Dalcin def configure_compiler(self, compiler): 3386f336411SStefano Zampini if compiler.compiler_type != 'unix': 3396f336411SStefano Zampini return 340f46a955bSLisandro Dalcin getenv = os.environ.get 341f46a955bSLisandro Dalcin # distutils C/C++ compiler 3426f336411SStefano Zampini (cc, cflags, ccshared, cxx) = get_config_vars('CC', 'CFLAGS', 'CCSHARED', 'CXX') 343f46a955bSLisandro Dalcin ccshared = getenv('CCSHARED', ccshared or '') 344f46a955bSLisandro Dalcin cflags = getenv('CFLAGS', cflags or '') 345f46a955bSLisandro Dalcin cflags = cflags.replace('-Wstrict-prototypes', '') 346f46a955bSLisandro Dalcin # distutils linker 3476f336411SStefano Zampini (ldflags, ldshared, so_ext) = get_config_vars('LDFLAGS', 'LDSHARED', 'SO') 348f46a955bSLisandro Dalcin ld = cc 349f46a955bSLisandro Dalcin ldshared = getenv('LDSHARED', ldshared) 350f46a955bSLisandro Dalcin ldflags = getenv('LDFLAGS', cflags + ' ' + (ldflags or '')) 351f46a955bSLisandro Dalcin ldcmd = split_quoted(ld) + split_quoted(ldflags) 3526f336411SStefano Zampini ldshared = [ 3536f336411SStefano Zampini flg 3546f336411SStefano Zampini for flg in split_quoted(ldshared) 355ad93f427SSatish Balay if flg not in ldcmd and (flg.find('/lib/spack/env') < 0) and (flg.find('/libexec/spack/') < 0) 3566f336411SStefano Zampini ] 357f46a955bSLisandro Dalcin ldshared = str.join(' ', ldshared) 3586f336411SStefano Zampini 359f46a955bSLisandro Dalcin # 360f46a955bSLisandro Dalcin def get_flags(cmd): 3616f336411SStefano Zampini if not cmd: 3626f336411SStefano Zampini return '' 363f46a955bSLisandro Dalcin cmd = split_quoted(cmd) 364f46a955bSLisandro Dalcin if os.path.basename(cmd[0]) == 'xcrun': 365f46a955bSLisandro Dalcin del cmd[0] 366f46a955bSLisandro Dalcin while True: 367f46a955bSLisandro Dalcin if cmd[0] == '-sdk': 368f46a955bSLisandro Dalcin del cmd[0:2] 369f46a955bSLisandro Dalcin continue 370f46a955bSLisandro Dalcin if cmd[0] == '-log': 371f46a955bSLisandro Dalcin del cmd[0] 372f46a955bSLisandro Dalcin continue 373f46a955bSLisandro Dalcin break 374f46a955bSLisandro Dalcin return ' '.join(cmd[1:]) 3756f336411SStefano Zampini 376f46a955bSLisandro Dalcin # PETSc C compiler 377f46a955bSLisandro Dalcin PCC = self['PCC'] 378f46a955bSLisandro Dalcin PCC_FLAGS = get_flags(cc) + ' ' + self['PCC_FLAGS'] 379f46a955bSLisandro Dalcin PCC_FLAGS = PCC_FLAGS.replace('-fvisibility=hidden', '') 38052c29a0dSSatish Balay PCC_FLAGS = PCC_FLAGS.replace('-Wpedantic', '-Wno-pedantic') 38152c29a0dSSatish Balay PCC_FLAGS = PCC_FLAGS.replace('-Wextra-semi-stmt', '-Wno-extra-semi-stmt') 382f46a955bSLisandro Dalcin PCC = getenv('PCC', PCC) + ' ' + getenv('PCCFLAGS', PCC_FLAGS) 383f46a955bSLisandro Dalcin PCC_SHARED = str.join(' ', (PCC, ccshared, cflags)) 384f46a955bSLisandro Dalcin # PETSc C++ compiler 385f46a955bSLisandro Dalcin PCXX = PCC if self.language == 'c++' else self.get('CXX', cxx) 386f46a955bSLisandro Dalcin # PETSc linker 387f46a955bSLisandro Dalcin PLD = self['PCC_LINKER'] 388f46a955bSLisandro Dalcin PLD_FLAGS = get_flags(ld) + ' ' + self['PCC_LINKER_FLAGS'] 389f46a955bSLisandro Dalcin PLD_FLAGS = PLD_FLAGS.replace('-fvisibility=hidden', '') 390f46a955bSLisandro Dalcin PLD = getenv('PLD', PLD) + ' ' + getenv('PLDFLAGS', PLD_FLAGS) 391f46a955bSLisandro Dalcin PLD_SHARED = str.join(' ', (PLD, ldshared, ldflags)) 392f46a955bSLisandro Dalcin # 393f46a955bSLisandro Dalcin compiler.set_executables( 394f46a955bSLisandro Dalcin compiler=PCC, 395f46a955bSLisandro Dalcin compiler_cxx=PCXX, 396f46a955bSLisandro Dalcin linker_exe=PLD, 397f46a955bSLisandro Dalcin compiler_so=PCC_SHARED, 398f46a955bSLisandro Dalcin linker_so=PLD_SHARED, 399f46a955bSLisandro Dalcin ) 400f46a955bSLisandro Dalcin compiler.shared_lib_extension = so_ext 401f46a955bSLisandro Dalcin 402f46a955bSLisandro Dalcin def log_info(self): 403f46a955bSLisandro Dalcin PETSC_DIR = self['PETSC_DIR'] 404f46a955bSLisandro Dalcin PETSC_ARCH = self['PETSC_ARCH'] 4056f336411SStefano Zampini version = '.'.join([str(i) for i in self.version[0]]) 4066f336411SStefano Zampini release = ('development', 'release')[self.version[1]] 407f46a955bSLisandro Dalcin version_info = version + ' ' + release 408f46a955bSLisandro Dalcin integer_size = '%s-bit' % self['PETSC_INDEX_SIZE'] 409f46a955bSLisandro Dalcin scalar_type = self['PETSC_SCALAR'] 410f46a955bSLisandro Dalcin precision = self['PETSC_PRECISION'] 411f46a955bSLisandro Dalcin language = self['PETSC_LANGUAGE'] 412f46a955bSLisandro Dalcin compiler = self['PCC'] 413f46a955bSLisandro Dalcin linker = self['PCC_LINKER'] 414f46a955bSLisandro Dalcin log.info('PETSC_DIR: %s' % PETSC_DIR) 415f46a955bSLisandro Dalcin log.info('PETSC_ARCH: %s' % PETSC_ARCH) 416f46a955bSLisandro Dalcin log.info('version: %s' % version_info) 417f46a955bSLisandro Dalcin log.info('integer-size: %s' % integer_size) 418f46a955bSLisandro Dalcin log.info('scalar-type: %s' % scalar_type) 419f46a955bSLisandro Dalcin log.info('precision: %s' % precision) 420f46a955bSLisandro Dalcin log.info('language: %s' % language) 421f46a955bSLisandro Dalcin log.info('compiler: %s' % compiler) 422f46a955bSLisandro Dalcin log.info('linker: %s' % linker) 423f46a955bSLisandro Dalcin 4246f336411SStefano Zampini 425f46a955bSLisandro Dalcin# -------------------------------------------------------------------- 426f46a955bSLisandro Dalcin 4276f336411SStefano Zampini 428f46a955bSLisandro Dalcinclass Extension(_Extension): 429f46a955bSLisandro Dalcin pass 430f46a955bSLisandro Dalcin 4316f336411SStefano Zampini 432f46a955bSLisandro Dalcin# -------------------------------------------------------------------- 433f46a955bSLisandro Dalcin 434f46a955bSLisandro Dalcincmd_petsc_opts = [ 4356f336411SStefano Zampini ('petsc-dir=', None, 'define PETSC_DIR, overriding environmental variables'), 4366f336411SStefano Zampini ('petsc-arch=', None, 'define PETSC_ARCH, overriding environmental variables'), 437f46a955bSLisandro Dalcin] 438f46a955bSLisandro Dalcin 439f46a955bSLisandro Dalcin 440f46a955bSLisandro Dalcinclass config(_config): 441f46a955bSLisandro Dalcin Configure = PetscConfig 442f46a955bSLisandro Dalcin 443f46a955bSLisandro Dalcin user_options = _config.user_options + cmd_petsc_opts 444f46a955bSLisandro Dalcin 445f46a955bSLisandro Dalcin def initialize_options(self): 446f46a955bSLisandro Dalcin _config.initialize_options(self) 447f46a955bSLisandro Dalcin self.petsc_dir = None 448f46a955bSLisandro Dalcin self.petsc_arch = None 449f46a955bSLisandro Dalcin 450f46a955bSLisandro Dalcin def get_config_arch(self, arch): 451f46a955bSLisandro Dalcin return config.Configure(self.petsc_dir, arch) 452f46a955bSLisandro Dalcin 453f46a955bSLisandro Dalcin def run(self): 454f46a955bSLisandro Dalcin _config.run(self) 455f46a955bSLisandro Dalcin self.petsc_dir = config.get_petsc_dir(self.petsc_dir) 4566f336411SStefano Zampini if self.petsc_dir is None: 4576f336411SStefano Zampini return 458f46a955bSLisandro Dalcin petsc_arch = config.get_petsc_arch(self.petsc_dir, self.petsc_arch) 459f46a955bSLisandro Dalcin log.info('-' * 70) 460f46a955bSLisandro Dalcin log.info('PETSC_DIR: %s' % self.petsc_dir) 461f46a955bSLisandro Dalcin arch_list = petsc_arch 462f46a955bSLisandro Dalcin if not arch_list: 463f46a955bSLisandro Dalcin arch_list = [None] 464f46a955bSLisandro Dalcin for arch in arch_list: 465f46a955bSLisandro Dalcin conf = self.get_config_arch(arch) 466f46a955bSLisandro Dalcin archname = conf.PETSC_ARCH or conf['PETSC_ARCH'] 467f46a955bSLisandro Dalcin scalar_type = conf['PETSC_SCALAR'] 468f46a955bSLisandro Dalcin precision = conf['PETSC_PRECISION'] 469f46a955bSLisandro Dalcin language = conf['PETSC_LANGUAGE'] 470f46a955bSLisandro Dalcin compiler = conf['PCC'] 471f46a955bSLisandro Dalcin linker = conf['PCC_LINKER'] 472f46a955bSLisandro Dalcin log.info('-' * 70) 473f46a955bSLisandro Dalcin log.info('PETSC_ARCH: %s' % archname) 474f46a955bSLisandro Dalcin log.info(' * scalar-type: %s' % scalar_type) 475f46a955bSLisandro Dalcin log.info(' * precision: %s' % precision) 476f46a955bSLisandro Dalcin log.info(' * language: %s' % language) 477f46a955bSLisandro Dalcin log.info(' * compiler: %s' % compiler) 478f46a955bSLisandro Dalcin log.info(' * linker: %s' % linker) 479f46a955bSLisandro Dalcin log.info('-' * 70) 480f46a955bSLisandro Dalcin 481f46a955bSLisandro Dalcin # @staticmethod 482f46a955bSLisandro Dalcin def get_petsc_dir(petsc_dir): 4836f336411SStefano Zampini if not petsc_dir: 4846f336411SStefano Zampini return None 485f46a955bSLisandro Dalcin petsc_dir = os.path.expandvars(petsc_dir) 486f46a955bSLisandro Dalcin if not petsc_dir or '$PETSC_DIR' in petsc_dir: 487f46a955bSLisandro Dalcin try: 488f46a955bSLisandro Dalcin import petsc 4896f336411SStefano Zampini 490f46a955bSLisandro Dalcin petsc_dir = petsc.get_petsc_dir() 491f46a955bSLisandro Dalcin except ImportError: 4926f336411SStefano Zampini log.warn('PETSC_DIR not specified') 493f46a955bSLisandro Dalcin return None 494f46a955bSLisandro Dalcin petsc_dir = os.path.expanduser(petsc_dir) 495f46a955bSLisandro Dalcin petsc_dir = os.path.abspath(petsc_dir) 496f46a955bSLisandro Dalcin return config.chk_petsc_dir(petsc_dir) 4976f336411SStefano Zampini 498f46a955bSLisandro Dalcin get_petsc_dir = staticmethod(get_petsc_dir) 499f46a955bSLisandro Dalcin 500f46a955bSLisandro Dalcin # @staticmethod 501f46a955bSLisandro Dalcin def chk_petsc_dir(petsc_dir): 502f46a955bSLisandro Dalcin if not os.path.isdir(petsc_dir): 503f46a955bSLisandro Dalcin log.error('invalid PETSC_DIR: %s (ignored)' % petsc_dir) 504f46a955bSLisandro Dalcin return None 505f46a955bSLisandro Dalcin return petsc_dir 5066f336411SStefano Zampini 507f46a955bSLisandro Dalcin chk_petsc_dir = staticmethod(chk_petsc_dir) 508f46a955bSLisandro Dalcin 509f46a955bSLisandro Dalcin # @staticmethod 510f46a955bSLisandro Dalcin def get_petsc_arch(petsc_dir, petsc_arch): 5116f336411SStefano Zampini if not petsc_dir: 5126f336411SStefano Zampini return None 513f46a955bSLisandro Dalcin petsc_arch = os.path.expandvars(petsc_arch) 5146f336411SStefano Zampini if not petsc_arch or '$PETSC_ARCH' in petsc_arch: 515f46a955bSLisandro Dalcin petsc_arch = '' 516f46a955bSLisandro Dalcin petsc_conf = os.path.join(petsc_dir, 'lib', 'petsc', 'conf') 517f46a955bSLisandro Dalcin if os.path.isdir(petsc_conf): 518f46a955bSLisandro Dalcin petscvariables = os.path.join(petsc_conf, 'petscvariables') 519f46a955bSLisandro Dalcin if os.path.exists(petscvariables): 520f46a955bSLisandro Dalcin conf = makefile(open(petscvariables, 'rt')) 521f46a955bSLisandro Dalcin petsc_arch = conf.get('PETSC_ARCH', '') 522f46a955bSLisandro Dalcin petsc_arch = petsc_arch.split(os.pathsep) 523f46a955bSLisandro Dalcin petsc_arch = unique(petsc_arch) 524f46a955bSLisandro Dalcin petsc_arch = [arch for arch in petsc_arch if arch] 525f46a955bSLisandro Dalcin return config.chk_petsc_arch(petsc_dir, petsc_arch) 5266f336411SStefano Zampini 527f46a955bSLisandro Dalcin get_petsc_arch = staticmethod(get_petsc_arch) 528f46a955bSLisandro Dalcin 529f46a955bSLisandro Dalcin # @staticmethod 530f46a955bSLisandro Dalcin def chk_petsc_arch(petsc_dir, petsc_arch): 531f46a955bSLisandro Dalcin valid_archs = [] 532f46a955bSLisandro Dalcin for arch in petsc_arch: 533f46a955bSLisandro Dalcin arch_path = os.path.join(petsc_dir, arch) 534f46a955bSLisandro Dalcin if os.path.isdir(arch_path): 535f46a955bSLisandro Dalcin valid_archs.append(arch) 536f46a955bSLisandro Dalcin else: 5376f336411SStefano Zampini log.warn('invalid PETSC_ARCH: %s (ignored)' % arch) 538f46a955bSLisandro Dalcin return valid_archs 5396f336411SStefano Zampini 540f46a955bSLisandro Dalcin chk_petsc_arch = staticmethod(chk_petsc_arch) 541f46a955bSLisandro Dalcin 542f46a955bSLisandro Dalcin 543f46a955bSLisandro Dalcinclass build(_build): 54455a74a43SLisandro Dalcin user_options = _build.user_options 5456f336411SStefano Zampini user_options += [ 5466f336411SStefano Zampini ( 54755a74a43SLisandro Dalcin 'inplace', 54855a74a43SLisandro Dalcin 'i', 5496f336411SStefano Zampini 'ignore build-lib and put compiled extensions into the source ' 5506f336411SStefano Zampini 'directory alongside your pure Python modules', 5516f336411SStefano Zampini ) 5526f336411SStefano Zampini ] 55355a74a43SLisandro Dalcin user_options += cmd_petsc_opts 55455a74a43SLisandro Dalcin 55555a74a43SLisandro Dalcin boolean_options = _build.boolean_options 55655a74a43SLisandro Dalcin boolean_options += ['inplace'] 557f46a955bSLisandro Dalcin 558f46a955bSLisandro Dalcin def initialize_options(self): 559f46a955bSLisandro Dalcin _build.initialize_options(self) 56055a74a43SLisandro Dalcin self.inplace = None 561f46a955bSLisandro Dalcin self.petsc_dir = None 562f46a955bSLisandro Dalcin self.petsc_arch = None 563f46a955bSLisandro Dalcin 564f46a955bSLisandro Dalcin def finalize_options(self): 565f46a955bSLisandro Dalcin _build.finalize_options(self) 56655a74a43SLisandro Dalcin if self.inplace is None: 56755a74a43SLisandro Dalcin self.inplace = False 5686f336411SStefano Zampini self.set_undefined_options( 5696f336411SStefano Zampini 'config', ('petsc_dir', 'petsc_dir'), ('petsc_arch', 'petsc_arch') 5706f336411SStefano Zampini ) 571f46a955bSLisandro Dalcin self.petsc_dir = config.get_petsc_dir(self.petsc_dir) 5726f336411SStefano Zampini self.petsc_arch = config.get_petsc_arch(self.petsc_dir, self.petsc_arch) 573f46a955bSLisandro Dalcin 5746f336411SStefano Zampini sub_commands = [('build_src', lambda *args: True)] + _build.sub_commands 575f46a955bSLisandro Dalcin 576f46a955bSLisandro Dalcin 577f46a955bSLisandro Dalcinclass build_src(Command): 5786f336411SStefano Zampini description = 'build C sources from Cython files' 579f46a955bSLisandro Dalcin 580f46a955bSLisandro Dalcin user_options = [ 5816f336411SStefano Zampini ('force', 'f', 'forcibly build everything (ignore file timestamps)'), 582f46a955bSLisandro Dalcin ] 583f46a955bSLisandro Dalcin 584f46a955bSLisandro Dalcin boolean_options = ['force'] 585f46a955bSLisandro Dalcin 586f46a955bSLisandro Dalcin def initialize_options(self): 587f46a955bSLisandro Dalcin self.force = False 588f46a955bSLisandro Dalcin 589f46a955bSLisandro Dalcin def finalize_options(self): 5906f336411SStefano Zampini self.set_undefined_options( 5916f336411SStefano Zampini 'build', 592f46a955bSLisandro Dalcin ('force', 'force'), 593f46a955bSLisandro Dalcin ) 594f46a955bSLisandro Dalcin 595f46a955bSLisandro Dalcin def run(self): 596f46a955bSLisandro Dalcin sources = getattr(self, 'sources', []) 597f46a955bSLisandro Dalcin for source in sources: 5986f336411SStefano Zampini cython_run(force=self.force, VERSION=cython_req(), **source) 599f46a955bSLisandro Dalcin 600f46a955bSLisandro Dalcin 601f46a955bSLisandro Dalcinclass build_ext(_build_ext): 602f46a955bSLisandro Dalcin user_options = _build_ext.user_options + cmd_petsc_opts 603f46a955bSLisandro Dalcin 604f46a955bSLisandro Dalcin def initialize_options(self): 605f46a955bSLisandro Dalcin _build_ext.initialize_options(self) 60655a74a43SLisandro Dalcin self.inplace = None 607f46a955bSLisandro Dalcin self.petsc_dir = None 608f46a955bSLisandro Dalcin self.petsc_arch = None 609f46a955bSLisandro Dalcin self._outputs = [] 610f46a955bSLisandro Dalcin 611f46a955bSLisandro Dalcin def finalize_options(self): 612f46a955bSLisandro Dalcin _build_ext.finalize_options(self) 61355a74a43SLisandro Dalcin self.set_undefined_options('build', ('inplace', 'inplace')) 6146f336411SStefano Zampini self.set_undefined_options( 6156f336411SStefano Zampini 'build', ('petsc_dir', 'petsc_dir'), ('petsc_arch', 'petsc_arch') 6166f336411SStefano Zampini ) 617f46a955bSLisandro Dalcin 618f46a955bSLisandro Dalcin def _copy_ext(self, ext): 619f46a955bSLisandro Dalcin extclass = ext.__class__ 620f46a955bSLisandro Dalcin fullname = self.get_ext_fullname(ext.name) 621f46a955bSLisandro Dalcin modpath = str.split(fullname, '.') 622f46a955bSLisandro Dalcin pkgpath = os.path.join('', *modpath[0:-1]) 623f46a955bSLisandro Dalcin name = modpath[-1] 624f46a955bSLisandro Dalcin sources = list(ext.sources) 625f46a955bSLisandro Dalcin newext = extclass(name, sources) 626f46a955bSLisandro Dalcin newext.__dict__.update(copy.deepcopy(ext.__dict__)) 627f46a955bSLisandro Dalcin newext.name = name 628f46a955bSLisandro Dalcin return pkgpath, newext 629f46a955bSLisandro Dalcin 630f46a955bSLisandro Dalcin def _build_ext_arch(self, ext, pkgpath, arch): 631f46a955bSLisandro Dalcin build_temp = self.build_temp 632f46a955bSLisandro Dalcin build_lib = self.build_lib 633f46a955bSLisandro Dalcin try: 634f46a955bSLisandro Dalcin self.build_temp = os.path.join(build_temp, arch) 635f46a955bSLisandro Dalcin self.build_lib = os.path.join(build_lib, pkgpath, arch) 636f46a955bSLisandro Dalcin _build_ext.build_extension(self, ext) 637f46a955bSLisandro Dalcin finally: 638f46a955bSLisandro Dalcin self.build_temp = build_temp 639f46a955bSLisandro Dalcin self.build_lib = build_lib 640f46a955bSLisandro Dalcin 641f46a955bSLisandro Dalcin def get_config_arch(self, arch): 642f46a955bSLisandro Dalcin return config.Configure(self.petsc_dir, arch) 643f46a955bSLisandro Dalcin 644f46a955bSLisandro Dalcin def build_extension(self, ext): 645f46a955bSLisandro Dalcin if not isinstance(ext, Extension): 646f46a955bSLisandro Dalcin return _build_ext.build_extension(self, ext) 647f46a955bSLisandro Dalcin petsc_arch = self.petsc_arch 648f46a955bSLisandro Dalcin if not petsc_arch: 649f46a955bSLisandro Dalcin petsc_arch = [None] 650f46a955bSLisandro Dalcin for arch in petsc_arch: 651f46a955bSLisandro Dalcin config = self.get_config_arch(arch) 652f46a955bSLisandro Dalcin ARCH = arch or config['PETSC_ARCH'] 653f46a955bSLisandro Dalcin if ARCH not in self.PETSC_ARCH_LIST: 654f46a955bSLisandro Dalcin self.PETSC_ARCH_LIST.append(ARCH) 655f46a955bSLisandro Dalcin self.DESTDIR = config.DESTDIR 656f46a955bSLisandro Dalcin ext.language = config.language 657f46a955bSLisandro Dalcin config.log_info() 658f46a955bSLisandro Dalcin pkgpath, newext = self._copy_ext(ext) 659f46a955bSLisandro Dalcin config.configure(newext, self.compiler) 660f46a955bSLisandro Dalcin self._build_ext_arch(newext, pkgpath, ARCH) 6616f336411SStefano Zampini return None 662f46a955bSLisandro Dalcin 663f46a955bSLisandro Dalcin def run(self): 664f46a955bSLisandro Dalcin self.build_sources() 665f46a955bSLisandro Dalcin _build_ext.run(self) 666*163a2e85Spaul.kuehner self.build_stubs() 667f46a955bSLisandro Dalcin 668f46a955bSLisandro Dalcin def build_sources(self): 669f46a955bSLisandro Dalcin if 'build_src' in self.distribution.cmdclass: 670f46a955bSLisandro Dalcin self.run_command('build_src') 671f46a955bSLisandro Dalcin 672*163a2e85Spaul.kuehner def build_stubs(self): 673*163a2e85Spaul.kuehner pkgname = self.distribution.get_name() 674*163a2e85Spaul.kuehner modname = self.extensions[0].name.split(".")[-1] 675*163a2e85Spaul.kuehner srcdir = Path(__file__).parent.parent / 'src' / pkgname 676*163a2e85Spaul.kuehner blddir = Path(self.build_lib) / pkgname 677*163a2e85Spaul.kuehner 678*163a2e85Spaul.kuehner alldeps = glob.glob(str(blddir / 'lib' / '*' / f'{modname}.*')) 679*163a2e85Spaul.kuehner target = srcdir / f'{modname}.pyi' 680*163a2e85Spaul.kuehner if not (self.force or modified.newer_group(alldeps, target)): 681*163a2e85Spaul.kuehner log.debug(f"skipping '{modname}.*.so' -> '{target}' (up-to-date)") 682*163a2e85Spaul.kuehner return 683*163a2e85Spaul.kuehner 684*163a2e85Spaul.kuehner env = os.environ.copy() 685*163a2e85Spaul.kuehner python_path = env.get('PYTHONPATH', "") 686*163a2e85Spaul.kuehner if python_path != "": 687*163a2e85Spaul.kuehner python_path += ":" 688*163a2e85Spaul.kuehner python_path += self.build_lib 689*163a2e85Spaul.kuehner env['PYTHONPATH'] = python_path 690*163a2e85Spaul.kuehner env.pop('PETSC_ARCH', None) 691*163a2e85Spaul.kuehner 692*163a2e85Spaul.kuehner stubgen = Path(__file__).parent / 'stubgen.py' 693*163a2e85Spaul.kuehner rc = subprocess.call([sys.executable, stubgen], env=env) # noqa S603 694*163a2e85Spaul.kuehner if rc != 0: 695*163a2e85Spaul.kuehner log.warn("Stubs could not be generated.") 696*163a2e85Spaul.kuehner return 697*163a2e85Spaul.kuehner 698*163a2e85Spaul.kuehner self.copy_file( 699*163a2e85Spaul.kuehner srcdir / f'{modname}.pyi', 700*163a2e85Spaul.kuehner blddir / f'{modname}.pyi', 701*163a2e85Spaul.kuehner level=self.verbose, 702*163a2e85Spaul.kuehner ) 703*163a2e85Spaul.kuehner 704f46a955bSLisandro Dalcin def build_extensions(self, *args, **kargs): 705f46a955bSLisandro Dalcin self.PETSC_ARCH_LIST = [] 706f46a955bSLisandro Dalcin _build_ext.build_extensions(self, *args, **kargs) 7076f336411SStefano Zampini if not self.PETSC_ARCH_LIST: 7086f336411SStefano Zampini return 709f46a955bSLisandro Dalcin self.build_configuration(self.PETSC_ARCH_LIST) 710f46a955bSLisandro Dalcin 711f46a955bSLisandro Dalcin def build_configuration(self, arch_list): 712f46a955bSLisandro Dalcin # 713f46a955bSLisandro Dalcin template, variables = self.get_config_data(arch_list) 714f46a955bSLisandro Dalcin config_data = template % variables 715f46a955bSLisandro Dalcin # 716f46a955bSLisandro Dalcin build_lib = self.build_lib 717f46a955bSLisandro Dalcin dist_name = self.distribution.get_name() 7186f336411SStefano Zampini config_file = os.path.join( 7196f336411SStefano Zampini build_lib, dist_name, 'lib', dist_name.replace('4py', '') + '.cfg' 7206f336411SStefano Zampini ) 7216f336411SStefano Zampini 722f46a955bSLisandro Dalcin # 723f46a955bSLisandro Dalcin def write_file(filename, data): 724f46a955bSLisandro Dalcin with open(filename, 'w') as fh: 725f46a955bSLisandro Dalcin fh.write(config_data) 7266f336411SStefano Zampini 7276f336411SStefano Zampini execute( 7286f336411SStefano Zampini write_file, 7296f336411SStefano Zampini (config_file, config_data), 730f46a955bSLisandro Dalcin msg='writing %s' % config_file, 7316f336411SStefano Zampini verbose=self.verbose, 7326f336411SStefano Zampini ) 733f46a955bSLisandro Dalcin 734f46a955bSLisandro Dalcin def get_config_data(self, arch_list): 735f46a955bSLisandro Dalcin DESTDIR = self.DESTDIR 7366f336411SStefano Zampini template = ( 7376f336411SStefano Zampini '\n'.join( 7386f336411SStefano Zampini [ 7396f336411SStefano Zampini 'PETSC_DIR = %(PETSC_DIR)s', 7406f336411SStefano Zampini 'PETSC_ARCH = %(PETSC_ARCH)s', 7416f336411SStefano Zampini ] 7426f336411SStefano Zampini ) 7436f336411SStefano Zampini + '\n' 7446f336411SStefano Zampini ) 745f46a955bSLisandro Dalcin variables = { 746f46a955bSLisandro Dalcin 'PETSC_DIR': strip_prefix(DESTDIR, self.petsc_dir), 747f46a955bSLisandro Dalcin 'PETSC_ARCH': os.path.pathsep.join(arch_list), 748f46a955bSLisandro Dalcin } 749f46a955bSLisandro Dalcin return template, variables 750f46a955bSLisandro Dalcin 751f46a955bSLisandro Dalcin def copy_extensions_to_source(self): 752f46a955bSLisandro Dalcin build_py = self.get_finalized_command('build_py') 753f46a955bSLisandro Dalcin for ext in self.extensions: 754f46a955bSLisandro Dalcin inp_file, reg_file = self._get_inplace_equivalent(build_py, ext) 755f46a955bSLisandro Dalcin 756f46a955bSLisandro Dalcin arch_list = [''] 757f46a955bSLisandro Dalcin if isinstance(ext, Extension) and self.petsc_arch: 758f46a955bSLisandro Dalcin arch_list = self.petsc_arch[:] 759f46a955bSLisandro Dalcin 760f46a955bSLisandro Dalcin file_pairs = [] 761f46a955bSLisandro Dalcin inp_head, inp_tail = os.path.split(inp_file) 762f46a955bSLisandro Dalcin reg_head, reg_tail = os.path.split(reg_file) 763f46a955bSLisandro Dalcin for arch in arch_list: 764f46a955bSLisandro Dalcin inp_file = os.path.join(inp_head, arch, inp_tail) 765f46a955bSLisandro Dalcin reg_file = os.path.join(reg_head, arch, reg_tail) 766f46a955bSLisandro Dalcin file_pairs.append((inp_file, reg_file)) 767f46a955bSLisandro Dalcin 768f46a955bSLisandro Dalcin for inp_file, reg_file in file_pairs: 769f46a955bSLisandro Dalcin if os.path.exists(reg_file) or not ext.optional: 770f46a955bSLisandro Dalcin dest_dir, _ = os.path.split(inp_file) 771f46a955bSLisandro Dalcin self.mkpath(dest_dir) 772f46a955bSLisandro Dalcin self.copy_file(reg_file, inp_file, level=self.verbose) 773f46a955bSLisandro Dalcin 774f46a955bSLisandro Dalcin def get_outputs(self): 775f46a955bSLisandro Dalcin self.check_extensions_list(self.extensions) 776f46a955bSLisandro Dalcin outputs = [] 777f46a955bSLisandro Dalcin for ext in self.extensions: 778f46a955bSLisandro Dalcin fullname = self.get_ext_fullname(ext.name) 779f46a955bSLisandro Dalcin filename = self.get_ext_filename(fullname) 780f46a955bSLisandro Dalcin if isinstance(ext, Extension) and self.petsc_arch: 781f46a955bSLisandro Dalcin head, tail = os.path.split(filename) 782f46a955bSLisandro Dalcin for arch in self.petsc_arch: 783f46a955bSLisandro Dalcin outfile = os.path.join(self.build_lib, head, arch, tail) 784f46a955bSLisandro Dalcin outputs.append(outfile) 785f46a955bSLisandro Dalcin else: 786f46a955bSLisandro Dalcin outfile = os.path.join(self.build_lib, filename) 787f46a955bSLisandro Dalcin outputs.append(outfile) 788*163a2e85Spaul.kuehner 789*163a2e85Spaul.kuehner pkgname = self.distribution.get_name() 790*163a2e85Spaul.kuehner modname = self.extensions[0].name.split(".")[-1] 791*163a2e85Spaul.kuehner outputs.append(os.path.join(self.build_lib, pkgname, f"{modname}.pyi")) 7926f336411SStefano Zampini return list(set(outputs)) 793f46a955bSLisandro Dalcin 794208c597fSJose E. Roman def get_source_files(self): 795208c597fSJose E. Roman orig = log.set_threshold(log.WARN) 796208c597fSJose E. Roman try: 797208c597fSJose E. Roman return super().get_source_files() 798208c597fSJose E. Roman finally: 799208c597fSJose E. Roman log.set_threshold(orig) 800208c597fSJose E. Roman 801f46a955bSLisandro Dalcin 802f46a955bSLisandro Dalcinclass install(_install): 803f46a955bSLisandro Dalcin def initialize_options(self): 804f46a955bSLisandro Dalcin with warnings.catch_warnings(): 805f46a955bSLisandro Dalcin if setuptools: 806f46a955bSLisandro Dalcin if hasattr(setuptools, 'SetuptoolsDeprecationWarning'): 807f46a955bSLisandro Dalcin category = setuptools.SetuptoolsDeprecationWarning 808f46a955bSLisandro Dalcin warnings.simplefilter('ignore', category) 809f46a955bSLisandro Dalcin _install.initialize_options(self) 810f46a955bSLisandro Dalcin self.old_and_unmanageable = True 811f46a955bSLisandro Dalcin 812f46a955bSLisandro Dalcin 813f46a955bSLisandro Dalcincmdclass_list = [ 814f46a955bSLisandro Dalcin config, 815f46a955bSLisandro Dalcin build, 816f46a955bSLisandro Dalcin build_src, 817f46a955bSLisandro Dalcin build_ext, 818f46a955bSLisandro Dalcin install, 819f46a955bSLisandro Dalcin] 820f46a955bSLisandro Dalcin 821f46a955bSLisandro Dalcin# -------------------------------------------------------------------- 822f46a955bSLisandro Dalcin 8236f336411SStefano Zampini 824f46a955bSLisandro Dalcindef setup(**attrs): 825f46a955bSLisandro Dalcin cmdclass = attrs.setdefault('cmdclass', {}) 826f46a955bSLisandro Dalcin for cmd in cmdclass_list: 827f46a955bSLisandro Dalcin cmdclass.setdefault(cmd.__name__, cmd) 828f46a955bSLisandro Dalcin build_src.sources = attrs.pop('cython_sources', None) 829f46a955bSLisandro Dalcin use_setup_requires = False # handle Cython requirement ourselves 830f46a955bSLisandro Dalcin if setuptools and build_src.sources and use_setup_requires: 831f46a955bSLisandro Dalcin version = cython_req() 832f46a955bSLisandro Dalcin if not cython_chk(version, verbose=False): 833f46a955bSLisandro Dalcin reqs = attrs.setdefault('setup_requires', []) 834693647e8SLisandro Dalcin reqs += ['Cython>=' + version] 835f46a955bSLisandro Dalcin return _setup(**attrs) 836f46a955bSLisandro Dalcin 8376f336411SStefano Zampini 838f46a955bSLisandro Dalcin# -------------------------------------------------------------------- 839f46a955bSLisandro Dalcin 840f46a955bSLisandro Dalcinif setuptools: 841f46a955bSLisandro Dalcin try: 842f46a955bSLisandro Dalcin from setuptools.command import egg_info as mod_egg_info 8436f336411SStefano Zampini 844f46a955bSLisandro Dalcin _FileList = mod_egg_info.FileList 8456f336411SStefano Zampini 846f46a955bSLisandro Dalcin class FileList(_FileList): 847f46a955bSLisandro Dalcin def process_template_line(self, line): 848f46a955bSLisandro Dalcin level = log.set_threshold(log.ERROR) 849f46a955bSLisandro Dalcin try: 850f46a955bSLisandro Dalcin _FileList.process_template_line(self, line) 851f46a955bSLisandro Dalcin finally: 852f46a955bSLisandro Dalcin log.set_threshold(level) 8536f336411SStefano Zampini 854f46a955bSLisandro Dalcin mod_egg_info.FileList = FileList 855f46a955bSLisandro Dalcin except (ImportError, AttributeError): 856f46a955bSLisandro Dalcin pass 857f46a955bSLisandro Dalcin 858f46a955bSLisandro Dalcin# -------------------------------------------------------------------- 859f46a955bSLisandro Dalcin 8606f336411SStefano Zampini 861f46a955bSLisandro Dalcindef append(seq, item): 862f46a955bSLisandro Dalcin if item not in seq: 863f46a955bSLisandro Dalcin seq.append(item) 864f46a955bSLisandro Dalcin 8656f336411SStefano Zampini 866f46a955bSLisandro Dalcindef append_dict(conf, dct): 867f46a955bSLisandro Dalcin for key, values in dct.items(): 868f46a955bSLisandro Dalcin if key in conf: 869f46a955bSLisandro Dalcin for value in values: 870f46a955bSLisandro Dalcin if value not in conf[key]: 871f46a955bSLisandro Dalcin conf[key].append(value) 8726f336411SStefano Zampini 8736f336411SStefano Zampini 874f46a955bSLisandro Dalcindef unique(seq): 875f46a955bSLisandro Dalcin res = [] 876f46a955bSLisandro Dalcin for item in seq: 877f46a955bSLisandro Dalcin if item not in res: 878f46a955bSLisandro Dalcin res.append(item) 879f46a955bSLisandro Dalcin return res 880f46a955bSLisandro Dalcin 881f46a955bSLisandro Dalcin 8826f336411SStefano Zampinidef flaglist(flags): 883f46a955bSLisandro Dalcin conf = { 884f46a955bSLisandro Dalcin 'define_macros': [], 885f46a955bSLisandro Dalcin 'undef_macros': [], 886f46a955bSLisandro Dalcin 'include_dirs': [], 887f46a955bSLisandro Dalcin 'libraries': [], 888f46a955bSLisandro Dalcin 'library_dirs': [], 889f46a955bSLisandro Dalcin 'runtime_library_dirs': [], 890f46a955bSLisandro Dalcin 'extra_compile_args': [], 891f46a955bSLisandro Dalcin 'extra_link_args': [], 892f46a955bSLisandro Dalcin } 893f46a955bSLisandro Dalcin 8946f336411SStefano Zampini if isinstance(flags, str): 895f46a955bSLisandro Dalcin flags = flags.split() 896f46a955bSLisandro Dalcin 897f46a955bSLisandro Dalcin switch = '-Wl,' 898f46a955bSLisandro Dalcin newflags = [] 899f46a955bSLisandro Dalcin linkopts = [] 900f46a955bSLisandro Dalcin for f in flags: 901f46a955bSLisandro Dalcin if f.startswith(switch): 902f46a955bSLisandro Dalcin if len(f) > 4: 903f46a955bSLisandro Dalcin append(linkopts, f[4:]) 904f46a955bSLisandro Dalcin else: 905f46a955bSLisandro Dalcin append(newflags, f) 906f46a955bSLisandro Dalcin if linkopts: 907f46a955bSLisandro Dalcin newflags.append(switch + ','.join(linkopts)) 908f46a955bSLisandro Dalcin flags = newflags 909f46a955bSLisandro Dalcin 910f46a955bSLisandro Dalcin append_next_word = None 911f46a955bSLisandro Dalcin 912f46a955bSLisandro Dalcin for word in flags: 913f46a955bSLisandro Dalcin if append_next_word is not None: 914f46a955bSLisandro Dalcin append(append_next_word, word) 915f46a955bSLisandro Dalcin append_next_word = None 916f46a955bSLisandro Dalcin continue 917f46a955bSLisandro Dalcin 918f46a955bSLisandro Dalcin switch, value = word[0:2], word[2:] 919f46a955bSLisandro Dalcin 9206f336411SStefano Zampini if switch == '-I': 921f46a955bSLisandro Dalcin append(conf['include_dirs'], value) 9226f336411SStefano Zampini elif switch == '-D': 923f46a955bSLisandro Dalcin try: 9246f336411SStefano Zampini idx = value.index('=') 925f46a955bSLisandro Dalcin macro = (value[:idx], value[idx + 1 :]) 926f46a955bSLisandro Dalcin except ValueError: 927f46a955bSLisandro Dalcin macro = (value, None) 928f46a955bSLisandro Dalcin append(conf['define_macros'], macro) 9296f336411SStefano Zampini elif switch == '-U': 930f46a955bSLisandro Dalcin append(conf['undef_macros'], value) 9316f336411SStefano Zampini elif switch == '-l': 932f46a955bSLisandro Dalcin append(conf['libraries'], value) 9336f336411SStefano Zampini elif switch == '-L': 934f46a955bSLisandro Dalcin append(conf['library_dirs'], value) 9356f336411SStefano Zampini elif switch == '-R': 936f46a955bSLisandro Dalcin append(conf['runtime_library_dirs'], value) 9376f336411SStefano Zampini elif word.startswith('-Wl'): 938f46a955bSLisandro Dalcin linkopts = word.split(',') 939f46a955bSLisandro Dalcin append_dict(conf, flaglist(linkopts[1:])) 9406f336411SStefano Zampini elif word == '-rpath': 941f46a955bSLisandro Dalcin append_next_word = conf['runtime_library_dirs'] 9426f336411SStefano Zampini elif word == '-Xlinker': 943f46a955bSLisandro Dalcin append_next_word = conf['extra_link_args'] 944f46a955bSLisandro Dalcin else: 945f46a955bSLisandro Dalcin # log.warn("unrecognized flag '%s'" % word) 946f46a955bSLisandro Dalcin pass 947f46a955bSLisandro Dalcin return conf 948f46a955bSLisandro Dalcin 9496f336411SStefano Zampini 950f46a955bSLisandro Dalcindef prepend_to_flags(path, flags): 951f46a955bSLisandro Dalcin """Prepend a path to compiler flags with absolute paths""" 952f46a955bSLisandro Dalcin if not path: 953f46a955bSLisandro Dalcin return flags 9546f336411SStefano Zampini 955f46a955bSLisandro Dalcin def append_path(m): 956f46a955bSLisandro Dalcin switch = m.group(1) 957f46a955bSLisandro Dalcin open_quote = m.group(4) 958f46a955bSLisandro Dalcin old_path = m.group(5) 959f46a955bSLisandro Dalcin close_quote = m.group(6) 960f46a955bSLisandro Dalcin if os.path.isabs(old_path): 961f46a955bSLisandro Dalcin moded_path = os.path.normpath(path + os.path.sep + old_path) 962f46a955bSLisandro Dalcin return switch + open_quote + moded_path + close_quote 963f46a955bSLisandro Dalcin return m.group(0) 9646f336411SStefano Zampini 9656f336411SStefano Zampini return re.sub(r'((^|\s+)(-I|-L))(\s*["\']?)(\S+)(["\']?)', append_path, flags) 9666f336411SStefano Zampini 967f46a955bSLisandro Dalcin 968f46a955bSLisandro Dalcindef strip_prefix(prefix, string): 969f46a955bSLisandro Dalcin if not prefix: 970f46a955bSLisandro Dalcin return string 971f46a955bSLisandro Dalcin return re.sub(r'^' + prefix, '', string) 972f46a955bSLisandro Dalcin 9736f336411SStefano Zampini 974f46a955bSLisandro Dalcin# -------------------------------------------------------------------- 975f46a955bSLisandro Dalcin 976f46a955bSLisandro Dalcin# Regexes needed for parsing Makefile-like syntaxes 9776f336411SStefano Zampini_variable_rx = re.compile(r'([a-zA-Z][a-zA-Z0-9_]+)\s*=\s*(.*)') 9786f336411SStefano Zampini_findvar1_rx = re.compile(r'\$\(([A-Za-z][A-Za-z0-9_]*)\)') 9796f336411SStefano Zampini_findvar2_rx = re.compile(r'\${([A-Za-z][A-Za-z0-9_]*)}') 9806f336411SStefano Zampini 981f46a955bSLisandro Dalcin 982f46a955bSLisandro Dalcindef makefile(fileobj, dct=None): 983f46a955bSLisandro Dalcin """Parse a Makefile-style file. 984f46a955bSLisandro Dalcin 985f46a955bSLisandro Dalcin A dictionary containing name/value pairs is returned. If an 986f46a955bSLisandro Dalcin optional dictionary is passed in as the second argument, it is 987f46a955bSLisandro Dalcin used instead of a new dictionary. 988f46a955bSLisandro Dalcin """ 9896f336411SStefano Zampini fp = TextFile(file=fileobj, strip_comments=1, skip_blanks=1, join_lines=1) 990f46a955bSLisandro Dalcin 991f46a955bSLisandro Dalcin if dct is None: 992f46a955bSLisandro Dalcin dct = {} 993f46a955bSLisandro Dalcin done = {} 994f46a955bSLisandro Dalcin notdone = {} 995f46a955bSLisandro Dalcin 996f46a955bSLisandro Dalcin while 1: 997f46a955bSLisandro Dalcin line = fp.readline() 998f46a955bSLisandro Dalcin if line is None: # eof 999f46a955bSLisandro Dalcin break 1000f46a955bSLisandro Dalcin m = _variable_rx.match(line) 1001f46a955bSLisandro Dalcin if m: 1002f46a955bSLisandro Dalcin n, v = m.group(1, 2) 1003f46a955bSLisandro Dalcin v = str.strip(v) 10046f336411SStefano Zampini if '$' in v: 1005f46a955bSLisandro Dalcin notdone[n] = v 1006f46a955bSLisandro Dalcin else: 10076f336411SStefano Zampini try: 10086f336411SStefano Zampini v = int(v) 10096f336411SStefano Zampini except ValueError: 10106f336411SStefano Zampini pass 1011f46a955bSLisandro Dalcin done[n] = v 10126f336411SStefano Zampini try: 10136f336411SStefano Zampini del notdone[n] 10146f336411SStefano Zampini except KeyError: 10156f336411SStefano Zampini pass 1016f46a955bSLisandro Dalcin fp.close() 1017f46a955bSLisandro Dalcin 1018f46a955bSLisandro Dalcin # do variable interpolation here 1019f46a955bSLisandro Dalcin while notdone: 1020f46a955bSLisandro Dalcin for name in list(notdone.keys()): 1021f46a955bSLisandro Dalcin value = notdone[name] 1022f46a955bSLisandro Dalcin m = _findvar1_rx.search(value) or _findvar2_rx.search(value) 1023f46a955bSLisandro Dalcin if m: 1024f46a955bSLisandro Dalcin n = m.group(1) 1025f46a955bSLisandro Dalcin found = True 1026f46a955bSLisandro Dalcin if n in done: 1027f46a955bSLisandro Dalcin item = str(done[n]) 1028f46a955bSLisandro Dalcin elif n in notdone: 1029f46a955bSLisandro Dalcin # get it on a subsequent round 1030f46a955bSLisandro Dalcin found = False 1031f46a955bSLisandro Dalcin else: 10326f336411SStefano Zampini done[n] = item = '' 1033f46a955bSLisandro Dalcin if found: 1034f46a955bSLisandro Dalcin after = value[m.end() :] 1035f46a955bSLisandro Dalcin value = value[: m.start()] + item + after 10366f336411SStefano Zampini if '$' in after: 1037f46a955bSLisandro Dalcin notdone[name] = value 1038f46a955bSLisandro Dalcin else: 10396f336411SStefano Zampini try: 10406f336411SStefano Zampini value = int(value) 1041f46a955bSLisandro Dalcin except ValueError: 1042f46a955bSLisandro Dalcin done[name] = str.strip(value) 1043f46a955bSLisandro Dalcin else: 1044f46a955bSLisandro Dalcin done[name] = value 1045f46a955bSLisandro Dalcin del notdone[name] 1046f46a955bSLisandro Dalcin else: 1047f46a955bSLisandro Dalcin # bogus variable reference; 1048f46a955bSLisandro Dalcin # just drop it since we can't deal 1049f46a955bSLisandro Dalcin del notdone[name] 1050f46a955bSLisandro Dalcin # save the results in the global dictionary 1051f46a955bSLisandro Dalcin dct.update(done) 1052f46a955bSLisandro Dalcin return dct 1053f46a955bSLisandro Dalcin 10546f336411SStefano Zampini 1055f46a955bSLisandro Dalcin# -------------------------------------------------------------------- 1056