1# -------------------------------------------------------------------- 2 3__all__ = ['PetscConfig', 4 'setup', 'Extension', 5 'config', 'build', 'build_src', 'build_ext', 6 'clean', 'test', 'sdist', 7 'log', 8 ] 9 10# -------------------------------------------------------------------- 11 12import sys, os 13try: 14 import setuptools 15except ImportError: 16 setuptools = None 17 18def import_command(cmd): 19 try: 20 from importlib import import_module 21 except ImportError: 22 import_module = lambda n: __import__(n, fromlist=[None]) 23 try: 24 if not setuptools: raise ImportError 25 mod = import_module('setuptools.command.' + cmd) 26 return getattr(mod, cmd) 27 except ImportError: 28 mod = import_module('distutils.command.' + cmd) 29 return getattr(mod, cmd) 30 31if setuptools: 32 from setuptools import setup 33 from setuptools import Extension as _Extension 34 from setuptools import Command 35else: 36 from distutils.core import setup 37 from distutils.core import Extension as _Extension 38 from distutils.core import Command 39 40_config = import_command('config') 41_build = import_command('build') 42_build_ext = import_command('build_ext') 43_install = import_command('install') 44_clean = import_command('clean') 45_sdist = import_command('sdist') 46 47from distutils import sysconfig 48from distutils import log 49from distutils.util import split_quoted, execute 50from distutils.errors import DistutilsError 51 52# -------------------------------------------------------------------- 53 54def fix_config_vars(names, values): 55 import os, re 56 values = list(values) 57 if sys.platform == 'darwin': 58 if 'ARCHFLAGS' in os.environ: 59 ARCHFLAGS = os.environ['ARCHFLAGS'] 60 for i, flag in enumerate(list(values)): 61 flag, count = re.subn('-arch\s+\w+', ' ', flag) 62 if count and ARCHFLAGS: 63 flag = flag + ' ' + ARCHFLAGS 64 values[i] = flag 65 if 'SDKROOT' in os.environ: 66 SDKROOT = os.environ['SDKROOT'] 67 for i, flag in enumerate(list(values)): 68 flag, count = re.subn('-isysroot [^ \t]*', ' ', flag) 69 if count and SDKROOT: 70 flag = flag + ' ' + '-isysroot ' + SDKROOT 71 values[i] = flag 72 return values 73 74def get_config_vars(*names): 75 # Core Python configuration 76 values = sysconfig.get_config_vars(*names) 77 # Do any distutils flags fixup right now 78 values = fix_config_vars(names, values) 79 return values 80 81from distutils.unixccompiler import UnixCCompiler 82rpath_option_orig = UnixCCompiler.runtime_library_dir_option 83def rpath_option(compiler, dir): 84 option = rpath_option_orig(compiler, dir) 85 if sys.platform[:5] == 'linux': 86 if option.startswith('-R'): 87 option = option.replace('-R', '-Wl,-rpath,', 1) 88 elif option.startswith('-Wl,-R'): 89 option = option.replace('-Wl,-R', '-Wl,-rpath,', 1) 90 return option 91UnixCCompiler.runtime_library_dir_option = rpath_option 92 93# -------------------------------------------------------------------- 94 95class PetscConfig: 96 97 def __init__(self, petsc_dir, petsc_arch): 98 self.configdict = { } 99 if not petsc_dir: 100 raise DistutilsError("PETSc not found") 101 if not os.path.isdir(petsc_dir): 102 raise DistutilsError("invalid PETSC_DIR: %s" % petsc_dir) 103 self.version = self._get_petsc_version(petsc_dir) 104 self.configdict = self._get_petsc_config(petsc_dir, petsc_arch) 105 self.PETSC_DIR = self['PETSC_DIR'] 106 self.PETSC_ARCH = self['PETSC_ARCH'] 107 language_map = {'CONLY':'c', 'CXXONLY':'c++'} 108 self.language = language_map[self['PETSC_LANGUAGE']] 109 110 def __getitem__(self, item): 111 return self.configdict[item] 112 113 def get(self, item, default=None): 114 return self.configdict.get(item, default) 115 116 def configure(self, extension, compiler=None): 117 self.configure_extension(extension) 118 if compiler is not None: 119 self.configure_compiler(compiler) 120 121 def _get_petsc_version(self, petsc_dir): 122 import re 123 version_re = { 124 'major' : re.compile(r"#define\s+PETSC_VERSION_MAJOR\s+(\d+)"), 125 'minor' : re.compile(r"#define\s+PETSC_VERSION_MINOR\s+(\d+)"), 126 'micro' : re.compile(r"#define\s+PETSC_VERSION_SUBMINOR\s+(\d+)"), 127 'patch' : re.compile(r"#define\s+PETSC_VERSION_PATCH\s+(\d+)"), 128 'release': re.compile(r"#define\s+PETSC_VERSION_RELEASE\s+(-*\d+)"), 129 } 130 petscversion_h = os.path.join(petsc_dir, 'include', 'petscversion.h') 131 with open(petscversion_h, 'rt') as f: data = f.read() 132 major = int(version_re['major'].search(data).groups()[0]) 133 minor = int(version_re['minor'].search(data).groups()[0]) 134 micro = int(version_re['micro'].search(data).groups()[0]) 135 release = int(version_re['release'].search(data).groups()[0]) 136 return (major, minor, micro), (release == 1) 137 138 def _get_petsc_config(self, petsc_dir, petsc_arch): 139 from os.path import join, isdir, exists 140 PETSC_DIR = petsc_dir 141 PETSC_ARCH = petsc_arch 142 # 143 confdir = join('lib', 'petsc', 'conf') 144 if not (PETSC_ARCH and isdir(join(PETSC_DIR, PETSC_ARCH))): 145 petscvars = join(PETSC_DIR, confdir, 'petscvariables') 146 PETSC_ARCH = makefile(open(petscvars, 'rt')).get('PETSC_ARCH') 147 if not (PETSC_ARCH and isdir(join(PETSC_DIR, PETSC_ARCH))): 148 PETSC_ARCH = '' 149 # 150 variables = join(PETSC_DIR, confdir, 'variables') 151 if not exists(variables): 152 variables = join(PETSC_DIR, PETSC_ARCH, confdir, 'variables') 153 petscvariables = join(PETSC_DIR, PETSC_ARCH, confdir, 'petscvariables') 154 # 155 with open(variables) as f: 156 contents = f.read() 157 with open(petscvariables) as f: 158 contents += f.read() 159 # 160 try: 161 from cStringIO import StringIO 162 except ImportError: 163 from io import StringIO 164 confstr = 'PETSC_DIR = %s\n' % PETSC_DIR 165 confstr += 'PETSC_ARCH = %s\n' % PETSC_ARCH 166 confstr += contents 167 confdict = makefile(StringIO(confstr)) 168 return confdict 169 170 def _configure_ext(self, ext, dct, preppend=False): 171 extdict = ext.__dict__ 172 for key, values in dct.items(): 173 if key in extdict: 174 for value in values: 175 if value not in extdict[key]: 176 if preppend: 177 extdict[key].insert(0, value) 178 else: 179 extdict[key].append(value) 180 181 def configure_extension(self, extension): 182 # includes and libraries 183 petsc_inc = flaglist(self['PETSC_CC_INCLUDES']) 184 petsc_lib = flaglist( 185 '-L%s %s' % (self['PETSC_LIB_DIR'], self['PETSC_LIB_BASIC'])) 186 # runtime_library_dirs is not supported on Windows 187 if sys.platform != 'win32': 188 petsc_lib['runtime_library_dirs'].append(self['PETSC_LIB_DIR']) 189 190 # Link in extra libraries on static builds 191 if self['BUILDSHAREDLIB'] != 'yes': 192 petsc_ext_lib = split_quoted(self['PETSC_EXTERNAL_LIB_BASIC']) 193 petsc_lib['extra_link_args'].extend(petsc_ext_lib) 194 195 self._configure_ext(extension, petsc_inc, preppend=True) 196 self._configure_ext(extension, petsc_lib) 197 198 def configure_compiler(self, compiler): 199 if compiler.compiler_type != 'unix': return 200 getenv = os.environ.get 201 # distutils C/C++ compiler 202 (cc, cflags, ccshared, cxx) = get_config_vars( 203 'CC', 'CFLAGS', 'CCSHARED', 'CXX') 204 ccshared = getenv('CCSHARED', ccshared or '') 205 cflags = getenv('CFLAGS', cflags or '') 206 cflags = cflags.replace('-Wstrict-prototypes', '') 207 # distutils linker 208 (ldflags, ldshared, so_ext) = get_config_vars( 209 'LDFLAGS', 'LDSHARED', 'SO') 210 ld = cc 211 ldshared = getenv('LDSHARED', ldshared) 212 ldflags = getenv('LDFLAGS', cflags + ' ' + (ldflags or '')) 213 ldcmd = split_quoted(ld) + split_quoted(ldflags) 214 ldshared = [flg for flg in split_quoted(ldshared) if flg not in ldcmd] 215 ldshared = str.join(' ', ldshared) 216 # 217 def get_flags(cmd): 218 try: return ' '.join(split_quoted(cmd)[1:]) 219 except: return '' 220 # PETSc C compiler 221 PCC = self['PCC'] 222 PCC_FLAGS = get_flags(cc) + ' ' + self['PCC_FLAGS'] 223 PCC_FLAGS = PCC_FLAGS.replace('-fvisibility=hidden', '') 224 PCC = getenv('PCC', PCC) + ' ' + getenv('PCCFLAGS', PCC_FLAGS) 225 PCC_SHARED = str.join(' ', (PCC, ccshared, cflags)) 226 # PETSc C++ compiler 227 PCXX = PCC if self.language == 'c++' else self.get('CXX', cxx) 228 # PETSc linker 229 PLD = self['PCC_LINKER'] 230 PLD_FLAGS = get_flags(ld) + ' ' + self['PCC_LINKER_FLAGS'] 231 PLD_FLAGS = PLD_FLAGS.replace('-fvisibility=hidden', '') 232 PLD = getenv('PLD', PLD) + ' ' + getenv('PLDFLAGS', PLD_FLAGS) 233 PLD_SHARED = str.join(' ', (PLD, ldshared, ldflags)) 234 # 235 compiler.set_executables( 236 compiler = PCC, 237 compiler_cxx = PCXX, 238 linker_exe = PLD, 239 compiler_so = PCC_SHARED, 240 linker_so = PLD_SHARED, 241 ) 242 compiler.shared_lib_extension = so_ext 243 # 244 if sys.platform == 'darwin': 245 for attr in ('preprocessor', 246 'compiler', 'compiler_cxx', 'compiler_so', 247 'linker_so', 'linker_exe'): 248 compiler_cmd = getattr(compiler, attr, []) 249 while '-mno-fused-madd' in compiler_cmd: 250 compiler_cmd.remove('-mno-fused-madd') 251 252 def log_info(self): 253 PETSC_DIR = self['PETSC_DIR'] 254 PETSC_ARCH = self['PETSC_ARCH'] 255 version = ".".join([str(i) for i in self.version[0]]) 256 release = ("development", "release")[self.version[1]] 257 version_info = version + ' ' + release 258 integer_size = '%s-bit' % self['PETSC_INDEX_SIZE'] 259 scalar_type = self['PETSC_SCALAR'] 260 precision = self['PETSC_PRECISION'] 261 language = self['PETSC_LANGUAGE'] 262 compiler = self['PCC'] 263 linker = self['PCC_LINKER'] 264 log.info('PETSC_DIR: %s' % PETSC_DIR ) 265 log.info('PETSC_ARCH: %s' % PETSC_ARCH ) 266 log.info('version: %s' % version_info) 267 log.info('integer-size: %s' % integer_size) 268 log.info('scalar-type: %s' % scalar_type) 269 log.info('precision: %s' % precision) 270 log.info('language: %s' % language) 271 log.info('compiler: %s' % compiler) 272 log.info('linker: %s' % linker) 273 274# -------------------------------------------------------------------- 275 276class Extension(_Extension): 277 pass 278 279# -------------------------------------------------------------------- 280 281cmd_petsc_opts = [ 282 ('petsc-dir=', None, 283 "define PETSC_DIR, overriding environmental variables"), 284 ('petsc-arch=', None, 285 "define PETSC_ARCH, overriding environmental variables"), 286 ] 287 288class config(_config): 289 290 Configure = PetscConfig 291 292 user_options = _config.user_options + cmd_petsc_opts 293 294 def initialize_options(self): 295 _config.initialize_options(self) 296 self.petsc_dir = None 297 self.petsc_arch = None 298 299 def get_config_arch(self, arch): 300 return config.Configure(self.petsc_dir, arch) 301 302 def run(self): 303 _config.run(self) 304 self.petsc_dir = config.get_petsc_dir(self.petsc_dir) 305 if self.petsc_dir is None: return 306 petsc_arch = config.get_petsc_arch(self.petsc_dir, self.petsc_arch) 307 log.info('-' * 70) 308 log.info('PETSC_DIR: %s' % self.petsc_dir) 309 arch_list = petsc_arch 310 if not arch_list : 311 arch_list = [ None ] 312 for arch in arch_list: 313 conf = self.get_config_arch(arch) 314 archname = conf.PETSC_ARCH or conf['PETSC_ARCH'] 315 scalar_type = conf['PETSC_SCALAR'] 316 precision = conf['PETSC_PRECISION'] 317 language = conf['PETSC_LANGUAGE'] 318 compiler = conf['PCC'] 319 linker = conf['PCC_LINKER'] 320 log.info('-'*70) 321 log.info('PETSC_ARCH: %s' % archname) 322 log.info(' * scalar-type: %s' % scalar_type) 323 log.info(' * precision: %s' % precision) 324 log.info(' * language: %s' % language) 325 log.info(' * compiler: %s' % compiler) 326 log.info(' * linker: %s' % linker) 327 log.info('-' * 70) 328 329 #@staticmethod 330 def get_petsc_dir(petsc_dir): 331 if not petsc_dir: return None 332 petsc_dir = os.path.expandvars(petsc_dir) 333 if not petsc_dir or '$PETSC_DIR' in petsc_dir: 334 try: 335 import petsc 336 petsc_dir = petsc.get_petsc_dir() 337 except ImportError: 338 log.warn("PETSC_DIR not specified") 339 return None 340 petsc_dir = os.path.expanduser(petsc_dir) 341 petsc_dir = os.path.abspath(petsc_dir) 342 return config.chk_petsc_dir(petsc_dir) 343 get_petsc_dir = staticmethod(get_petsc_dir) 344 345 #@staticmethod 346 def chk_petsc_dir(petsc_dir): 347 if not os.path.isdir(petsc_dir): 348 log.error('invalid PETSC_DIR: %s (ignored)' % petsc_dir) 349 return None 350 return petsc_dir 351 chk_petsc_dir = staticmethod(chk_petsc_dir) 352 353 #@staticmethod 354 def get_petsc_arch(petsc_dir, petsc_arch): 355 if not petsc_dir: return None 356 petsc_arch = os.path.expandvars(petsc_arch) 357 if (not petsc_arch or '$PETSC_ARCH' in petsc_arch): 358 petsc_arch = '' 359 petsc_conf = os.path.join(petsc_dir, 'lib', 'petsc', 'conf') 360 if os.path.isdir(petsc_conf): 361 petscvariables = os.path.join(petsc_conf, 'petscvariables') 362 if os.path.exists(petscvariables): 363 conf = makefile(open(petscvariables, 'rt')) 364 petsc_arch = conf.get('PETSC_ARCH', '') 365 petsc_arch = petsc_arch.split(os.pathsep) 366 petsc_arch = unique(petsc_arch) 367 petsc_arch = [arch for arch in petsc_arch if arch] 368 return config.chk_petsc_arch(petsc_dir, petsc_arch) 369 get_petsc_arch = staticmethod(get_petsc_arch) 370 371 #@staticmethod 372 def chk_petsc_arch(petsc_dir, petsc_arch): 373 valid_archs = [] 374 for arch in petsc_arch: 375 arch_path = os.path.join(petsc_dir, arch) 376 if os.path.isdir(arch_path): 377 valid_archs.append(arch) 378 else: 379 log.warn("invalid PETSC_ARCH: %s (ignored)" % arch) 380 return valid_archs 381 chk_petsc_arch = staticmethod(chk_petsc_arch) 382 383 384class build(_build): 385 386 user_options = _build.user_options + cmd_petsc_opts 387 388 def initialize_options(self): 389 _build.initialize_options(self) 390 self.petsc_dir = None 391 self.petsc_arch = None 392 393 def finalize_options(self): 394 _build.finalize_options(self) 395 self.set_undefined_options('config', 396 ('petsc_dir', 'petsc_dir'), 397 ('petsc_arch', 'petsc_arch')) 398 self.petsc_dir = config.get_petsc_dir(self.petsc_dir) 399 self.petsc_arch = config.get_petsc_arch(self.petsc_dir, 400 self.petsc_arch) 401 402 sub_commands = \ 403 [('build_src', lambda *args: True)] + \ 404 _build.sub_commands 405 406class build_src(Command): 407 description = "build C sources from Cython files" 408 user_options = [ 409 ('force', 'f', 410 "forcibly build everything (ignore file timestamps)"), 411 ] 412 boolean_options = ['force'] 413 def initialize_options(self): 414 self.force = False 415 def finalize_options(self): 416 self.set_undefined_options('build', 417 ('force', 'force'), 418 ) 419 def run(self): 420 pass 421 422class build_ext(_build_ext): 423 424 user_options = _build_ext.user_options + cmd_petsc_opts 425 426 def initialize_options(self): 427 _build_ext.initialize_options(self) 428 self.petsc_dir = None 429 self.petsc_arch = None 430 self._outputs = [] 431 432 def finalize_options(self): 433 _build_ext.finalize_options(self) 434 self.set_undefined_options('build', 435 ('petsc_dir', 'petsc_dir'), 436 ('petsc_arch', 'petsc_arch')) 437 if ((sys.platform.startswith('linux') or 438 sys.platform.startswith('gnu') or 439 sys.platform.startswith('sunos')) and 440 sysconfig.get_config_var('Py_ENABLE_SHARED')): 441 py_version = sysconfig.get_python_version() 442 bad_pylib_dir = os.path.join(sys.prefix, "lib", 443 "python" + py_version, 444 "config") 445 try: 446 self.library_dirs.remove(bad_pylib_dir) 447 except ValueError: 448 pass 449 pylib_dir = sysconfig.get_config_var("LIBDIR") 450 if pylib_dir not in self.library_dirs: 451 self.library_dirs.append(pylib_dir) 452 if pylib_dir not in self.rpath: 453 self.rpath.append(pylib_dir) 454 if sys.exec_prefix == '/usr': 455 self.library_dirs.remove(pylib_dir) 456 self.rpath.remove(pylib_dir) 457 458 def _copy_ext(self, ext): 459 from copy import deepcopy 460 extclass = ext.__class__ 461 fullname = self.get_ext_fullname(ext.name) 462 modpath = str.split(fullname, '.') 463 pkgpath = os.path.join('', *modpath[0:-1]) 464 name = modpath[-1] 465 sources = list(ext.sources) 466 newext = extclass(name, sources) 467 newext.__dict__.update(deepcopy(ext.__dict__)) 468 newext.name = name 469 return pkgpath, newext 470 471 def _build_ext_arch(self, ext, pkgpath, arch): 472 build_temp = self.build_temp 473 build_lib = self.build_lib 474 try: 475 self.build_temp = os.path.join(build_temp, arch) 476 self.build_lib = os.path.join(build_lib, pkgpath, arch) 477 _build_ext.build_extension(self, ext) 478 finally: 479 self.build_temp = build_temp 480 self.build_lib = build_lib 481 482 def get_config_arch(self, arch): 483 return config.Configure(self.petsc_dir, arch) 484 485 def build_extension(self, ext): 486 if not isinstance(ext, Extension): 487 return _build_ext.build_extension(self, ext) 488 petsc_arch = self.petsc_arch 489 if not petsc_arch: 490 petsc_arch = [ None ] 491 for arch in petsc_arch: 492 config = self.get_config_arch(arch) 493 ARCH = arch or config['PETSC_ARCH'] 494 if ARCH not in self.PETSC_ARCH_LIST: 495 self.PETSC_ARCH_LIST.append(ARCH) 496 ext.language = config.language 497 config.log_info() 498 pkgpath, newext = self._copy_ext(ext) 499 config.configure(newext, self.compiler) 500 name = self.distribution.get_name() 501 version = self.distribution.get_version() 502 distdir = "%s-%s/" % (name, version) 503 self._build_ext_arch(newext, pkgpath, ARCH) 504 505 def build_extensions(self, *args, **kargs): 506 self.PETSC_ARCH_LIST = [] 507 _build_ext.build_extensions(self, *args,**kargs) 508 if not self.PETSC_ARCH_LIST: return 509 self.build_configuration(self.PETSC_ARCH_LIST) 510 511 512 def build_configuration(self, arch_list): 513 # 514 template, variables = self.get_config_data(arch_list) 515 config_data = template % variables 516 # 517 build_lib = self.build_lib 518 dist_name = self.distribution.get_name() 519 config_file = os.path.join(build_lib, dist_name, 'lib', 520 dist_name.replace('4py', '') + '.cfg') 521 # 522 def write_file(filename, data): 523 with open(filename, 'w') as fh: 524 fh.write(config_data) 525 execute(write_file, (config_file, config_data), 526 msg='writing %s' % config_file, 527 verbose=self.verbose, dry_run=self.dry_run) 528 529 def get_config_data(self, arch_list): 530 template = """\ 531PETSC_DIR = %(PETSC_DIR)s 532PETSC_ARCH = %(PETSC_ARCH)s 533""" 534 variables = {'PETSC_DIR' : self.petsc_dir, 535 'PETSC_ARCH' : os.path.pathsep.join(arch_list)} 536 return template, variables 537 538 def get_outputs(self): 539 self.check_extensions_list(self.extensions) 540 outputs = [] 541 for ext in self.extensions: 542 fullname = self.get_ext_fullname(ext.name) 543 filename = self.get_ext_filename(fullname) 544 if isinstance(ext, Extension) and self.petsc_arch: 545 head, tail = os.path.split(filename) 546 for arch in self.petsc_arch: 547 outfile = os.path.join(self.build_lib, 548 head, arch, tail) 549 outputs.append(outfile) 550 else: 551 outfile = os.path.join(self.build_lib, filename) 552 outputs.append(outfile) 553 outputs = list(set(outputs)) 554 return outputs 555 556class install(_install): 557 def run(self): 558 _install.run(self) 559 560class clean(_clean): 561 def run(self): 562 _clean.run(self) 563 from distutils.dir_util import remove_tree 564 if self.all: 565 # remove the <package>.egg_info directory 566 try: 567 egg_info = self.get_finalized_command('egg_info').egg_info 568 if os.path.exists(egg_info): 569 remove_tree(egg_info, dry_run=self.dry_run) 570 else: 571 log.debug("'%s' does not exist -- can't clean it", 572 egg_info) 573 except DistutilsError: 574 pass 575 576class test(Command): 577 description = "run the test suite" 578 user_options = [('args=', None, "options")] 579 def initialize_options(self): 580 self.args = None 581 def finalize_options(self): 582 if self.args: 583 self.args = split_quoted(self.args) 584 else: 585 self.args = [] 586 def run(self): 587 pass 588 589class sdist(_sdist): 590 def run(self): 591 build_src = self.get_finalized_command('build_src') 592 build_src.run() 593 _sdist.run(self) 594 595# -------------------------------------------------------------------- 596 597if setuptools: 598 try: 599 from setuptools.command import egg_info as mod_egg_info 600 _FileList = mod_egg_info.FileList 601 class FileList(_FileList): 602 def process_template_line(self, line): 603 level = log.set_threshold(log.ERROR) 604 try: 605 _FileList.process_template_line(self, line) 606 finally: 607 log.set_threshold(level) 608 mod_egg_info.FileList = FileList 609 except: 610 pass 611 612# -------------------------------------------------------------------- 613 614def append(seq, item): 615 if item not in seq: 616 seq.append(item) 617 618def append_dict(conf, dct): 619 for key, values in dct.items(): 620 if key in conf: 621 for value in values: 622 if value not in conf[key]: 623 conf[key].append(value) 624def unique(seq): 625 res = [] 626 for item in seq: 627 if item not in res: 628 res.append(item) 629 return res 630 631def flaglist(flags): 632 633 conf = { 634 'define_macros' : [], 635 'undef_macros' : [], 636 'include_dirs' : [], 637 638 'libraries' : [], 639 'library_dirs' : [], 640 'runtime_library_dirs': [], 641 642 'extra_compile_args' : [], 643 'extra_link_args' : [], 644 } 645 646 if type(flags) is str: 647 flags = flags.split() 648 649 switch = '-Wl,' 650 newflags = [] 651 linkopts = [] 652 for f in flags: 653 if f.startswith(switch): 654 if len(f) > 4: 655 append(linkopts, f[4:]) 656 else: 657 append(newflags, f) 658 if linkopts: 659 newflags.append(switch + ','.join(linkopts)) 660 flags = newflags 661 662 append_next_word = None 663 664 for word in flags: 665 666 if append_next_word is not None: 667 append(append_next_word, word) 668 append_next_word = None 669 continue 670 671 switch, value = word[0:2], word[2:] 672 673 if switch == "-I": 674 append(conf['include_dirs'], value) 675 elif switch == "-D": 676 try: 677 idx = value.index("=") 678 macro = (value[:idx], value[idx+1:]) 679 except ValueError: 680 macro = (value, None) 681 append(conf['define_macros'], macro) 682 elif switch == "-U": 683 append(conf['undef_macros'], value) 684 elif switch == "-l": 685 append(conf['libraries'], value) 686 elif switch == "-L": 687 append(conf['library_dirs'], value) 688 elif switch == "-R": 689 append(conf['runtime_library_dirs'], value) 690 elif word.startswith("-Wl"): 691 linkopts = word.split(',') 692 append_dict(conf, flaglist(linkopts[1:])) 693 elif word == "-rpath": 694 append_next_word = conf['runtime_library_dirs'] 695 elif word == "-Xlinker": 696 append_next_word = conf['extra_link_args'] 697 else: 698 #log.warn("unrecognized flag '%s'" % word) 699 pass 700 return conf 701 702# -------------------------------------------------------------------- 703 704from distutils.text_file import TextFile 705 706# Regexes needed for parsing Makefile-like syntaxes 707import re as _re 708_variable_rx = _re.compile("([a-zA-Z][a-zA-Z0-9_]+)\s*=\s*(.*)") 709_findvar1_rx = _re.compile(r"\$\(([A-Za-z][A-Za-z0-9_]*)\)") 710_findvar2_rx = _re.compile(r"\${([A-Za-z][A-Za-z0-9_]*)}") 711 712def makefile(fileobj, dct=None): 713 """Parse a Makefile-style file. 714 715 A dictionary containing name/value pairs is returned. If an 716 optional dictionary is passed in as the second argument, it is 717 used instead of a new dictionary. 718 """ 719 fp = TextFile(file=fileobj, 720 strip_comments=1, 721 skip_blanks=1, 722 join_lines=1) 723 724 if dct is None: 725 dct = {} 726 done = {} 727 notdone = {} 728 729 while 1: 730 line = fp.readline() 731 if line is None: # eof 732 break 733 m = _variable_rx.match(line) 734 if m: 735 n, v = m.group(1, 2) 736 v = str.strip(v) 737 if "$" in v: 738 notdone[n] = v 739 else: 740 try: v = int(v) 741 except ValueError: pass 742 done[n] = v 743 try: del notdone[n] 744 except KeyError: pass 745 fp.close() 746 747 # do variable interpolation here 748 while notdone: 749 for name in list(notdone.keys()): 750 value = notdone[name] 751 m = _findvar1_rx.search(value) or _findvar2_rx.search(value) 752 if m: 753 n = m.group(1) 754 found = True 755 if n in done: 756 item = str(done[n]) 757 elif n in notdone: 758 # get it on a subsequent round 759 found = False 760 else: 761 done[n] = item = "" 762 if found: 763 after = value[m.end():] 764 value = value[:m.start()] + item + after 765 if "$" in after: 766 notdone[name] = value 767 else: 768 try: value = int(value) 769 except ValueError: 770 done[name] = str.strip(value) 771 else: 772 done[name] = value 773 del notdone[name] 774 else: 775 # bogus variable reference; 776 # just drop it since we can't deal 777 del notdone[name] 778 # save the results in the global dictionary 779 dct.update(done) 780 return dct 781 782# -------------------------------------------------------------------- 783