annotate DEPENDENCIES/mingw32/Python27/Lib/site-packages/numpy/distutils/misc_util.py @ 128:3a8658f7e0b7

Add script to run build in Docker
author Chris Cannam
date Thu, 07 Feb 2019 11:38:32 +0000
parents 2a2c65a20a8b
children
rev   line source
Chris@87 1 from __future__ import division, absolute_import, print_function
Chris@87 2
Chris@87 3 import os
Chris@87 4 import re
Chris@87 5 import sys
Chris@87 6 import imp
Chris@87 7 import copy
Chris@87 8 import glob
Chris@87 9 import atexit
Chris@87 10 import tempfile
Chris@87 11 import subprocess
Chris@87 12 import shutil
Chris@87 13
Chris@87 14 import distutils
Chris@87 15 from distutils.errors import DistutilsError
Chris@87 16
Chris@87 17 try:
Chris@87 18 set
Chris@87 19 except NameError:
Chris@87 20 from sets import Set as set
Chris@87 21
Chris@87 22 from numpy.distutils.compat import get_exception
Chris@87 23
Chris@87 24 __all__ = ['Configuration', 'get_numpy_include_dirs', 'default_config_dict',
Chris@87 25 'dict_append', 'appendpath', 'generate_config_py',
Chris@87 26 'get_cmd', 'allpath', 'get_mathlibs',
Chris@87 27 'terminal_has_colors', 'red_text', 'green_text', 'yellow_text',
Chris@87 28 'blue_text', 'cyan_text', 'cyg2win32', 'mingw32', 'all_strings',
Chris@87 29 'has_f_sources', 'has_cxx_sources', 'filter_sources',
Chris@87 30 'get_dependencies', 'is_local_src_dir', 'get_ext_source_files',
Chris@87 31 'get_script_files', 'get_lib_source_files', 'get_data_files',
Chris@87 32 'dot_join', 'get_frame', 'minrelpath', 'njoin',
Chris@87 33 'is_sequence', 'is_string', 'as_list', 'gpaths', 'get_language',
Chris@87 34 'quote_args', 'get_build_architecture', 'get_info', 'get_pkg_info']
Chris@87 35
Chris@87 36 class InstallableLib(object):
Chris@87 37 """
Chris@87 38 Container to hold information on an installable library.
Chris@87 39
Chris@87 40 Parameters
Chris@87 41 ----------
Chris@87 42 name : str
Chris@87 43 Name of the installed library.
Chris@87 44 build_info : dict
Chris@87 45 Dictionary holding build information.
Chris@87 46 target_dir : str
Chris@87 47 Absolute path specifying where to install the library.
Chris@87 48
Chris@87 49 See Also
Chris@87 50 --------
Chris@87 51 Configuration.add_installed_library
Chris@87 52
Chris@87 53 Notes
Chris@87 54 -----
Chris@87 55 The three parameters are stored as attributes with the same names.
Chris@87 56
Chris@87 57 """
Chris@87 58 def __init__(self, name, build_info, target_dir):
Chris@87 59 self.name = name
Chris@87 60 self.build_info = build_info
Chris@87 61 self.target_dir = target_dir
Chris@87 62
Chris@87 63 def quote_args(args):
Chris@87 64 # don't used _nt_quote_args as it does not check if
Chris@87 65 # args items already have quotes or not.
Chris@87 66 args = list(args)
Chris@87 67 for i in range(len(args)):
Chris@87 68 a = args[i]
Chris@87 69 if ' ' in a and a[0] not in '"\'':
Chris@87 70 args[i] = '"%s"' % (a)
Chris@87 71 return args
Chris@87 72
Chris@87 73 def allpath(name):
Chris@87 74 "Convert a /-separated pathname to one using the OS's path separator."
Chris@87 75 splitted = name.split('/')
Chris@87 76 return os.path.join(*splitted)
Chris@87 77
Chris@87 78 def rel_path(path, parent_path):
Chris@87 79 """Return path relative to parent_path.
Chris@87 80 """
Chris@87 81 pd = os.path.abspath(parent_path)
Chris@87 82 apath = os.path.abspath(path)
Chris@87 83 if len(apath)<len(pd):
Chris@87 84 return path
Chris@87 85 if apath==pd:
Chris@87 86 return ''
Chris@87 87 if pd == apath[:len(pd)]:
Chris@87 88 assert apath[len(pd)] in [os.sep], repr((path, apath[len(pd)]))
Chris@87 89 path = apath[len(pd)+1:]
Chris@87 90 return path
Chris@87 91
Chris@87 92 def get_path_from_frame(frame, parent_path=None):
Chris@87 93 """Return path of the module given a frame object from the call stack.
Chris@87 94
Chris@87 95 Returned path is relative to parent_path when given,
Chris@87 96 otherwise it is absolute path.
Chris@87 97 """
Chris@87 98
Chris@87 99 # First, try to find if the file name is in the frame.
Chris@87 100 try:
Chris@87 101 caller_file = eval('__file__', frame.f_globals, frame.f_locals)
Chris@87 102 d = os.path.dirname(os.path.abspath(caller_file))
Chris@87 103 except NameError:
Chris@87 104 # __file__ is not defined, so let's try __name__. We try this second
Chris@87 105 # because setuptools spoofs __name__ to be '__main__' even though
Chris@87 106 # sys.modules['__main__'] might be something else, like easy_install(1).
Chris@87 107 caller_name = eval('__name__', frame.f_globals, frame.f_locals)
Chris@87 108 __import__(caller_name)
Chris@87 109 mod = sys.modules[caller_name]
Chris@87 110 if hasattr(mod, '__file__'):
Chris@87 111 d = os.path.dirname(os.path.abspath(mod.__file__))
Chris@87 112 else:
Chris@87 113 # we're probably running setup.py as execfile("setup.py")
Chris@87 114 # (likely we're building an egg)
Chris@87 115 d = os.path.abspath('.')
Chris@87 116 # hmm, should we use sys.argv[0] like in __builtin__ case?
Chris@87 117
Chris@87 118 if parent_path is not None:
Chris@87 119 d = rel_path(d, parent_path)
Chris@87 120
Chris@87 121 return d or '.'
Chris@87 122
Chris@87 123 def njoin(*path):
Chris@87 124 """Join two or more pathname components +
Chris@87 125 - convert a /-separated pathname to one using the OS's path separator.
Chris@87 126 - resolve `..` and `.` from path.
Chris@87 127
Chris@87 128 Either passing n arguments as in njoin('a','b'), or a sequence
Chris@87 129 of n names as in njoin(['a','b']) is handled, or a mixture of such arguments.
Chris@87 130 """
Chris@87 131 paths = []
Chris@87 132 for p in path:
Chris@87 133 if is_sequence(p):
Chris@87 134 # njoin(['a', 'b'], 'c')
Chris@87 135 paths.append(njoin(*p))
Chris@87 136 else:
Chris@87 137 assert is_string(p)
Chris@87 138 paths.append(p)
Chris@87 139 path = paths
Chris@87 140 if not path:
Chris@87 141 # njoin()
Chris@87 142 joined = ''
Chris@87 143 else:
Chris@87 144 # njoin('a', 'b')
Chris@87 145 joined = os.path.join(*path)
Chris@87 146 if os.path.sep != '/':
Chris@87 147 joined = joined.replace('/', os.path.sep)
Chris@87 148 return minrelpath(joined)
Chris@87 149
Chris@87 150 def get_mathlibs(path=None):
Chris@87 151 """Return the MATHLIB line from numpyconfig.h
Chris@87 152 """
Chris@87 153 if path is not None:
Chris@87 154 config_file = os.path.join(path, '_numpyconfig.h')
Chris@87 155 else:
Chris@87 156 # Look for the file in each of the numpy include directories.
Chris@87 157 dirs = get_numpy_include_dirs()
Chris@87 158 for path in dirs:
Chris@87 159 fn = os.path.join(path, '_numpyconfig.h')
Chris@87 160 if os.path.exists(fn):
Chris@87 161 config_file = fn
Chris@87 162 break
Chris@87 163 else:
Chris@87 164 raise DistutilsError('_numpyconfig.h not found in numpy include '
Chris@87 165 'dirs %r' % (dirs,))
Chris@87 166
Chris@87 167 fid = open(config_file)
Chris@87 168 mathlibs = []
Chris@87 169 s = '#define MATHLIB'
Chris@87 170 for line in fid:
Chris@87 171 if line.startswith(s):
Chris@87 172 value = line[len(s):].strip()
Chris@87 173 if value:
Chris@87 174 mathlibs.extend(value.split(','))
Chris@87 175 fid.close()
Chris@87 176 return mathlibs
Chris@87 177
Chris@87 178 def minrelpath(path):
Chris@87 179 """Resolve `..` and '.' from path.
Chris@87 180 """
Chris@87 181 if not is_string(path):
Chris@87 182 return path
Chris@87 183 if '.' not in path:
Chris@87 184 return path
Chris@87 185 l = path.split(os.sep)
Chris@87 186 while l:
Chris@87 187 try:
Chris@87 188 i = l.index('.', 1)
Chris@87 189 except ValueError:
Chris@87 190 break
Chris@87 191 del l[i]
Chris@87 192 j = 1
Chris@87 193 while l:
Chris@87 194 try:
Chris@87 195 i = l.index('..', j)
Chris@87 196 except ValueError:
Chris@87 197 break
Chris@87 198 if l[i-1]=='..':
Chris@87 199 j += 1
Chris@87 200 else:
Chris@87 201 del l[i], l[i-1]
Chris@87 202 j = 1
Chris@87 203 if not l:
Chris@87 204 return ''
Chris@87 205 return os.sep.join(l)
Chris@87 206
Chris@87 207 def _fix_paths(paths, local_path, include_non_existing):
Chris@87 208 assert is_sequence(paths), repr(type(paths))
Chris@87 209 new_paths = []
Chris@87 210 assert not is_string(paths), repr(paths)
Chris@87 211 for n in paths:
Chris@87 212 if is_string(n):
Chris@87 213 if '*' in n or '?' in n:
Chris@87 214 p = glob.glob(n)
Chris@87 215 p2 = glob.glob(njoin(local_path, n))
Chris@87 216 if p2:
Chris@87 217 new_paths.extend(p2)
Chris@87 218 elif p:
Chris@87 219 new_paths.extend(p)
Chris@87 220 else:
Chris@87 221 if include_non_existing:
Chris@87 222 new_paths.append(n)
Chris@87 223 print('could not resolve pattern in %r: %r' %
Chris@87 224 (local_path, n))
Chris@87 225 else:
Chris@87 226 n2 = njoin(local_path, n)
Chris@87 227 if os.path.exists(n2):
Chris@87 228 new_paths.append(n2)
Chris@87 229 else:
Chris@87 230 if os.path.exists(n):
Chris@87 231 new_paths.append(n)
Chris@87 232 elif include_non_existing:
Chris@87 233 new_paths.append(n)
Chris@87 234 if not os.path.exists(n):
Chris@87 235 print('non-existing path in %r: %r' %
Chris@87 236 (local_path, n))
Chris@87 237
Chris@87 238 elif is_sequence(n):
Chris@87 239 new_paths.extend(_fix_paths(n, local_path, include_non_existing))
Chris@87 240 else:
Chris@87 241 new_paths.append(n)
Chris@87 242 return [minrelpath(p) for p in new_paths]
Chris@87 243
Chris@87 244 def gpaths(paths, local_path='', include_non_existing=True):
Chris@87 245 """Apply glob to paths and prepend local_path if needed.
Chris@87 246 """
Chris@87 247 if is_string(paths):
Chris@87 248 paths = (paths,)
Chris@87 249 return _fix_paths(paths, local_path, include_non_existing)
Chris@87 250
Chris@87 251
Chris@87 252 _temporary_directory = None
Chris@87 253 def clean_up_temporary_directory():
Chris@87 254 global _temporary_directory
Chris@87 255 if not _temporary_directory:
Chris@87 256 return
Chris@87 257 try:
Chris@87 258 shutil.rmtree(_temporary_directory)
Chris@87 259 except OSError:
Chris@87 260 pass
Chris@87 261 _temporary_directory = None
Chris@87 262
Chris@87 263 def make_temp_file(suffix='', prefix='', text=True):
Chris@87 264 global _temporary_directory
Chris@87 265 if not _temporary_directory:
Chris@87 266 _temporary_directory = tempfile.mkdtemp()
Chris@87 267 atexit.register(clean_up_temporary_directory)
Chris@87 268 fid, name = tempfile.mkstemp(suffix=suffix,
Chris@87 269 prefix=prefix,
Chris@87 270 dir=_temporary_directory,
Chris@87 271 text=text)
Chris@87 272 fo = os.fdopen(fid, 'w')
Chris@87 273 return fo, name
Chris@87 274
Chris@87 275 # Hooks for colored terminal output.
Chris@87 276 # See also http://www.livinglogic.de/Python/ansistyle
Chris@87 277 def terminal_has_colors():
Chris@87 278 if sys.platform=='cygwin' and 'USE_COLOR' not in os.environ:
Chris@87 279 # Avoid importing curses that causes illegal operation
Chris@87 280 # with a message:
Chris@87 281 # PYTHON2 caused an invalid page fault in
Chris@87 282 # module CYGNURSES7.DLL as 015f:18bbfc28
Chris@87 283 # Details: Python 2.3.3 [GCC 3.3.1 (cygming special)]
Chris@87 284 # ssh to Win32 machine from debian
Chris@87 285 # curses.version is 2.2
Chris@87 286 # CYGWIN_98-4.10, release 1.5.7(0.109/3/2))
Chris@87 287 return 0
Chris@87 288 if hasattr(sys.stdout, 'isatty') and sys.stdout.isatty():
Chris@87 289 try:
Chris@87 290 import curses
Chris@87 291 curses.setupterm()
Chris@87 292 if (curses.tigetnum("colors") >= 0
Chris@87 293 and curses.tigetnum("pairs") >= 0
Chris@87 294 and ((curses.tigetstr("setf") is not None
Chris@87 295 and curses.tigetstr("setb") is not None)
Chris@87 296 or (curses.tigetstr("setaf") is not None
Chris@87 297 and curses.tigetstr("setab") is not None)
Chris@87 298 or curses.tigetstr("scp") is not None)):
Chris@87 299 return 1
Chris@87 300 except Exception:
Chris@87 301 pass
Chris@87 302 return 0
Chris@87 303
Chris@87 304 if terminal_has_colors():
Chris@87 305 _colour_codes = dict(black=0, red=1, green=2, yellow=3,
Chris@87 306 blue=4, magenta=5, cyan=6, white=7, default=9)
Chris@87 307 def colour_text(s, fg=None, bg=None, bold=False):
Chris@87 308 seq = []
Chris@87 309 if bold:
Chris@87 310 seq.append('1')
Chris@87 311 if fg:
Chris@87 312 fgcode = 30 + _colour_codes.get(fg.lower(), 0)
Chris@87 313 seq.append(str(fgcode))
Chris@87 314 if bg:
Chris@87 315 bgcode = 40 + _colour_codes.get(fg.lower(), 7)
Chris@87 316 seq.append(str(bgcode))
Chris@87 317 if seq:
Chris@87 318 return '\x1b[%sm%s\x1b[0m' % (';'.join(seq), s)
Chris@87 319 else:
Chris@87 320 return s
Chris@87 321 else:
Chris@87 322 def colour_text(s, fg=None, bg=None):
Chris@87 323 return s
Chris@87 324
Chris@87 325 def default_text(s):
Chris@87 326 return colour_text(s, 'default')
Chris@87 327 def red_text(s):
Chris@87 328 return colour_text(s, 'red')
Chris@87 329 def green_text(s):
Chris@87 330 return colour_text(s, 'green')
Chris@87 331 def yellow_text(s):
Chris@87 332 return colour_text(s, 'yellow')
Chris@87 333 def cyan_text(s):
Chris@87 334 return colour_text(s, 'cyan')
Chris@87 335 def blue_text(s):
Chris@87 336 return colour_text(s, 'blue')
Chris@87 337
Chris@87 338 #########################
Chris@87 339
Chris@87 340 def cyg2win32(path):
Chris@87 341 if sys.platform=='cygwin' and path.startswith('/cygdrive'):
Chris@87 342 path = path[10] + ':' + os.path.normcase(path[11:])
Chris@87 343 return path
Chris@87 344
Chris@87 345 def mingw32():
Chris@87 346 """Return true when using mingw32 environment.
Chris@87 347 """
Chris@87 348 if sys.platform=='win32':
Chris@87 349 if os.environ.get('OSTYPE', '')=='msys':
Chris@87 350 return True
Chris@87 351 if os.environ.get('MSYSTEM', '')=='MINGW32':
Chris@87 352 return True
Chris@87 353 return False
Chris@87 354
Chris@87 355 def msvc_runtime_library():
Chris@87 356 "Return name of MSVC runtime library if Python was built with MSVC >= 7"
Chris@87 357 msc_pos = sys.version.find('MSC v.')
Chris@87 358 if msc_pos != -1:
Chris@87 359 msc_ver = sys.version[msc_pos+6:msc_pos+10]
Chris@87 360 lib = {'1300': 'msvcr70', # MSVC 7.0
Chris@87 361 '1310': 'msvcr71', # MSVC 7.1
Chris@87 362 '1400': 'msvcr80', # MSVC 8
Chris@87 363 '1500': 'msvcr90', # MSVC 9 (VS 2008)
Chris@87 364 '1600': 'msvcr100', # MSVC 10 (aka 2010)
Chris@87 365 }.get(msc_ver, None)
Chris@87 366 else:
Chris@87 367 lib = None
Chris@87 368 return lib
Chris@87 369
Chris@87 370
Chris@87 371 #########################
Chris@87 372
Chris@87 373 #XXX need support for .C that is also C++
Chris@87 374 cxx_ext_match = re.compile(r'.*[.](cpp|cxx|cc)\Z', re.I).match
Chris@87 375 fortran_ext_match = re.compile(r'.*[.](f90|f95|f77|for|ftn|f)\Z', re.I).match
Chris@87 376 f90_ext_match = re.compile(r'.*[.](f90|f95)\Z', re.I).match
Chris@87 377 f90_module_name_match = re.compile(r'\s*module\s*(?P<name>[\w_]+)', re.I).match
Chris@87 378 def _get_f90_modules(source):
Chris@87 379 """Return a list of Fortran f90 module names that
Chris@87 380 given source file defines.
Chris@87 381 """
Chris@87 382 if not f90_ext_match(source):
Chris@87 383 return []
Chris@87 384 modules = []
Chris@87 385 f = open(source, 'r')
Chris@87 386 for line in f:
Chris@87 387 m = f90_module_name_match(line)
Chris@87 388 if m:
Chris@87 389 name = m.group('name')
Chris@87 390 modules.append(name)
Chris@87 391 # break # XXX can we assume that there is one module per file?
Chris@87 392 f.close()
Chris@87 393 return modules
Chris@87 394
Chris@87 395 def is_string(s):
Chris@87 396 return isinstance(s, str)
Chris@87 397
Chris@87 398 def all_strings(lst):
Chris@87 399 """Return True if all items in lst are string objects. """
Chris@87 400 for item in lst:
Chris@87 401 if not is_string(item):
Chris@87 402 return False
Chris@87 403 return True
Chris@87 404
Chris@87 405 def is_sequence(seq):
Chris@87 406 if is_string(seq):
Chris@87 407 return False
Chris@87 408 try:
Chris@87 409 len(seq)
Chris@87 410 except:
Chris@87 411 return False
Chris@87 412 return True
Chris@87 413
Chris@87 414 def is_glob_pattern(s):
Chris@87 415 return is_string(s) and ('*' in s or '?' is s)
Chris@87 416
Chris@87 417 def as_list(seq):
Chris@87 418 if is_sequence(seq):
Chris@87 419 return list(seq)
Chris@87 420 else:
Chris@87 421 return [seq]
Chris@87 422
Chris@87 423 def get_language(sources):
Chris@87 424 # not used in numpy/scipy packages, use build_ext.detect_language instead
Chris@87 425 """Determine language value (c,f77,f90) from sources """
Chris@87 426 language = None
Chris@87 427 for source in sources:
Chris@87 428 if isinstance(source, str):
Chris@87 429 if f90_ext_match(source):
Chris@87 430 language = 'f90'
Chris@87 431 break
Chris@87 432 elif fortran_ext_match(source):
Chris@87 433 language = 'f77'
Chris@87 434 return language
Chris@87 435
Chris@87 436 def has_f_sources(sources):
Chris@87 437 """Return True if sources contains Fortran files """
Chris@87 438 for source in sources:
Chris@87 439 if fortran_ext_match(source):
Chris@87 440 return True
Chris@87 441 return False
Chris@87 442
Chris@87 443 def has_cxx_sources(sources):
Chris@87 444 """Return True if sources contains C++ files """
Chris@87 445 for source in sources:
Chris@87 446 if cxx_ext_match(source):
Chris@87 447 return True
Chris@87 448 return False
Chris@87 449
Chris@87 450 def filter_sources(sources):
Chris@87 451 """Return four lists of filenames containing
Chris@87 452 C, C++, Fortran, and Fortran 90 module sources,
Chris@87 453 respectively.
Chris@87 454 """
Chris@87 455 c_sources = []
Chris@87 456 cxx_sources = []
Chris@87 457 f_sources = []
Chris@87 458 fmodule_sources = []
Chris@87 459 for source in sources:
Chris@87 460 if fortran_ext_match(source):
Chris@87 461 modules = _get_f90_modules(source)
Chris@87 462 if modules:
Chris@87 463 fmodule_sources.append(source)
Chris@87 464 else:
Chris@87 465 f_sources.append(source)
Chris@87 466 elif cxx_ext_match(source):
Chris@87 467 cxx_sources.append(source)
Chris@87 468 else:
Chris@87 469 c_sources.append(source)
Chris@87 470 return c_sources, cxx_sources, f_sources, fmodule_sources
Chris@87 471
Chris@87 472
Chris@87 473 def _get_headers(directory_list):
Chris@87 474 # get *.h files from list of directories
Chris@87 475 headers = []
Chris@87 476 for d in directory_list:
Chris@87 477 head = glob.glob(os.path.join(d, "*.h")) #XXX: *.hpp files??
Chris@87 478 headers.extend(head)
Chris@87 479 return headers
Chris@87 480
Chris@87 481 def _get_directories(list_of_sources):
Chris@87 482 # get unique directories from list of sources.
Chris@87 483 direcs = []
Chris@87 484 for f in list_of_sources:
Chris@87 485 d = os.path.split(f)
Chris@87 486 if d[0] != '' and not d[0] in direcs:
Chris@87 487 direcs.append(d[0])
Chris@87 488 return direcs
Chris@87 489
Chris@87 490 def get_dependencies(sources):
Chris@87 491 #XXX scan sources for include statements
Chris@87 492 return _get_headers(_get_directories(sources))
Chris@87 493
Chris@87 494 def is_local_src_dir(directory):
Chris@87 495 """Return true if directory is local directory.
Chris@87 496 """
Chris@87 497 if not is_string(directory):
Chris@87 498 return False
Chris@87 499 abs_dir = os.path.abspath(directory)
Chris@87 500 c = os.path.commonprefix([os.getcwd(), abs_dir])
Chris@87 501 new_dir = abs_dir[len(c):].split(os.sep)
Chris@87 502 if new_dir and not new_dir[0]:
Chris@87 503 new_dir = new_dir[1:]
Chris@87 504 if new_dir and new_dir[0]=='build':
Chris@87 505 return False
Chris@87 506 new_dir = os.sep.join(new_dir)
Chris@87 507 return os.path.isdir(new_dir)
Chris@87 508
Chris@87 509 def general_source_files(top_path):
Chris@87 510 pruned_directories = {'CVS':1, '.svn':1, 'build':1}
Chris@87 511 prune_file_pat = re.compile(r'(?:[~#]|\.py[co]|\.o)$')
Chris@87 512 for dirpath, dirnames, filenames in os.walk(top_path, topdown=True):
Chris@87 513 pruned = [ d for d in dirnames if d not in pruned_directories ]
Chris@87 514 dirnames[:] = pruned
Chris@87 515 for f in filenames:
Chris@87 516 if not prune_file_pat.search(f):
Chris@87 517 yield os.path.join(dirpath, f)
Chris@87 518
Chris@87 519 def general_source_directories_files(top_path):
Chris@87 520 """Return a directory name relative to top_path and
Chris@87 521 files contained.
Chris@87 522 """
Chris@87 523 pruned_directories = ['CVS', '.svn', 'build']
Chris@87 524 prune_file_pat = re.compile(r'(?:[~#]|\.py[co]|\.o)$')
Chris@87 525 for dirpath, dirnames, filenames in os.walk(top_path, topdown=True):
Chris@87 526 pruned = [ d for d in dirnames if d not in pruned_directories ]
Chris@87 527 dirnames[:] = pruned
Chris@87 528 for d in dirnames:
Chris@87 529 dpath = os.path.join(dirpath, d)
Chris@87 530 rpath = rel_path(dpath, top_path)
Chris@87 531 files = []
Chris@87 532 for f in os.listdir(dpath):
Chris@87 533 fn = os.path.join(dpath, f)
Chris@87 534 if os.path.isfile(fn) and not prune_file_pat.search(fn):
Chris@87 535 files.append(fn)
Chris@87 536 yield rpath, files
Chris@87 537 dpath = top_path
Chris@87 538 rpath = rel_path(dpath, top_path)
Chris@87 539 filenames = [os.path.join(dpath, f) for f in os.listdir(dpath) \
Chris@87 540 if not prune_file_pat.search(f)]
Chris@87 541 files = [f for f in filenames if os.path.isfile(f)]
Chris@87 542 yield rpath, files
Chris@87 543
Chris@87 544
Chris@87 545 def get_ext_source_files(ext):
Chris@87 546 # Get sources and any include files in the same directory.
Chris@87 547 filenames = []
Chris@87 548 sources = [_m for _m in ext.sources if is_string(_m)]
Chris@87 549 filenames.extend(sources)
Chris@87 550 filenames.extend(get_dependencies(sources))
Chris@87 551 for d in ext.depends:
Chris@87 552 if is_local_src_dir(d):
Chris@87 553 filenames.extend(list(general_source_files(d)))
Chris@87 554 elif os.path.isfile(d):
Chris@87 555 filenames.append(d)
Chris@87 556 return filenames
Chris@87 557
Chris@87 558 def get_script_files(scripts):
Chris@87 559 scripts = [_m for _m in scripts if is_string(_m)]
Chris@87 560 return scripts
Chris@87 561
Chris@87 562 def get_lib_source_files(lib):
Chris@87 563 filenames = []
Chris@87 564 sources = lib[1].get('sources', [])
Chris@87 565 sources = [_m for _m in sources if is_string(_m)]
Chris@87 566 filenames.extend(sources)
Chris@87 567 filenames.extend(get_dependencies(sources))
Chris@87 568 depends = lib[1].get('depends', [])
Chris@87 569 for d in depends:
Chris@87 570 if is_local_src_dir(d):
Chris@87 571 filenames.extend(list(general_source_files(d)))
Chris@87 572 elif os.path.isfile(d):
Chris@87 573 filenames.append(d)
Chris@87 574 return filenames
Chris@87 575
Chris@87 576 def get_shared_lib_extension(is_python_ext=False):
Chris@87 577 """Return the correct file extension for shared libraries.
Chris@87 578
Chris@87 579 Parameters
Chris@87 580 ----------
Chris@87 581 is_python_ext : bool, optional
Chris@87 582 Whether the shared library is a Python extension. Default is False.
Chris@87 583
Chris@87 584 Returns
Chris@87 585 -------
Chris@87 586 so_ext : str
Chris@87 587 The shared library extension.
Chris@87 588
Chris@87 589 Notes
Chris@87 590 -----
Chris@87 591 For Python shared libs, `so_ext` will typically be '.so' on Linux and OS X,
Chris@87 592 and '.pyd' on Windows. For Python >= 3.2 `so_ext` has a tag prepended on
Chris@87 593 POSIX systems according to PEP 3149. For Python 3.2 this is implemented on
Chris@87 594 Linux, but not on OS X.
Chris@87 595
Chris@87 596 """
Chris@87 597 confvars = distutils.sysconfig.get_config_vars()
Chris@87 598 # SO is deprecated in 3.3.1, use EXT_SUFFIX instead
Chris@87 599 so_ext = confvars.get('EXT_SUFFIX', None)
Chris@87 600 if so_ext is None:
Chris@87 601 so_ext = confvars.get('SO', '')
Chris@87 602
Chris@87 603 if not is_python_ext:
Chris@87 604 # hardcode known values, config vars (including SHLIB_SUFFIX) are
Chris@87 605 # unreliable (see #3182)
Chris@87 606 # darwin, windows and debug linux are wrong in 3.3.1 and older
Chris@87 607 if (sys.platform.startswith('linux') or
Chris@87 608 sys.platform.startswith('gnukfreebsd')):
Chris@87 609 so_ext = '.so'
Chris@87 610 elif sys.platform.startswith('darwin'):
Chris@87 611 so_ext = '.dylib'
Chris@87 612 elif sys.platform.startswith('win'):
Chris@87 613 so_ext = '.dll'
Chris@87 614 else:
Chris@87 615 # fall back to config vars for unknown platforms
Chris@87 616 # fix long extension for Python >=3.2, see PEP 3149.
Chris@87 617 if 'SOABI' in confvars:
Chris@87 618 # Does nothing unless SOABI config var exists
Chris@87 619 so_ext = so_ext.replace('.' + confvars.get('SOABI'), '', 1)
Chris@87 620
Chris@87 621 return so_ext
Chris@87 622
Chris@87 623 def get_data_files(data):
Chris@87 624 if is_string(data):
Chris@87 625 return [data]
Chris@87 626 sources = data[1]
Chris@87 627 filenames = []
Chris@87 628 for s in sources:
Chris@87 629 if hasattr(s, '__call__'):
Chris@87 630 continue
Chris@87 631 if is_local_src_dir(s):
Chris@87 632 filenames.extend(list(general_source_files(s)))
Chris@87 633 elif is_string(s):
Chris@87 634 if os.path.isfile(s):
Chris@87 635 filenames.append(s)
Chris@87 636 else:
Chris@87 637 print('Not existing data file:', s)
Chris@87 638 else:
Chris@87 639 raise TypeError(repr(s))
Chris@87 640 return filenames
Chris@87 641
Chris@87 642 def dot_join(*args):
Chris@87 643 return '.'.join([a for a in args if a])
Chris@87 644
Chris@87 645 def get_frame(level=0):
Chris@87 646 """Return frame object from call stack with given level.
Chris@87 647 """
Chris@87 648 try:
Chris@87 649 return sys._getframe(level+1)
Chris@87 650 except AttributeError:
Chris@87 651 frame = sys.exc_info()[2].tb_frame
Chris@87 652 for _ in range(level+1):
Chris@87 653 frame = frame.f_back
Chris@87 654 return frame
Chris@87 655
Chris@87 656
Chris@87 657 ######################
Chris@87 658
Chris@87 659 class Configuration(object):
Chris@87 660
Chris@87 661 _list_keys = ['packages', 'ext_modules', 'data_files', 'include_dirs',
Chris@87 662 'libraries', 'headers', 'scripts', 'py_modules',
Chris@87 663 'installed_libraries', 'define_macros']
Chris@87 664 _dict_keys = ['package_dir', 'installed_pkg_config']
Chris@87 665 _extra_keys = ['name', 'version']
Chris@87 666
Chris@87 667 numpy_include_dirs = []
Chris@87 668
Chris@87 669 def __init__(self,
Chris@87 670 package_name=None,
Chris@87 671 parent_name=None,
Chris@87 672 top_path=None,
Chris@87 673 package_path=None,
Chris@87 674 caller_level=1,
Chris@87 675 setup_name='setup.py',
Chris@87 676 **attrs):
Chris@87 677 """Construct configuration instance of a package.
Chris@87 678
Chris@87 679 package_name -- name of the package
Chris@87 680 Ex.: 'distutils'
Chris@87 681 parent_name -- name of the parent package
Chris@87 682 Ex.: 'numpy'
Chris@87 683 top_path -- directory of the toplevel package
Chris@87 684 Ex.: the directory where the numpy package source sits
Chris@87 685 package_path -- directory of package. Will be computed by magic from the
Chris@87 686 directory of the caller module if not specified
Chris@87 687 Ex.: the directory where numpy.distutils is
Chris@87 688 caller_level -- frame level to caller namespace, internal parameter.
Chris@87 689 """
Chris@87 690 self.name = dot_join(parent_name, package_name)
Chris@87 691 self.version = None
Chris@87 692
Chris@87 693 caller_frame = get_frame(caller_level)
Chris@87 694 self.local_path = get_path_from_frame(caller_frame, top_path)
Chris@87 695 # local_path -- directory of a file (usually setup.py) that
Chris@87 696 # defines a configuration() function.
Chris@87 697 # local_path -- directory of a file (usually setup.py) that
Chris@87 698 # defines a configuration() function.
Chris@87 699 if top_path is None:
Chris@87 700 top_path = self.local_path
Chris@87 701 self.local_path = ''
Chris@87 702 if package_path is None:
Chris@87 703 package_path = self.local_path
Chris@87 704 elif os.path.isdir(njoin(self.local_path, package_path)):
Chris@87 705 package_path = njoin(self.local_path, package_path)
Chris@87 706 if not os.path.isdir(package_path or '.'):
Chris@87 707 raise ValueError("%r is not a directory" % (package_path,))
Chris@87 708 self.top_path = top_path
Chris@87 709 self.package_path = package_path
Chris@87 710 # this is the relative path in the installed package
Chris@87 711 self.path_in_package = os.path.join(*self.name.split('.'))
Chris@87 712
Chris@87 713 self.list_keys = self._list_keys[:]
Chris@87 714 self.dict_keys = self._dict_keys[:]
Chris@87 715
Chris@87 716 for n in self.list_keys:
Chris@87 717 v = copy.copy(attrs.get(n, []))
Chris@87 718 setattr(self, n, as_list(v))
Chris@87 719
Chris@87 720 for n in self.dict_keys:
Chris@87 721 v = copy.copy(attrs.get(n, {}))
Chris@87 722 setattr(self, n, v)
Chris@87 723
Chris@87 724 known_keys = self.list_keys + self.dict_keys
Chris@87 725 self.extra_keys = self._extra_keys[:]
Chris@87 726 for n in attrs.keys():
Chris@87 727 if n in known_keys:
Chris@87 728 continue
Chris@87 729 a = attrs[n]
Chris@87 730 setattr(self, n, a)
Chris@87 731 if isinstance(a, list):
Chris@87 732 self.list_keys.append(n)
Chris@87 733 elif isinstance(a, dict):
Chris@87 734 self.dict_keys.append(n)
Chris@87 735 else:
Chris@87 736 self.extra_keys.append(n)
Chris@87 737
Chris@87 738 if os.path.exists(njoin(package_path, '__init__.py')):
Chris@87 739 self.packages.append(self.name)
Chris@87 740 self.package_dir[self.name] = package_path
Chris@87 741
Chris@87 742 self.options = dict(
Chris@87 743 ignore_setup_xxx_py = False,
Chris@87 744 assume_default_configuration = False,
Chris@87 745 delegate_options_to_subpackages = False,
Chris@87 746 quiet = False,
Chris@87 747 )
Chris@87 748
Chris@87 749 caller_instance = None
Chris@87 750 for i in range(1, 3):
Chris@87 751 try:
Chris@87 752 f = get_frame(i)
Chris@87 753 except ValueError:
Chris@87 754 break
Chris@87 755 try:
Chris@87 756 caller_instance = eval('self', f.f_globals, f.f_locals)
Chris@87 757 break
Chris@87 758 except NameError:
Chris@87 759 pass
Chris@87 760 if isinstance(caller_instance, self.__class__):
Chris@87 761 if caller_instance.options['delegate_options_to_subpackages']:
Chris@87 762 self.set_options(**caller_instance.options)
Chris@87 763
Chris@87 764 self.setup_name = setup_name
Chris@87 765
Chris@87 766 def todict(self):
Chris@87 767 """
Chris@87 768 Return a dictionary compatible with the keyword arguments of distutils
Chris@87 769 setup function.
Chris@87 770
Chris@87 771 Examples
Chris@87 772 --------
Chris@87 773 >>> setup(**config.todict()) #doctest: +SKIP
Chris@87 774 """
Chris@87 775
Chris@87 776 self._optimize_data_files()
Chris@87 777 d = {}
Chris@87 778 known_keys = self.list_keys + self.dict_keys + self.extra_keys
Chris@87 779 for n in known_keys:
Chris@87 780 a = getattr(self, n)
Chris@87 781 if a:
Chris@87 782 d[n] = a
Chris@87 783 return d
Chris@87 784
Chris@87 785 def info(self, message):
Chris@87 786 if not self.options['quiet']:
Chris@87 787 print(message)
Chris@87 788
Chris@87 789 def warn(self, message):
Chris@87 790 sys.stderr.write('Warning: %s' % (message,))
Chris@87 791
Chris@87 792 def set_options(self, **options):
Chris@87 793 """
Chris@87 794 Configure Configuration instance.
Chris@87 795
Chris@87 796 The following options are available:
Chris@87 797 - ignore_setup_xxx_py
Chris@87 798 - assume_default_configuration
Chris@87 799 - delegate_options_to_subpackages
Chris@87 800 - quiet
Chris@87 801
Chris@87 802 """
Chris@87 803 for key, value in options.items():
Chris@87 804 if key in self.options:
Chris@87 805 self.options[key] = value
Chris@87 806 else:
Chris@87 807 raise ValueError('Unknown option: '+key)
Chris@87 808
Chris@87 809 def get_distribution(self):
Chris@87 810 """Return the distutils distribution object for self."""
Chris@87 811 from numpy.distutils.core import get_distribution
Chris@87 812 return get_distribution()
Chris@87 813
Chris@87 814 def _wildcard_get_subpackage(self, subpackage_name,
Chris@87 815 parent_name,
Chris@87 816 caller_level = 1):
Chris@87 817 l = subpackage_name.split('.')
Chris@87 818 subpackage_path = njoin([self.local_path]+l)
Chris@87 819 dirs = [_m for _m in glob.glob(subpackage_path) if os.path.isdir(_m)]
Chris@87 820 config_list = []
Chris@87 821 for d in dirs:
Chris@87 822 if not os.path.isfile(njoin(d, '__init__.py')):
Chris@87 823 continue
Chris@87 824 if 'build' in d.split(os.sep):
Chris@87 825 continue
Chris@87 826 n = '.'.join(d.split(os.sep)[-len(l):])
Chris@87 827 c = self.get_subpackage(n,
Chris@87 828 parent_name = parent_name,
Chris@87 829 caller_level = caller_level+1)
Chris@87 830 config_list.extend(c)
Chris@87 831 return config_list
Chris@87 832
Chris@87 833 def _get_configuration_from_setup_py(self, setup_py,
Chris@87 834 subpackage_name,
Chris@87 835 subpackage_path,
Chris@87 836 parent_name,
Chris@87 837 caller_level = 1):
Chris@87 838 # In case setup_py imports local modules:
Chris@87 839 sys.path.insert(0, os.path.dirname(setup_py))
Chris@87 840 try:
Chris@87 841 fo_setup_py = open(setup_py, 'U')
Chris@87 842 setup_name = os.path.splitext(os.path.basename(setup_py))[0]
Chris@87 843 n = dot_join(self.name, subpackage_name, setup_name)
Chris@87 844 setup_module = imp.load_module('_'.join(n.split('.')),
Chris@87 845 fo_setup_py,
Chris@87 846 setup_py,
Chris@87 847 ('.py', 'U', 1))
Chris@87 848 fo_setup_py.close()
Chris@87 849 if not hasattr(setup_module, 'configuration'):
Chris@87 850 if not self.options['assume_default_configuration']:
Chris@87 851 self.warn('Assuming default configuration '\
Chris@87 852 '(%s does not define configuration())'\
Chris@87 853 % (setup_module))
Chris@87 854 config = Configuration(subpackage_name, parent_name,
Chris@87 855 self.top_path, subpackage_path,
Chris@87 856 caller_level = caller_level + 1)
Chris@87 857 else:
Chris@87 858 pn = dot_join(*([parent_name] + subpackage_name.split('.')[:-1]))
Chris@87 859 args = (pn,)
Chris@87 860 def fix_args_py2(args):
Chris@87 861 if setup_module.configuration.__code__.co_argcount > 1:
Chris@87 862 args = args + (self.top_path,)
Chris@87 863 return args
Chris@87 864 def fix_args_py3(args):
Chris@87 865 if setup_module.configuration.__code__.co_argcount > 1:
Chris@87 866 args = args + (self.top_path,)
Chris@87 867 return args
Chris@87 868 if sys.version_info[0] < 3:
Chris@87 869 args = fix_args_py2(args)
Chris@87 870 else:
Chris@87 871 args = fix_args_py3(args)
Chris@87 872 config = setup_module.configuration(*args)
Chris@87 873 if config.name!=dot_join(parent_name, subpackage_name):
Chris@87 874 self.warn('Subpackage %r configuration returned as %r' % \
Chris@87 875 (dot_join(parent_name, subpackage_name), config.name))
Chris@87 876 finally:
Chris@87 877 del sys.path[0]
Chris@87 878 return config
Chris@87 879
Chris@87 880 def get_subpackage(self,subpackage_name,
Chris@87 881 subpackage_path=None,
Chris@87 882 parent_name=None,
Chris@87 883 caller_level = 1):
Chris@87 884 """Return list of subpackage configurations.
Chris@87 885
Chris@87 886 Parameters
Chris@87 887 ----------
Chris@87 888 subpackage_name : str or None
Chris@87 889 Name of the subpackage to get the configuration. '*' in
Chris@87 890 subpackage_name is handled as a wildcard.
Chris@87 891 subpackage_path : str
Chris@87 892 If None, then the path is assumed to be the local path plus the
Chris@87 893 subpackage_name. If a setup.py file is not found in the
Chris@87 894 subpackage_path, then a default configuration is used.
Chris@87 895 parent_name : str
Chris@87 896 Parent name.
Chris@87 897 """
Chris@87 898 if subpackage_name is None:
Chris@87 899 if subpackage_path is None:
Chris@87 900 raise ValueError(
Chris@87 901 "either subpackage_name or subpackage_path must be specified")
Chris@87 902 subpackage_name = os.path.basename(subpackage_path)
Chris@87 903
Chris@87 904 # handle wildcards
Chris@87 905 l = subpackage_name.split('.')
Chris@87 906 if subpackage_path is None and '*' in subpackage_name:
Chris@87 907 return self._wildcard_get_subpackage(subpackage_name,
Chris@87 908 parent_name,
Chris@87 909 caller_level = caller_level+1)
Chris@87 910 assert '*' not in subpackage_name, repr((subpackage_name, subpackage_path, parent_name))
Chris@87 911 if subpackage_path is None:
Chris@87 912 subpackage_path = njoin([self.local_path] + l)
Chris@87 913 else:
Chris@87 914 subpackage_path = njoin([subpackage_path] + l[:-1])
Chris@87 915 subpackage_path = self.paths([subpackage_path])[0]
Chris@87 916 setup_py = njoin(subpackage_path, self.setup_name)
Chris@87 917 if not self.options['ignore_setup_xxx_py']:
Chris@87 918 if not os.path.isfile(setup_py):
Chris@87 919 setup_py = njoin(subpackage_path,
Chris@87 920 'setup_%s.py' % (subpackage_name))
Chris@87 921 if not os.path.isfile(setup_py):
Chris@87 922 if not self.options['assume_default_configuration']:
Chris@87 923 self.warn('Assuming default configuration '\
Chris@87 924 '(%s/{setup_%s,setup}.py was not found)' \
Chris@87 925 % (os.path.dirname(setup_py), subpackage_name))
Chris@87 926 config = Configuration(subpackage_name, parent_name,
Chris@87 927 self.top_path, subpackage_path,
Chris@87 928 caller_level = caller_level+1)
Chris@87 929 else:
Chris@87 930 config = self._get_configuration_from_setup_py(
Chris@87 931 setup_py,
Chris@87 932 subpackage_name,
Chris@87 933 subpackage_path,
Chris@87 934 parent_name,
Chris@87 935 caller_level = caller_level + 1)
Chris@87 936 if config:
Chris@87 937 return [config]
Chris@87 938 else:
Chris@87 939 return []
Chris@87 940
Chris@87 941 def add_subpackage(self,subpackage_name,
Chris@87 942 subpackage_path=None,
Chris@87 943 standalone = False):
Chris@87 944 """Add a sub-package to the current Configuration instance.
Chris@87 945
Chris@87 946 This is useful in a setup.py script for adding sub-packages to a
Chris@87 947 package.
Chris@87 948
Chris@87 949 Parameters
Chris@87 950 ----------
Chris@87 951 subpackage_name : str
Chris@87 952 name of the subpackage
Chris@87 953 subpackage_path : str
Chris@87 954 if given, the subpackage path such as the subpackage is in
Chris@87 955 subpackage_path / subpackage_name. If None,the subpackage is
Chris@87 956 assumed to be located in the local path / subpackage_name.
Chris@87 957 standalone : bool
Chris@87 958 """
Chris@87 959
Chris@87 960 if standalone:
Chris@87 961 parent_name = None
Chris@87 962 else:
Chris@87 963 parent_name = self.name
Chris@87 964 config_list = self.get_subpackage(subpackage_name, subpackage_path,
Chris@87 965 parent_name = parent_name,
Chris@87 966 caller_level = 2)
Chris@87 967 if not config_list:
Chris@87 968 self.warn('No configuration returned, assuming unavailable.')
Chris@87 969 for config in config_list:
Chris@87 970 d = config
Chris@87 971 if isinstance(config, Configuration):
Chris@87 972 d = config.todict()
Chris@87 973 assert isinstance(d, dict), repr(type(d))
Chris@87 974
Chris@87 975 self.info('Appending %s configuration to %s' \
Chris@87 976 % (d.get('name'), self.name))
Chris@87 977 self.dict_append(**d)
Chris@87 978
Chris@87 979 dist = self.get_distribution()
Chris@87 980 if dist is not None:
Chris@87 981 self.warn('distutils distribution has been initialized,'\
Chris@87 982 ' it may be too late to add a subpackage '+ subpackage_name)
Chris@87 983
Chris@87 984 def add_data_dir(self, data_path):
Chris@87 985 """Recursively add files under data_path to data_files list.
Chris@87 986
Chris@87 987 Recursively add files under data_path to the list of data_files to be
Chris@87 988 installed (and distributed). The data_path can be either a relative
Chris@87 989 path-name, or an absolute path-name, or a 2-tuple where the first
Chris@87 990 argument shows where in the install directory the data directory
Chris@87 991 should be installed to.
Chris@87 992
Chris@87 993 Parameters
Chris@87 994 ----------
Chris@87 995 data_path : seq or str
Chris@87 996 Argument can be either
Chris@87 997
Chris@87 998 * 2-sequence (<datadir suffix>, <path to data directory>)
Chris@87 999 * path to data directory where python datadir suffix defaults
Chris@87 1000 to package dir.
Chris@87 1001
Chris@87 1002 Notes
Chris@87 1003 -----
Chris@87 1004 Rules for installation paths:
Chris@87 1005 foo/bar -> (foo/bar, foo/bar) -> parent/foo/bar
Chris@87 1006 (gun, foo/bar) -> parent/gun
Chris@87 1007 foo/* -> (foo/a, foo/a), (foo/b, foo/b) -> parent/foo/a, parent/foo/b
Chris@87 1008 (gun, foo/*) -> (gun, foo/a), (gun, foo/b) -> gun
Chris@87 1009 (gun/*, foo/*) -> parent/gun/a, parent/gun/b
Chris@87 1010 /foo/bar -> (bar, /foo/bar) -> parent/bar
Chris@87 1011 (gun, /foo/bar) -> parent/gun
Chris@87 1012 (fun/*/gun/*, sun/foo/bar) -> parent/fun/foo/gun/bar
Chris@87 1013
Chris@87 1014 Examples
Chris@87 1015 --------
Chris@87 1016 For example suppose the source directory contains fun/foo.dat and
Chris@87 1017 fun/bar/car.dat::
Chris@87 1018
Chris@87 1019 >>> self.add_data_dir('fun') #doctest: +SKIP
Chris@87 1020 >>> self.add_data_dir(('sun', 'fun')) #doctest: +SKIP
Chris@87 1021 >>> self.add_data_dir(('gun', '/full/path/to/fun'))#doctest: +SKIP
Chris@87 1022
Chris@87 1023 Will install data-files to the locations::
Chris@87 1024
Chris@87 1025 <package install directory>/
Chris@87 1026 fun/
Chris@87 1027 foo.dat
Chris@87 1028 bar/
Chris@87 1029 car.dat
Chris@87 1030 sun/
Chris@87 1031 foo.dat
Chris@87 1032 bar/
Chris@87 1033 car.dat
Chris@87 1034 gun/
Chris@87 1035 foo.dat
Chris@87 1036 car.dat
Chris@87 1037 """
Chris@87 1038 if is_sequence(data_path):
Chris@87 1039 d, data_path = data_path
Chris@87 1040 else:
Chris@87 1041 d = None
Chris@87 1042 if is_sequence(data_path):
Chris@87 1043 [self.add_data_dir((d, p)) for p in data_path]
Chris@87 1044 return
Chris@87 1045 if not is_string(data_path):
Chris@87 1046 raise TypeError("not a string: %r" % (data_path,))
Chris@87 1047 if d is None:
Chris@87 1048 if os.path.isabs(data_path):
Chris@87 1049 return self.add_data_dir((os.path.basename(data_path), data_path))
Chris@87 1050 return self.add_data_dir((data_path, data_path))
Chris@87 1051 paths = self.paths(data_path, include_non_existing=False)
Chris@87 1052 if is_glob_pattern(data_path):
Chris@87 1053 if is_glob_pattern(d):
Chris@87 1054 pattern_list = allpath(d).split(os.sep)
Chris@87 1055 pattern_list.reverse()
Chris@87 1056 # /a/*//b/ -> /a/*/b
Chris@87 1057 rl = list(range(len(pattern_list)-1)); rl.reverse()
Chris@87 1058 for i in rl:
Chris@87 1059 if not pattern_list[i]:
Chris@87 1060 del pattern_list[i]
Chris@87 1061 #
Chris@87 1062 for path in paths:
Chris@87 1063 if not os.path.isdir(path):
Chris@87 1064 print('Not a directory, skipping', path)
Chris@87 1065 continue
Chris@87 1066 rpath = rel_path(path, self.local_path)
Chris@87 1067 path_list = rpath.split(os.sep)
Chris@87 1068 path_list.reverse()
Chris@87 1069 target_list = []
Chris@87 1070 i = 0
Chris@87 1071 for s in pattern_list:
Chris@87 1072 if is_glob_pattern(s):
Chris@87 1073 if i>=len(path_list):
Chris@87 1074 raise ValueError('cannot fill pattern %r with %r' \
Chris@87 1075 % (d, path))
Chris@87 1076 target_list.append(path_list[i])
Chris@87 1077 else:
Chris@87 1078 assert s==path_list[i], repr((s, path_list[i], data_path, d, path, rpath))
Chris@87 1079 target_list.append(s)
Chris@87 1080 i += 1
Chris@87 1081 if path_list[i:]:
Chris@87 1082 self.warn('mismatch of pattern_list=%s and path_list=%s'\
Chris@87 1083 % (pattern_list, path_list))
Chris@87 1084 target_list.reverse()
Chris@87 1085 self.add_data_dir((os.sep.join(target_list), path))
Chris@87 1086 else:
Chris@87 1087 for path in paths:
Chris@87 1088 self.add_data_dir((d, path))
Chris@87 1089 return
Chris@87 1090 assert not is_glob_pattern(d), repr(d)
Chris@87 1091
Chris@87 1092 dist = self.get_distribution()
Chris@87 1093 if dist is not None and dist.data_files is not None:
Chris@87 1094 data_files = dist.data_files
Chris@87 1095 else:
Chris@87 1096 data_files = self.data_files
Chris@87 1097
Chris@87 1098 for path in paths:
Chris@87 1099 for d1, f in list(general_source_directories_files(path)):
Chris@87 1100 target_path = os.path.join(self.path_in_package, d, d1)
Chris@87 1101 data_files.append((target_path, f))
Chris@87 1102
Chris@87 1103 def _optimize_data_files(self):
Chris@87 1104 data_dict = {}
Chris@87 1105 for p, files in self.data_files:
Chris@87 1106 if p not in data_dict:
Chris@87 1107 data_dict[p] = set()
Chris@87 1108 for f in files:
Chris@87 1109 data_dict[p].add(f)
Chris@87 1110 self.data_files[:] = [(p, list(files)) for p, files in data_dict.items()]
Chris@87 1111
Chris@87 1112 def add_data_files(self,*files):
Chris@87 1113 """Add data files to configuration data_files.
Chris@87 1114
Chris@87 1115 Parameters
Chris@87 1116 ----------
Chris@87 1117 files : sequence
Chris@87 1118 Argument(s) can be either
Chris@87 1119
Chris@87 1120 * 2-sequence (<datadir prefix>,<path to data file(s)>)
Chris@87 1121 * paths to data files where python datadir prefix defaults
Chris@87 1122 to package dir.
Chris@87 1123
Chris@87 1124 Notes
Chris@87 1125 -----
Chris@87 1126 The form of each element of the files sequence is very flexible
Chris@87 1127 allowing many combinations of where to get the files from the package
Chris@87 1128 and where they should ultimately be installed on the system. The most
Chris@87 1129 basic usage is for an element of the files argument sequence to be a
Chris@87 1130 simple filename. This will cause that file from the local path to be
Chris@87 1131 installed to the installation path of the self.name package (package
Chris@87 1132 path). The file argument can also be a relative path in which case the
Chris@87 1133 entire relative path will be installed into the package directory.
Chris@87 1134 Finally, the file can be an absolute path name in which case the file
Chris@87 1135 will be found at the absolute path name but installed to the package
Chris@87 1136 path.
Chris@87 1137
Chris@87 1138 This basic behavior can be augmented by passing a 2-tuple in as the
Chris@87 1139 file argument. The first element of the tuple should specify the
Chris@87 1140 relative path (under the package install directory) where the
Chris@87 1141 remaining sequence of files should be installed to (it has nothing to
Chris@87 1142 do with the file-names in the source distribution). The second element
Chris@87 1143 of the tuple is the sequence of files that should be installed. The
Chris@87 1144 files in this sequence can be filenames, relative paths, or absolute
Chris@87 1145 paths. For absolute paths the file will be installed in the top-level
Chris@87 1146 package installation directory (regardless of the first argument).
Chris@87 1147 Filenames and relative path names will be installed in the package
Chris@87 1148 install directory under the path name given as the first element of
Chris@87 1149 the tuple.
Chris@87 1150
Chris@87 1151 Rules for installation paths:
Chris@87 1152
Chris@87 1153 #. file.txt -> (., file.txt)-> parent/file.txt
Chris@87 1154 #. foo/file.txt -> (foo, foo/file.txt) -> parent/foo/file.txt
Chris@87 1155 #. /foo/bar/file.txt -> (., /foo/bar/file.txt) -> parent/file.txt
Chris@87 1156 #. *.txt -> parent/a.txt, parent/b.txt
Chris@87 1157 #. foo/*.txt -> parent/foo/a.txt, parent/foo/b.txt
Chris@87 1158 #. */*.txt -> (*, */*.txt) -> parent/c/a.txt, parent/d/b.txt
Chris@87 1159 #. (sun, file.txt) -> parent/sun/file.txt
Chris@87 1160 #. (sun, bar/file.txt) -> parent/sun/file.txt
Chris@87 1161 #. (sun, /foo/bar/file.txt) -> parent/sun/file.txt
Chris@87 1162 #. (sun, *.txt) -> parent/sun/a.txt, parent/sun/b.txt
Chris@87 1163 #. (sun, bar/*.txt) -> parent/sun/a.txt, parent/sun/b.txt
Chris@87 1164 #. (sun/*, */*.txt) -> parent/sun/c/a.txt, parent/d/b.txt
Chris@87 1165
Chris@87 1166 An additional feature is that the path to a data-file can actually be
Chris@87 1167 a function that takes no arguments and returns the actual path(s) to
Chris@87 1168 the data-files. This is useful when the data files are generated while
Chris@87 1169 building the package.
Chris@87 1170
Chris@87 1171 Examples
Chris@87 1172 --------
Chris@87 1173 Add files to the list of data_files to be included with the package.
Chris@87 1174
Chris@87 1175 >>> self.add_data_files('foo.dat',
Chris@87 1176 ... ('fun', ['gun.dat', 'nun/pun.dat', '/tmp/sun.dat']),
Chris@87 1177 ... 'bar/cat.dat',
Chris@87 1178 ... '/full/path/to/can.dat') #doctest: +SKIP
Chris@87 1179
Chris@87 1180 will install these data files to::
Chris@87 1181
Chris@87 1182 <package install directory>/
Chris@87 1183 foo.dat
Chris@87 1184 fun/
Chris@87 1185 gun.dat
Chris@87 1186 nun/
Chris@87 1187 pun.dat
Chris@87 1188 sun.dat
Chris@87 1189 bar/
Chris@87 1190 car.dat
Chris@87 1191 can.dat
Chris@87 1192
Chris@87 1193 where <package install directory> is the package (or sub-package)
Chris@87 1194 directory such as '/usr/lib/python2.4/site-packages/mypackage' ('C:
Chris@87 1195 \\Python2.4 \\Lib \\site-packages \\mypackage') or
Chris@87 1196 '/usr/lib/python2.4/site- packages/mypackage/mysubpackage' ('C:
Chris@87 1197 \\Python2.4 \\Lib \\site-packages \\mypackage \\mysubpackage').
Chris@87 1198 """
Chris@87 1199
Chris@87 1200 if len(files)>1:
Chris@87 1201 for f in files:
Chris@87 1202 self.add_data_files(f)
Chris@87 1203 return
Chris@87 1204 assert len(files)==1
Chris@87 1205 if is_sequence(files[0]):
Chris@87 1206 d, files = files[0]
Chris@87 1207 else:
Chris@87 1208 d = None
Chris@87 1209 if is_string(files):
Chris@87 1210 filepat = files
Chris@87 1211 elif is_sequence(files):
Chris@87 1212 if len(files)==1:
Chris@87 1213 filepat = files[0]
Chris@87 1214 else:
Chris@87 1215 for f in files:
Chris@87 1216 self.add_data_files((d, f))
Chris@87 1217 return
Chris@87 1218 else:
Chris@87 1219 raise TypeError(repr(type(files)))
Chris@87 1220
Chris@87 1221 if d is None:
Chris@87 1222 if hasattr(filepat, '__call__'):
Chris@87 1223 d = ''
Chris@87 1224 elif os.path.isabs(filepat):
Chris@87 1225 d = ''
Chris@87 1226 else:
Chris@87 1227 d = os.path.dirname(filepat)
Chris@87 1228 self.add_data_files((d, files))
Chris@87 1229 return
Chris@87 1230
Chris@87 1231 paths = self.paths(filepat, include_non_existing=False)
Chris@87 1232 if is_glob_pattern(filepat):
Chris@87 1233 if is_glob_pattern(d):
Chris@87 1234 pattern_list = d.split(os.sep)
Chris@87 1235 pattern_list.reverse()
Chris@87 1236 for path in paths:
Chris@87 1237 path_list = path.split(os.sep)
Chris@87 1238 path_list.reverse()
Chris@87 1239 path_list.pop() # filename
Chris@87 1240 target_list = []
Chris@87 1241 i = 0
Chris@87 1242 for s in pattern_list:
Chris@87 1243 if is_glob_pattern(s):
Chris@87 1244 target_list.append(path_list[i])
Chris@87 1245 i += 1
Chris@87 1246 else:
Chris@87 1247 target_list.append(s)
Chris@87 1248 target_list.reverse()
Chris@87 1249 self.add_data_files((os.sep.join(target_list), path))
Chris@87 1250 else:
Chris@87 1251 self.add_data_files((d, paths))
Chris@87 1252 return
Chris@87 1253 assert not is_glob_pattern(d), repr((d, filepat))
Chris@87 1254
Chris@87 1255 dist = self.get_distribution()
Chris@87 1256 if dist is not None and dist.data_files is not None:
Chris@87 1257 data_files = dist.data_files
Chris@87 1258 else:
Chris@87 1259 data_files = self.data_files
Chris@87 1260
Chris@87 1261 data_files.append((os.path.join(self.path_in_package, d), paths))
Chris@87 1262
Chris@87 1263 ### XXX Implement add_py_modules
Chris@87 1264
Chris@87 1265 def add_define_macros(self, macros):
Chris@87 1266 """Add define macros to configuration
Chris@87 1267
Chris@87 1268 Add the given sequence of macro name and value duples to the beginning
Chris@87 1269 of the define_macros list This list will be visible to all extension
Chris@87 1270 modules of the current package.
Chris@87 1271 """
Chris@87 1272 dist = self.get_distribution()
Chris@87 1273 if dist is not None:
Chris@87 1274 if not hasattr(dist, 'define_macros'):
Chris@87 1275 dist.define_macros = []
Chris@87 1276 dist.define_macros.extend(macros)
Chris@87 1277 else:
Chris@87 1278 self.define_macros.extend(macros)
Chris@87 1279
Chris@87 1280
Chris@87 1281 def add_include_dirs(self,*paths):
Chris@87 1282 """Add paths to configuration include directories.
Chris@87 1283
Chris@87 1284 Add the given sequence of paths to the beginning of the include_dirs
Chris@87 1285 list. This list will be visible to all extension modules of the
Chris@87 1286 current package.
Chris@87 1287 """
Chris@87 1288 include_dirs = self.paths(paths)
Chris@87 1289 dist = self.get_distribution()
Chris@87 1290 if dist is not None:
Chris@87 1291 if dist.include_dirs is None:
Chris@87 1292 dist.include_dirs = []
Chris@87 1293 dist.include_dirs.extend(include_dirs)
Chris@87 1294 else:
Chris@87 1295 self.include_dirs.extend(include_dirs)
Chris@87 1296
Chris@87 1297 def add_headers(self,*files):
Chris@87 1298 """Add installable headers to configuration.
Chris@87 1299
Chris@87 1300 Add the given sequence of files to the beginning of the headers list.
Chris@87 1301 By default, headers will be installed under <python-
Chris@87 1302 include>/<self.name.replace('.','/')>/ directory. If an item of files
Chris@87 1303 is a tuple, then its first argument specifies the actual installation
Chris@87 1304 location relative to the <python-include> path.
Chris@87 1305
Chris@87 1306 Parameters
Chris@87 1307 ----------
Chris@87 1308 files : str or seq
Chris@87 1309 Argument(s) can be either:
Chris@87 1310
Chris@87 1311 * 2-sequence (<includedir suffix>,<path to header file(s)>)
Chris@87 1312 * path(s) to header file(s) where python includedir suffix will
Chris@87 1313 default to package name.
Chris@87 1314 """
Chris@87 1315 headers = []
Chris@87 1316 for path in files:
Chris@87 1317 if is_string(path):
Chris@87 1318 [headers.append((self.name, p)) for p in self.paths(path)]
Chris@87 1319 else:
Chris@87 1320 if not isinstance(path, (tuple, list)) or len(path) != 2:
Chris@87 1321 raise TypeError(repr(path))
Chris@87 1322 [headers.append((path[0], p)) for p in self.paths(path[1])]
Chris@87 1323 dist = self.get_distribution()
Chris@87 1324 if dist is not None:
Chris@87 1325 if dist.headers is None:
Chris@87 1326 dist.headers = []
Chris@87 1327 dist.headers.extend(headers)
Chris@87 1328 else:
Chris@87 1329 self.headers.extend(headers)
Chris@87 1330
Chris@87 1331 def paths(self,*paths,**kws):
Chris@87 1332 """Apply glob to paths and prepend local_path if needed.
Chris@87 1333
Chris@87 1334 Applies glob.glob(...) to each path in the sequence (if needed) and
Chris@87 1335 pre-pends the local_path if needed. Because this is called on all
Chris@87 1336 source lists, this allows wildcard characters to be specified in lists
Chris@87 1337 of sources for extension modules and libraries and scripts and allows
Chris@87 1338 path-names be relative to the source directory.
Chris@87 1339
Chris@87 1340 """
Chris@87 1341 include_non_existing = kws.get('include_non_existing', True)
Chris@87 1342 return gpaths(paths,
Chris@87 1343 local_path = self.local_path,
Chris@87 1344 include_non_existing=include_non_existing)
Chris@87 1345
Chris@87 1346 def _fix_paths_dict(self, kw):
Chris@87 1347 for k in kw.keys():
Chris@87 1348 v = kw[k]
Chris@87 1349 if k in ['sources', 'depends', 'include_dirs', 'library_dirs',
Chris@87 1350 'module_dirs', 'extra_objects']:
Chris@87 1351 new_v = self.paths(v)
Chris@87 1352 kw[k] = new_v
Chris@87 1353
Chris@87 1354 def add_extension(self,name,sources,**kw):
Chris@87 1355 """Add extension to configuration.
Chris@87 1356
Chris@87 1357 Create and add an Extension instance to the ext_modules list. This
Chris@87 1358 method also takes the following optional keyword arguments that are
Chris@87 1359 passed on to the Extension constructor.
Chris@87 1360
Chris@87 1361 Parameters
Chris@87 1362 ----------
Chris@87 1363 name : str
Chris@87 1364 name of the extension
Chris@87 1365 sources : seq
Chris@87 1366 list of the sources. The list of sources may contain functions
Chris@87 1367 (called source generators) which must take an extension instance
Chris@87 1368 and a build directory as inputs and return a source file or list of
Chris@87 1369 source files or None. If None is returned then no sources are
Chris@87 1370 generated. If the Extension instance has no sources after
Chris@87 1371 processing all source generators, then no extension module is
Chris@87 1372 built.
Chris@87 1373 include_dirs :
Chris@87 1374 define_macros :
Chris@87 1375 undef_macros :
Chris@87 1376 library_dirs :
Chris@87 1377 libraries :
Chris@87 1378 runtime_library_dirs :
Chris@87 1379 extra_objects :
Chris@87 1380 extra_compile_args :
Chris@87 1381 extra_link_args :
Chris@87 1382 extra_f77_compile_args :
Chris@87 1383 extra_f90_compile_args :
Chris@87 1384 export_symbols :
Chris@87 1385 swig_opts :
Chris@87 1386 depends :
Chris@87 1387 The depends list contains paths to files or directories that the
Chris@87 1388 sources of the extension module depend on. If any path in the
Chris@87 1389 depends list is newer than the extension module, then the module
Chris@87 1390 will be rebuilt.
Chris@87 1391 language :
Chris@87 1392 f2py_options :
Chris@87 1393 module_dirs :
Chris@87 1394 extra_info : dict or list
Chris@87 1395 dict or list of dict of keywords to be appended to keywords.
Chris@87 1396
Chris@87 1397 Notes
Chris@87 1398 -----
Chris@87 1399 The self.paths(...) method is applied to all lists that may contain
Chris@87 1400 paths.
Chris@87 1401 """
Chris@87 1402 ext_args = copy.copy(kw)
Chris@87 1403 ext_args['name'] = dot_join(self.name, name)
Chris@87 1404 ext_args['sources'] = sources
Chris@87 1405
Chris@87 1406 if 'extra_info' in ext_args:
Chris@87 1407 extra_info = ext_args['extra_info']
Chris@87 1408 del ext_args['extra_info']
Chris@87 1409 if isinstance(extra_info, dict):
Chris@87 1410 extra_info = [extra_info]
Chris@87 1411 for info in extra_info:
Chris@87 1412 assert isinstance(info, dict), repr(info)
Chris@87 1413 dict_append(ext_args,**info)
Chris@87 1414
Chris@87 1415 self._fix_paths_dict(ext_args)
Chris@87 1416
Chris@87 1417 # Resolve out-of-tree dependencies
Chris@87 1418 libraries = ext_args.get('libraries', [])
Chris@87 1419 libnames = []
Chris@87 1420 ext_args['libraries'] = []
Chris@87 1421 for libname in libraries:
Chris@87 1422 if isinstance(libname, tuple):
Chris@87 1423 self._fix_paths_dict(libname[1])
Chris@87 1424
Chris@87 1425 # Handle library names of the form libname@relative/path/to/library
Chris@87 1426 if '@' in libname:
Chris@87 1427 lname, lpath = libname.split('@', 1)
Chris@87 1428 lpath = os.path.abspath(njoin(self.local_path, lpath))
Chris@87 1429 if os.path.isdir(lpath):
Chris@87 1430 c = self.get_subpackage(None, lpath,
Chris@87 1431 caller_level = 2)
Chris@87 1432 if isinstance(c, Configuration):
Chris@87 1433 c = c.todict()
Chris@87 1434 for l in [l[0] for l in c.get('libraries', [])]:
Chris@87 1435 llname = l.split('__OF__', 1)[0]
Chris@87 1436 if llname == lname:
Chris@87 1437 c.pop('name', None)
Chris@87 1438 dict_append(ext_args,**c)
Chris@87 1439 break
Chris@87 1440 continue
Chris@87 1441 libnames.append(libname)
Chris@87 1442
Chris@87 1443 ext_args['libraries'] = libnames + ext_args['libraries']
Chris@87 1444 ext_args['define_macros'] = \
Chris@87 1445 self.define_macros + ext_args.get('define_macros', [])
Chris@87 1446
Chris@87 1447 from numpy.distutils.core import Extension
Chris@87 1448 ext = Extension(**ext_args)
Chris@87 1449 self.ext_modules.append(ext)
Chris@87 1450
Chris@87 1451 dist = self.get_distribution()
Chris@87 1452 if dist is not None:
Chris@87 1453 self.warn('distutils distribution has been initialized,'\
Chris@87 1454 ' it may be too late to add an extension '+name)
Chris@87 1455 return ext
Chris@87 1456
Chris@87 1457 def add_library(self,name,sources,**build_info):
Chris@87 1458 """
Chris@87 1459 Add library to configuration.
Chris@87 1460
Chris@87 1461 Parameters
Chris@87 1462 ----------
Chris@87 1463 name : str
Chris@87 1464 Name of the extension.
Chris@87 1465 sources : sequence
Chris@87 1466 List of the sources. The list of sources may contain functions
Chris@87 1467 (called source generators) which must take an extension instance
Chris@87 1468 and a build directory as inputs and return a source file or list of
Chris@87 1469 source files or None. If None is returned then no sources are
Chris@87 1470 generated. If the Extension instance has no sources after
Chris@87 1471 processing all source generators, then no extension module is
Chris@87 1472 built.
Chris@87 1473 build_info : dict, optional
Chris@87 1474 The following keys are allowed:
Chris@87 1475
Chris@87 1476 * depends
Chris@87 1477 * macros
Chris@87 1478 * include_dirs
Chris@87 1479 * extra_compiler_args
Chris@87 1480 * extra_f77_compiler_args
Chris@87 1481 * extra_f90_compiler_args
Chris@87 1482 * f2py_options
Chris@87 1483 * language
Chris@87 1484
Chris@87 1485 """
Chris@87 1486 self._add_library(name, sources, None, build_info)
Chris@87 1487
Chris@87 1488 dist = self.get_distribution()
Chris@87 1489 if dist is not None:
Chris@87 1490 self.warn('distutils distribution has been initialized,'\
Chris@87 1491 ' it may be too late to add a library '+ name)
Chris@87 1492
Chris@87 1493 def _add_library(self, name, sources, install_dir, build_info):
Chris@87 1494 """Common implementation for add_library and add_installed_library. Do
Chris@87 1495 not use directly"""
Chris@87 1496 build_info = copy.copy(build_info)
Chris@87 1497 name = name #+ '__OF__' + self.name
Chris@87 1498 build_info['sources'] = sources
Chris@87 1499
Chris@87 1500 # Sometimes, depends is not set up to an empty list by default, and if
Chris@87 1501 # depends is not given to add_library, distutils barfs (#1134)
Chris@87 1502 if not 'depends' in build_info:
Chris@87 1503 build_info['depends'] = []
Chris@87 1504
Chris@87 1505 self._fix_paths_dict(build_info)
Chris@87 1506
Chris@87 1507 # Add to libraries list so that it is build with build_clib
Chris@87 1508 self.libraries.append((name, build_info))
Chris@87 1509
Chris@87 1510 def add_installed_library(self, name, sources, install_dir, build_info=None):
Chris@87 1511 """
Chris@87 1512 Similar to add_library, but the specified library is installed.
Chris@87 1513
Chris@87 1514 Most C libraries used with `distutils` are only used to build python
Chris@87 1515 extensions, but libraries built through this method will be installed
Chris@87 1516 so that they can be reused by third-party packages.
Chris@87 1517
Chris@87 1518 Parameters
Chris@87 1519 ----------
Chris@87 1520 name : str
Chris@87 1521 Name of the installed library.
Chris@87 1522 sources : sequence
Chris@87 1523 List of the library's source files. See `add_library` for details.
Chris@87 1524 install_dir : str
Chris@87 1525 Path to install the library, relative to the current sub-package.
Chris@87 1526 build_info : dict, optional
Chris@87 1527 The following keys are allowed:
Chris@87 1528
Chris@87 1529 * depends
Chris@87 1530 * macros
Chris@87 1531 * include_dirs
Chris@87 1532 * extra_compiler_args
Chris@87 1533 * extra_f77_compiler_args
Chris@87 1534 * extra_f90_compiler_args
Chris@87 1535 * f2py_options
Chris@87 1536 * language
Chris@87 1537
Chris@87 1538 Returns
Chris@87 1539 -------
Chris@87 1540 None
Chris@87 1541
Chris@87 1542 See Also
Chris@87 1543 --------
Chris@87 1544 add_library, add_npy_pkg_config, get_info
Chris@87 1545
Chris@87 1546 Notes
Chris@87 1547 -----
Chris@87 1548 The best way to encode the options required to link against the specified
Chris@87 1549 C libraries is to use a "libname.ini" file, and use `get_info` to
Chris@87 1550 retrieve the required options (see `add_npy_pkg_config` for more
Chris@87 1551 information).
Chris@87 1552
Chris@87 1553 """
Chris@87 1554 if not build_info:
Chris@87 1555 build_info = {}
Chris@87 1556
Chris@87 1557 install_dir = os.path.join(self.package_path, install_dir)
Chris@87 1558 self._add_library(name, sources, install_dir, build_info)
Chris@87 1559 self.installed_libraries.append(InstallableLib(name, build_info, install_dir))
Chris@87 1560
Chris@87 1561 def add_npy_pkg_config(self, template, install_dir, subst_dict=None):
Chris@87 1562 """
Chris@87 1563 Generate and install a npy-pkg config file from a template.
Chris@87 1564
Chris@87 1565 The config file generated from `template` is installed in the
Chris@87 1566 given install directory, using `subst_dict` for variable substitution.
Chris@87 1567
Chris@87 1568 Parameters
Chris@87 1569 ----------
Chris@87 1570 template : str
Chris@87 1571 The path of the template, relatively to the current package path.
Chris@87 1572 install_dir : str
Chris@87 1573 Where to install the npy-pkg config file, relatively to the current
Chris@87 1574 package path.
Chris@87 1575 subst_dict : dict, optional
Chris@87 1576 If given, any string of the form ``@key@`` will be replaced by
Chris@87 1577 ``subst_dict[key]`` in the template file when installed. The install
Chris@87 1578 prefix is always available through the variable ``@prefix@``, since the
Chris@87 1579 install prefix is not easy to get reliably from setup.py.
Chris@87 1580
Chris@87 1581 See also
Chris@87 1582 --------
Chris@87 1583 add_installed_library, get_info
Chris@87 1584
Chris@87 1585 Notes
Chris@87 1586 -----
Chris@87 1587 This works for both standard installs and in-place builds, i.e. the
Chris@87 1588 ``@prefix@`` refer to the source directory for in-place builds.
Chris@87 1589
Chris@87 1590 Examples
Chris@87 1591 --------
Chris@87 1592 ::
Chris@87 1593
Chris@87 1594 config.add_npy_pkg_config('foo.ini.in', 'lib', {'foo': bar})
Chris@87 1595
Chris@87 1596 Assuming the foo.ini.in file has the following content::
Chris@87 1597
Chris@87 1598 [meta]
Chris@87 1599 Name=@foo@
Chris@87 1600 Version=1.0
Chris@87 1601 Description=dummy description
Chris@87 1602
Chris@87 1603 [default]
Chris@87 1604 Cflags=-I@prefix@/include
Chris@87 1605 Libs=
Chris@87 1606
Chris@87 1607 The generated file will have the following content::
Chris@87 1608
Chris@87 1609 [meta]
Chris@87 1610 Name=bar
Chris@87 1611 Version=1.0
Chris@87 1612 Description=dummy description
Chris@87 1613
Chris@87 1614 [default]
Chris@87 1615 Cflags=-Iprefix_dir/include
Chris@87 1616 Libs=
Chris@87 1617
Chris@87 1618 and will be installed as foo.ini in the 'lib' subpath.
Chris@87 1619
Chris@87 1620 """
Chris@87 1621 if subst_dict is None:
Chris@87 1622 subst_dict = {}
Chris@87 1623 basename = os.path.splitext(template)[0]
Chris@87 1624 template = os.path.join(self.package_path, template)
Chris@87 1625
Chris@87 1626 if self.name in self.installed_pkg_config:
Chris@87 1627 self.installed_pkg_config[self.name].append((template, install_dir,
Chris@87 1628 subst_dict))
Chris@87 1629 else:
Chris@87 1630 self.installed_pkg_config[self.name] = [(template, install_dir,
Chris@87 1631 subst_dict)]
Chris@87 1632
Chris@87 1633
Chris@87 1634 def add_scripts(self,*files):
Chris@87 1635 """Add scripts to configuration.
Chris@87 1636
Chris@87 1637 Add the sequence of files to the beginning of the scripts list.
Chris@87 1638 Scripts will be installed under the <prefix>/bin/ directory.
Chris@87 1639
Chris@87 1640 """
Chris@87 1641 scripts = self.paths(files)
Chris@87 1642 dist = self.get_distribution()
Chris@87 1643 if dist is not None:
Chris@87 1644 if dist.scripts is None:
Chris@87 1645 dist.scripts = []
Chris@87 1646 dist.scripts.extend(scripts)
Chris@87 1647 else:
Chris@87 1648 self.scripts.extend(scripts)
Chris@87 1649
Chris@87 1650 def dict_append(self,**dict):
Chris@87 1651 for key in self.list_keys:
Chris@87 1652 a = getattr(self, key)
Chris@87 1653 a.extend(dict.get(key, []))
Chris@87 1654 for key in self.dict_keys:
Chris@87 1655 a = getattr(self, key)
Chris@87 1656 a.update(dict.get(key, {}))
Chris@87 1657 known_keys = self.list_keys + self.dict_keys + self.extra_keys
Chris@87 1658 for key in dict.keys():
Chris@87 1659 if key not in known_keys:
Chris@87 1660 a = getattr(self, key, None)
Chris@87 1661 if a and a==dict[key]: continue
Chris@87 1662 self.warn('Inheriting attribute %r=%r from %r' \
Chris@87 1663 % (key, dict[key], dict.get('name', '?')))
Chris@87 1664 setattr(self, key, dict[key])
Chris@87 1665 self.extra_keys.append(key)
Chris@87 1666 elif key in self.extra_keys:
Chris@87 1667 self.info('Ignoring attempt to set %r (from %r to %r)' \
Chris@87 1668 % (key, getattr(self, key), dict[key]))
Chris@87 1669 elif key in known_keys:
Chris@87 1670 # key is already processed above
Chris@87 1671 pass
Chris@87 1672 else:
Chris@87 1673 raise ValueError("Don't know about key=%r" % (key))
Chris@87 1674
Chris@87 1675 def __str__(self):
Chris@87 1676 from pprint import pformat
Chris@87 1677 known_keys = self.list_keys + self.dict_keys + self.extra_keys
Chris@87 1678 s = '<'+5*'-' + '\n'
Chris@87 1679 s += 'Configuration of '+self.name+':\n'
Chris@87 1680 known_keys.sort()
Chris@87 1681 for k in known_keys:
Chris@87 1682 a = getattr(self, k, None)
Chris@87 1683 if a:
Chris@87 1684 s += '%s = %s\n' % (k, pformat(a))
Chris@87 1685 s += 5*'-' + '>'
Chris@87 1686 return s
Chris@87 1687
Chris@87 1688 def get_config_cmd(self):
Chris@87 1689 """
Chris@87 1690 Returns the numpy.distutils config command instance.
Chris@87 1691 """
Chris@87 1692 cmd = get_cmd('config')
Chris@87 1693 cmd.ensure_finalized()
Chris@87 1694 cmd.dump_source = 0
Chris@87 1695 cmd.noisy = 0
Chris@87 1696 old_path = os.environ.get('PATH')
Chris@87 1697 if old_path:
Chris@87 1698 path = os.pathsep.join(['.', old_path])
Chris@87 1699 os.environ['PATH'] = path
Chris@87 1700 return cmd
Chris@87 1701
Chris@87 1702 def get_build_temp_dir(self):
Chris@87 1703 """
Chris@87 1704 Return a path to a temporary directory where temporary files should be
Chris@87 1705 placed.
Chris@87 1706 """
Chris@87 1707 cmd = get_cmd('build')
Chris@87 1708 cmd.ensure_finalized()
Chris@87 1709 return cmd.build_temp
Chris@87 1710
Chris@87 1711 def have_f77c(self):
Chris@87 1712 """Check for availability of Fortran 77 compiler.
Chris@87 1713
Chris@87 1714 Use it inside source generating function to ensure that
Chris@87 1715 setup distribution instance has been initialized.
Chris@87 1716
Chris@87 1717 Notes
Chris@87 1718 -----
Chris@87 1719 True if a Fortran 77 compiler is available (because a simple Fortran 77
Chris@87 1720 code was able to be compiled successfully).
Chris@87 1721 """
Chris@87 1722 simple_fortran_subroutine = '''
Chris@87 1723 subroutine simple
Chris@87 1724 end
Chris@87 1725 '''
Chris@87 1726 config_cmd = self.get_config_cmd()
Chris@87 1727 flag = config_cmd.try_compile(simple_fortran_subroutine, lang='f77')
Chris@87 1728 return flag
Chris@87 1729
Chris@87 1730 def have_f90c(self):
Chris@87 1731 """Check for availability of Fortran 90 compiler.
Chris@87 1732
Chris@87 1733 Use it inside source generating function to ensure that
Chris@87 1734 setup distribution instance has been initialized.
Chris@87 1735
Chris@87 1736 Notes
Chris@87 1737 -----
Chris@87 1738 True if a Fortran 90 compiler is available (because a simple Fortran
Chris@87 1739 90 code was able to be compiled successfully)
Chris@87 1740 """
Chris@87 1741 simple_fortran_subroutine = '''
Chris@87 1742 subroutine simple
Chris@87 1743 end
Chris@87 1744 '''
Chris@87 1745 config_cmd = self.get_config_cmd()
Chris@87 1746 flag = config_cmd.try_compile(simple_fortran_subroutine, lang='f90')
Chris@87 1747 return flag
Chris@87 1748
Chris@87 1749 def append_to(self, extlib):
Chris@87 1750 """Append libraries, include_dirs to extension or library item.
Chris@87 1751 """
Chris@87 1752 if is_sequence(extlib):
Chris@87 1753 lib_name, build_info = extlib
Chris@87 1754 dict_append(build_info,
Chris@87 1755 libraries=self.libraries,
Chris@87 1756 include_dirs=self.include_dirs)
Chris@87 1757 else:
Chris@87 1758 from numpy.distutils.core import Extension
Chris@87 1759 assert isinstance(extlib, Extension), repr(extlib)
Chris@87 1760 extlib.libraries.extend(self.libraries)
Chris@87 1761 extlib.include_dirs.extend(self.include_dirs)
Chris@87 1762
Chris@87 1763 def _get_svn_revision(self, path):
Chris@87 1764 """Return path's SVN revision number.
Chris@87 1765 """
Chris@87 1766 revision = None
Chris@87 1767 m = None
Chris@87 1768 cwd = os.getcwd()
Chris@87 1769 try:
Chris@87 1770 os.chdir(path or '.')
Chris@87 1771 p = subprocess.Popen(['svnversion'], shell=True,
Chris@87 1772 stdout=subprocess.PIPE, stderr=None,
Chris@87 1773 close_fds=True)
Chris@87 1774 sout = p.stdout
Chris@87 1775 m = re.match(r'(?P<revision>\d+)', sout.read())
Chris@87 1776 except:
Chris@87 1777 pass
Chris@87 1778 os.chdir(cwd)
Chris@87 1779 if m:
Chris@87 1780 revision = int(m.group('revision'))
Chris@87 1781 return revision
Chris@87 1782 if sys.platform=='win32' and os.environ.get('SVN_ASP_DOT_NET_HACK', None):
Chris@87 1783 entries = njoin(path, '_svn', 'entries')
Chris@87 1784 else:
Chris@87 1785 entries = njoin(path, '.svn', 'entries')
Chris@87 1786 if os.path.isfile(entries):
Chris@87 1787 f = open(entries)
Chris@87 1788 fstr = f.read()
Chris@87 1789 f.close()
Chris@87 1790 if fstr[:5] == '<?xml': # pre 1.4
Chris@87 1791 m = re.search(r'revision="(?P<revision>\d+)"', fstr)
Chris@87 1792 if m:
Chris@87 1793 revision = int(m.group('revision'))
Chris@87 1794 else: # non-xml entries file --- check to be sure that
Chris@87 1795 m = re.search(r'dir[\n\r]+(?P<revision>\d+)', fstr)
Chris@87 1796 if m:
Chris@87 1797 revision = int(m.group('revision'))
Chris@87 1798 return revision
Chris@87 1799
Chris@87 1800 def _get_hg_revision(self, path):
Chris@87 1801 """Return path's Mercurial revision number.
Chris@87 1802 """
Chris@87 1803 revision = None
Chris@87 1804 m = None
Chris@87 1805 cwd = os.getcwd()
Chris@87 1806 try:
Chris@87 1807 os.chdir(path or '.')
Chris@87 1808 p = subprocess.Popen(['hg identify --num'], shell=True,
Chris@87 1809 stdout=subprocess.PIPE, stderr=None,
Chris@87 1810 close_fds=True)
Chris@87 1811 sout = p.stdout
Chris@87 1812 m = re.match(r'(?P<revision>\d+)', sout.read())
Chris@87 1813 except:
Chris@87 1814 pass
Chris@87 1815 os.chdir(cwd)
Chris@87 1816 if m:
Chris@87 1817 revision = int(m.group('revision'))
Chris@87 1818 return revision
Chris@87 1819 branch_fn = njoin(path, '.hg', 'branch')
Chris@87 1820 branch_cache_fn = njoin(path, '.hg', 'branch.cache')
Chris@87 1821
Chris@87 1822 if os.path.isfile(branch_fn):
Chris@87 1823 branch0 = None
Chris@87 1824 f = open(branch_fn)
Chris@87 1825 revision0 = f.read().strip()
Chris@87 1826 f.close()
Chris@87 1827
Chris@87 1828 branch_map = {}
Chris@87 1829 for line in file(branch_cache_fn, 'r'):
Chris@87 1830 branch1, revision1 = line.split()[:2]
Chris@87 1831 if revision1==revision0:
Chris@87 1832 branch0 = branch1
Chris@87 1833 try:
Chris@87 1834 revision1 = int(revision1)
Chris@87 1835 except ValueError:
Chris@87 1836 continue
Chris@87 1837 branch_map[branch1] = revision1
Chris@87 1838
Chris@87 1839 revision = branch_map.get(branch0)
Chris@87 1840 return revision
Chris@87 1841
Chris@87 1842
Chris@87 1843 def get_version(self, version_file=None, version_variable=None):
Chris@87 1844 """Try to get version string of a package.
Chris@87 1845
Chris@87 1846 Return a version string of the current package or None if the version
Chris@87 1847 information could not be detected.
Chris@87 1848
Chris@87 1849 Notes
Chris@87 1850 -----
Chris@87 1851 This method scans files named
Chris@87 1852 __version__.py, <packagename>_version.py, version.py, and
Chris@87 1853 __svn_version__.py for string variables version, __version\__, and
Chris@87 1854 <packagename>_version, until a version number is found.
Chris@87 1855 """
Chris@87 1856 version = getattr(self, 'version', None)
Chris@87 1857 if version is not None:
Chris@87 1858 return version
Chris@87 1859
Chris@87 1860 # Get version from version file.
Chris@87 1861 if version_file is None:
Chris@87 1862 files = ['__version__.py',
Chris@87 1863 self.name.split('.')[-1]+'_version.py',
Chris@87 1864 'version.py',
Chris@87 1865 '__svn_version__.py',
Chris@87 1866 '__hg_version__.py']
Chris@87 1867 else:
Chris@87 1868 files = [version_file]
Chris@87 1869 if version_variable is None:
Chris@87 1870 version_vars = ['version',
Chris@87 1871 '__version__',
Chris@87 1872 self.name.split('.')[-1]+'_version']
Chris@87 1873 else:
Chris@87 1874 version_vars = [version_variable]
Chris@87 1875 for f in files:
Chris@87 1876 fn = njoin(self.local_path, f)
Chris@87 1877 if os.path.isfile(fn):
Chris@87 1878 info = (open(fn), fn, ('.py', 'U', 1))
Chris@87 1879 name = os.path.splitext(os.path.basename(fn))[0]
Chris@87 1880 n = dot_join(self.name, name)
Chris@87 1881 try:
Chris@87 1882 version_module = imp.load_module('_'.join(n.split('.')),*info)
Chris@87 1883 except ImportError:
Chris@87 1884 msg = get_exception()
Chris@87 1885 self.warn(str(msg))
Chris@87 1886 version_module = None
Chris@87 1887 if version_module is None:
Chris@87 1888 continue
Chris@87 1889
Chris@87 1890 for a in version_vars:
Chris@87 1891 version = getattr(version_module, a, None)
Chris@87 1892 if version is not None:
Chris@87 1893 break
Chris@87 1894 if version is not None:
Chris@87 1895 break
Chris@87 1896
Chris@87 1897 if version is not None:
Chris@87 1898 self.version = version
Chris@87 1899 return version
Chris@87 1900
Chris@87 1901 # Get version as SVN or Mercurial revision number
Chris@87 1902 revision = self._get_svn_revision(self.local_path)
Chris@87 1903 if revision is None:
Chris@87 1904 revision = self._get_hg_revision(self.local_path)
Chris@87 1905
Chris@87 1906 if revision is not None:
Chris@87 1907 version = str(revision)
Chris@87 1908 self.version = version
Chris@87 1909
Chris@87 1910 return version
Chris@87 1911
Chris@87 1912 def make_svn_version_py(self, delete=True):
Chris@87 1913 """Appends a data function to the data_files list that will generate
Chris@87 1914 __svn_version__.py file to the current package directory.
Chris@87 1915
Chris@87 1916 Generate package __svn_version__.py file from SVN revision number,
Chris@87 1917 it will be removed after python exits but will be available
Chris@87 1918 when sdist, etc commands are executed.
Chris@87 1919
Chris@87 1920 Notes
Chris@87 1921 -----
Chris@87 1922 If __svn_version__.py existed before, nothing is done.
Chris@87 1923
Chris@87 1924 This is
Chris@87 1925 intended for working with source directories that are in an SVN
Chris@87 1926 repository.
Chris@87 1927 """
Chris@87 1928 target = njoin(self.local_path, '__svn_version__.py')
Chris@87 1929 revision = self._get_svn_revision(self.local_path)
Chris@87 1930 if os.path.isfile(target) or revision is None:
Chris@87 1931 return
Chris@87 1932 else:
Chris@87 1933 def generate_svn_version_py():
Chris@87 1934 if not os.path.isfile(target):
Chris@87 1935 version = str(revision)
Chris@87 1936 self.info('Creating %s (version=%r)' % (target, version))
Chris@87 1937 f = open(target, 'w')
Chris@87 1938 f.write('version = %r\n' % (version))
Chris@87 1939 f.close()
Chris@87 1940
Chris@87 1941 import atexit
Chris@87 1942 def rm_file(f=target,p=self.info):
Chris@87 1943 if delete:
Chris@87 1944 try: os.remove(f); p('removed '+f)
Chris@87 1945 except OSError: pass
Chris@87 1946 try: os.remove(f+'c'); p('removed '+f+'c')
Chris@87 1947 except OSError: pass
Chris@87 1948
Chris@87 1949 atexit.register(rm_file)
Chris@87 1950
Chris@87 1951 return target
Chris@87 1952
Chris@87 1953 self.add_data_files(('', generate_svn_version_py()))
Chris@87 1954
Chris@87 1955 def make_hg_version_py(self, delete=True):
Chris@87 1956 """Appends a data function to the data_files list that will generate
Chris@87 1957 __hg_version__.py file to the current package directory.
Chris@87 1958
Chris@87 1959 Generate package __hg_version__.py file from Mercurial revision,
Chris@87 1960 it will be removed after python exits but will be available
Chris@87 1961 when sdist, etc commands are executed.
Chris@87 1962
Chris@87 1963 Notes
Chris@87 1964 -----
Chris@87 1965 If __hg_version__.py existed before, nothing is done.
Chris@87 1966
Chris@87 1967 This is intended for working with source directories that are
Chris@87 1968 in an Mercurial repository.
Chris@87 1969 """
Chris@87 1970 target = njoin(self.local_path, '__hg_version__.py')
Chris@87 1971 revision = self._get_hg_revision(self.local_path)
Chris@87 1972 if os.path.isfile(target) or revision is None:
Chris@87 1973 return
Chris@87 1974 else:
Chris@87 1975 def generate_hg_version_py():
Chris@87 1976 if not os.path.isfile(target):
Chris@87 1977 version = str(revision)
Chris@87 1978 self.info('Creating %s (version=%r)' % (target, version))
Chris@87 1979 f = open(target, 'w')
Chris@87 1980 f.write('version = %r\n' % (version))
Chris@87 1981 f.close()
Chris@87 1982
Chris@87 1983 import atexit
Chris@87 1984 def rm_file(f=target,p=self.info):
Chris@87 1985 if delete:
Chris@87 1986 try: os.remove(f); p('removed '+f)
Chris@87 1987 except OSError: pass
Chris@87 1988 try: os.remove(f+'c'); p('removed '+f+'c')
Chris@87 1989 except OSError: pass
Chris@87 1990
Chris@87 1991 atexit.register(rm_file)
Chris@87 1992
Chris@87 1993 return target
Chris@87 1994
Chris@87 1995 self.add_data_files(('', generate_hg_version_py()))
Chris@87 1996
Chris@87 1997 def make_config_py(self,name='__config__'):
Chris@87 1998 """Generate package __config__.py file containing system_info
Chris@87 1999 information used during building the package.
Chris@87 2000
Chris@87 2001 This file is installed to the
Chris@87 2002 package installation directory.
Chris@87 2003
Chris@87 2004 """
Chris@87 2005 self.py_modules.append((self.name, name, generate_config_py))
Chris@87 2006
Chris@87 2007
Chris@87 2008 def get_info(self,*names):
Chris@87 2009 """Get resources information.
Chris@87 2010
Chris@87 2011 Return information (from system_info.get_info) for all of the names in
Chris@87 2012 the argument list in a single dictionary.
Chris@87 2013 """
Chris@87 2014 from .system_info import get_info, dict_append
Chris@87 2015 info_dict = {}
Chris@87 2016 for a in names:
Chris@87 2017 dict_append(info_dict,**get_info(a))
Chris@87 2018 return info_dict
Chris@87 2019
Chris@87 2020
Chris@87 2021 def get_cmd(cmdname, _cache={}):
Chris@87 2022 if cmdname not in _cache:
Chris@87 2023 import distutils.core
Chris@87 2024 dist = distutils.core._setup_distribution
Chris@87 2025 if dist is None:
Chris@87 2026 from distutils.errors import DistutilsInternalError
Chris@87 2027 raise DistutilsInternalError(
Chris@87 2028 'setup distribution instance not initialized')
Chris@87 2029 cmd = dist.get_command_obj(cmdname)
Chris@87 2030 _cache[cmdname] = cmd
Chris@87 2031 return _cache[cmdname]
Chris@87 2032
Chris@87 2033 def get_numpy_include_dirs():
Chris@87 2034 # numpy_include_dirs are set by numpy/core/setup.py, otherwise []
Chris@87 2035 include_dirs = Configuration.numpy_include_dirs[:]
Chris@87 2036 if not include_dirs:
Chris@87 2037 import numpy
Chris@87 2038 include_dirs = [ numpy.get_include() ]
Chris@87 2039 # else running numpy/core/setup.py
Chris@87 2040 return include_dirs
Chris@87 2041
Chris@87 2042 def get_npy_pkg_dir():
Chris@87 2043 """Return the path where to find the npy-pkg-config directory."""
Chris@87 2044 # XXX: import here for bootstrapping reasons
Chris@87 2045 import numpy
Chris@87 2046 d = os.path.join(os.path.dirname(numpy.__file__),
Chris@87 2047 'core', 'lib', 'npy-pkg-config')
Chris@87 2048 return d
Chris@87 2049
Chris@87 2050 def get_pkg_info(pkgname, dirs=None):
Chris@87 2051 """
Chris@87 2052 Return library info for the given package.
Chris@87 2053
Chris@87 2054 Parameters
Chris@87 2055 ----------
Chris@87 2056 pkgname : str
Chris@87 2057 Name of the package (should match the name of the .ini file, without
Chris@87 2058 the extension, e.g. foo for the file foo.ini).
Chris@87 2059 dirs : sequence, optional
Chris@87 2060 If given, should be a sequence of additional directories where to look
Chris@87 2061 for npy-pkg-config files. Those directories are searched prior to the
Chris@87 2062 NumPy directory.
Chris@87 2063
Chris@87 2064 Returns
Chris@87 2065 -------
Chris@87 2066 pkginfo : class instance
Chris@87 2067 The `LibraryInfo` instance containing the build information.
Chris@87 2068
Chris@87 2069 Raises
Chris@87 2070 ------
Chris@87 2071 PkgNotFound
Chris@87 2072 If the package is not found.
Chris@87 2073
Chris@87 2074 See Also
Chris@87 2075 --------
Chris@87 2076 Configuration.add_npy_pkg_config, Configuration.add_installed_library,
Chris@87 2077 get_info
Chris@87 2078
Chris@87 2079 """
Chris@87 2080 from numpy.distutils.npy_pkg_config import read_config
Chris@87 2081
Chris@87 2082 if dirs:
Chris@87 2083 dirs.append(get_npy_pkg_dir())
Chris@87 2084 else:
Chris@87 2085 dirs = [get_npy_pkg_dir()]
Chris@87 2086 return read_config(pkgname, dirs)
Chris@87 2087
Chris@87 2088 def get_info(pkgname, dirs=None):
Chris@87 2089 """
Chris@87 2090 Return an info dict for a given C library.
Chris@87 2091
Chris@87 2092 The info dict contains the necessary options to use the C library.
Chris@87 2093
Chris@87 2094 Parameters
Chris@87 2095 ----------
Chris@87 2096 pkgname : str
Chris@87 2097 Name of the package (should match the name of the .ini file, without
Chris@87 2098 the extension, e.g. foo for the file foo.ini).
Chris@87 2099 dirs : sequence, optional
Chris@87 2100 If given, should be a sequence of additional directories where to look
Chris@87 2101 for npy-pkg-config files. Those directories are searched prior to the
Chris@87 2102 NumPy directory.
Chris@87 2103
Chris@87 2104 Returns
Chris@87 2105 -------
Chris@87 2106 info : dict
Chris@87 2107 The dictionary with build information.
Chris@87 2108
Chris@87 2109 Raises
Chris@87 2110 ------
Chris@87 2111 PkgNotFound
Chris@87 2112 If the package is not found.
Chris@87 2113
Chris@87 2114 See Also
Chris@87 2115 --------
Chris@87 2116 Configuration.add_npy_pkg_config, Configuration.add_installed_library,
Chris@87 2117 get_pkg_info
Chris@87 2118
Chris@87 2119 Examples
Chris@87 2120 --------
Chris@87 2121 To get the necessary information for the npymath library from NumPy:
Chris@87 2122
Chris@87 2123 >>> npymath_info = np.distutils.misc_util.get_info('npymath')
Chris@87 2124 >>> npymath_info #doctest: +SKIP
Chris@87 2125 {'define_macros': [], 'libraries': ['npymath'], 'library_dirs':
Chris@87 2126 ['.../numpy/core/lib'], 'include_dirs': ['.../numpy/core/include']}
Chris@87 2127
Chris@87 2128 This info dict can then be used as input to a `Configuration` instance::
Chris@87 2129
Chris@87 2130 config.add_extension('foo', sources=['foo.c'], extra_info=npymath_info)
Chris@87 2131
Chris@87 2132 """
Chris@87 2133 from numpy.distutils.npy_pkg_config import parse_flags
Chris@87 2134 pkg_info = get_pkg_info(pkgname, dirs)
Chris@87 2135
Chris@87 2136 # Translate LibraryInfo instance into a build_info dict
Chris@87 2137 info = parse_flags(pkg_info.cflags())
Chris@87 2138 for k, v in parse_flags(pkg_info.libs()).items():
Chris@87 2139 info[k].extend(v)
Chris@87 2140
Chris@87 2141 # add_extension extra_info argument is ANAL
Chris@87 2142 info['define_macros'] = info['macros']
Chris@87 2143 del info['macros']
Chris@87 2144 del info['ignored']
Chris@87 2145
Chris@87 2146 return info
Chris@87 2147
Chris@87 2148 def is_bootstrapping():
Chris@87 2149 if sys.version_info[0] >= 3:
Chris@87 2150 import builtins
Chris@87 2151 else:
Chris@87 2152 import __builtin__ as builtins
Chris@87 2153
Chris@87 2154 try:
Chris@87 2155 builtins.__NUMPY_SETUP__
Chris@87 2156 return True
Chris@87 2157 except AttributeError:
Chris@87 2158 return False
Chris@87 2159 __NUMPY_SETUP__ = False
Chris@87 2160
Chris@87 2161
Chris@87 2162 #########################
Chris@87 2163
Chris@87 2164 def default_config_dict(name = None, parent_name = None, local_path=None):
Chris@87 2165 """Return a configuration dictionary for usage in
Chris@87 2166 configuration() function defined in file setup_<name>.py.
Chris@87 2167 """
Chris@87 2168 import warnings
Chris@87 2169 warnings.warn('Use Configuration(%r,%r,top_path=%r) instead of '\
Chris@87 2170 'deprecated default_config_dict(%r,%r,%r)'
Chris@87 2171 % (name, parent_name, local_path,
Chris@87 2172 name, parent_name, local_path,
Chris@87 2173 ))
Chris@87 2174 c = Configuration(name, parent_name, local_path)
Chris@87 2175 return c.todict()
Chris@87 2176
Chris@87 2177
Chris@87 2178 def dict_append(d, **kws):
Chris@87 2179 for k, v in kws.items():
Chris@87 2180 if k in d:
Chris@87 2181 ov = d[k]
Chris@87 2182 if isinstance(ov, str):
Chris@87 2183 d[k] = v
Chris@87 2184 else:
Chris@87 2185 d[k].extend(v)
Chris@87 2186 else:
Chris@87 2187 d[k] = v
Chris@87 2188
Chris@87 2189 def appendpath(prefix, path):
Chris@87 2190 if os.path.sep != '/':
Chris@87 2191 prefix = prefix.replace('/', os.path.sep)
Chris@87 2192 path = path.replace('/', os.path.sep)
Chris@87 2193 drive = ''
Chris@87 2194 if os.path.isabs(path):
Chris@87 2195 drive = os.path.splitdrive(prefix)[0]
Chris@87 2196 absprefix = os.path.splitdrive(os.path.abspath(prefix))[1]
Chris@87 2197 pathdrive, path = os.path.splitdrive(path)
Chris@87 2198 d = os.path.commonprefix([absprefix, path])
Chris@87 2199 if os.path.join(absprefix[:len(d)], absprefix[len(d):]) != absprefix \
Chris@87 2200 or os.path.join(path[:len(d)], path[len(d):]) != path:
Chris@87 2201 # Handle invalid paths
Chris@87 2202 d = os.path.dirname(d)
Chris@87 2203 subpath = path[len(d):]
Chris@87 2204 if os.path.isabs(subpath):
Chris@87 2205 subpath = subpath[1:]
Chris@87 2206 else:
Chris@87 2207 subpath = path
Chris@87 2208 return os.path.normpath(njoin(drive + prefix, subpath))
Chris@87 2209
Chris@87 2210 def generate_config_py(target):
Chris@87 2211 """Generate config.py file containing system_info information
Chris@87 2212 used during building the package.
Chris@87 2213
Chris@87 2214 Usage:
Chris@87 2215 config['py_modules'].append((packagename, '__config__',generate_config_py))
Chris@87 2216 """
Chris@87 2217 from numpy.distutils.system_info import system_info
Chris@87 2218 from distutils.dir_util import mkpath
Chris@87 2219 mkpath(os.path.dirname(target))
Chris@87 2220 f = open(target, 'w')
Chris@87 2221 f.write('# This file is generated by %s\n' % (os.path.abspath(sys.argv[0])))
Chris@87 2222 f.write('# It contains system_info results at the time of building this package.\n')
Chris@87 2223 f.write('__all__ = ["get_info","show"]\n\n')
Chris@87 2224 for k, i in system_info.saved_results.items():
Chris@87 2225 f.write('%s=%r\n' % (k, i))
Chris@87 2226 f.write(r'''
Chris@87 2227 def get_info(name):
Chris@87 2228 g = globals()
Chris@87 2229 return g.get(name, g.get(name + "_info", {}))
Chris@87 2230
Chris@87 2231 def show():
Chris@87 2232 for name,info_dict in globals().items():
Chris@87 2233 if name[0] == "_" or type(info_dict) is not type({}): continue
Chris@87 2234 print(name + ":")
Chris@87 2235 if not info_dict:
Chris@87 2236 print(" NOT AVAILABLE")
Chris@87 2237 for k,v in info_dict.items():
Chris@87 2238 v = str(v)
Chris@87 2239 if k == "sources" and len(v) > 200:
Chris@87 2240 v = v[:60] + " ...\n... " + v[-60:]
Chris@87 2241 print(" %s = %s" % (k,v))
Chris@87 2242 ''')
Chris@87 2243
Chris@87 2244 f.close()
Chris@87 2245 return target
Chris@87 2246
Chris@87 2247 def msvc_version(compiler):
Chris@87 2248 """Return version major and minor of compiler instance if it is
Chris@87 2249 MSVC, raise an exception otherwise."""
Chris@87 2250 if not compiler.compiler_type == "msvc":
Chris@87 2251 raise ValueError("Compiler instance is not msvc (%s)"\
Chris@87 2252 % compiler.compiler_type)
Chris@87 2253 return compiler._MSVCCompiler__version
Chris@87 2254
Chris@87 2255 if sys.version[:3] >= '2.5':
Chris@87 2256 def get_build_architecture():
Chris@87 2257 from distutils.msvccompiler import get_build_architecture
Chris@87 2258 return get_build_architecture()
Chris@87 2259 else:
Chris@87 2260 #copied from python 2.5.1 distutils/msvccompiler.py
Chris@87 2261 def get_build_architecture():
Chris@87 2262 """Return the processor architecture.
Chris@87 2263
Chris@87 2264 Possible results are "Intel", "Itanium", or "AMD64".
Chris@87 2265 """
Chris@87 2266 prefix = " bit ("
Chris@87 2267 i = sys.version.find(prefix)
Chris@87 2268 if i == -1:
Chris@87 2269 return "Intel"
Chris@87 2270 j = sys.version.find(")", i)
Chris@87 2271 return sys.version[i+len(prefix):j]