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