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]
|