blob: 28731dfdc1660243157aa0a20d4448e602d4d969 [file] [log] [blame]
Tarek Ziadéedacea32010-01-29 11:41:03 +00001"""Provide access to Python's configuration information.
2
3"""
4import sys
5import os
Florent Xiclunaa4707382010-03-11 00:05:17 +00006from os.path import pardir, realpath
Tarek Ziadéedacea32010-01-29 11:41:03 +00007
Tarek Ziadé16ed6cb2010-05-25 09:47:06 +00008__all__ = ['parse_config_h', 'get_config_h_filename', 'get_scheme_names',
9 'get_path_names', 'get_paths', 'get_path', 'get_config_vars',
10 'get_config_var', 'get_platform', 'get_python_version']
11
Tarek Ziadéedacea32010-01-29 11:41:03 +000012_INSTALL_SCHEMES = {
13 'posix_prefix': {
14 'stdlib': '{base}/lib/python{py_version_short}',
15 'platstdlib': '{platbase}/lib/python{py_version_short}',
16 'purelib': '{base}/lib/python{py_version_short}/site-packages',
17 'platlib': '{platbase}/lib/python{py_version_short}/site-packages',
18 'include': '{base}/include/python{py_version_short}',
19 'platinclude': '{platbase}/include/python{py_version_short}',
20 'scripts': '{base}/bin',
21 'data': '{base}',
22 },
23 'posix_home': {
24 'stdlib': '{base}/lib/python',
25 'platstdlib': '{base}/lib/python',
26 'purelib': '{base}/lib/python',
27 'platlib': '{base}/lib/python',
28 'include': '{base}/include/python',
29 'platinclude': '{base}/include/python',
30 'scripts': '{base}/bin',
31 'data' : '{base}',
32 },
33 'nt': {
34 'stdlib': '{base}/Lib',
35 'platstdlib': '{base}/Lib',
36 'purelib': '{base}/Lib/site-packages',
37 'platlib': '{base}/Lib/site-packages',
38 'include': '{base}/Include',
39 'platinclude': '{base}/Include',
40 'scripts': '{base}/Scripts',
41 'data' : '{base}',
42 },
43 'os2': {
44 'stdlib': '{base}/Lib',
45 'platstdlib': '{base}/Lib',
46 'purelib': '{base}/Lib/site-packages',
47 'platlib': '{base}/Lib/site-packages',
48 'include': '{base}/Include',
49 'platinclude': '{base}/Include',
50 'scripts': '{base}/Scripts',
51 'data' : '{base}',
52 },
53 'os2_home': {
Tarek Ziadé06710a82010-05-19 22:25:00 +000054 'stdlib': '{userbase}/lib/python{py_version_short}',
55 'platstdlib': '{userbase}/lib/python{py_version_short}',
56 'purelib': '{userbase}/lib/python{py_version_short}/site-packages',
57 'platlib': '{userbase}/lib/python{py_version_short}/site-packages',
Tarek Ziadéedacea32010-01-29 11:41:03 +000058 'include': '{userbase}/include/python{py_version_short}',
59 'scripts': '{userbase}/bin',
60 'data' : '{userbase}',
61 },
62 'nt_user': {
63 'stdlib': '{userbase}/Python{py_version_nodot}',
64 'platstdlib': '{userbase}/Python{py_version_nodot}',
65 'purelib': '{userbase}/Python{py_version_nodot}/site-packages',
66 'platlib': '{userbase}/Python{py_version_nodot}/site-packages',
67 'include': '{userbase}/Python{py_version_nodot}/Include',
68 'scripts': '{userbase}/Scripts',
69 'data' : '{userbase}',
70 },
71 'posix_user': {
Tarek Ziadé06710a82010-05-19 22:25:00 +000072 'stdlib': '{userbase}/lib/python{py_version_short}',
73 'platstdlib': '{userbase}/lib/python{py_version_short}',
74 'purelib': '{userbase}/lib/python{py_version_short}/site-packages',
75 'platlib': '{userbase}/lib/python{py_version_short}/site-packages',
Tarek Ziadéedacea32010-01-29 11:41:03 +000076 'include': '{userbase}/include/python{py_version_short}',
77 'scripts': '{userbase}/bin',
78 'data' : '{userbase}',
79 },
Ronald Oussoren4cda46a2010-05-08 10:49:43 +000080 'osx_framework_user': {
81 'stdlib': '{userbase}/lib/python',
82 'platstdlib': '{userbase}/lib/python',
83 'purelib': '{userbase}/lib/python/site-packages',
84 'platlib': '{userbase}/lib/python/site-packages',
85 'include': '{userbase}/include',
86 'scripts': '{userbase}/bin',
87 'data' : '{userbase}',
88 },
Tarek Ziadéedacea32010-01-29 11:41:03 +000089 }
90
91_SCHEME_KEYS = ('stdlib', 'platstdlib', 'purelib', 'platlib', 'include',
92 'scripts', 'data')
93_PY_VERSION = sys.version.split()[0]
94_PY_VERSION_SHORT = sys.version[:3]
95_PY_VERSION_SHORT_NO_DOT = _PY_VERSION[0] + _PY_VERSION[2]
96_PREFIX = os.path.normpath(sys.prefix)
97_EXEC_PREFIX = os.path.normpath(sys.exec_prefix)
98_CONFIG_VARS = None
99_USER_BASE = None
Victor Stinner171ba052010-03-12 14:20:59 +0000100if sys.executable:
101 _PROJECT_BASE = os.path.dirname(realpath(sys.executable))
102else:
103 # sys.executable can be empty if argv[0] has been changed and Python is
104 # unable to retrieve the real program name
105 _PROJECT_BASE = realpath(os.getcwd())
Tarek Ziadéedacea32010-01-29 11:41:03 +0000106
107if os.name == "nt" and "pcbuild" in _PROJECT_BASE[-8:].lower():
Florent Xiclunaa4707382010-03-11 00:05:17 +0000108 _PROJECT_BASE = realpath(os.path.join(_PROJECT_BASE, pardir))
Tarek Ziadéedacea32010-01-29 11:41:03 +0000109# PC/VS7.1
110if os.name == "nt" and "\\pc\\v" in _PROJECT_BASE[-10:].lower():
Florent Xiclunaa4707382010-03-11 00:05:17 +0000111 _PROJECT_BASE = realpath(os.path.join(_PROJECT_BASE, pardir, pardir))
Tarek Ziadéedacea32010-01-29 11:41:03 +0000112# PC/AMD64
113if os.name == "nt" and "\\pcbuild\\amd64" in _PROJECT_BASE[-14:].lower():
Florent Xiclunaa4707382010-03-11 00:05:17 +0000114 _PROJECT_BASE = realpath(os.path.join(_PROJECT_BASE, pardir, pardir))
Tarek Ziadéedacea32010-01-29 11:41:03 +0000115
116def is_python_build():
117 for fn in ("Setup.dist", "Setup.local"):
118 if os.path.isfile(os.path.join(_PROJECT_BASE, "Modules", fn)):
119 return True
120 return False
121
122_PYTHON_BUILD = is_python_build()
123
124if _PYTHON_BUILD:
125 for scheme in ('posix_prefix', 'posix_home'):
Ronald Oussorene41a19e2010-06-15 16:05:20 +0000126 _INSTALL_SCHEMES[scheme]['include'] = '{srcdir}/Include'
127 _INSTALL_SCHEMES[scheme]['platinclude'] = '{projectbase}/.'
Tarek Ziadéedacea32010-01-29 11:41:03 +0000128
129def _subst_vars(s, local_vars):
130 try:
131 return s.format(**local_vars)
132 except KeyError:
133 try:
134 return s.format(**os.environ)
135 except KeyError as var:
136 raise AttributeError('{%s}' % var)
137
138def _extend_dict(target_dict, other_dict):
139 target_keys = target_dict.keys()
140 for key, value in other_dict.items():
141 if key in target_keys:
142 continue
143 target_dict[key] = value
144
145def _expand_vars(scheme, vars):
146 res = {}
147 if vars is None:
148 vars = {}
149 _extend_dict(vars, get_config_vars())
150
151 for key, value in _INSTALL_SCHEMES[scheme].items():
152 if os.name in ('posix', 'nt'):
153 value = os.path.expanduser(value)
154 res[key] = os.path.normpath(_subst_vars(value, vars))
155 return res
156
157def _get_default_scheme():
158 if os.name == 'posix':
159 # the default scheme for posix is posix_prefix
160 return 'posix_prefix'
161 return os.name
162
163def _getuserbase():
164 env_base = os.environ.get("PYTHONUSERBASE", None)
165 def joinuser(*args):
166 return os.path.expanduser(os.path.join(*args))
167
168 # what about 'os2emx', 'riscos' ?
169 if os.name == "nt":
170 base = os.environ.get("APPDATA") or "~"
171 return env_base if env_base else joinuser(base, "Python")
172
Ronald Oussoren4cda46a2010-05-08 10:49:43 +0000173 if sys.platform == "darwin":
174 framework = get_config_var("PYTHONFRAMEWORK")
175 if framework:
176 return joinuser("~", "Library", framework, "%d.%d"%(
177 sys.version_info[:2]))
178
Tarek Ziadéedacea32010-01-29 11:41:03 +0000179 return env_base if env_base else joinuser("~", ".local")
180
181
182def _parse_makefile(filename, vars=None):
183 """Parse a Makefile-style file.
184
185 A dictionary containing name/value pairs is returned. If an
186 optional dictionary is passed in as the second argument, it is
187 used instead of a new dictionary.
188 """
189 import re
190 # Regexes needed for parsing Makefile (and similar syntaxes,
191 # like old-style Setup files).
192 _variable_rx = re.compile("([a-zA-Z][a-zA-Z0-9_]+)\s*=\s*(.*)")
193 _findvar1_rx = re.compile(r"\$\(([A-Za-z][A-Za-z0-9_]*)\)")
194 _findvar2_rx = re.compile(r"\${([A-Za-z][A-Za-z0-9_]*)}")
195
196 if vars is None:
197 vars = {}
198 done = {}
199 notdone = {}
200
201 with open(filename) as f:
202 lines = f.readlines()
203
204 for line in lines:
205 if line.startswith('#') or line.strip() == '':
206 continue
207 m = _variable_rx.match(line)
208 if m:
209 n, v = m.group(1, 2)
210 v = v.strip()
211 # `$$' is a literal `$' in make
212 tmpv = v.replace('$$', '')
213
214 if "$" in tmpv:
215 notdone[n] = v
216 else:
217 try:
218 v = int(v)
219 except ValueError:
220 # insert literal `$'
221 done[n] = v.replace('$$', '$')
222 else:
223 done[n] = v
224
225 # do variable interpolation here
226 variables = list(notdone.keys())
227
228 while len(variables) > 0:
229 for name in tuple(variables):
230 value = notdone[name]
231 m = _findvar1_rx.search(value) or _findvar2_rx.search(value)
232 if m is not None:
233 n = m.group(1)
234 found = True
235 if n in done:
236 item = str(done[n])
237 elif n in notdone:
238 # get it on a subsequent round
239 found = False
240 elif n in os.environ:
241 # do it like make: fall back to environment
242 item = os.environ[n]
243 else:
244 done[n] = item = ""
245 if found:
246 after = value[m.end():]
247 value = value[:m.start()] + item + after
248 if "$" in after:
249 notdone[name] = value
250 else:
251 try:
252 value = int(value)
253 except ValueError:
254 done[name] = value.strip()
255 else:
256 done[name] = value
257 variables.remove(name)
258 else:
259 # bogus variable reference; just drop it since we can't deal
260 variables.remove(name)
261
Jeffrey Yasskind4fcdb12010-07-09 16:30:58 +0000262 # Add in CFLAGS, LDFLAGS, and CPPFLAGS, which are named with a
263 # prefix in the Makefile.
264 for var in ('CFLAGS', 'LDFLAGS', 'CPPFLAGS'):
Jeffrey Yasskin61c061a2010-07-09 19:55:05 +0000265 makefile_value = done.get('PY_' + var)
266 if makefile_value is not None:
267 done[var] = makefile_value
Jeffrey Yasskind4fcdb12010-07-09 16:30:58 +0000268
Tarek Ziadéedacea32010-01-29 11:41:03 +0000269 # save the results in the global dictionary
270 vars.update(done)
271 return vars
272
Tarek Ziadéedacea32010-01-29 11:41:03 +0000273
274def _get_makefile_filename():
275 if _PYTHON_BUILD:
276 return os.path.join(_PROJECT_BASE, "Makefile")
277 return os.path.join(get_path('stdlib'), "config", "Makefile")
278
Tarek Ziadéedacea32010-01-29 11:41:03 +0000279
280def _init_posix(vars):
281 """Initialize the module as appropriate for POSIX systems."""
282 # load the installed Makefile:
283 makefile = _get_makefile_filename()
284 try:
285 _parse_makefile(makefile, vars)
286 except IOError as e:
287 msg = "invalid Python installation: unable to open %s" % makefile
288 if hasattr(e, "strerror"):
289 msg = msg + " (%s)" % e.strerror
290 raise IOError(msg)
291 # load the installed pyconfig.h:
292 config_h = get_config_h_filename()
293 try:
294 parse_config_h(open(config_h), vars)
295 except IOError as e:
296 msg = "invalid Python installation: unable to open %s" % config_h
297 if hasattr(e, "strerror"):
298 msg = msg + " (%s)" % e.strerror
299 raise IOError(msg)
300 # On MacOSX we need to check the setting of the environment variable
301 # MACOSX_DEPLOYMENT_TARGET: configure bases some choices on it so
302 # it needs to be compatible.
303 # If it isn't set we set it to the configure-time value
304 if sys.platform == 'darwin' and 'MACOSX_DEPLOYMENT_TARGET' in vars:
305 cfg_target = vars['MACOSX_DEPLOYMENT_TARGET']
306 cur_target = os.getenv('MACOSX_DEPLOYMENT_TARGET', '')
307 if cur_target == '':
308 cur_target = cfg_target
309 os.putenv('MACOSX_DEPLOYMENT_TARGET', cfg_target)
310 elif (list(map(int, cfg_target.split('.'))) >
311 list(map(int, cur_target.split('.')))):
312 msg = ('$MACOSX_DEPLOYMENT_TARGET mismatch: now "%s" but "%s" '
313 'during configure' % (cur_target, cfg_target))
314 raise IOError(msg)
315 # On AIX, there are wrong paths to the linker scripts in the Makefile
316 # -- these paths are relative to the Python source, but when installed
317 # the scripts are in another directory.
318 if _PYTHON_BUILD:
319 vars['LDSHARED'] = vars['BLDSHARED']
320
321def _init_non_posix(vars):
322 """Initialize the module as appropriate for NT"""
323 # set basic install directories
324 vars['LIBDEST'] = get_path('stdlib')
325 vars['BINLIBDEST'] = get_path('platstdlib')
326 vars['INCLUDEPY'] = get_path('include')
327 vars['SO'] = '.pyd'
328 vars['EXE'] = '.exe'
329 vars['VERSION'] = _PY_VERSION_SHORT_NO_DOT
Florent Xicluna1d1ab972010-03-11 01:53:10 +0000330 vars['BINDIR'] = os.path.dirname(realpath(sys.executable))
Tarek Ziadéedacea32010-01-29 11:41:03 +0000331
332#
333# public APIs
334#
335
Tarek Ziadébd797682010-02-02 23:16:13 +0000336
337def parse_config_h(fp, vars=None):
338 """Parse a config.h-style file.
339
340 A dictionary containing name/value pairs is returned. If an
341 optional dictionary is passed in as the second argument, it is
342 used instead of a new dictionary.
343 """
344 import re
345 if vars is None:
346 vars = {}
347 define_rx = re.compile("#define ([A-Z][A-Za-z0-9_]+) (.*)\n")
348 undef_rx = re.compile("/[*] #undef ([A-Z][A-Za-z0-9_]+) [*]/\n")
349
350 while True:
351 line = fp.readline()
352 if not line:
353 break
354 m = define_rx.match(line)
355 if m:
356 n, v = m.group(1, 2)
357 try: v = int(v)
358 except ValueError: pass
359 vars[n] = v
360 else:
361 m = undef_rx.match(line)
362 if m:
363 vars[m.group(1)] = 0
364 return vars
365
366def get_config_h_filename():
367 """Returns the path of pyconfig.h."""
368 if _PYTHON_BUILD:
369 if os.name == "nt":
370 inc_dir = os.path.join(_PROJECT_BASE, "PC")
371 else:
372 inc_dir = _PROJECT_BASE
373 else:
374 inc_dir = get_path('platinclude')
375 return os.path.join(inc_dir, 'pyconfig.h')
376
Tarek Ziadéedacea32010-01-29 11:41:03 +0000377def get_scheme_names():
Tarek Ziadébd797682010-02-02 23:16:13 +0000378 """Returns a tuple containing the schemes names."""
379 schemes = list(_INSTALL_SCHEMES.keys())
380 schemes.sort()
381 return tuple(schemes)
Tarek Ziadéedacea32010-01-29 11:41:03 +0000382
383def get_path_names():
Tarek Ziadébd797682010-02-02 23:16:13 +0000384 """Returns a tuple containing the paths names."""
Tarek Ziadéedacea32010-01-29 11:41:03 +0000385 return _SCHEME_KEYS
386
387def get_paths(scheme=_get_default_scheme(), vars=None, expand=True):
388 """Returns a mapping containing an install scheme.
389
390 ``scheme`` is the install scheme name. If not provided, it will
391 return the default scheme for the current platform.
392 """
393 if expand:
394 return _expand_vars(scheme, vars)
395 else:
396 return _INSTALL_SCHEMES[scheme]
397
398def get_path(name, scheme=_get_default_scheme(), vars=None, expand=True):
399 """Returns a path corresponding to the scheme.
400
401 ``scheme`` is the install scheme name.
402 """
403 return get_paths(scheme, vars, expand)[name]
404
405def get_config_vars(*args):
406 """With no arguments, return a dictionary of all configuration
407 variables relevant for the current platform.
408
409 On Unix, this means every variable defined in Python's installed Makefile;
410 On Windows and Mac OS it's a much smaller set.
411
412 With arguments, return a list of values that result from looking up
413 each argument in the configuration variable dictionary.
414 """
415 import re
416 global _CONFIG_VARS
417 if _CONFIG_VARS is None:
418 _CONFIG_VARS = {}
419 # Normalized versions of prefix and exec_prefix are handy to have;
420 # in fact, these are the standard versions used most places in the
421 # Distutils.
422 _CONFIG_VARS['prefix'] = _PREFIX
423 _CONFIG_VARS['exec_prefix'] = _EXEC_PREFIX
424 _CONFIG_VARS['py_version'] = _PY_VERSION
425 _CONFIG_VARS['py_version_short'] = _PY_VERSION_SHORT
426 _CONFIG_VARS['py_version_nodot'] = _PY_VERSION[0] + _PY_VERSION[2]
427 _CONFIG_VARS['base'] = _PREFIX
428 _CONFIG_VARS['platbase'] = _EXEC_PREFIX
Tarek Ziadéedacea32010-01-29 11:41:03 +0000429 _CONFIG_VARS['projectbase'] = _PROJECT_BASE
430
431 if os.name in ('nt', 'os2'):
432 _init_non_posix(_CONFIG_VARS)
433 if os.name == 'posix':
434 _init_posix(_CONFIG_VARS)
Ronald Oussoren4cda46a2010-05-08 10:49:43 +0000435 # Setting 'userbase' is done below the call to the
436 # init function to enable using 'get_config_var' in
437 # the init-function.
438 _CONFIG_VARS['userbase'] = _getuserbase()
439
Tarek Ziadéedacea32010-01-29 11:41:03 +0000440 if 'srcdir' not in _CONFIG_VARS:
441 _CONFIG_VARS['srcdir'] = _PROJECT_BASE
Ronald Oussorenab4fd612010-06-15 21:19:50 +0000442 else:
443 _CONFIG_VARS['srcdir'] = realpath(_CONFIG_VARS['srcdir'])
Tarek Ziadéedacea32010-01-29 11:41:03 +0000444
445
446 # Convert srcdir into an absolute path if it appears necessary.
447 # Normally it is relative to the build directory. However, during
448 # testing, for example, we might be running a non-installed python
449 # from a different directory.
450 if _PYTHON_BUILD and os.name == "posix":
451 base = _PROJECT_BASE
452 if (not os.path.isabs(_CONFIG_VARS['srcdir']) and
453 base != os.getcwd()):
454 # srcdir is relative and we are not in the same directory
455 # as the executable. Assume executable is in the build
456 # directory and make srcdir absolute.
457 srcdir = os.path.join(base, _CONFIG_VARS['srcdir'])
458 _CONFIG_VARS['srcdir'] = os.path.normpath(srcdir)
459
460 if sys.platform == 'darwin':
461 kernel_version = os.uname()[2] # Kernel version (8.4.3)
462 major_version = int(kernel_version.split('.')[0])
463
464 if major_version < 8:
465 # On Mac OS X before 10.4, check if -arch and -isysroot
466 # are in CFLAGS or LDFLAGS and remove them if they are.
467 # This is needed when building extensions on a 10.3 system
468 # using a universal build of python.
469 for key in ('LDFLAGS', 'BASECFLAGS',
470 # a number of derived variables. These need to be
471 # patched up as well.
472 'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'):
473 flags = _CONFIG_VARS[key]
474 flags = re.sub('-arch\s+\w+\s', ' ', flags)
475 flags = re.sub('-isysroot [^ \t]*', ' ', flags)
476 _CONFIG_VARS[key] = flags
477 else:
478 # Allow the user to override the architecture flags using
479 # an environment variable.
480 # NOTE: This name was introduced by Apple in OSX 10.5 and
481 # is used by several scripting languages distributed with
482 # that OS release.
483 if 'ARCHFLAGS' in os.environ:
484 arch = os.environ['ARCHFLAGS']
485 for key in ('LDFLAGS', 'BASECFLAGS',
486 # a number of derived variables. These need to be
487 # patched up as well.
488 'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'):
489
490 flags = _CONFIG_VARS[key]
491 flags = re.sub('-arch\s+\w+\s', ' ', flags)
492 flags = flags + ' ' + arch
493 _CONFIG_VARS[key] = flags
494
495 # If we're on OSX 10.5 or later and the user tries to
496 # compiles an extension using an SDK that is not present
497 # on the current machine it is better to not use an SDK
498 # than to fail.
499 #
500 # The major usecase for this is users using a Python.org
501 # binary installer on OSX 10.6: that installer uses
502 # the 10.4u SDK, but that SDK is not installed by default
503 # when you install Xcode.
504 #
505 CFLAGS = _CONFIG_VARS.get('CFLAGS', '')
506 m = re.search('-isysroot\s+(\S+)', CFLAGS)
507 if m is not None:
508 sdk = m.group(1)
509 if not os.path.exists(sdk):
510 for key in ('LDFLAGS', 'BASECFLAGS',
511 # a number of derived variables. These need to be
512 # patched up as well.
513 'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'):
514
515 flags = _CONFIG_VARS[key]
516 flags = re.sub('-isysroot\s+\S+(\s|$)', ' ', flags)
517 _CONFIG_VARS[key] = flags
518
519 if args:
520 vals = []
521 for name in args:
522 vals.append(_CONFIG_VARS.get(name))
523 return vals
524 else:
525 return _CONFIG_VARS
526
527def get_config_var(name):
528 """Return the value of a single variable using the dictionary returned by
529 'get_config_vars()'.
530
531 Equivalent to get_config_vars().get(name)
532 """
533 return get_config_vars().get(name)
534
535def get_platform():
536 """Return a string that identifies the current platform.
537
538 This is used mainly to distinguish platform-specific build directories and
539 platform-specific built distributions. Typically includes the OS name
540 and version and the architecture (as supplied by 'os.uname()'),
541 although the exact information included depends on the OS; eg. for IRIX
542 the architecture isn't particularly important (IRIX only runs on SGI
543 hardware), but for Linux the kernel version isn't particularly
544 important.
545
546 Examples of returned values:
547 linux-i586
548 linux-alpha (?)
549 solaris-2.6-sun4u
550 irix-5.3
551 irix64-6.2
552
553 Windows will return one of:
554 win-amd64 (64bit Windows on AMD64 (aka x86_64, Intel64, EM64T, etc)
555 win-ia64 (64bit Windows on Itanium)
556 win32 (all others - specifically, sys.platform is returned)
557
558 For other non-POSIX platforms, currently just returns 'sys.platform'.
559 """
560 import re
561 if os.name == 'nt':
562 # sniff sys.version for architecture.
563 prefix = " bit ("
564 i = sys.version.find(prefix)
565 if i == -1:
566 return sys.platform
567 j = sys.version.find(")", i)
568 look = sys.version[i+len(prefix):j].lower()
569 if look == 'amd64':
570 return 'win-amd64'
571 if look == 'itanium':
572 return 'win-ia64'
573 return sys.platform
574
575 if os.name != "posix" or not hasattr(os, 'uname'):
576 # XXX what about the architecture? NT is Intel or Alpha,
577 # Mac OS is M68k or PPC, etc.
578 return sys.platform
579
580 # Try to distinguish various flavours of Unix
581 osname, host, release, version, machine = os.uname()
582
583 # Convert the OS name to lowercase, remove '/' characters
584 # (to accommodate BSD/OS), and translate spaces (for "Power Macintosh")
585 osname = osname.lower().replace('/', '')
586 machine = machine.replace(' ', '_')
587 machine = machine.replace('/', '-')
588
589 if osname[:5] == "linux":
590 # At least on Linux/Intel, 'machine' is the processor --
591 # i386, etc.
592 # XXX what about Alpha, SPARC, etc?
593 return "%s-%s" % (osname, machine)
594 elif osname[:5] == "sunos":
595 if release[0] >= "5": # SunOS 5 == Solaris 2
596 osname = "solaris"
597 release = "%d.%s" % (int(release[0]) - 3, release[2:])
598 # fall through to standard osname-release-machine representation
599 elif osname[:4] == "irix": # could be "irix64"!
600 return "%s-%s" % (osname, release)
601 elif osname[:3] == "aix":
602 return "%s-%s.%s" % (osname, version, release)
603 elif osname[:6] == "cygwin":
604 osname = "cygwin"
605 rel_re = re.compile (r'[\d.]+')
606 m = rel_re.match(release)
607 if m:
608 release = m.group()
609 elif osname[:6] == "darwin":
610 #
611 # For our purposes, we'll assume that the system version from
612 # distutils' perspective is what MACOSX_DEPLOYMENT_TARGET is set
613 # to. This makes the compatibility story a bit more sane because the
614 # machine is going to compile and link as if it were
615 # MACOSX_DEPLOYMENT_TARGET.
616 cfgvars = get_config_vars()
617 macver = os.environ.get('MACOSX_DEPLOYMENT_TARGET')
618 if not macver:
619 macver = cfgvars.get('MACOSX_DEPLOYMENT_TARGET')
620
621 if 1:
622 # Always calculate the release of the running machine,
623 # needed to determine if we can build fat binaries or not.
624
625 macrelease = macver
626 # Get the system version. Reading this plist is a documented
627 # way to get the system version (see the documentation for
628 # the Gestalt Manager)
629 try:
630 f = open('/System/Library/CoreServices/SystemVersion.plist')
631 except IOError:
632 # We're on a plain darwin box, fall back to the default
633 # behaviour.
634 pass
635 else:
636 m = re.search(
637 r'<key>ProductUserVisibleVersion</key>\s*' +
638 r'<string>(.*?)</string>', f.read())
639 f.close()
640 if m is not None:
641 macrelease = '.'.join(m.group(1).split('.')[:2])
642 # else: fall back to the default behaviour
643
644 if not macver:
645 macver = macrelease
646
647 if macver:
648 release = macver
649 osname = "macosx"
650
651 if (macrelease + '.') >= '10.4.' and \
652 '-arch' in get_config_vars().get('CFLAGS', '').strip():
653 # The universal build will build fat binaries, but not on
654 # systems before 10.4
655 #
656 # Try to detect 4-way universal builds, those have machine-type
657 # 'universal' instead of 'fat'.
658
659 machine = 'fat'
660 cflags = get_config_vars().get('CFLAGS')
661
662 archs = re.findall('-arch\s+(\S+)', cflags)
Ronald Oussorend3950522010-07-11 09:05:07 +0000663 archs = tuple(sorted(set(archs)))
Tarek Ziadéedacea32010-01-29 11:41:03 +0000664
665 if len(archs) == 1:
666 machine = archs[0]
667 elif archs == ('i386', 'ppc'):
668 machine = 'fat'
669 elif archs == ('i386', 'x86_64'):
670 machine = 'intel'
671 elif archs == ('i386', 'ppc', 'x86_64'):
672 machine = 'fat3'
673 elif archs == ('ppc64', 'x86_64'):
674 machine = 'fat64'
675 elif archs == ('i386', 'ppc', 'ppc64', 'x86_64'):
676 machine = 'universal'
677 else:
678 raise ValueError(
679 "Don't know machine value for archs=%r"%(archs,))
680
681 elif machine == 'i386':
682 # On OSX the machine type returned by uname is always the
683 # 32-bit variant, even if the executable architecture is
684 # the 64-bit variant
685 if sys.maxsize >= 2**32:
686 machine = 'x86_64'
687
688 elif machine in ('PowerPC', 'Power_Macintosh'):
689 # Pick a sane name for the PPC architecture.
690 # See 'i386' case
691 if sys.maxsize >= 2**32:
692 machine = 'ppc64'
693 else:
694 machine = 'ppc'
695
696 return "%s-%s-%s" % (osname, release, machine)
697
698
699def get_python_version():
700 return _PY_VERSION_SHORT
Tarek Ziadéa7514992010-05-25 09:44:36 +0000701
702def _print_dict(title, data):
703 for index, (key, value) in enumerate(sorted(data.items())):
704 if index == 0:
705 print('{0}: '.format(title))
706 print('\t{0} = "{1}"'.format(key, value))
707
708def _main():
709 """Displays all information sysconfig detains."""
710 print('Platform: "{0}"'.format(get_platform()))
711 print('Python version: "{0}"'.format(get_python_version()))
712 print('Current installation scheme: "{0}"'.format(_get_default_scheme()))
713 print('')
714 _print_dict('Paths', get_paths())
715 print('')
716 _print_dict('Variables', get_config_vars())
717
718if __name__ == '__main__':
719 _main()