blob: 44a612b28fcef0d66dc3e4444e0fd99f0eb2ac9e [file] [log] [blame]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001#!/usr/bin/env python
2
Brett Cannon8ab27df2003-08-05 03:52:04 +00003""" This module tries to retrieve as much platform-identifying data as
Marc-André Lemburg246d8472003-04-24 11:36:11 +00004 possible. It makes this information available via function APIs.
5
6 If called from the command line, it prints the platform
7 information concatenated as single string to stdout. The output
8 format is useable as part of a filename.
9
10"""
11# This module is maintained by Marc-Andre Lemburg <mal@egenix.com>.
12# If you find problems, please submit bug reports/patches via the
Georg Brandl52c17942009-09-19 08:43:16 +000013# Python bug tracker (http://bugs.python.org) and assign them to "lemburg".
Marc-André Lemburg246d8472003-04-24 11:36:11 +000014#
15# Note: Please keep this module compatible to Python 1.5.2.
16#
17# Still needed:
18# * more support for WinCE
19# * support for MS-DOS (PythonDX ?)
20# * support for Amiga and other still unsupported platforms running Python
21# * support for additional Linux distributions
22#
Brett Cannon8ab27df2003-08-05 03:52:04 +000023# Many thanks to all those who helped adding platform-specific
Marc-André Lemburg246d8472003-04-24 11:36:11 +000024# checks (in no particular order):
25#
26# Charles G Waldman, David Arnold, Gordon McMillan, Ben Darnell,
27# Jeff Bauer, Cliff Crawford, Ivan Van Laningham, Josef
28# Betancourt, Randall Hopper, Karl Putland, John Farrell, Greg
29# Andruk, Just van Rossum, Thomas Heller, Mark R. Levinson, Mark
30# Hammond, Bill Tutt, Hans Nowak, Uwe Zessin (OpenVMS support),
Steve Dower044cde52015-09-22 17:25:30 -070031# Colin Kong, Trent Mick, Guido van Rossum, Anthony Baxter, Steve
32# Dower
Marc-André Lemburg246d8472003-04-24 11:36:11 +000033#
34# History:
Marc-André Lemburg380f4172005-11-07 16:11:02 +000035#
36# <see CVS and SVN checkin messages for history>
37#
Steve Dower044cde52015-09-22 17:25:30 -070038# 1.0.8 - changed Windows support to read version from kernel32.dll
Marc-André Lemburg19e5b3f2009-07-13 20:23:49 +000039# 1.0.7 - added DEV_NULL
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +000040# 1.0.6 - added linux_distribution()
41# 1.0.5 - fixed Java support to allow running the module on Jython
42# 1.0.4 - added IronPython support
Marc-André Lemburgcdc79232004-06-19 17:17:00 +000043# 1.0.3 - added normalization of Windows system name
Marc-André Lemburg91e83e22004-03-25 18:35:12 +000044# 1.0.2 - added more Windows support
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +000045# 1.0.1 - reformatted to make doc.py happy
Marc-André Lemburg246d8472003-04-24 11:36:11 +000046# 1.0.0 - reformatted a bit and checked into Python CVS
47# 0.8.0 - added sys.version parser and various new access
48# APIs (python_version(), python_compiler(), etc.)
49# 0.7.2 - fixed architecture() to use sizeof(pointer) where available
50# 0.7.1 - added support for Caldera OpenLinux
51# 0.7.0 - some fixes for WinCE; untabified the source file
52# 0.6.2 - support for OpenVMS - requires version 1.5.2-V006 or higher and
53# vms_lib.getsyi() configured
54# 0.6.1 - added code to prevent 'uname -p' on platforms which are
55# known not to support it
56# 0.6.0 - fixed win32_ver() to hopefully work on Win95,98,NT and Win2k;
57# did some cleanup of the interfaces - some APIs have changed
58# 0.5.5 - fixed another type in the MacOS code... should have
59# used more coffee today ;-)
60# 0.5.4 - fixed a few typos in the MacOS code
61# 0.5.3 - added experimental MacOS support; added better popen()
62# workarounds in _syscmd_ver() -- still not 100% elegant
63# though
64# 0.5.2 - fixed uname() to return '' instead of 'unknown' in all
65# return values (the system uname command tends to return
Martin Pantera850ef62016-07-28 01:11:04 +000066# 'unknown' instead of just leaving the field empty)
Marc-André Lemburg246d8472003-04-24 11:36:11 +000067# 0.5.1 - included code for slackware dist; added exception handlers
68# to cover up situations where platforms don't have os.popen
69# (e.g. Mac) or fail on socket.gethostname(); fixed libc
70# detection RE
71# 0.5.0 - changed the API names referring to system commands to *syscmd*;
72# added java_ver(); made syscmd_ver() a private
73# API (was system_ver() in previous versions) -- use uname()
74# instead; extended the win32_ver() to also return processor
75# type information
76# 0.4.0 - added win32_ver() and modified the platform() output for WinXX
77# 0.3.4 - fixed a bug in _follow_symlinks()
78# 0.3.3 - fixed popen() and "file" command invokation bugs
79# 0.3.2 - added architecture() API and support for it in platform()
80# 0.3.1 - fixed syscmd_ver() RE to support Windows NT
81# 0.3.0 - added system alias support
82# 0.2.3 - removed 'wince' again... oh well.
83# 0.2.2 - added 'wince' to syscmd_ver() supported platforms
84# 0.2.1 - added cache logic and changed the platform string format
85# 0.2.0 - changed the API to use functions instead of module globals
86# since some action take too long to be run on module import
87# 0.1.0 - first release
88#
89# You can always get the latest version of this module at:
90#
91# http://www.egenix.com/files/python/platform.py
92#
93# If that URL should fail, try contacting the author.
94
95__copyright__ = """
96 Copyright (c) 1999-2000, Marc-Andre Lemburg; mailto:mal@lemburg.com
Georg Brandl8cdc9bc2010-01-01 13:07:05 +000097 Copyright (c) 2000-2010, eGenix.com Software GmbH; mailto:info@egenix.com
Marc-André Lemburg246d8472003-04-24 11:36:11 +000098
99 Permission to use, copy, modify, and distribute this software and its
100 documentation for any purpose and without fee or royalty is hereby granted,
101 provided that the above copyright notice appear in all copies and that
102 both that copyright notice and this permission notice appear in
103 supporting documentation or portions thereof, including modifications,
104 that you make.
105
106 EGENIX.COM SOFTWARE GMBH DISCLAIMS ALL WARRANTIES WITH REGARD TO
107 THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
108 FITNESS, IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
109 INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
110 FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
111 NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
112 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE !
113
114"""
115
Marc-André Lemburg19e5b3f2009-07-13 20:23:49 +0000116__version__ = '1.0.7'
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000117
Jesus Ceadebda5d2012-10-04 15:14:56 +0200118import sys,string,os,re
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000119
Marc-André Lemburg19e5b3f2009-07-13 20:23:49 +0000120### Globals & Constants
121
122# Determine the platform's /dev/null device
123try:
124 DEV_NULL = os.devnull
125except AttributeError:
126 # os.devnull was added in Python 2.4, so emulate it for earlier
127 # Python versions
128 if sys.platform in ('dos','win32','win16','os2'):
129 # Use the old CP/M NUL as device name
130 DEV_NULL = 'NUL'
131 else:
132 # Standard Unix uses /dev/null
133 DEV_NULL = '/dev/null'
134
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000135### Platform specific APIs
136
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000137_libc_search = re.compile(r'(__libc_init)'
138 '|'
Tim Peters0eadaac2003-04-24 16:02:54 +0000139 '(GLIBC_([0-9.]+))'
140 '|'
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000141 '(libc(_\w+)?\.so(?:\.(\d[0-9.]*))?)')
142
Serhiy Storchakab1e6e562018-07-09 14:39:06 +0300143def libc_ver(executable=sys.executable,lib='',version='', chunksize=2048):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000144
Brett Cannon8ab27df2003-08-05 03:52:04 +0000145 """ Tries to determine the libc version that the file executable
146 (which defaults to the Python interpreter) is linked against.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000147
148 Returns a tuple of strings (lib,version) which default to the
149 given parameters in case the lookup fails.
150
151 Note that the function has intimate knowledge of how different
Brett Cannon8ab27df2003-08-05 03:52:04 +0000152 libc versions add symbols to the executable and thus is probably
153 only useable for executables compiled using gcc.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000154
155 The file is read and scanned in chunks of chunksize bytes.
156
157 """
Serhiy Storchakab1e6e562018-07-09 14:39:06 +0300158 from distutils.version import LooseVersion as V
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000159 if hasattr(os.path, 'realpath'):
160 # Python 2.2 introduced os.path.realpath(); it is used
161 # here to work around problems with Cygwin not being
162 # able to open symlinks for reading
163 executable = os.path.realpath(executable)
Serhiy Storchakab1e6e562018-07-09 14:39:06 +0300164 with open(executable, 'rb') as f:
165 binary = f.read(chunksize)
166 pos = 0
167 while pos < len(binary):
168 m = _libc_search.search(binary,pos)
169 if not m or m.end() == len(binary):
170 chunk = f.read(chunksize)
171 if chunk:
172 binary = binary[max(pos, len(binary) - 1000):] + chunk
173 pos = 0
174 continue
175 if not m:
176 break
177 libcinit,glibc,glibcversion,so,threads,soversion = m.groups()
178 if libcinit and not lib:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000179 lib = 'libc'
Serhiy Storchakab1e6e562018-07-09 14:39:06 +0300180 elif glibc:
181 if lib != 'glibc':
182 lib = 'glibc'
183 version = glibcversion
184 elif V(glibcversion) > V(version):
185 version = glibcversion
186 elif so:
187 if lib != 'glibc':
188 lib = 'libc'
189 if soversion and (not version or V(soversion) > V(version)):
190 version = soversion
191 if threads and version[-len(threads):] != threads:
192 version = version + threads
193 pos = m.end()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000194 return lib,version
195
196def _dist_try_harder(distname,version,id):
197
Tim Peters0eadaac2003-04-24 16:02:54 +0000198 """ Tries some special tricks to get the distribution
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000199 information in case the default method fails.
200
201 Currently supports older SuSE Linux, Caldera OpenLinux and
202 Slackware Linux distributions.
203
204 """
205 if os.path.exists('/var/adm/inst-log/info'):
206 # SuSE Linux stores distribution information in that file
207 info = open('/var/adm/inst-log/info').readlines()
208 distname = 'SuSE'
209 for line in info:
210 tv = string.split(line)
211 if len(tv) == 2:
212 tag,value = tv
213 else:
214 continue
215 if tag == 'MIN_DIST_VERSION':
216 version = string.strip(value)
217 elif tag == 'DIST_IDENT':
218 values = string.split(value,'-')
219 id = values[2]
220 return distname,version,id
221
222 if os.path.exists('/etc/.installed'):
223 # Caldera OpenLinux has some infos in that file (thanks to Colin Kong)
224 info = open('/etc/.installed').readlines()
225 for line in info:
226 pkg = string.split(line,'-')
227 if len(pkg) >= 2 and pkg[0] == 'OpenLinux':
228 # XXX does Caldera support non Intel platforms ? If yes,
229 # where can we find the needed id ?
230 return 'OpenLinux',pkg[1],id
231
232 if os.path.isdir('/usr/lib/setup'):
Ezio Melottif5469cf2013-08-17 15:43:51 +0300233 # Check for slackware version tag file (thanks to Greg Andruk)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000234 verfiles = os.listdir('/usr/lib/setup')
Guido van Rossum843c7342004-05-04 18:18:59 +0000235 for n in range(len(verfiles)-1, -1, -1):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000236 if verfiles[n][:14] != 'slack-version-':
237 del verfiles[n]
238 if verfiles:
239 verfiles.sort()
240 distname = 'slackware'
241 version = verfiles[-1][14:]
242 return distname,version,id
243
244 return distname,version,id
245
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000246_release_filename = re.compile(r'(\w+)[-_](release|version)')
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000247_lsb_release_version = re.compile(r'(.+)'
248 ' release '
249 '([\d.]+)'
250 '[^(]*(?:\((.+)\))?')
251_release_version = re.compile(r'([^0-9]+)'
252 '(?: release )?'
253 '([\d.]+)'
254 '[^(]*(?:\((.+)\))?')
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000255
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000256# See also http://www.novell.com/coolsolutions/feature/11251.html
Tim Petersf733abb2007-01-30 03:03:46 +0000257# and http://linuxmafia.com/faq/Admin/release-files.html
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000258# and http://data.linux-ntfs.org/rpm/whichrpm
259# and http://www.die.net/doc/linux/man/man1/lsb_release.1.html
Marc-André Lemburg380f4172005-11-07 16:11:02 +0000260
Marc-André Lemburg50967bd2008-03-08 10:01:43 +0000261_supported_dists = (
262 'SuSE', 'debian', 'fedora', 'redhat', 'centos',
263 'mandrake', 'mandriva', 'rocks', 'slackware', 'yellowdog', 'gentoo',
264 'UnitedLinux', 'turbolinux')
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000265
266def _parse_release_file(firstline):
Tim Petersf733abb2007-01-30 03:03:46 +0000267
Benjamin Petersona43f34c2010-01-25 03:31:13 +0000268 # Default to empty 'version' and 'id' strings. Both defaults are used
269 # when 'firstline' is empty. 'id' defaults to empty when an id can not
270 # be deduced.
271 version = ''
272 id = ''
273
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000274 # Parse the first line
275 m = _lsb_release_version.match(firstline)
276 if m is not None:
277 # LSB format: "distro release x.x (codename)"
278 return tuple(m.groups())
279
280 # Pre-LSB format: "distro x.x (codename)"
281 m = _release_version.match(firstline)
282 if m is not None:
283 return tuple(m.groups())
284
Ezio Melottif5469cf2013-08-17 15:43:51 +0300285 # Unknown format... take the first two words
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000286 l = string.split(string.strip(firstline))
287 if l:
288 version = l[0]
289 if len(l) > 1:
290 id = l[1]
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000291 return '', version, id
292
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000293def linux_distribution(distname='', version='', id='',
294
295 supported_dists=_supported_dists,
296 full_distribution_name=1):
297
298 """ Tries to determine the name of the Linux OS distribution name.
299
300 The function first looks for a distribution release file in
301 /etc and then reverts to _dist_try_harder() in case no
302 suitable files are found.
303
304 supported_dists may be given to define the set of Linux
305 distributions to look for. It defaults to a list of currently
306 supported Linux distributions identified by their release file
307 name.
308
309 If full_distribution_name is true (default), the full
310 distribution read from the OS is returned. Otherwise the short
311 name taken from supported_dists is used.
312
313 Returns a tuple (distname,version,id) which default to the
314 args given as parameters.
315
316 """
317 try:
318 etc = os.listdir('/etc')
319 except os.error:
320 # Probably not a Unix system
321 return distname,version,id
322 etc.sort()
323 for file in etc:
324 m = _release_filename.match(file)
325 if m is not None:
326 _distname,dummy = m.groups()
327 if _distname in supported_dists:
328 distname = _distname
329 break
330 else:
331 return _dist_try_harder(distname,version,id)
Tim Petersf733abb2007-01-30 03:03:46 +0000332
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000333 # Read the first line
334 f = open('/etc/'+file, 'r')
335 firstline = f.readline()
336 f.close()
337 _distname, _version, _id = _parse_release_file(firstline)
338
339 if _distname and full_distribution_name:
340 distname = _distname
341 if _version:
342 version = _version
343 if _id:
344 id = _id
345 return distname, version, id
346
347# To maintain backwards compatibility:
Tim Petersf733abb2007-01-30 03:03:46 +0000348
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000349def dist(distname='',version='',id='',
350
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000351 supported_dists=_supported_dists):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000352
Brett Cannon8ab27df2003-08-05 03:52:04 +0000353 """ Tries to determine the name of the Linux OS distribution name.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000354
355 The function first looks for a distribution release file in
356 /etc and then reverts to _dist_try_harder() in case no
357 suitable files are found.
358
Brett Cannon8ab27df2003-08-05 03:52:04 +0000359 Returns a tuple (distname,version,id) which default to the
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000360 args given as parameters.
361
362 """
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000363 return linux_distribution(distname, version, id,
364 supported_dists=supported_dists,
365 full_distribution_name=0)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000366
367class _popen:
368
369 """ Fairly portable (alternative) popen implementation.
370
371 This is mostly needed in case os.popen() is not available, or
372 doesn't work as advertised, e.g. in Win9X GUI programs like
373 PythonWin or IDLE.
374
375 Writing to the pipe is currently not supported.
376
377 """
378 tmpfile = ''
379 pipe = None
380 bufsize = None
381 mode = 'r'
382
383 def __init__(self,cmd,mode='r',bufsize=None):
384
385 if mode != 'r':
386 raise ValueError,'popen()-emulation only supports read mode'
387 import tempfile
388 self.tmpfile = tmpfile = tempfile.mktemp()
389 os.system(cmd + ' > %s' % tmpfile)
390 self.pipe = open(tmpfile,'rb')
391 self.bufsize = bufsize
392 self.mode = mode
393
394 def read(self):
395
396 return self.pipe.read()
397
398 def readlines(self):
399
400 if self.bufsize is not None:
401 return self.pipe.readlines()
402
403 def close(self,
404
405 remove=os.unlink,error=os.error):
406
407 if self.pipe:
408 rc = self.pipe.close()
409 else:
410 rc = 255
411 if self.tmpfile:
412 try:
413 remove(self.tmpfile)
414 except error:
415 pass
416 return rc
417
418 # Alias
419 __del__ = close
420
421def popen(cmd, mode='r', bufsize=None):
422
423 """ Portable popen() interface.
424 """
425 # Find a working popen implementation preferring win32pipe.popen
426 # over os.popen over _popen
427 popen = None
428 if os.environ.get('OS','') == 'Windows_NT':
429 # On NT win32pipe should work; on Win9x it hangs due to bugs
430 # in the MS C lib (see MS KnowledgeBase article Q150956)
431 try:
432 import win32pipe
433 except ImportError:
434 pass
435 else:
436 popen = win32pipe.popen
437 if popen is None:
438 if hasattr(os,'popen'):
439 popen = os.popen
440 # Check whether it works... it doesn't in GUI programs
441 # on Windows platforms
442 if sys.platform == 'win32': # XXX Others too ?
443 try:
444 popen('')
445 except os.error:
446 popen = _popen
447 else:
448 popen = _popen
449 if bufsize is None:
450 return popen(cmd,mode)
451 else:
452 return popen(cmd,mode,bufsize)
453
Serhiy Storchakab1e6e562018-07-09 14:39:06 +0300454
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000455def _norm_version(version, build=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000456
Brett Cannon8ab27df2003-08-05 03:52:04 +0000457 """ Normalize the version and build strings and return a single
Walter Dörwalde5a7fad2005-11-21 17:01:27 +0000458 version string using the format major.minor.build (or patchlevel).
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000459 """
460 l = string.split(version,'.')
461 if build:
462 l.append(build)
463 try:
464 ints = map(int,l)
465 except ValueError:
466 strings = l
467 else:
468 strings = map(str,ints)
469 version = string.join(strings[:3],'.')
470 return version
471
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000472_ver_output = re.compile(r'(?:([\w ]+) ([\w.]+) '
473 '.*'
Marc-André Lemburgcecaa652009-07-13 21:28:33 +0000474 '\[.* ([\d.]+)\])')
475
476# Examples of VER command output:
477#
478# Windows 2000: Microsoft Windows 2000 [Version 5.00.2195]
479# Windows XP: Microsoft Windows XP [Version 5.1.2600]
480# Windows Vista: Microsoft Windows [Version 6.0.6002]
481#
482# Note that the "Version" string gets localized on different
483# Windows versions.
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000484
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000485def _syscmd_ver(system='', release='', version='',
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000486
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000487 supported_platforms=('win32','win16','dos','os2')):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000488
489 """ Tries to figure out the OS version used and returns
490 a tuple (system,release,version).
Tim Peters0eadaac2003-04-24 16:02:54 +0000491
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000492 It uses the "ver" shell command for this which is known
493 to exists on Windows, DOS and OS/2. XXX Others too ?
494
495 In case this fails, the given parameters are used as
496 defaults.
497
498 """
499 if sys.platform not in supported_platforms:
500 return system,release,version
501
502 # Try some common cmd strings
503 for cmd in ('ver','command /c ver','cmd /c ver'):
504 try:
505 pipe = popen(cmd)
506 info = pipe.read()
507 if pipe.close():
508 raise os.error,'command failed'
Ezio Melottic2077b02011-03-16 12:34:31 +0200509 # XXX How can I suppress shell errors from being written
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000510 # to stderr ?
511 except os.error,why:
512 #print 'Command %s failed: %s' % (cmd,why)
513 continue
514 except IOError,why:
515 #print 'Command %s failed: %s' % (cmd,why)
516 continue
517 else:
518 break
519 else:
520 return system,release,version
521
522 # Parse the output
523 info = string.strip(info)
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000524 m = _ver_output.match(info)
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000525 if m is not None:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000526 system,release,version = m.groups()
527 # Strip trailing dots from version and release
528 if release[-1] == '.':
529 release = release[:-1]
530 if version[-1] == '.':
531 version = version[:-1]
532 # Normalize the version and build strings (eliminating additional
533 # zeros)
534 version = _norm_version(version)
535 return system,release,version
536
Steve Dower044cde52015-09-22 17:25:30 -0700537_WIN32_CLIENT_RELEASES = {
538 (5, 0): "2000",
539 (5, 1): "XP",
540 # Strictly, 5.2 client is XP 64-bit, but platform.py historically
541 # has always called it 2003 Server
542 (5, 2): "2003Server",
543 (5, None): "post2003",
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000544
Steve Dower044cde52015-09-22 17:25:30 -0700545 (6, 0): "Vista",
546 (6, 1): "7",
547 (6, 2): "8",
548 (6, 3): "8.1",
549 (6, None): "post8.1",
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000550
Steve Dower044cde52015-09-22 17:25:30 -0700551 (10, 0): "10",
552 (10, None): "post10",
553}
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000554
Steve Dower044cde52015-09-22 17:25:30 -0700555# Server release name lookup will default to client names if necessary
556_WIN32_SERVER_RELEASES = {
557 (5, 2): "2003Server",
558
559 (6, 0): "2008Server",
560 (6, 1): "2008ServerR2",
561 (6, 2): "2012Server",
562 (6, 3): "2012ServerR2",
563 (6, None): "post2012ServerR2",
564}
565
566def _get_real_winver(maj, min, build):
567 if maj < 6 or (maj == 6 and min < 2):
568 return maj, min, build
569
570 from ctypes import (c_buffer, POINTER, byref, create_unicode_buffer,
Steve Dowerdb01b3e2016-09-17 16:43:01 -0700571 Structure, WinDLL, _Pointer)
Steve Dower044cde52015-09-22 17:25:30 -0700572 from ctypes.wintypes import DWORD, HANDLE
573
574 class VS_FIXEDFILEINFO(Structure):
575 _fields_ = [
576 ("dwSignature", DWORD),
577 ("dwStrucVersion", DWORD),
578 ("dwFileVersionMS", DWORD),
579 ("dwFileVersionLS", DWORD),
580 ("dwProductVersionMS", DWORD),
581 ("dwProductVersionLS", DWORD),
582 ("dwFileFlagsMask", DWORD),
583 ("dwFileFlags", DWORD),
584 ("dwFileOS", DWORD),
585 ("dwFileType", DWORD),
586 ("dwFileSubtype", DWORD),
587 ("dwFileDateMS", DWORD),
588 ("dwFileDateLS", DWORD),
589 ]
Steve Dowerdb01b3e2016-09-17 16:43:01 -0700590 class PVS_FIXEDFILEINFO(_Pointer):
591 _type_ = VS_FIXEDFILEINFO
Steve Dower044cde52015-09-22 17:25:30 -0700592
593 kernel32 = WinDLL('kernel32')
594 version = WinDLL('version')
595
596 # We will immediately double the length up to MAX_PATH, but the
597 # path may be longer, so we retry until the returned string is
598 # shorter than our buffer.
599 name_len = actual_len = 130
600 while actual_len == name_len:
601 name_len *= 2
602 name = create_unicode_buffer(name_len)
603 actual_len = kernel32.GetModuleFileNameW(HANDLE(kernel32._handle),
604 name, len(name))
605 if not actual_len:
606 return maj, min, build
607
608 size = version.GetFileVersionInfoSizeW(name, None)
609 if not size:
610 return maj, min, build
611
612 ver_block = c_buffer(size)
613 if (not version.GetFileVersionInfoW(name, None, size, ver_block) or
614 not ver_block):
615 return maj, min, build
616
Steve Dowerdb01b3e2016-09-17 16:43:01 -0700617 pvi = PVS_FIXEDFILEINFO()
Steve Dower044cde52015-09-22 17:25:30 -0700618 if not version.VerQueryValueW(ver_block, "", byref(pvi), byref(DWORD())):
619 return maj, min, build
620
621 maj = pvi.contents.dwProductVersionMS >> 16
622 min = pvi.contents.dwProductVersionMS & 0xFFFF
623 build = pvi.contents.dwProductVersionLS >> 16
624
625 return maj, min, build
626
627def win32_ver(release='', version='', csd='', ptype=''):
Steve Dowere20c2a62015-09-22 17:35:24 -0700628 try:
629 from sys import getwindowsversion
630 except ImportError:
631 return release, version, csd, ptype
Marc-André Lemburgdbd61a22008-03-20 17:31:36 +0000632 try:
Steve Dower044cde52015-09-22 17:25:30 -0700633 from winreg import OpenKeyEx, QueryValueEx, CloseKey, HKEY_LOCAL_MACHINE
Marc-André Lemburgdbd61a22008-03-20 17:31:36 +0000634 except ImportError:
Steve Dower044cde52015-09-22 17:25:30 -0700635 from _winreg import OpenKeyEx, QueryValueEx, CloseKey, HKEY_LOCAL_MACHINE
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000636
Steve Dower044cde52015-09-22 17:25:30 -0700637 winver = getwindowsversion()
638 maj, min, build = _get_real_winver(*winver[:3])
639 version = '{0}.{1}.{2}'.format(maj, min, build)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000640
Steve Dower044cde52015-09-22 17:25:30 -0700641 release = (_WIN32_CLIENT_RELEASES.get((maj, min)) or
642 _WIN32_CLIENT_RELEASES.get((maj, None)) or
643 release)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000644
Steve Dower044cde52015-09-22 17:25:30 -0700645 # getwindowsversion() reflect the compatibility mode Python is
646 # running under, and so the service pack value is only going to be
647 # valid if the versions match.
648 if winver[:2] == (maj, min):
Marc-André Lemburgdbd61a22008-03-20 17:31:36 +0000649 try:
Steve Dower044cde52015-09-22 17:25:30 -0700650 csd = 'SP{}'.format(winver.service_pack_major)
Marc-André Lemburgdbd61a22008-03-20 17:31:36 +0000651 except AttributeError:
Steve Dower044cde52015-09-22 17:25:30 -0700652 if csd[:13] == 'Service Pack ':
653 csd = 'SP' + csd[13:]
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000654
Steve Dower044cde52015-09-22 17:25:30 -0700655 # VER_NT_SERVER = 3
Steve Dower1de99f72016-09-21 09:10:21 -0700656 if getattr(winver, 'product_type', None) == 3:
Steve Dower044cde52015-09-22 17:25:30 -0700657 release = (_WIN32_SERVER_RELEASES.get((maj, min)) or
658 _WIN32_SERVER_RELEASES.get((maj, None)) or
659 release)
Marc-André Lemburgcecaa652009-07-13 21:28:33 +0000660
Steve Dower044cde52015-09-22 17:25:30 -0700661 key = None
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000662 try:
Steve Dower044cde52015-09-22 17:25:30 -0700663 key = OpenKeyEx(HKEY_LOCAL_MACHINE,
664 r'SOFTWARE\Microsoft\Windows NT\CurrentVersion')
665 ptype = QueryValueEx(key, 'CurrentType')[0]
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000666 except:
Steve Dower044cde52015-09-22 17:25:30 -0700667 pass
668 finally:
669 if key:
670 CloseKey(key)
Tim Peters0eadaac2003-04-24 16:02:54 +0000671
Steve Dower044cde52015-09-22 17:25:30 -0700672 return release, version, csd, ptype
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000673
674def _mac_ver_lookup(selectors,default=None):
675
676 from gestalt import gestalt
Jack Jansena290e3d2003-08-11 11:08:49 +0000677 import MacOS
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000678 l = []
679 append = l.append
680 for selector in selectors:
681 try:
682 append(gestalt(selector))
Jack Jansena290e3d2003-08-11 11:08:49 +0000683 except (RuntimeError, MacOS.Error):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000684 append(default)
685 return l
686
687def _bcd2str(bcd):
688
689 return hex(bcd)[2:]
690
Ronald Oussoren3a04a252010-07-23 12:41:00 +0000691def _mac_ver_gestalt():
692 """
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000693 Thanks to Mark R. Levinson for mailing documentation links and
694 code examples for this function. Documentation for the
695 gestalt() API is available online at:
696
697 http://www.rgaros.nl/gestalt/
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000698 """
699 # Check whether the version info module is available
700 try:
701 import gestalt
Jack Jansena290e3d2003-08-11 11:08:49 +0000702 import MacOS
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000703 except ImportError:
Ronald Oussoren3a04a252010-07-23 12:41:00 +0000704 return None
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000705 # Get the infos
Ronald Oussoren9341ad22010-02-07 11:29:31 +0000706 sysv,sysa = _mac_ver_lookup(('sysv','sysa'))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000707 # Decode the infos
708 if sysv:
709 major = (sysv & 0xFF00) >> 8
710 minor = (sysv & 0x00F0) >> 4
711 patch = (sysv & 0x000F)
Ronald Oussorenc27b8b82008-05-08 10:34:39 +0000712
713 if (major, minor) >= (10, 4):
714 # the 'sysv' gestald cannot return patchlevels
715 # higher than 9. Apple introduced 3 new
716 # gestalt codes in 10.4 to deal with this
717 # issue (needed because patch levels can
718 # run higher than 9, such as 10.4.11)
719 major,minor,patch = _mac_ver_lookup(('sys1','sys2','sys3'))
720 release = '%i.%i.%i' %(major, minor, patch)
721 else:
722 release = '%s.%i.%i' % (_bcd2str(major),minor,patch)
Ronald Oussoren7a0f4c72008-05-18 20:54:47 +0000723
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000724 if sysa:
Tim Peters0eadaac2003-04-24 16:02:54 +0000725 machine = {0x1: '68k',
Ronald Oussoren749d0702006-04-17 13:37:15 +0000726 0x2: 'PowerPC',
727 0xa: 'i386'}.get(sysa,'')
Ronald Oussoren3a04a252010-07-23 12:41:00 +0000728
Ned Deily0ab67ee2011-07-13 15:05:31 -0700729 versioninfo=('', '', '')
Ronald Oussoren3a04a252010-07-23 12:41:00 +0000730 return release,versioninfo,machine
731
732def _mac_ver_xml():
733 fn = '/System/Library/CoreServices/SystemVersion.plist'
734 if not os.path.exists(fn):
735 return None
736
737 try:
738 import plistlib
739 except ImportError:
740 return None
741
742 pl = plistlib.readPlist(fn)
743 release = pl['ProductVersion']
744 versioninfo=('', '', '')
745 machine = os.uname()[4]
Ronald Oussoren22e3e692010-08-03 07:44:35 +0000746 if machine in ('ppc', 'Power Macintosh'):
Ronald Oussoren3a04a252010-07-23 12:41:00 +0000747 # for compatibility with the gestalt based code
748 machine = 'PowerPC'
749
750 return release,versioninfo,machine
751
752
753def mac_ver(release='',versioninfo=('','',''),machine=''):
754
755 """ Get MacOS version information and return it as tuple (release,
756 versioninfo, machine) with versioninfo being a tuple (version,
757 dev_stage, non_release_version).
758
Ezio Melottif5469cf2013-08-17 15:43:51 +0300759 Entries which cannot be determined are set to the parameter values
Ronald Oussoren3a04a252010-07-23 12:41:00 +0000760 which default to ''. All tuple entries are strings.
761 """
762
763 # First try reading the information from an XML file which should
764 # always be present
765 info = _mac_ver_xml()
766 if info is not None:
767 return info
768
769 # If that doesn't work for some reason fall back to reading the
770 # information using gestalt calls.
771 info = _mac_ver_gestalt()
772 if info is not None:
773 return info
774
775 # If that also doesn't work return the default values
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000776 return release,versioninfo,machine
777
Neal Norwitz9b924c62003-06-29 04:17:45 +0000778def _java_getprop(name,default):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000779
780 from java.lang import System
781 try:
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000782 value = System.getProperty(name)
783 if value is None:
784 return default
785 return value
786 except AttributeError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000787 return default
788
789def java_ver(release='',vendor='',vminfo=('','',''),osinfo=('','','')):
Tim Peters0eadaac2003-04-24 16:02:54 +0000790
Brett Cannon8ab27df2003-08-05 03:52:04 +0000791 """ Version interface for Jython.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000792
793 Returns a tuple (release,vendor,vminfo,osinfo) with vminfo being
794 a tuple (vm_name,vm_release,vm_vendor) and osinfo being a
795 tuple (os_name,os_version,os_arch).
796
797 Values which cannot be determined are set to the defaults
798 given as parameters (which all default to '').
799
800 """
801 # Import the needed APIs
802 try:
803 import java.lang
804 except ImportError:
805 return release,vendor,vminfo,osinfo
806
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000807 vendor = _java_getprop('java.vendor', vendor)
808 release = _java_getprop('java.version', release)
809 vm_name, vm_release, vm_vendor = vminfo
810 vm_name = _java_getprop('java.vm.name', vm_name)
811 vm_vendor = _java_getprop('java.vm.vendor', vm_vendor)
812 vm_release = _java_getprop('java.vm.version', vm_release)
813 vminfo = vm_name, vm_release, vm_vendor
814 os_name, os_version, os_arch = osinfo
815 os_arch = _java_getprop('java.os.arch', os_arch)
816 os_name = _java_getprop('java.os.name', os_name)
817 os_version = _java_getprop('java.os.version', os_version)
818 osinfo = os_name, os_version, os_arch
Tim Peters0eadaac2003-04-24 16:02:54 +0000819
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000820 return release, vendor, vminfo, osinfo
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000821
822### System name aliasing
823
824def system_alias(system,release,version):
825
826 """ Returns (system,release,version) aliased to common
827 marketing names used for some systems.
828
829 It also does some reordering of the information in some cases
830 where it would otherwise cause confusion.
831
832 """
833 if system == 'Rhapsody':
834 # Apple's BSD derivative
835 # XXX How can we determine the marketing release number ?
836 return 'MacOS X Server',system+release,version
837
838 elif system == 'SunOS':
839 # Sun's OS
840 if release < '5':
841 # These releases use the old name SunOS
842 return system,release,version
843 # Modify release (marketing release = SunOS release - 3)
844 l = string.split(release,'.')
845 if l:
846 try:
847 major = int(l[0])
848 except ValueError:
849 pass
850 else:
851 major = major - 3
852 l[0] = str(major)
853 release = string.join(l,'.')
854 if release < '6':
855 system = 'Solaris'
856 else:
857 # XXX Whatever the new SunOS marketing name is...
858 system = 'Solaris'
859
860 elif system == 'IRIX64':
861 # IRIX reports IRIX64 on platforms with 64-bit support; yet it
862 # is really a version and not a different platform, since 32-bit
863 # apps are also supported..
864 system = 'IRIX'
865 if version:
866 version = version + ' (64bit)'
867 else:
868 version = '64bit'
869
870 elif system in ('win32','win16'):
871 # In case one of the other tricks
872 system = 'Windows'
873
874 return system,release,version
875
876### Various internal helpers
877
878def _platform(*args):
879
880 """ Helper to format the platform string in a filename
881 compatible format e.g. "system-version-machine".
882 """
883 # Format the platform string
884 platform = string.join(
885 map(string.strip,
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000886 filter(len, args)),
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000887 '-')
888
889 # Cleanup some possible filename obstacles...
890 replace = string.replace
891 platform = replace(platform,' ','_')
892 platform = replace(platform,'/','-')
893 platform = replace(platform,'\\','-')
894 platform = replace(platform,':','-')
895 platform = replace(platform,';','-')
896 platform = replace(platform,'"','-')
897 platform = replace(platform,'(','-')
898 platform = replace(platform,')','-')
899
900 # No need to report 'unknown' information...
901 platform = replace(platform,'unknown','')
902
903 # Fold '--'s and remove trailing '-'
904 while 1:
905 cleaned = replace(platform,'--','-')
906 if cleaned == platform:
907 break
908 platform = cleaned
909 while platform[-1] == '-':
910 platform = platform[:-1]
911
912 return platform
913
914def _node(default=''):
915
916 """ Helper to determine the node name of this machine.
917 """
918 try:
919 import socket
920 except ImportError:
921 # No sockets...
922 return default
923 try:
924 return socket.gethostname()
925 except socket.error:
926 # Still not working...
927 return default
928
929# os.path.abspath is new in Python 1.5.2:
930if not hasattr(os.path,'abspath'):
931
932 def _abspath(path,
933
934 isabs=os.path.isabs,join=os.path.join,getcwd=os.getcwd,
935 normpath=os.path.normpath):
936
937 if not isabs(path):
938 path = join(getcwd(), path)
939 return normpath(path)
940
941else:
942
943 _abspath = os.path.abspath
944
945def _follow_symlinks(filepath):
946
947 """ In case filepath is a symlink, follow it until a
948 real file is reached.
949 """
950 filepath = _abspath(filepath)
951 while os.path.islink(filepath):
952 filepath = os.path.normpath(
Hirokazu Yamamoto171c4aa2008-09-04 11:15:14 +0000953 os.path.join(os.path.dirname(filepath),os.readlink(filepath)))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000954 return filepath
955
956def _syscmd_uname(option,default=''):
957
958 """ Interface to the system's uname command.
959 """
960 if sys.platform in ('dos','win32','win16','os2'):
961 # XXX Others too ?
962 return default
963 try:
Marc-André Lemburg19e5b3f2009-07-13 20:23:49 +0000964 f = os.popen('uname %s 2> %s' % (option, DEV_NULL))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000965 except (AttributeError,os.error):
966 return default
967 output = string.strip(f.read())
968 rc = f.close()
969 if not output or rc:
970 return default
971 else:
972 return output
973
974def _syscmd_file(target,default=''):
975
976 """ Interface to the system's file command.
977
978 The function uses the -b option of the file command to have it
979 ommit the filename in its output and if possible the -L option
980 to have the command follow symlinks. It returns default in
981 case the command should fail.
982
983 """
Jesus Ceadebda5d2012-10-04 15:14:56 +0200984
985 # We do the import here to avoid a bootstrap issue.
986 # See c73b90b6dadd changeset.
987 #
988 # [..]
989 # ranlib libpython2.7.a
990 # gcc -o python \
991 # Modules/python.o \
992 # libpython2.7.a -lsocket -lnsl -ldl -lm
993 # Traceback (most recent call last):
994 # File "./setup.py", line 8, in <module>
995 # from platform import machine as platform_machine
996 # File "[..]/build/Lib/platform.py", line 116, in <module>
997 # import sys,string,os,re,subprocess
998 # File "[..]/build/Lib/subprocess.py", line 429, in <module>
999 # import select
1000 # ImportError: No module named select
1001
1002 import subprocess
1003
Hirokazu Yamamotoed8c6442008-09-01 14:32:58 +00001004 if sys.platform in ('dos','win32','win16','os2'):
1005 # XXX Others too ?
1006 return default
Jesus Cea3e94e142012-10-04 15:06:57 +02001007 target = _follow_symlinks(target)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001008 try:
Jesus Cea2699c9d2012-10-05 05:18:47 +02001009 proc = subprocess.Popen(['file', target],
1010 stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
Jesus Cea3e94e142012-10-04 15:06:57 +02001011
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001012 except (AttributeError,os.error):
1013 return default
Jesus Cea69e7c9b2012-10-05 04:50:17 +02001014 output = proc.communicate()[0]
Jesus Cea3e94e142012-10-04 15:06:57 +02001015 rc = proc.wait()
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001016 if not output or rc:
1017 return default
1018 else:
1019 return output
1020
1021### Information about the used architecture
1022
1023# Default values for architecture; non-empty strings override the
1024# defaults given as parameters
1025_default_architecture = {
1026 'win32': ('','WindowsPE'),
1027 'win16': ('','Windows'),
1028 'dos': ('','MSDOS'),
1029}
1030
Victor Stinner814b6c22010-04-18 18:22:25 +00001031_architecture_split = re.compile(r'[\s,]').split
1032
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +00001033def architecture(executable=sys.executable,bits='',linkage=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001034
1035 """ Queries the given executable (defaults to the Python interpreter
Brett Cannon8ab27df2003-08-05 03:52:04 +00001036 binary) for various architecture information.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001037
Brett Cannon8ab27df2003-08-05 03:52:04 +00001038 Returns a tuple (bits,linkage) which contains information about
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001039 the bit architecture and the linkage format used for the
1040 executable. Both values are returned as strings.
1041
1042 Values that cannot be determined are returned as given by the
1043 parameter presets. If bits is given as '', the sizeof(pointer)
1044 (or sizeof(long) on Python version < 1.5.2) is used as
1045 indicator for the supported pointer size.
1046
1047 The function relies on the system's "file" command to do the
1048 actual work. This is available on most if not all Unix
Brett Cannon8ab27df2003-08-05 03:52:04 +00001049 platforms. On some non-Unix platforms where the "file" command
1050 does not exist and the executable is set to the Python interpreter
1051 binary defaults from _default_architecture are used.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001052
1053 """
1054 # Use the sizeof(pointer) as default number of bits if nothing
1055 # else is given as default.
1056 if not bits:
1057 import struct
1058 try:
1059 size = struct.calcsize('P')
1060 except struct.error:
1061 # Older installations can only query longs
1062 size = struct.calcsize('l')
1063 bits = str(size*8) + 'bit'
Tim Peters0eadaac2003-04-24 16:02:54 +00001064
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001065 # Get data from the 'file' system command
Marc-André Lemburg3b8f60b2007-01-13 23:13:54 +00001066 if executable:
Victor Stinner814b6c22010-04-18 18:22:25 +00001067 output = _syscmd_file(executable, '')
Marc-André Lemburg3b8f60b2007-01-13 23:13:54 +00001068 else:
Victor Stinner814b6c22010-04-18 18:22:25 +00001069 output = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001070
Victor Stinner814b6c22010-04-18 18:22:25 +00001071 if not output and \
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001072 executable == sys.executable:
1073 # "file" command did not return anything; we'll try to provide
Tim Peters0eadaac2003-04-24 16:02:54 +00001074 # some sensible defaults then...
Florent Xicluna8d1da0f2010-04-01 18:17:09 +00001075 if sys.platform in _default_architecture:
1076 b, l = _default_architecture[sys.platform]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001077 if b:
1078 bits = b
1079 if l:
1080 linkage = l
Florent Xicluna8d1da0f2010-04-01 18:17:09 +00001081 return bits, linkage
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001082
Victor Stinner814b6c22010-04-18 18:22:25 +00001083 # Split the output into a list of strings omitting the filename
1084 fileout = _architecture_split(output)[1:]
1085
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001086 if 'executable' not in fileout:
1087 # Format not supported
1088 return bits,linkage
1089
1090 # Bits
1091 if '32-bit' in fileout:
1092 bits = '32bit'
1093 elif 'N32' in fileout:
1094 # On Irix only
1095 bits = 'n32bit'
1096 elif '64-bit' in fileout:
1097 bits = '64bit'
1098
1099 # Linkage
1100 if 'ELF' in fileout:
1101 linkage = 'ELF'
1102 elif 'PE' in fileout:
1103 # E.g. Windows uses this format
1104 if 'Windows' in fileout:
1105 linkage = 'WindowsPE'
1106 else:
1107 linkage = 'PE'
1108 elif 'COFF' in fileout:
1109 linkage = 'COFF'
1110 elif 'MS-DOS' in fileout:
1111 linkage = 'MSDOS'
1112 else:
1113 # XXX the A.OUT format also falls under this class...
1114 pass
1115
1116 return bits,linkage
1117
1118### Portable uname() interface
Tim Peters0eadaac2003-04-24 16:02:54 +00001119
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001120_uname_cache = None
1121
1122def uname():
1123
1124 """ Fairly portable uname interface. Returns a tuple
1125 of strings (system,node,release,version,machine,processor)
1126 identifying the underlying platform.
1127
1128 Note that unlike the os.uname function this also returns
Brett Cannon8ab27df2003-08-05 03:52:04 +00001129 possible processor information as an additional tuple entry.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001130
1131 Entries which cannot be determined are set to ''.
1132
1133 """
1134 global _uname_cache
Benjamin Peterson5c0be322008-06-13 15:11:50 +00001135 no_os_uname = 0
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001136
1137 if _uname_cache is not None:
1138 return _uname_cache
1139
Benjamin Peterson5c0be322008-06-13 15:11:50 +00001140 processor = ''
1141
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001142 # Get some infos from the builtin os.uname API...
1143 try:
1144 system,node,release,version,machine = os.uname()
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001145 except AttributeError:
Benjamin Peterson5c0be322008-06-13 15:11:50 +00001146 no_os_uname = 1
1147
1148 if no_os_uname or not filter(None, (system, node, release, version, machine)):
1149 # Hmm, no there is either no uname or uname has returned
1150 #'unknowns'... we'll have to poke around the system then.
1151 if no_os_uname:
1152 system = sys.platform
1153 release = ''
1154 version = ''
1155 node = _node()
1156 machine = ''
1157
Marc-André Lemburgcecaa652009-07-13 21:28:33 +00001158 use_syscmd_ver = 1
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001159
1160 # Try win32_ver() on win32 platforms
1161 if system == 'win32':
1162 release,version,csd,ptype = win32_ver()
1163 if release and version:
1164 use_syscmd_ver = 0
Marc-André Lemburgdbd61a22008-03-20 17:31:36 +00001165 # Try to use the PROCESSOR_* environment variables
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001166 # available on Win XP and later; see
1167 # http://support.microsoft.com/kb/888731 and
1168 # http://www.geocities.com/rick_lively/MANUALS/ENV/MSWIN/PROCESSI.HTM
Benjamin Peterson5c0be322008-06-13 15:11:50 +00001169 if not machine:
R. David Murrayc9d1a782010-03-22 15:55:09 +00001170 # WOW64 processes mask the native architecture
1171 if "PROCESSOR_ARCHITEW6432" in os.environ:
1172 machine = os.environ.get("PROCESSOR_ARCHITEW6432", '')
1173 else:
1174 machine = os.environ.get('PROCESSOR_ARCHITECTURE', '')
Benjamin Peterson5c0be322008-06-13 15:11:50 +00001175 if not processor:
1176 processor = os.environ.get('PROCESSOR_IDENTIFIER', machine)
Tim Peters0eadaac2003-04-24 16:02:54 +00001177
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001178 # Try the 'ver' system command available on some
1179 # platforms
1180 if use_syscmd_ver:
1181 system,release,version = _syscmd_ver(system)
Marc-André Lemburgcdc79232004-06-19 17:17:00 +00001182 # Normalize system to what win32_ver() normally returns
1183 # (_syscmd_ver() tends to return the vendor name as well)
1184 if system == 'Microsoft Windows':
1185 system = 'Windows'
Marc-André Lemburgb24cd0f2007-06-12 09:26:49 +00001186 elif system == 'Microsoft' and release == 'Windows':
1187 # Under Windows Vista and Windows Server 2008,
1188 # Microsoft changed the output of the ver command. The
1189 # release is no longer printed. This causes the
1190 # system and release to be misidentified.
1191 system = 'Windows'
1192 if '6.0' == version[:3]:
1193 release = 'Vista'
1194 else:
1195 release = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001196
1197 # In case we still don't know anything useful, we'll try to
1198 # help ourselves
1199 if system in ('win32','win16'):
1200 if not version:
1201 if system == 'win32':
1202 version = '32bit'
1203 else:
1204 version = '16bit'
1205 system = 'Windows'
1206
1207 elif system[:4] == 'java':
1208 release,vendor,vminfo,osinfo = java_ver()
1209 system = 'Java'
1210 version = string.join(vminfo,', ')
1211 if not version:
1212 version = vendor
1213
Benjamin Peterson5c0be322008-06-13 15:11:50 +00001214 # System specific extensions
1215 if system == 'OpenVMS':
1216 # OpenVMS seems to have release and version mixed up
1217 if not release or release == '0':
1218 release = version
1219 version = ''
1220 # Get processor information
1221 try:
1222 import vms_lib
1223 except ImportError:
1224 pass
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001225 else:
Benjamin Peterson5c0be322008-06-13 15:11:50 +00001226 csid, cpu_number = vms_lib.getsyi('SYI$_CPU',0)
1227 if (cpu_number >= 128):
1228 processor = 'Alpha'
1229 else:
1230 processor = 'VAX'
1231 if not processor:
1232 # Get processor information from the uname system command
1233 processor = _syscmd_uname('-p','')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001234
Benjamin Peterson5c0be322008-06-13 15:11:50 +00001235 #If any unknowns still exist, replace them with ''s, which are more portable
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001236 if system == 'unknown':
1237 system = ''
1238 if node == 'unknown':
1239 node = ''
1240 if release == 'unknown':
1241 release = ''
1242 if version == 'unknown':
1243 version = ''
1244 if machine == 'unknown':
1245 machine = ''
1246 if processor == 'unknown':
1247 processor = ''
Sean Reifscheiderf09597c2007-09-17 20:53:21 +00001248
1249 # normalize name
1250 if system == 'Microsoft' and release == 'Windows':
1251 system = 'Windows'
1252 release = 'Vista'
1253
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001254 _uname_cache = system,node,release,version,machine,processor
1255 return _uname_cache
1256
1257### Direct interfaces to some of the uname() return values
1258
1259def system():
1260
1261 """ Returns the system/OS name, e.g. 'Linux', 'Windows' or 'Java'.
1262
1263 An empty string is returned if the value cannot be determined.
1264
1265 """
1266 return uname()[0]
1267
1268def node():
1269
Brett Cannon8ab27df2003-08-05 03:52:04 +00001270 """ Returns the computer's network name (which may not be fully
1271 qualified)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001272
1273 An empty string is returned if the value cannot be determined.
1274
1275 """
1276 return uname()[1]
1277
1278def release():
1279
1280 """ Returns the system's release, e.g. '2.2.0' or 'NT'
1281
1282 An empty string is returned if the value cannot be determined.
1283
1284 """
1285 return uname()[2]
1286
1287def version():
1288
1289 """ Returns the system's release version, e.g. '#3 on degas'
1290
1291 An empty string is returned if the value cannot be determined.
1292
1293 """
1294 return uname()[3]
1295
1296def machine():
1297
1298 """ Returns the machine type, e.g. 'i386'
1299
1300 An empty string is returned if the value cannot be determined.
1301
1302 """
1303 return uname()[4]
1304
1305def processor():
1306
1307 """ Returns the (true) processor name, e.g. 'amdk6'
1308
1309 An empty string is returned if the value cannot be
1310 determined. Note that many platforms do not provide this
1311 information or simply return the same value as for machine(),
1312 e.g. NetBSD does this.
1313
1314 """
1315 return uname()[5]
1316
1317### Various APIs for extracting information from sys.version
1318
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001319_sys_version_parser = re.compile(
Martin Panterc3636442016-06-08 06:12:22 +00001320 r'([\w.+]+)\s*' # "version<space>"
1321 r'\(#?([^,]+)' # "(#buildno"
1322 r'(?:,\s*([\w ]*)' # ", builddate"
1323 r'(?:,\s*([\w :]*))?)?\)\s*' # ", buildtime)<space>"
1324 r'\[([^\]]+)\]?') # "[compiler]"
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001325
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001326_ironpython_sys_version_parser = re.compile(
1327 r'IronPython\s*'
1328 '([\d\.]+)'
1329 '(?: \(([\d\.]+)\))?'
1330 ' on (.NET [\d\.]+)')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001331
Ezio Melottibc385482013-10-21 03:03:32 +03001332# IronPython covering 2.6 and 2.7
1333_ironpython26_sys_version_parser = re.compile(
1334 r'([\d.]+)\s*'
1335 '\(IronPython\s*'
1336 '[\d.]+\s*'
1337 '\(([\d.]+)\) on ([\w.]+ [\d.]+(?: \(\d+-bit\))?)\)'
1338)
1339
Benjamin Peterson0ad9b772009-03-26 19:09:21 +00001340_pypy_sys_version_parser = re.compile(
1341 r'([\w.+]+)\s*'
1342 '\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*'
1343 '\[PyPy [^\]]+\]?')
1344
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001345_sys_version_cache = {}
1346
1347def _sys_version(sys_version=None):
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001348
1349 """ Returns a parsed version of Python's sys.version as tuple
Marc-André Lemburga519cfc2009-03-25 19:44:58 +00001350 (name, version, branch, revision, buildno, builddate, compiler)
1351 referring to the Python implementation name, version, branch,
1352 revision, build number, build date/time as string and the compiler
1353 identification string.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001354
1355 Note that unlike the Python sys.version, the returned value
1356 for the Python version will always include the patchlevel (it
1357 defaults to '.0').
1358
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001359 The function returns empty strings for tuple entries that
1360 cannot be determined.
1361
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001362 sys_version may be given to parse an alternative version
1363 string, e.g. if the version was read from a different Python
1364 interpreter.
1365
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001366 """
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001367 # Get the Python version
1368 if sys_version is None:
1369 sys_version = sys.version
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001370
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001371 # Try the cache first
1372 result = _sys_version_cache.get(sys_version, None)
1373 if result is not None:
1374 return result
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001375
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001376 # Parse it
Ezio Melottibc385482013-10-21 03:03:32 +03001377 if 'IronPython' in sys_version:
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001378 # IronPython
1379 name = 'IronPython'
Ezio Melottibc385482013-10-21 03:03:32 +03001380 if sys_version.startswith('IronPython'):
1381 match = _ironpython_sys_version_parser.match(sys_version)
1382 else:
1383 match = _ironpython26_sys_version_parser.match(sys_version)
1384
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001385 if match is None:
1386 raise ValueError(
1387 'failed to parse IronPython sys.version: %s' %
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001388 repr(sys_version))
Ezio Melottibc385482013-10-21 03:03:32 +03001389
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001390 version, alt_version, compiler = match.groups()
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001391 buildno = ''
1392 builddate = ''
1393
Ezio Melottibc385482013-10-21 03:03:32 +03001394 elif sys.platform.startswith('java'):
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001395 # Jython
1396 name = 'Jython'
Benjamin Petersonf521b8c2009-03-26 18:35:37 +00001397 match = _sys_version_parser.match(sys_version)
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001398 if match is None:
1399 raise ValueError(
1400 'failed to parse Jython sys.version: %s' %
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001401 repr(sys_version))
Benjamin Petersonf521b8c2009-03-26 18:35:37 +00001402 version, buildno, builddate, buildtime, _ = match.groups()
Martin Panterc3636442016-06-08 06:12:22 +00001403 if builddate is None:
1404 builddate = ''
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001405 compiler = sys.platform
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001406
Benjamin Peterson0ad9b772009-03-26 19:09:21 +00001407 elif "PyPy" in sys_version:
1408 # PyPy
1409 name = "PyPy"
1410 match = _pypy_sys_version_parser.match(sys_version)
1411 if match is None:
1412 raise ValueError("failed to parse PyPy sys.version: %s" %
1413 repr(sys_version))
1414 version, buildno, builddate, buildtime = match.groups()
1415 compiler = ""
1416
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001417 else:
1418 # CPython
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001419 match = _sys_version_parser.match(sys_version)
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001420 if match is None:
1421 raise ValueError(
1422 'failed to parse CPython sys.version: %s' %
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001423 repr(sys_version))
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001424 version, buildno, builddate, buildtime, compiler = \
1425 match.groups()
Benjamin Petersonb457b892009-03-26 18:55:48 +00001426 name = 'CPython'
Martin Panterc3636442016-06-08 06:12:22 +00001427 if builddate is None:
1428 builddate = ''
1429 elif buildtime:
1430 builddate = builddate + ' ' + buildtime
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001431
Benjamin Petersonb457b892009-03-26 18:55:48 +00001432 if hasattr(sys, 'subversion'):
1433 # sys.subversion was added in Python 2.5
1434 _, branch, revision = sys.subversion
1435 else:
1436 branch = ''
1437 revision = ''
1438
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001439 # Add the patchlevel version if missing
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001440 l = string.split(version, '.')
1441 if len(l) == 2:
1442 l.append('0')
1443 version = string.join(l, '.')
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001444
1445 # Build and cache the result
1446 result = (name, version, branch, revision, buildno, builddate, compiler)
1447 _sys_version_cache[sys_version] = result
1448 return result
1449
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001450def python_implementation():
1451
1452 """ Returns a string identifying the Python implementation.
1453
1454 Currently, the following implementations are identified:
Ezio Melotti6fa09472011-05-04 18:37:50 +03001455 'CPython' (C implementation of Python),
1456 'IronPython' (.NET implementation of Python),
1457 'Jython' (Java implementation of Python),
1458 'PyPy' (Python implementation of Python).
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001459
1460 """
1461 return _sys_version()[0]
1462
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001463def python_version():
1464
1465 """ Returns the Python version as string 'major.minor.patchlevel'
1466
1467 Note that unlike the Python sys.version, the returned value
1468 will always include the patchlevel (it defaults to 0).
1469
1470 """
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001471 return _sys_version()[1]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001472
1473def python_version_tuple():
1474
1475 """ Returns the Python version as tuple (major, minor, patchlevel)
1476 of strings.
1477
1478 Note that unlike the Python sys.version, the returned value
1479 will always include the patchlevel (it defaults to 0).
1480
1481 """
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001482 return tuple(string.split(_sys_version()[1], '.'))
1483
1484def python_branch():
1485
Neal Norwitz4b86f8b2007-01-13 21:22:37 +00001486 """ Returns a string identifying the Python implementation
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001487 branch.
1488
1489 For CPython this is the Subversion branch from which the
1490 Python binary was built.
1491
1492 If not available, an empty string is returned.
1493
1494 """
Tim Petersf733abb2007-01-30 03:03:46 +00001495
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001496 return _sys_version()[2]
1497
1498def python_revision():
1499
Neal Norwitz4b86f8b2007-01-13 21:22:37 +00001500 """ Returns a string identifying the Python implementation
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001501 revision.
1502
1503 For CPython this is the Subversion revision from which the
1504 Python binary was built.
1505
1506 If not available, an empty string is returned.
1507
1508 """
1509 return _sys_version()[3]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001510
1511def python_build():
1512
1513 """ Returns a tuple (buildno, builddate) stating the Python
1514 build number and date as strings.
1515
1516 """
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001517 return _sys_version()[4:6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001518
1519def python_compiler():
1520
1521 """ Returns a string identifying the compiler used for compiling
1522 Python.
1523
1524 """
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001525 return _sys_version()[6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001526
1527### The Opus Magnum of platform strings :-)
1528
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001529_platform_cache = {}
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001530
1531def platform(aliased=0, terse=0):
1532
1533 """ Returns a single string identifying the underlying platform
1534 with as much useful information as possible (but no more :).
Tim Peters0eadaac2003-04-24 16:02:54 +00001535
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001536 The output is intended to be human readable rather than
1537 machine parseable. It may look different on different
1538 platforms and this is intended.
1539
1540 If "aliased" is true, the function will use aliases for
1541 various platforms that report system names which differ from
1542 their common names, e.g. SunOS will be reported as
1543 Solaris. The system_alias() function is used to implement
1544 this.
1545
1546 Setting terse to true causes the function to return only the
1547 absolute minimum information needed to identify the platform.
1548
1549 """
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001550 result = _platform_cache.get((aliased, terse), None)
1551 if result is not None:
1552 return result
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001553
1554 # Get uname information and then apply platform specific cosmetics
1555 # to it...
1556 system,node,release,version,machine,processor = uname()
1557 if machine == processor:
1558 processor = ''
1559 if aliased:
1560 system,release,version = system_alias(system,release,version)
1561
1562 if system == 'Windows':
1563 # MS platforms
1564 rel,vers,csd,ptype = win32_ver(version)
1565 if terse:
1566 platform = _platform(system,release)
1567 else:
1568 platform = _platform(system,release,version,csd)
1569
1570 elif system in ('Linux',):
1571 # Linux based systems
1572 distname,distversion,distid = dist('')
1573 if distname and not terse:
1574 platform = _platform(system,release,machine,processor,
1575 'with',
1576 distname,distversion,distid)
1577 else:
1578 # If the distribution name is unknown check for libc vs. glibc
1579 libcname,libcversion = libc_ver(sys.executable)
1580 platform = _platform(system,release,machine,processor,
1581 'with',
1582 libcname+libcversion)
1583 elif system == 'Java':
1584 # Java platforms
1585 r,v,vminfo,(os_name,os_version,os_arch) = java_ver()
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001586 if terse or not os_name:
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001587 platform = _platform(system,release,version)
1588 else:
1589 platform = _platform(system,release,version,
1590 'on',
1591 os_name,os_version,os_arch)
1592
1593 elif system == 'MacOS':
1594 # MacOS platforms
1595 if terse:
1596 platform = _platform(system,release)
1597 else:
1598 platform = _platform(system,release,machine)
1599
1600 else:
1601 # Generic handler
1602 if terse:
1603 platform = _platform(system,release)
1604 else:
1605 bits,linkage = architecture(sys.executable)
1606 platform = _platform(system,release,machine,processor,bits,linkage)
Tim Peters0eadaac2003-04-24 16:02:54 +00001607
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001608 _platform_cache[(aliased, terse)] = platform
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001609 return platform
1610
1611### Command line interface
1612
1613if __name__ == '__main__':
1614 # Default is to print the aliased verbose platform string
Tim Peters0eadaac2003-04-24 16:02:54 +00001615 terse = ('terse' in sys.argv or '--terse' in sys.argv)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001616 aliased = (not 'nonaliased' in sys.argv and not '--nonaliased' in sys.argv)
1617 print platform(aliased,terse)
1618 sys.exit(0)