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