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