1# -*- coding: utf-8 -*- 2# Licensed under a 3-clause BSD style license - see LICENSE.rst 3 4import os 5import re 6import sys 7import functools 8import setuptools 9import subprocess 10from warnings import warn 11from distutils.dep_util import newer 12import packaging.version 13 14 15LIBERFADIR = os.path.join('liberfa', 'erfa') 16ERFA_SRC = os.path.join(LIBERFADIR, 'src') 17GEN_FILES = [ 18 os.path.join('erfa', 'core.py'), 19 os.path.join('erfa', 'ufunc.c'), 20] 21 22 23# https://mail.python.org/pipermail/distutils-sig/2007-September/008253.html 24class NumpyExtension(setuptools.Extension): 25 """Extension type that adds the NumPy include directory to include_dirs.""" 26 27 @property 28 def include_dirs(self): 29 from numpy import get_include 30 return self._include_dirs + [get_include()] 31 32 @include_dirs.setter 33 def include_dirs(self, include_dirs): 34 self._include_dirs = include_dirs 35 36 37def get_liberfa_versions(path=os.path.join(LIBERFADIR, 'configure.ac')): 38 with open(path) as fd: 39 s = fd.read() 40 41 mobj = re.search(r'AC_INIT\(\[erfa\],\[(?P<version>[0-9.]+)\]\)', s) 42 if not mobj: 43 warn('unable to detect liberfa version') 44 return [] 45 46 version = packaging.version.parse(mobj.group('version')) 47 48 mobj = re.search( 49 r'AC_DEFINE\(\[SOFA_VERSION\], \["(?P<version>\d{8}(_\w)?)"\],', s) 50 if not mobj: 51 warn('unable to detect SOFA version') 52 return [] 53 sofa_version = mobj.group('version') 54 55 return [ 56 ('PACKAGE_VERSION', version.base_version), 57 ('PACKAGE_VERSION_MAJOR', version.major), 58 ('PACKAGE_VERSION_MINOR', version.minor), 59 ('PACKAGE_VERSION_MICRO', version.micro), 60 ('SOFA_VERSION', sofa_version), 61 ] 62 63 64def get_extensions(): 65 gen_files_exist = all(os.path.isfile(fn) for fn in GEN_FILES) 66 gen_files_outdated = False 67 if os.path.isdir(ERFA_SRC): 68 # assume that 'erfaversion.c' is updated at each release at least 69 src = os.path.join(ERFA_SRC, 'erfaversion.c') 70 gen_files_outdated = any(newer(src, fn) for fn in GEN_FILES) 71 elif not gen_files_exist: 72 raise RuntimeError( 73 'Missing "liberfa" source files, unable to generate ' 74 '"erfa/ufunc.c" and "erfa/core.py". ' 75 'Please check your source tree. ' 76 'Maybe "git submodule update" could help.') 77 78 if not gen_files_exist or gen_files_outdated: 79 print('Run "erfa_generator.py"') 80 cmd = [sys.executable, 'erfa_generator.py', ERFA_SRC, '--quiet'] 81 subprocess.run(cmd, check=True) 82 83 sources = [os.path.join('erfa', 'ufunc.c')] 84 include_dirs = [] 85 libraries = [] 86 define_macros = [] 87 88 if int(os.environ.get('PYERFA_USE_SYSTEM_LIBERFA', 0)): 89 print('Using system liberfa') 90 libraries.append('erfa') 91 else: 92 # get all of the .c files in the liberfa/erfa/src directory 93 erfafns = os.listdir(ERFA_SRC) 94 sources.extend([os.path.join(ERFA_SRC, fn) 95 for fn in erfafns 96 if fn.endswith('.c') and not fn.startswith('t_')]) 97 98 include_dirs.append(ERFA_SRC) 99 100 # liberfa configuration 101 config_h = os.path.join(LIBERFADIR, 'config.h') 102 if not os.path.exists(config_h): 103 print('Configure liberfa') 104 configure = os.path.join(LIBERFADIR, 'configure') 105 try: 106 if not os.path.exists(configure): 107 subprocess.run( 108 ['./bootstrap.sh'], check=True, cwd=LIBERFADIR) 109 subprocess.run(['./configure'], check=True, cwd=LIBERFADIR) 110 except (subprocess.SubprocessError, OSError) as exc: 111 warn(f'unable to configure liberfa: {exc}') 112 113 if not os.path.exists(config_h): 114 liberfa_versions = get_liberfa_versions() 115 if liberfa_versions: 116 print('Configure liberfa ("configure.ac" scan)') 117 lines = [] 118 for name, value in get_liberfa_versions(): 119 lines.append(f'#define {name} "{value}"') 120 with open(config_h, 'w') as fd: 121 fd.write('\n'.join(lines)) 122 else: 123 warn('unable to get liberfa version') 124 125 if os.path.exists(config_h): 126 include_dirs.append(LIBERFADIR) 127 define_macros.append(('HAVE_CONFIG_H', '1')) 128 elif 'sdist' in sys.argv: 129 raise RuntimeError('missing "configure" script in "liberfa/erfa"') 130 131 erfa_ext = NumpyExtension( 132 name="erfa.ufunc", 133 sources=sources, 134 include_dirs=include_dirs, 135 libraries=libraries, 136 define_macros=define_macros, 137 language="c") 138 139 return [erfa_ext] 140 141 142try: 143 with open('erfa/_dev/scm_version.py') as fd: 144 source = fd.read() 145except FileNotFoundError: 146 guess_next_dev = None 147else: 148 import types 149 scm_version = types.ModuleType('scm_version') 150 scm_version.__file__ = 'erfa/_dev/scm_version.py' 151 code = compile(source, scm_version.__file__, 'exec') 152 try: 153 exec(code, scm_version.__dict__) 154 except ImportError: 155 guess_next_dev = None 156 else: 157 guess_next_dev = functools.partial(scm_version._guess_next_dev, 158 liberfadir=LIBERFADIR) 159 160use_scm_version = { 161 'write_to': os.path.join('erfa', '_version.py'), 162 'version_scheme': guess_next_dev, 163} 164 165setuptools.setup(use_scm_version=use_scm_version, ext_modules=get_extensions()) 166