blob: 03f2d5c54207d72aec81f1f547da83b7869bd485 [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
262 # save the results in the global dictionary
263 vars.update(done)
264 return vars
265
Tarek Ziadéedacea32010-01-29 11:41:03 +0000266
267def _get_makefile_filename():
268 if _PYTHON_BUILD:
269 return os.path.join(_PROJECT_BASE, "Makefile")
270 return os.path.join(get_path('stdlib'), "config", "Makefile")
271
Tarek Ziadéedacea32010-01-29 11:41:03 +0000272
273def _init_posix(vars):
274 """Initialize the module as appropriate for POSIX systems."""
275 # load the installed Makefile:
276 makefile = _get_makefile_filename()
277 try:
278 _parse_makefile(makefile, vars)
279 except IOError as e:
280 msg = "invalid Python installation: unable to open %s" % makefile
281 if hasattr(e, "strerror"):
282 msg = msg + " (%s)" % e.strerror
283 raise IOError(msg)
284 # load the installed pyconfig.h:
285 config_h = get_config_h_filename()
286 try:
287 parse_config_h(open(config_h), vars)
288 except IOError as e:
289 msg = "invalid Python installation: unable to open %s" % config_h
290 if hasattr(e, "strerror"):
291 msg = msg + " (%s)" % e.strerror
292 raise IOError(msg)
293 # On MacOSX we need to check the setting of the environment variable
294 # MACOSX_DEPLOYMENT_TARGET: configure bases some choices on it so
295 # it needs to be compatible.
296 # If it isn't set we set it to the configure-time value
297 if sys.platform == 'darwin' and 'MACOSX_DEPLOYMENT_TARGET' in vars:
298 cfg_target = vars['MACOSX_DEPLOYMENT_TARGET']
299 cur_target = os.getenv('MACOSX_DEPLOYMENT_TARGET', '')
300 if cur_target == '':
301 cur_target = cfg_target
302 os.putenv('MACOSX_DEPLOYMENT_TARGET', cfg_target)
303 elif (list(map(int, cfg_target.split('.'))) >
304 list(map(int, cur_target.split('.')))):
305 msg = ('$MACOSX_DEPLOYMENT_TARGET mismatch: now "%s" but "%s" '
306 'during configure' % (cur_target, cfg_target))
307 raise IOError(msg)
308 # On AIX, there are wrong paths to the linker scripts in the Makefile
309 # -- these paths are relative to the Python source, but when installed
310 # the scripts are in another directory.
311 if _PYTHON_BUILD:
312 vars['LDSHARED'] = vars['BLDSHARED']
313
314def _init_non_posix(vars):
315 """Initialize the module as appropriate for NT"""
316 # set basic install directories
317 vars['LIBDEST'] = get_path('stdlib')
318 vars['BINLIBDEST'] = get_path('platstdlib')
319 vars['INCLUDEPY'] = get_path('include')
320 vars['SO'] = '.pyd'
321 vars['EXE'] = '.exe'
322 vars['VERSION'] = _PY_VERSION_SHORT_NO_DOT
Florent Xicluna1d1ab972010-03-11 01:53:10 +0000323 vars['BINDIR'] = os.path.dirname(realpath(sys.executable))
Tarek Ziadéedacea32010-01-29 11:41:03 +0000324
325#
326# public APIs
327#
328
Tarek Ziadébd797682010-02-02 23:16:13 +0000329
330def parse_config_h(fp, vars=None):
331 """Parse a config.h-style file.
332
333 A dictionary containing name/value pairs is returned. If an
334 optional dictionary is passed in as the second argument, it is
335 used instead of a new dictionary.
336 """
337 import re
338 if vars is None:
339 vars = {}
340 define_rx = re.compile("#define ([A-Z][A-Za-z0-9_]+) (.*)\n")
341 undef_rx = re.compile("/[*] #undef ([A-Z][A-Za-z0-9_]+) [*]/\n")
342
343 while True:
344 line = fp.readline()
345 if not line:
346 break
347 m = define_rx.match(line)
348 if m:
349 n, v = m.group(1, 2)
350 try: v = int(v)
351 except ValueError: pass
352 vars[n] = v
353 else:
354 m = undef_rx.match(line)
355 if m:
356 vars[m.group(1)] = 0
357 return vars
358
359def get_config_h_filename():
360 """Returns the path of pyconfig.h."""
361 if _PYTHON_BUILD:
362 if os.name == "nt":
363 inc_dir = os.path.join(_PROJECT_BASE, "PC")
364 else:
365 inc_dir = _PROJECT_BASE
366 else:
367 inc_dir = get_path('platinclude')
368 return os.path.join(inc_dir, 'pyconfig.h')
369
Tarek Ziadéedacea32010-01-29 11:41:03 +0000370def get_scheme_names():
Tarek Ziadébd797682010-02-02 23:16:13 +0000371 """Returns a tuple containing the schemes names."""
372 schemes = list(_INSTALL_SCHEMES.keys())
373 schemes.sort()
374 return tuple(schemes)
Tarek Ziadéedacea32010-01-29 11:41:03 +0000375
376def get_path_names():
Tarek Ziadébd797682010-02-02 23:16:13 +0000377 """Returns a tuple containing the paths names."""
Tarek Ziadéedacea32010-01-29 11:41:03 +0000378 return _SCHEME_KEYS
379
380def get_paths(scheme=_get_default_scheme(), vars=None, expand=True):
381 """Returns a mapping containing an install scheme.
382
383 ``scheme`` is the install scheme name. If not provided, it will
384 return the default scheme for the current platform.
385 """
386 if expand:
387 return _expand_vars(scheme, vars)
388 else:
389 return _INSTALL_SCHEMES[scheme]
390
391def get_path(name, scheme=_get_default_scheme(), vars=None, expand=True):
392 """Returns a path corresponding to the scheme.
393
394 ``scheme`` is the install scheme name.
395 """
396 return get_paths(scheme, vars, expand)[name]
397
398def get_config_vars(*args):
399 """With no arguments, return a dictionary of all configuration
400 variables relevant for the current platform.
401
402 On Unix, this means every variable defined in Python's installed Makefile;
403 On Windows and Mac OS it's a much smaller set.
404
405 With arguments, return a list of values that result from looking up
406 each argument in the configuration variable dictionary.
407 """
408 import re
409 global _CONFIG_VARS
410 if _CONFIG_VARS is None:
411 _CONFIG_VARS = {}
412 # Normalized versions of prefix and exec_prefix are handy to have;
413 # in fact, these are the standard versions used most places in the
414 # Distutils.
415 _CONFIG_VARS['prefix'] = _PREFIX
416 _CONFIG_VARS['exec_prefix'] = _EXEC_PREFIX
417 _CONFIG_VARS['py_version'] = _PY_VERSION
418 _CONFIG_VARS['py_version_short'] = _PY_VERSION_SHORT
419 _CONFIG_VARS['py_version_nodot'] = _PY_VERSION[0] + _PY_VERSION[2]
420 _CONFIG_VARS['base'] = _PREFIX
421 _CONFIG_VARS['platbase'] = _EXEC_PREFIX
Tarek Ziadéedacea32010-01-29 11:41:03 +0000422 _CONFIG_VARS['projectbase'] = _PROJECT_BASE
423
424 if os.name in ('nt', 'os2'):
425 _init_non_posix(_CONFIG_VARS)
426 if os.name == 'posix':
427 _init_posix(_CONFIG_VARS)
Ronald Oussoren4cda46a2010-05-08 10:49:43 +0000428 # Setting 'userbase' is done below the call to the
429 # init function to enable using 'get_config_var' in
430 # the init-function.
431 _CONFIG_VARS['userbase'] = _getuserbase()
432
Tarek Ziadéedacea32010-01-29 11:41:03 +0000433 if 'srcdir' not in _CONFIG_VARS:
434 _CONFIG_VARS['srcdir'] = _PROJECT_BASE
Ronald Oussorenab4fd612010-06-15 21:19:50 +0000435 else:
436 _CONFIG_VARS['srcdir'] = realpath(_CONFIG_VARS['srcdir'])
Tarek Ziadéedacea32010-01-29 11:41:03 +0000437
438
439 # Convert srcdir into an absolute path if it appears necessary.
440 # Normally it is relative to the build directory. However, during
441 # testing, for example, we might be running a non-installed python
442 # from a different directory.
443 if _PYTHON_BUILD and os.name == "posix":
444 base = _PROJECT_BASE
445 if (not os.path.isabs(_CONFIG_VARS['srcdir']) and
446 base != os.getcwd()):
447 # srcdir is relative and we are not in the same directory
448 # as the executable. Assume executable is in the build
449 # directory and make srcdir absolute.
450 srcdir = os.path.join(base, _CONFIG_VARS['srcdir'])
451 _CONFIG_VARS['srcdir'] = os.path.normpath(srcdir)
452
453 if sys.platform == 'darwin':
454 kernel_version = os.uname()[2] # Kernel version (8.4.3)
455 major_version = int(kernel_version.split('.')[0])
456
457 if major_version < 8:
458 # On Mac OS X before 10.4, check if -arch and -isysroot
459 # are in CFLAGS or LDFLAGS and remove them if they are.
460 # This is needed when building extensions on a 10.3 system
461 # using a universal build of python.
462 for key in ('LDFLAGS', 'BASECFLAGS',
463 # a number of derived variables. These need to be
464 # patched up as well.
465 'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'):
466 flags = _CONFIG_VARS[key]
467 flags = re.sub('-arch\s+\w+\s', ' ', flags)
468 flags = re.sub('-isysroot [^ \t]*', ' ', flags)
469 _CONFIG_VARS[key] = flags
470 else:
471 # Allow the user to override the architecture flags using
472 # an environment variable.
473 # NOTE: This name was introduced by Apple in OSX 10.5 and
474 # is used by several scripting languages distributed with
475 # that OS release.
476 if 'ARCHFLAGS' in os.environ:
477 arch = os.environ['ARCHFLAGS']
478 for key in ('LDFLAGS', 'BASECFLAGS',
479 # a number of derived variables. These need to be
480 # patched up as well.
481 'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'):
482
483 flags = _CONFIG_VARS[key]
484 flags = re.sub('-arch\s+\w+\s', ' ', flags)
485 flags = flags + ' ' + arch
486 _CONFIG_VARS[key] = flags
487
488 # If we're on OSX 10.5 or later and the user tries to
489 # compiles an extension using an SDK that is not present
490 # on the current machine it is better to not use an SDK
491 # than to fail.
492 #
493 # The major usecase for this is users using a Python.org
494 # binary installer on OSX 10.6: that installer uses
495 # the 10.4u SDK, but that SDK is not installed by default
496 # when you install Xcode.
497 #
498 CFLAGS = _CONFIG_VARS.get('CFLAGS', '')
499 m = re.search('-isysroot\s+(\S+)', CFLAGS)
500 if m is not None:
501 sdk = m.group(1)
502 if not os.path.exists(sdk):
503 for key in ('LDFLAGS', 'BASECFLAGS',
504 # a number of derived variables. These need to be
505 # patched up as well.
506 'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'):
507
508 flags = _CONFIG_VARS[key]
509 flags = re.sub('-isysroot\s+\S+(\s|$)', ' ', flags)
510 _CONFIG_VARS[key] = flags
511
512 if args:
513 vals = []
514 for name in args:
515 vals.append(_CONFIG_VARS.get(name))
516 return vals
517 else:
518 return _CONFIG_VARS
519
520def get_config_var(name):
521 """Return the value of a single variable using the dictionary returned by
522 'get_config_vars()'.
523
524 Equivalent to get_config_vars().get(name)
525 """
526 return get_config_vars().get(name)
527
528def get_platform():
529 """Return a string that identifies the current platform.
530
531 This is used mainly to distinguish platform-specific build directories and
532 platform-specific built distributions. Typically includes the OS name
533 and version and the architecture (as supplied by 'os.uname()'),
534 although the exact information included depends on the OS; eg. for IRIX
535 the architecture isn't particularly important (IRIX only runs on SGI
536 hardware), but for Linux the kernel version isn't particularly
537 important.
538
539 Examples of returned values:
540 linux-i586
541 linux-alpha (?)
542 solaris-2.6-sun4u
543 irix-5.3
544 irix64-6.2
545
546 Windows will return one of:
547 win-amd64 (64bit Windows on AMD64 (aka x86_64, Intel64, EM64T, etc)
548 win-ia64 (64bit Windows on Itanium)
549 win32 (all others - specifically, sys.platform is returned)
550
551 For other non-POSIX platforms, currently just returns 'sys.platform'.
552 """
553 import re
554 if os.name == 'nt':
555 # sniff sys.version for architecture.
556 prefix = " bit ("
557 i = sys.version.find(prefix)
558 if i == -1:
559 return sys.platform
560 j = sys.version.find(")", i)
561 look = sys.version[i+len(prefix):j].lower()
562 if look == 'amd64':
563 return 'win-amd64'
564 if look == 'itanium':
565 return 'win-ia64'
566 return sys.platform
567
568 if os.name != "posix" or not hasattr(os, 'uname'):
569 # XXX what about the architecture? NT is Intel or Alpha,
570 # Mac OS is M68k or PPC, etc.
571 return sys.platform
572
573 # Try to distinguish various flavours of Unix
574 osname, host, release, version, machine = os.uname()
575
576 # Convert the OS name to lowercase, remove '/' characters
577 # (to accommodate BSD/OS), and translate spaces (for "Power Macintosh")
578 osname = osname.lower().replace('/', '')
579 machine = machine.replace(' ', '_')
580 machine = machine.replace('/', '-')
581
582 if osname[:5] == "linux":
583 # At least on Linux/Intel, 'machine' is the processor --
584 # i386, etc.
585 # XXX what about Alpha, SPARC, etc?
586 return "%s-%s" % (osname, machine)
587 elif osname[:5] == "sunos":
588 if release[0] >= "5": # SunOS 5 == Solaris 2
589 osname = "solaris"
590 release = "%d.%s" % (int(release[0]) - 3, release[2:])
591 # fall through to standard osname-release-machine representation
592 elif osname[:4] == "irix": # could be "irix64"!
593 return "%s-%s" % (osname, release)
594 elif osname[:3] == "aix":
595 return "%s-%s.%s" % (osname, version, release)
596 elif osname[:6] == "cygwin":
597 osname = "cygwin"
598 rel_re = re.compile (r'[\d.]+')
599 m = rel_re.match(release)
600 if m:
601 release = m.group()
602 elif osname[:6] == "darwin":
603 #
604 # For our purposes, we'll assume that the system version from
605 # distutils' perspective is what MACOSX_DEPLOYMENT_TARGET is set
606 # to. This makes the compatibility story a bit more sane because the
607 # machine is going to compile and link as if it were
608 # MACOSX_DEPLOYMENT_TARGET.
609 cfgvars = get_config_vars()
610 macver = os.environ.get('MACOSX_DEPLOYMENT_TARGET')
611 if not macver:
612 macver = cfgvars.get('MACOSX_DEPLOYMENT_TARGET')
613
614 if 1:
615 # Always calculate the release of the running machine,
616 # needed to determine if we can build fat binaries or not.
617
618 macrelease = macver
619 # Get the system version. Reading this plist is a documented
620 # way to get the system version (see the documentation for
621 # the Gestalt Manager)
622 try:
623 f = open('/System/Library/CoreServices/SystemVersion.plist')
624 except IOError:
625 # We're on a plain darwin box, fall back to the default
626 # behaviour.
627 pass
628 else:
629 m = re.search(
630 r'<key>ProductUserVisibleVersion</key>\s*' +
631 r'<string>(.*?)</string>', f.read())
632 f.close()
633 if m is not None:
634 macrelease = '.'.join(m.group(1).split('.')[:2])
635 # else: fall back to the default behaviour
636
637 if not macver:
638 macver = macrelease
639
640 if macver:
641 release = macver
642 osname = "macosx"
643
644 if (macrelease + '.') >= '10.4.' and \
645 '-arch' in get_config_vars().get('CFLAGS', '').strip():
646 # The universal build will build fat binaries, but not on
647 # systems before 10.4
648 #
649 # Try to detect 4-way universal builds, those have machine-type
650 # 'universal' instead of 'fat'.
651
652 machine = 'fat'
653 cflags = get_config_vars().get('CFLAGS')
654
655 archs = re.findall('-arch\s+(\S+)', cflags)
656 archs.sort()
657 archs = tuple(archs)
658
659 if len(archs) == 1:
660 machine = archs[0]
661 elif archs == ('i386', 'ppc'):
662 machine = 'fat'
663 elif archs == ('i386', 'x86_64'):
664 machine = 'intel'
665 elif archs == ('i386', 'ppc', 'x86_64'):
666 machine = 'fat3'
667 elif archs == ('ppc64', 'x86_64'):
668 machine = 'fat64'
669 elif archs == ('i386', 'ppc', 'ppc64', 'x86_64'):
670 machine = 'universal'
671 else:
672 raise ValueError(
673 "Don't know machine value for archs=%r"%(archs,))
674
675 elif machine == 'i386':
676 # On OSX the machine type returned by uname is always the
677 # 32-bit variant, even if the executable architecture is
678 # the 64-bit variant
679 if sys.maxsize >= 2**32:
680 machine = 'x86_64'
681
682 elif machine in ('PowerPC', 'Power_Macintosh'):
683 # Pick a sane name for the PPC architecture.
684 # See 'i386' case
685 if sys.maxsize >= 2**32:
686 machine = 'ppc64'
687 else:
688 machine = 'ppc'
689
690 return "%s-%s-%s" % (osname, release, machine)
691
692
693def get_python_version():
694 return _PY_VERSION_SHORT
Tarek Ziadéa7514992010-05-25 09:44:36 +0000695
696def _print_dict(title, data):
697 for index, (key, value) in enumerate(sorted(data.items())):
698 if index == 0:
699 print('{0}: '.format(title))
700 print('\t{0} = "{1}"'.format(key, value))
701
702def _main():
703 """Displays all information sysconfig detains."""
704 print('Platform: "{0}"'.format(get_platform()))
705 print('Python version: "{0}"'.format(get_python_version()))
706 print('Current installation scheme: "{0}"'.format(_get_default_scheme()))
707 print('')
708 _print_dict('Paths', get_paths())
709 print('')
710 _print_dict('Variables', get_config_vars())
711
712if __name__ == '__main__':
713 _main()