blob: 37dfbeea92548f49df580ab5e3bcf2bd867f93da [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
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000143def libc_ver(executable=sys.executable,lib='',version='',
144
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000145 chunksize=2048):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000146
Brett Cannon8ab27df2003-08-05 03:52:04 +0000147 """ Tries to determine the libc version that the file executable
148 (which defaults to the Python interpreter) is linked against.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000149
150 Returns a tuple of strings (lib,version) which default to the
151 given parameters in case the lookup fails.
152
153 Note that the function has intimate knowledge of how different
Brett Cannon8ab27df2003-08-05 03:52:04 +0000154 libc versions add symbols to the executable and thus is probably
155 only useable for executables compiled using gcc.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000156
157 The file is read and scanned in chunks of chunksize bytes.
158
159 """
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000160 if hasattr(os.path, 'realpath'):
161 # Python 2.2 introduced os.path.realpath(); it is used
162 # here to work around problems with Cygwin not being
163 # able to open symlinks for reading
164 executable = os.path.realpath(executable)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000165 f = open(executable,'rb')
166 binary = f.read(chunksize)
167 pos = 0
168 while 1:
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000169 m = _libc_search.search(binary,pos)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000170 if not m:
171 binary = f.read(chunksize)
172 if not binary:
173 break
174 pos = 0
175 continue
176 libcinit,glibc,glibcversion,so,threads,soversion = m.groups()
177 if libcinit and not lib:
178 lib = 'libc'
179 elif glibc:
180 if lib != 'glibc':
181 lib = 'glibc'
182 version = glibcversion
183 elif glibcversion > version:
184 version = glibcversion
185 elif so:
186 if lib != 'glibc':
187 lib = 'libc'
Victor Stinner429a12b2011-12-15 21:42:03 +0100188 if soversion and soversion > version:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000189 version = soversion
190 if threads and version[-len(threads):] != threads:
191 version = version + threads
192 pos = m.end()
193 f.close()
194 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
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000454def _norm_version(version, build=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000455
Brett Cannon8ab27df2003-08-05 03:52:04 +0000456 """ Normalize the version and build strings and return a single
Walter Dörwalde5a7fad2005-11-21 17:01:27 +0000457 version string using the format major.minor.build (or patchlevel).
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000458 """
459 l = string.split(version,'.')
460 if build:
461 l.append(build)
462 try:
463 ints = map(int,l)
464 except ValueError:
465 strings = l
466 else:
467 strings = map(str,ints)
468 version = string.join(strings[:3],'.')
469 return version
470
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000471_ver_output = re.compile(r'(?:([\w ]+) ([\w.]+) '
472 '.*'
Marc-André Lemburgcecaa652009-07-13 21:28:33 +0000473 '\[.* ([\d.]+)\])')
474
475# Examples of VER command output:
476#
477# Windows 2000: Microsoft Windows 2000 [Version 5.00.2195]
478# Windows XP: Microsoft Windows XP [Version 5.1.2600]
479# Windows Vista: Microsoft Windows [Version 6.0.6002]
480#
481# Note that the "Version" string gets localized on different
482# Windows versions.
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000483
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000484def _syscmd_ver(system='', release='', version='',
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000485
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000486 supported_platforms=('win32','win16','dos','os2')):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000487
488 """ Tries to figure out the OS version used and returns
489 a tuple (system,release,version).
Tim Peters0eadaac2003-04-24 16:02:54 +0000490
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000491 It uses the "ver" shell command for this which is known
492 to exists on Windows, DOS and OS/2. XXX Others too ?
493
494 In case this fails, the given parameters are used as
495 defaults.
496
497 """
498 if sys.platform not in supported_platforms:
499 return system,release,version
500
501 # Try some common cmd strings
502 for cmd in ('ver','command /c ver','cmd /c ver'):
503 try:
504 pipe = popen(cmd)
505 info = pipe.read()
506 if pipe.close():
507 raise os.error,'command failed'
Ezio Melottic2077b02011-03-16 12:34:31 +0200508 # XXX How can I suppress shell errors from being written
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000509 # to stderr ?
510 except os.error,why:
511 #print 'Command %s failed: %s' % (cmd,why)
512 continue
513 except IOError,why:
514 #print 'Command %s failed: %s' % (cmd,why)
515 continue
516 else:
517 break
518 else:
519 return system,release,version
520
521 # Parse the output
522 info = string.strip(info)
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000523 m = _ver_output.match(info)
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000524 if m is not None:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000525 system,release,version = m.groups()
526 # Strip trailing dots from version and release
527 if release[-1] == '.':
528 release = release[:-1]
529 if version[-1] == '.':
530 version = version[:-1]
531 # Normalize the version and build strings (eliminating additional
532 # zeros)
533 version = _norm_version(version)
534 return system,release,version
535
Steve Dower044cde52015-09-22 17:25:30 -0700536_WIN32_CLIENT_RELEASES = {
537 (5, 0): "2000",
538 (5, 1): "XP",
539 # Strictly, 5.2 client is XP 64-bit, but platform.py historically
540 # has always called it 2003 Server
541 (5, 2): "2003Server",
542 (5, None): "post2003",
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000543
Steve Dower044cde52015-09-22 17:25:30 -0700544 (6, 0): "Vista",
545 (6, 1): "7",
546 (6, 2): "8",
547 (6, 3): "8.1",
548 (6, None): "post8.1",
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000549
Steve Dower044cde52015-09-22 17:25:30 -0700550 (10, 0): "10",
551 (10, None): "post10",
552}
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000553
Steve Dower044cde52015-09-22 17:25:30 -0700554# Server release name lookup will default to client names if necessary
555_WIN32_SERVER_RELEASES = {
556 (5, 2): "2003Server",
557
558 (6, 0): "2008Server",
559 (6, 1): "2008ServerR2",
560 (6, 2): "2012Server",
561 (6, 3): "2012ServerR2",
562 (6, None): "post2012ServerR2",
563}
564
565def _get_real_winver(maj, min, build):
566 if maj < 6 or (maj == 6 and min < 2):
567 return maj, min, build
568
569 from ctypes import (c_buffer, POINTER, byref, create_unicode_buffer,
Steve Dowerdb01b3e2016-09-17 16:43:01 -0700570 Structure, WinDLL, _Pointer)
Steve Dower044cde52015-09-22 17:25:30 -0700571 from ctypes.wintypes import DWORD, HANDLE
572
573 class VS_FIXEDFILEINFO(Structure):
574 _fields_ = [
575 ("dwSignature", DWORD),
576 ("dwStrucVersion", DWORD),
577 ("dwFileVersionMS", DWORD),
578 ("dwFileVersionLS", DWORD),
579 ("dwProductVersionMS", DWORD),
580 ("dwProductVersionLS", DWORD),
581 ("dwFileFlagsMask", DWORD),
582 ("dwFileFlags", DWORD),
583 ("dwFileOS", DWORD),
584 ("dwFileType", DWORD),
585 ("dwFileSubtype", DWORD),
586 ("dwFileDateMS", DWORD),
587 ("dwFileDateLS", DWORD),
588 ]
Steve Dowerdb01b3e2016-09-17 16:43:01 -0700589 class PVS_FIXEDFILEINFO(_Pointer):
590 _type_ = VS_FIXEDFILEINFO
Steve Dower044cde52015-09-22 17:25:30 -0700591
592 kernel32 = WinDLL('kernel32')
593 version = WinDLL('version')
594
595 # We will immediately double the length up to MAX_PATH, but the
596 # path may be longer, so we retry until the returned string is
597 # shorter than our buffer.
598 name_len = actual_len = 130
599 while actual_len == name_len:
600 name_len *= 2
601 name = create_unicode_buffer(name_len)
602 actual_len = kernel32.GetModuleFileNameW(HANDLE(kernel32._handle),
603 name, len(name))
604 if not actual_len:
605 return maj, min, build
606
607 size = version.GetFileVersionInfoSizeW(name, None)
608 if not size:
609 return maj, min, build
610
611 ver_block = c_buffer(size)
612 if (not version.GetFileVersionInfoW(name, None, size, ver_block) or
613 not ver_block):
614 return maj, min, build
615
Steve Dowerdb01b3e2016-09-17 16:43:01 -0700616 pvi = PVS_FIXEDFILEINFO()
Steve Dower044cde52015-09-22 17:25:30 -0700617 if not version.VerQueryValueW(ver_block, "", byref(pvi), byref(DWORD())):
618 return maj, min, build
619
620 maj = pvi.contents.dwProductVersionMS >> 16
621 min = pvi.contents.dwProductVersionMS & 0xFFFF
622 build = pvi.contents.dwProductVersionLS >> 16
623
624 return maj, min, build
625
626def win32_ver(release='', version='', csd='', ptype=''):
Steve Dowere20c2a62015-09-22 17:35:24 -0700627 try:
628 from sys import getwindowsversion
629 except ImportError:
630 return release, version, csd, ptype
Marc-André Lemburgdbd61a22008-03-20 17:31:36 +0000631 try:
Steve Dower044cde52015-09-22 17:25:30 -0700632 from winreg import OpenKeyEx, QueryValueEx, CloseKey, HKEY_LOCAL_MACHINE
Marc-André Lemburgdbd61a22008-03-20 17:31:36 +0000633 except ImportError:
Steve Dower044cde52015-09-22 17:25:30 -0700634 from _winreg import OpenKeyEx, QueryValueEx, CloseKey, HKEY_LOCAL_MACHINE
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000635
Steve Dower044cde52015-09-22 17:25:30 -0700636 winver = getwindowsversion()
637 maj, min, build = _get_real_winver(*winver[:3])
638 version = '{0}.{1}.{2}'.format(maj, min, build)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000639
Steve Dower044cde52015-09-22 17:25:30 -0700640 release = (_WIN32_CLIENT_RELEASES.get((maj, min)) or
641 _WIN32_CLIENT_RELEASES.get((maj, None)) or
642 release)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000643
Steve Dower044cde52015-09-22 17:25:30 -0700644 # getwindowsversion() reflect the compatibility mode Python is
645 # running under, and so the service pack value is only going to be
646 # valid if the versions match.
647 if winver[:2] == (maj, min):
Marc-André Lemburgdbd61a22008-03-20 17:31:36 +0000648 try:
Steve Dower044cde52015-09-22 17:25:30 -0700649 csd = 'SP{}'.format(winver.service_pack_major)
Marc-André Lemburgdbd61a22008-03-20 17:31:36 +0000650 except AttributeError:
Steve Dower044cde52015-09-22 17:25:30 -0700651 if csd[:13] == 'Service Pack ':
652 csd = 'SP' + csd[13:]
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000653
Steve Dower044cde52015-09-22 17:25:30 -0700654 # VER_NT_SERVER = 3
Steve Dowerdeb1a902016-03-12 08:07:04 -0800655 if getattr(winver, 'product', None) == 3:
Steve Dower044cde52015-09-22 17:25:30 -0700656 release = (_WIN32_SERVER_RELEASES.get((maj, min)) or
657 _WIN32_SERVER_RELEASES.get((maj, None)) or
658 release)
Marc-André Lemburgcecaa652009-07-13 21:28:33 +0000659
Steve Dower044cde52015-09-22 17:25:30 -0700660 key = None
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000661 try:
Steve Dower044cde52015-09-22 17:25:30 -0700662 key = OpenKeyEx(HKEY_LOCAL_MACHINE,
663 r'SOFTWARE\Microsoft\Windows NT\CurrentVersion')
664 ptype = QueryValueEx(key, 'CurrentType')[0]
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000665 except:
Steve Dower044cde52015-09-22 17:25:30 -0700666 pass
667 finally:
668 if key:
669 CloseKey(key)
Tim Peters0eadaac2003-04-24 16:02:54 +0000670
Steve Dower044cde52015-09-22 17:25:30 -0700671 return release, version, csd, ptype
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000672
673def _mac_ver_lookup(selectors,default=None):
674
675 from gestalt import gestalt
Jack Jansena290e3d2003-08-11 11:08:49 +0000676 import MacOS
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000677 l = []
678 append = l.append
679 for selector in selectors:
680 try:
681 append(gestalt(selector))
Jack Jansena290e3d2003-08-11 11:08:49 +0000682 except (RuntimeError, MacOS.Error):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000683 append(default)
684 return l
685
686def _bcd2str(bcd):
687
688 return hex(bcd)[2:]
689
Ronald Oussoren3a04a252010-07-23 12:41:00 +0000690def _mac_ver_gestalt():
691 """
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000692 Thanks to Mark R. Levinson for mailing documentation links and
693 code examples for this function. Documentation for the
694 gestalt() API is available online at:
695
696 http://www.rgaros.nl/gestalt/
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000697 """
698 # Check whether the version info module is available
699 try:
700 import gestalt
Jack Jansena290e3d2003-08-11 11:08:49 +0000701 import MacOS
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000702 except ImportError:
Ronald Oussoren3a04a252010-07-23 12:41:00 +0000703 return None
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000704 # Get the infos
Ronald Oussoren9341ad22010-02-07 11:29:31 +0000705 sysv,sysa = _mac_ver_lookup(('sysv','sysa'))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000706 # Decode the infos
707 if sysv:
708 major = (sysv & 0xFF00) >> 8
709 minor = (sysv & 0x00F0) >> 4
710 patch = (sysv & 0x000F)
Ronald Oussorenc27b8b82008-05-08 10:34:39 +0000711
712 if (major, minor) >= (10, 4):
713 # the 'sysv' gestald cannot return patchlevels
714 # higher than 9. Apple introduced 3 new
715 # gestalt codes in 10.4 to deal with this
716 # issue (needed because patch levels can
717 # run higher than 9, such as 10.4.11)
718 major,minor,patch = _mac_ver_lookup(('sys1','sys2','sys3'))
719 release = '%i.%i.%i' %(major, minor, patch)
720 else:
721 release = '%s.%i.%i' % (_bcd2str(major),minor,patch)
Ronald Oussoren7a0f4c72008-05-18 20:54:47 +0000722
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000723 if sysa:
Tim Peters0eadaac2003-04-24 16:02:54 +0000724 machine = {0x1: '68k',
Ronald Oussoren749d0702006-04-17 13:37:15 +0000725 0x2: 'PowerPC',
726 0xa: 'i386'}.get(sysa,'')
Ronald Oussoren3a04a252010-07-23 12:41:00 +0000727
Ned Deily0ab67ee2011-07-13 15:05:31 -0700728 versioninfo=('', '', '')
Ronald Oussoren3a04a252010-07-23 12:41:00 +0000729 return release,versioninfo,machine
730
731def _mac_ver_xml():
732 fn = '/System/Library/CoreServices/SystemVersion.plist'
733 if not os.path.exists(fn):
734 return None
735
736 try:
737 import plistlib
738 except ImportError:
739 return None
740
741 pl = plistlib.readPlist(fn)
742 release = pl['ProductVersion']
743 versioninfo=('', '', '')
744 machine = os.uname()[4]
Ronald Oussoren22e3e692010-08-03 07:44:35 +0000745 if machine in ('ppc', 'Power Macintosh'):
Ronald Oussoren3a04a252010-07-23 12:41:00 +0000746 # for compatibility with the gestalt based code
747 machine = 'PowerPC'
748
749 return release,versioninfo,machine
750
751
752def mac_ver(release='',versioninfo=('','',''),machine=''):
753
754 """ Get MacOS version information and return it as tuple (release,
755 versioninfo, machine) with versioninfo being a tuple (version,
756 dev_stage, non_release_version).
757
Ezio Melottif5469cf2013-08-17 15:43:51 +0300758 Entries which cannot be determined are set to the parameter values
Ronald Oussoren3a04a252010-07-23 12:41:00 +0000759 which default to ''. All tuple entries are strings.
760 """
761
762 # First try reading the information from an XML file which should
763 # always be present
764 info = _mac_ver_xml()
765 if info is not None:
766 return info
767
768 # If that doesn't work for some reason fall back to reading the
769 # information using gestalt calls.
770 info = _mac_ver_gestalt()
771 if info is not None:
772 return info
773
774 # If that also doesn't work return the default values
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000775 return release,versioninfo,machine
776
Neal Norwitz9b924c62003-06-29 04:17:45 +0000777def _java_getprop(name,default):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000778
779 from java.lang import System
780 try:
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000781 value = System.getProperty(name)
782 if value is None:
783 return default
784 return value
785 except AttributeError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000786 return default
787
788def java_ver(release='',vendor='',vminfo=('','',''),osinfo=('','','')):
Tim Peters0eadaac2003-04-24 16:02:54 +0000789
Brett Cannon8ab27df2003-08-05 03:52:04 +0000790 """ Version interface for Jython.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000791
792 Returns a tuple (release,vendor,vminfo,osinfo) with vminfo being
793 a tuple (vm_name,vm_release,vm_vendor) and osinfo being a
794 tuple (os_name,os_version,os_arch).
795
796 Values which cannot be determined are set to the defaults
797 given as parameters (which all default to '').
798
799 """
800 # Import the needed APIs
801 try:
802 import java.lang
803 except ImportError:
804 return release,vendor,vminfo,osinfo
805
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000806 vendor = _java_getprop('java.vendor', vendor)
807 release = _java_getprop('java.version', release)
808 vm_name, vm_release, vm_vendor = vminfo
809 vm_name = _java_getprop('java.vm.name', vm_name)
810 vm_vendor = _java_getprop('java.vm.vendor', vm_vendor)
811 vm_release = _java_getprop('java.vm.version', vm_release)
812 vminfo = vm_name, vm_release, vm_vendor
813 os_name, os_version, os_arch = osinfo
814 os_arch = _java_getprop('java.os.arch', os_arch)
815 os_name = _java_getprop('java.os.name', os_name)
816 os_version = _java_getprop('java.os.version', os_version)
817 osinfo = os_name, os_version, os_arch
Tim Peters0eadaac2003-04-24 16:02:54 +0000818
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000819 return release, vendor, vminfo, osinfo
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000820
821### System name aliasing
822
823def system_alias(system,release,version):
824
825 """ Returns (system,release,version) aliased to common
826 marketing names used for some systems.
827
828 It also does some reordering of the information in some cases
829 where it would otherwise cause confusion.
830
831 """
832 if system == 'Rhapsody':
833 # Apple's BSD derivative
834 # XXX How can we determine the marketing release number ?
835 return 'MacOS X Server',system+release,version
836
837 elif system == 'SunOS':
838 # Sun's OS
839 if release < '5':
840 # These releases use the old name SunOS
841 return system,release,version
842 # Modify release (marketing release = SunOS release - 3)
843 l = string.split(release,'.')
844 if l:
845 try:
846 major = int(l[0])
847 except ValueError:
848 pass
849 else:
850 major = major - 3
851 l[0] = str(major)
852 release = string.join(l,'.')
853 if release < '6':
854 system = 'Solaris'
855 else:
856 # XXX Whatever the new SunOS marketing name is...
857 system = 'Solaris'
858
859 elif system == 'IRIX64':
860 # IRIX reports IRIX64 on platforms with 64-bit support; yet it
861 # is really a version and not a different platform, since 32-bit
862 # apps are also supported..
863 system = 'IRIX'
864 if version:
865 version = version + ' (64bit)'
866 else:
867 version = '64bit'
868
869 elif system in ('win32','win16'):
870 # In case one of the other tricks
871 system = 'Windows'
872
873 return system,release,version
874
875### Various internal helpers
876
877def _platform(*args):
878
879 """ Helper to format the platform string in a filename
880 compatible format e.g. "system-version-machine".
881 """
882 # Format the platform string
883 platform = string.join(
884 map(string.strip,
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000885 filter(len, args)),
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000886 '-')
887
888 # Cleanup some possible filename obstacles...
889 replace = string.replace
890 platform = replace(platform,' ','_')
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
899 # No need to report 'unknown' information...
900 platform = replace(platform,'unknown','')
901
902 # Fold '--'s and remove trailing '-'
903 while 1:
904 cleaned = replace(platform,'--','-')
905 if cleaned == platform:
906 break
907 platform = cleaned
908 while platform[-1] == '-':
909 platform = platform[:-1]
910
911 return platform
912
913def _node(default=''):
914
915 """ Helper to determine the node name of this machine.
916 """
917 try:
918 import socket
919 except ImportError:
920 # No sockets...
921 return default
922 try:
923 return socket.gethostname()
924 except socket.error:
925 # Still not working...
926 return default
927
928# os.path.abspath is new in Python 1.5.2:
929if not hasattr(os.path,'abspath'):
930
931 def _abspath(path,
932
933 isabs=os.path.isabs,join=os.path.join,getcwd=os.getcwd,
934 normpath=os.path.normpath):
935
936 if not isabs(path):
937 path = join(getcwd(), path)
938 return normpath(path)
939
940else:
941
942 _abspath = os.path.abspath
943
944def _follow_symlinks(filepath):
945
946 """ In case filepath is a symlink, follow it until a
947 real file is reached.
948 """
949 filepath = _abspath(filepath)
950 while os.path.islink(filepath):
951 filepath = os.path.normpath(
Hirokazu Yamamoto171c4aa2008-09-04 11:15:14 +0000952 os.path.join(os.path.dirname(filepath),os.readlink(filepath)))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000953 return filepath
954
955def _syscmd_uname(option,default=''):
956
957 """ Interface to the system's uname command.
958 """
959 if sys.platform in ('dos','win32','win16','os2'):
960 # XXX Others too ?
961 return default
962 try:
Marc-André Lemburg19e5b3f2009-07-13 20:23:49 +0000963 f = os.popen('uname %s 2> %s' % (option, DEV_NULL))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000964 except (AttributeError,os.error):
965 return default
966 output = string.strip(f.read())
967 rc = f.close()
968 if not output or rc:
969 return default
970 else:
971 return output
972
973def _syscmd_file(target,default=''):
974
975 """ Interface to the system's file command.
976
977 The function uses the -b option of the file command to have it
978 ommit the filename in its output and if possible the -L option
979 to have the command follow symlinks. It returns default in
980 case the command should fail.
981
982 """
Jesus Ceadebda5d2012-10-04 15:14:56 +0200983
984 # We do the import here to avoid a bootstrap issue.
985 # See c73b90b6dadd changeset.
986 #
987 # [..]
988 # ranlib libpython2.7.a
989 # gcc -o python \
990 # Modules/python.o \
991 # libpython2.7.a -lsocket -lnsl -ldl -lm
992 # Traceback (most recent call last):
993 # File "./setup.py", line 8, in <module>
994 # from platform import machine as platform_machine
995 # File "[..]/build/Lib/platform.py", line 116, in <module>
996 # import sys,string,os,re,subprocess
997 # File "[..]/build/Lib/subprocess.py", line 429, in <module>
998 # import select
999 # ImportError: No module named select
1000
1001 import subprocess
1002
Hirokazu Yamamotoed8c6442008-09-01 14:32:58 +00001003 if sys.platform in ('dos','win32','win16','os2'):
1004 # XXX Others too ?
1005 return default
Jesus Cea3e94e142012-10-04 15:06:57 +02001006 target = _follow_symlinks(target)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001007 try:
Jesus Cea2699c9d2012-10-05 05:18:47 +02001008 proc = subprocess.Popen(['file', target],
1009 stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
Jesus Cea3e94e142012-10-04 15:06:57 +02001010
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001011 except (AttributeError,os.error):
1012 return default
Jesus Cea69e7c9b2012-10-05 04:50:17 +02001013 output = proc.communicate()[0]
Jesus Cea3e94e142012-10-04 15:06:57 +02001014 rc = proc.wait()
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001015 if not output or rc:
1016 return default
1017 else:
1018 return output
1019
1020### Information about the used architecture
1021
1022# Default values for architecture; non-empty strings override the
1023# defaults given as parameters
1024_default_architecture = {
1025 'win32': ('','WindowsPE'),
1026 'win16': ('','Windows'),
1027 'dos': ('','MSDOS'),
1028}
1029
Victor Stinner814b6c22010-04-18 18:22:25 +00001030_architecture_split = re.compile(r'[\s,]').split
1031
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +00001032def architecture(executable=sys.executable,bits='',linkage=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001033
1034 """ Queries the given executable (defaults to the Python interpreter
Brett Cannon8ab27df2003-08-05 03:52:04 +00001035 binary) for various architecture information.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001036
Brett Cannon8ab27df2003-08-05 03:52:04 +00001037 Returns a tuple (bits,linkage) which contains information about
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001038 the bit architecture and the linkage format used for the
1039 executable. Both values are returned as strings.
1040
1041 Values that cannot be determined are returned as given by the
1042 parameter presets. If bits is given as '', the sizeof(pointer)
1043 (or sizeof(long) on Python version < 1.5.2) is used as
1044 indicator for the supported pointer size.
1045
1046 The function relies on the system's "file" command to do the
1047 actual work. This is available on most if not all Unix
Brett Cannon8ab27df2003-08-05 03:52:04 +00001048 platforms. On some non-Unix platforms where the "file" command
1049 does not exist and the executable is set to the Python interpreter
1050 binary defaults from _default_architecture are used.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001051
1052 """
1053 # Use the sizeof(pointer) as default number of bits if nothing
1054 # else is given as default.
1055 if not bits:
1056 import struct
1057 try:
1058 size = struct.calcsize('P')
1059 except struct.error:
1060 # Older installations can only query longs
1061 size = struct.calcsize('l')
1062 bits = str(size*8) + 'bit'
Tim Peters0eadaac2003-04-24 16:02:54 +00001063
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001064 # Get data from the 'file' system command
Marc-André Lemburg3b8f60b2007-01-13 23:13:54 +00001065 if executable:
Victor Stinner814b6c22010-04-18 18:22:25 +00001066 output = _syscmd_file(executable, '')
Marc-André Lemburg3b8f60b2007-01-13 23:13:54 +00001067 else:
Victor Stinner814b6c22010-04-18 18:22:25 +00001068 output = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001069
Victor Stinner814b6c22010-04-18 18:22:25 +00001070 if not output and \
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001071 executable == sys.executable:
1072 # "file" command did not return anything; we'll try to provide
Tim Peters0eadaac2003-04-24 16:02:54 +00001073 # some sensible defaults then...
Florent Xicluna8d1da0f2010-04-01 18:17:09 +00001074 if sys.platform in _default_architecture:
1075 b, l = _default_architecture[sys.platform]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001076 if b:
1077 bits = b
1078 if l:
1079 linkage = l
Florent Xicluna8d1da0f2010-04-01 18:17:09 +00001080 return bits, linkage
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001081
Victor Stinner814b6c22010-04-18 18:22:25 +00001082 # Split the output into a list of strings omitting the filename
1083 fileout = _architecture_split(output)[1:]
1084
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001085 if 'executable' not in fileout:
1086 # Format not supported
1087 return bits,linkage
1088
1089 # Bits
1090 if '32-bit' in fileout:
1091 bits = '32bit'
1092 elif 'N32' in fileout:
1093 # On Irix only
1094 bits = 'n32bit'
1095 elif '64-bit' in fileout:
1096 bits = '64bit'
1097
1098 # Linkage
1099 if 'ELF' in fileout:
1100 linkage = 'ELF'
1101 elif 'PE' in fileout:
1102 # E.g. Windows uses this format
1103 if 'Windows' in fileout:
1104 linkage = 'WindowsPE'
1105 else:
1106 linkage = 'PE'
1107 elif 'COFF' in fileout:
1108 linkage = 'COFF'
1109 elif 'MS-DOS' in fileout:
1110 linkage = 'MSDOS'
1111 else:
1112 # XXX the A.OUT format also falls under this class...
1113 pass
1114
1115 return bits,linkage
1116
1117### Portable uname() interface
Tim Peters0eadaac2003-04-24 16:02:54 +00001118
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001119_uname_cache = None
1120
1121def uname():
1122
1123 """ Fairly portable uname interface. Returns a tuple
1124 of strings (system,node,release,version,machine,processor)
1125 identifying the underlying platform.
1126
1127 Note that unlike the os.uname function this also returns
Brett Cannon8ab27df2003-08-05 03:52:04 +00001128 possible processor information as an additional tuple entry.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001129
1130 Entries which cannot be determined are set to ''.
1131
1132 """
1133 global _uname_cache
Benjamin Peterson5c0be322008-06-13 15:11:50 +00001134 no_os_uname = 0
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001135
1136 if _uname_cache is not None:
1137 return _uname_cache
1138
Benjamin Peterson5c0be322008-06-13 15:11:50 +00001139 processor = ''
1140
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001141 # Get some infos from the builtin os.uname API...
1142 try:
1143 system,node,release,version,machine = os.uname()
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001144 except AttributeError:
Benjamin Peterson5c0be322008-06-13 15:11:50 +00001145 no_os_uname = 1
1146
1147 if no_os_uname or not filter(None, (system, node, release, version, machine)):
1148 # Hmm, no there is either no uname or uname has returned
1149 #'unknowns'... we'll have to poke around the system then.
1150 if no_os_uname:
1151 system = sys.platform
1152 release = ''
1153 version = ''
1154 node = _node()
1155 machine = ''
1156
Marc-André Lemburgcecaa652009-07-13 21:28:33 +00001157 use_syscmd_ver = 1
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001158
1159 # Try win32_ver() on win32 platforms
1160 if system == 'win32':
1161 release,version,csd,ptype = win32_ver()
1162 if release and version:
1163 use_syscmd_ver = 0
Marc-André Lemburgdbd61a22008-03-20 17:31:36 +00001164 # Try to use the PROCESSOR_* environment variables
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001165 # available on Win XP and later; see
1166 # http://support.microsoft.com/kb/888731 and
1167 # http://www.geocities.com/rick_lively/MANUALS/ENV/MSWIN/PROCESSI.HTM
Benjamin Peterson5c0be322008-06-13 15:11:50 +00001168 if not machine:
R. David Murrayc9d1a782010-03-22 15:55:09 +00001169 # WOW64 processes mask the native architecture
1170 if "PROCESSOR_ARCHITEW6432" in os.environ:
1171 machine = os.environ.get("PROCESSOR_ARCHITEW6432", '')
1172 else:
1173 machine = os.environ.get('PROCESSOR_ARCHITECTURE', '')
Benjamin Peterson5c0be322008-06-13 15:11:50 +00001174 if not processor:
1175 processor = os.environ.get('PROCESSOR_IDENTIFIER', machine)
Tim Peters0eadaac2003-04-24 16:02:54 +00001176
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001177 # Try the 'ver' system command available on some
1178 # platforms
1179 if use_syscmd_ver:
1180 system,release,version = _syscmd_ver(system)
Marc-André Lemburgcdc79232004-06-19 17:17:00 +00001181 # Normalize system to what win32_ver() normally returns
1182 # (_syscmd_ver() tends to return the vendor name as well)
1183 if system == 'Microsoft Windows':
1184 system = 'Windows'
Marc-André Lemburgb24cd0f2007-06-12 09:26:49 +00001185 elif system == 'Microsoft' and release == 'Windows':
1186 # Under Windows Vista and Windows Server 2008,
1187 # Microsoft changed the output of the ver command. The
1188 # release is no longer printed. This causes the
1189 # system and release to be misidentified.
1190 system = 'Windows'
1191 if '6.0' == version[:3]:
1192 release = 'Vista'
1193 else:
1194 release = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001195
1196 # In case we still don't know anything useful, we'll try to
1197 # help ourselves
1198 if system in ('win32','win16'):
1199 if not version:
1200 if system == 'win32':
1201 version = '32bit'
1202 else:
1203 version = '16bit'
1204 system = 'Windows'
1205
1206 elif system[:4] == 'java':
1207 release,vendor,vminfo,osinfo = java_ver()
1208 system = 'Java'
1209 version = string.join(vminfo,', ')
1210 if not version:
1211 version = vendor
1212
Benjamin Peterson5c0be322008-06-13 15:11:50 +00001213 # System specific extensions
1214 if system == 'OpenVMS':
1215 # OpenVMS seems to have release and version mixed up
1216 if not release or release == '0':
1217 release = version
1218 version = ''
1219 # Get processor information
1220 try:
1221 import vms_lib
1222 except ImportError:
1223 pass
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001224 else:
Benjamin Peterson5c0be322008-06-13 15:11:50 +00001225 csid, cpu_number = vms_lib.getsyi('SYI$_CPU',0)
1226 if (cpu_number >= 128):
1227 processor = 'Alpha'
1228 else:
1229 processor = 'VAX'
1230 if not processor:
1231 # Get processor information from the uname system command
1232 processor = _syscmd_uname('-p','')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001233
Benjamin Peterson5c0be322008-06-13 15:11:50 +00001234 #If any unknowns still exist, replace them with ''s, which are more portable
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001235 if system == 'unknown':
1236 system = ''
1237 if node == 'unknown':
1238 node = ''
1239 if release == 'unknown':
1240 release = ''
1241 if version == 'unknown':
1242 version = ''
1243 if machine == 'unknown':
1244 machine = ''
1245 if processor == 'unknown':
1246 processor = ''
Sean Reifscheiderf09597c2007-09-17 20:53:21 +00001247
1248 # normalize name
1249 if system == 'Microsoft' and release == 'Windows':
1250 system = 'Windows'
1251 release = 'Vista'
1252
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001253 _uname_cache = system,node,release,version,machine,processor
1254 return _uname_cache
1255
1256### Direct interfaces to some of the uname() return values
1257
1258def system():
1259
1260 """ Returns the system/OS name, e.g. 'Linux', 'Windows' or 'Java'.
1261
1262 An empty string is returned if the value cannot be determined.
1263
1264 """
1265 return uname()[0]
1266
1267def node():
1268
Brett Cannon8ab27df2003-08-05 03:52:04 +00001269 """ Returns the computer's network name (which may not be fully
1270 qualified)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001271
1272 An empty string is returned if the value cannot be determined.
1273
1274 """
1275 return uname()[1]
1276
1277def release():
1278
1279 """ Returns the system's release, e.g. '2.2.0' or 'NT'
1280
1281 An empty string is returned if the value cannot be determined.
1282
1283 """
1284 return uname()[2]
1285
1286def version():
1287
1288 """ Returns the system's release version, e.g. '#3 on degas'
1289
1290 An empty string is returned if the value cannot be determined.
1291
1292 """
1293 return uname()[3]
1294
1295def machine():
1296
1297 """ Returns the machine type, e.g. 'i386'
1298
1299 An empty string is returned if the value cannot be determined.
1300
1301 """
1302 return uname()[4]
1303
1304def processor():
1305
1306 """ Returns the (true) processor name, e.g. 'amdk6'
1307
1308 An empty string is returned if the value cannot be
1309 determined. Note that many platforms do not provide this
1310 information or simply return the same value as for machine(),
1311 e.g. NetBSD does this.
1312
1313 """
1314 return uname()[5]
1315
1316### Various APIs for extracting information from sys.version
1317
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001318_sys_version_parser = re.compile(
Martin Panterc3636442016-06-08 06:12:22 +00001319 r'([\w.+]+)\s*' # "version<space>"
1320 r'\(#?([^,]+)' # "(#buildno"
1321 r'(?:,\s*([\w ]*)' # ", builddate"
1322 r'(?:,\s*([\w :]*))?)?\)\s*' # ", buildtime)<space>"
1323 r'\[([^\]]+)\]?') # "[compiler]"
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001324
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001325_ironpython_sys_version_parser = re.compile(
1326 r'IronPython\s*'
1327 '([\d\.]+)'
1328 '(?: \(([\d\.]+)\))?'
1329 ' on (.NET [\d\.]+)')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001330
Ezio Melottibc385482013-10-21 03:03:32 +03001331# IronPython covering 2.6 and 2.7
1332_ironpython26_sys_version_parser = re.compile(
1333 r'([\d.]+)\s*'
1334 '\(IronPython\s*'
1335 '[\d.]+\s*'
1336 '\(([\d.]+)\) on ([\w.]+ [\d.]+(?: \(\d+-bit\))?)\)'
1337)
1338
Benjamin Peterson0ad9b772009-03-26 19:09:21 +00001339_pypy_sys_version_parser = re.compile(
1340 r'([\w.+]+)\s*'
1341 '\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*'
1342 '\[PyPy [^\]]+\]?')
1343
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001344_sys_version_cache = {}
1345
1346def _sys_version(sys_version=None):
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001347
1348 """ Returns a parsed version of Python's sys.version as tuple
Marc-André Lemburga519cfc2009-03-25 19:44:58 +00001349 (name, version, branch, revision, buildno, builddate, compiler)
1350 referring to the Python implementation name, version, branch,
1351 revision, build number, build date/time as string and the compiler
1352 identification string.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001353
1354 Note that unlike the Python sys.version, the returned value
1355 for the Python version will always include the patchlevel (it
1356 defaults to '.0').
1357
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001358 The function returns empty strings for tuple entries that
1359 cannot be determined.
1360
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001361 sys_version may be given to parse an alternative version
1362 string, e.g. if the version was read from a different Python
1363 interpreter.
1364
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001365 """
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001366 # Get the Python version
1367 if sys_version is None:
1368 sys_version = sys.version
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001369
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001370 # Try the cache first
1371 result = _sys_version_cache.get(sys_version, None)
1372 if result is not None:
1373 return result
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001374
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001375 # Parse it
Ezio Melottibc385482013-10-21 03:03:32 +03001376 if 'IronPython' in sys_version:
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001377 # IronPython
1378 name = 'IronPython'
Ezio Melottibc385482013-10-21 03:03:32 +03001379 if sys_version.startswith('IronPython'):
1380 match = _ironpython_sys_version_parser.match(sys_version)
1381 else:
1382 match = _ironpython26_sys_version_parser.match(sys_version)
1383
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001384 if match is None:
1385 raise ValueError(
1386 'failed to parse IronPython sys.version: %s' %
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001387 repr(sys_version))
Ezio Melottibc385482013-10-21 03:03:32 +03001388
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001389 version, alt_version, compiler = match.groups()
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001390 buildno = ''
1391 builddate = ''
1392
Ezio Melottibc385482013-10-21 03:03:32 +03001393 elif sys.platform.startswith('java'):
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001394 # Jython
1395 name = 'Jython'
Benjamin Petersonf521b8c2009-03-26 18:35:37 +00001396 match = _sys_version_parser.match(sys_version)
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001397 if match is None:
1398 raise ValueError(
1399 'failed to parse Jython sys.version: %s' %
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001400 repr(sys_version))
Benjamin Petersonf521b8c2009-03-26 18:35:37 +00001401 version, buildno, builddate, buildtime, _ = match.groups()
Martin Panterc3636442016-06-08 06:12:22 +00001402 if builddate is None:
1403 builddate = ''
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001404 compiler = sys.platform
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001405
Benjamin Peterson0ad9b772009-03-26 19:09:21 +00001406 elif "PyPy" in sys_version:
1407 # PyPy
1408 name = "PyPy"
1409 match = _pypy_sys_version_parser.match(sys_version)
1410 if match is None:
1411 raise ValueError("failed to parse PyPy sys.version: %s" %
1412 repr(sys_version))
1413 version, buildno, builddate, buildtime = match.groups()
1414 compiler = ""
1415
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001416 else:
1417 # CPython
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001418 match = _sys_version_parser.match(sys_version)
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001419 if match is None:
1420 raise ValueError(
1421 'failed to parse CPython sys.version: %s' %
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001422 repr(sys_version))
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001423 version, buildno, builddate, buildtime, compiler = \
1424 match.groups()
Benjamin Petersonb457b892009-03-26 18:55:48 +00001425 name = 'CPython'
Martin Panterc3636442016-06-08 06:12:22 +00001426 if builddate is None:
1427 builddate = ''
1428 elif buildtime:
1429 builddate = builddate + ' ' + buildtime
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001430
Benjamin Petersonb457b892009-03-26 18:55:48 +00001431 if hasattr(sys, 'subversion'):
1432 # sys.subversion was added in Python 2.5
1433 _, branch, revision = sys.subversion
1434 else:
1435 branch = ''
1436 revision = ''
1437
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001438 # Add the patchlevel version if missing
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001439 l = string.split(version, '.')
1440 if len(l) == 2:
1441 l.append('0')
1442 version = string.join(l, '.')
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001443
1444 # Build and cache the result
1445 result = (name, version, branch, revision, buildno, builddate, compiler)
1446 _sys_version_cache[sys_version] = result
1447 return result
1448
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001449def python_implementation():
1450
1451 """ Returns a string identifying the Python implementation.
1452
1453 Currently, the following implementations are identified:
Ezio Melotti6fa09472011-05-04 18:37:50 +03001454 'CPython' (C implementation of Python),
1455 'IronPython' (.NET implementation of Python),
1456 'Jython' (Java implementation of Python),
1457 'PyPy' (Python implementation of Python).
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001458
1459 """
1460 return _sys_version()[0]
1461
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001462def python_version():
1463
1464 """ Returns the Python version as string 'major.minor.patchlevel'
1465
1466 Note that unlike the Python sys.version, the returned value
1467 will always include the patchlevel (it defaults to 0).
1468
1469 """
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001470 return _sys_version()[1]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001471
1472def python_version_tuple():
1473
1474 """ Returns the Python version as tuple (major, minor, patchlevel)
1475 of strings.
1476
1477 Note that unlike the Python sys.version, the returned value
1478 will always include the patchlevel (it defaults to 0).
1479
1480 """
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001481 return tuple(string.split(_sys_version()[1], '.'))
1482
1483def python_branch():
1484
Neal Norwitz4b86f8b2007-01-13 21:22:37 +00001485 """ Returns a string identifying the Python implementation
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001486 branch.
1487
1488 For CPython this is the Subversion branch from which the
1489 Python binary was built.
1490
1491 If not available, an empty string is returned.
1492
1493 """
Tim Petersf733abb2007-01-30 03:03:46 +00001494
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001495 return _sys_version()[2]
1496
1497def python_revision():
1498
Neal Norwitz4b86f8b2007-01-13 21:22:37 +00001499 """ Returns a string identifying the Python implementation
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001500 revision.
1501
1502 For CPython this is the Subversion revision from which the
1503 Python binary was built.
1504
1505 If not available, an empty string is returned.
1506
1507 """
1508 return _sys_version()[3]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001509
1510def python_build():
1511
1512 """ Returns a tuple (buildno, builddate) stating the Python
1513 build number and date as strings.
1514
1515 """
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001516 return _sys_version()[4:6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001517
1518def python_compiler():
1519
1520 """ Returns a string identifying the compiler used for compiling
1521 Python.
1522
1523 """
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001524 return _sys_version()[6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001525
1526### The Opus Magnum of platform strings :-)
1527
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001528_platform_cache = {}
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001529
1530def platform(aliased=0, terse=0):
1531
1532 """ Returns a single string identifying the underlying platform
1533 with as much useful information as possible (but no more :).
Tim Peters0eadaac2003-04-24 16:02:54 +00001534
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001535 The output is intended to be human readable rather than
1536 machine parseable. It may look different on different
1537 platforms and this is intended.
1538
1539 If "aliased" is true, the function will use aliases for
1540 various platforms that report system names which differ from
1541 their common names, e.g. SunOS will be reported as
1542 Solaris. The system_alias() function is used to implement
1543 this.
1544
1545 Setting terse to true causes the function to return only the
1546 absolute minimum information needed to identify the platform.
1547
1548 """
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001549 result = _platform_cache.get((aliased, terse), None)
1550 if result is not None:
1551 return result
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001552
1553 # Get uname information and then apply platform specific cosmetics
1554 # to it...
1555 system,node,release,version,machine,processor = uname()
1556 if machine == processor:
1557 processor = ''
1558 if aliased:
1559 system,release,version = system_alias(system,release,version)
1560
1561 if system == 'Windows':
1562 # MS platforms
1563 rel,vers,csd,ptype = win32_ver(version)
1564 if terse:
1565 platform = _platform(system,release)
1566 else:
1567 platform = _platform(system,release,version,csd)
1568
1569 elif system in ('Linux',):
1570 # Linux based systems
1571 distname,distversion,distid = dist('')
1572 if distname and not terse:
1573 platform = _platform(system,release,machine,processor,
1574 'with',
1575 distname,distversion,distid)
1576 else:
1577 # If the distribution name is unknown check for libc vs. glibc
1578 libcname,libcversion = libc_ver(sys.executable)
1579 platform = _platform(system,release,machine,processor,
1580 'with',
1581 libcname+libcversion)
1582 elif system == 'Java':
1583 # Java platforms
1584 r,v,vminfo,(os_name,os_version,os_arch) = java_ver()
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001585 if terse or not os_name:
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001586 platform = _platform(system,release,version)
1587 else:
1588 platform = _platform(system,release,version,
1589 'on',
1590 os_name,os_version,os_arch)
1591
1592 elif system == 'MacOS':
1593 # MacOS platforms
1594 if terse:
1595 platform = _platform(system,release)
1596 else:
1597 platform = _platform(system,release,machine)
1598
1599 else:
1600 # Generic handler
1601 if terse:
1602 platform = _platform(system,release)
1603 else:
1604 bits,linkage = architecture(sys.executable)
1605 platform = _platform(system,release,machine,processor,bits,linkage)
Tim Peters0eadaac2003-04-24 16:02:54 +00001606
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001607 _platform_cache[(aliased, terse)] = platform
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001608 return platform
1609
1610### Command line interface
1611
1612if __name__ == '__main__':
1613 # Default is to print the aliased verbose platform string
Tim Peters0eadaac2003-04-24 16:02:54 +00001614 terse = ('terse' in sys.argv or '--terse' in sys.argv)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001615 aliased = (not 'nonaliased' in sys.argv and not '--nonaliased' in sys.argv)
1616 print platform(aliased,terse)
1617 sys.exit(0)