blob: 3dbdfe0b7fe32ee7e22264068afae18678ed61fc [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
66# 'unknown' instead of just leaving the field emtpy)
67# 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,
570 Structure, WinDLL)
571 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 ]
589
590 kernel32 = WinDLL('kernel32')
591 version = WinDLL('version')
592
593 # We will immediately double the length up to MAX_PATH, but the
594 # path may be longer, so we retry until the returned string is
595 # shorter than our buffer.
596 name_len = actual_len = 130
597 while actual_len == name_len:
598 name_len *= 2
599 name = create_unicode_buffer(name_len)
600 actual_len = kernel32.GetModuleFileNameW(HANDLE(kernel32._handle),
601 name, len(name))
602 if not actual_len:
603 return maj, min, build
604
605 size = version.GetFileVersionInfoSizeW(name, None)
606 if not size:
607 return maj, min, build
608
609 ver_block = c_buffer(size)
610 if (not version.GetFileVersionInfoW(name, None, size, ver_block) or
611 not ver_block):
612 return maj, min, build
613
614 pvi = POINTER(VS_FIXEDFILEINFO)()
615 if not version.VerQueryValueW(ver_block, "", byref(pvi), byref(DWORD())):
616 return maj, min, build
617
618 maj = pvi.contents.dwProductVersionMS >> 16
619 min = pvi.contents.dwProductVersionMS & 0xFFFF
620 build = pvi.contents.dwProductVersionLS >> 16
621
622 return maj, min, build
623
624def win32_ver(release='', version='', csd='', ptype=''):
Steve Dowere20c2a62015-09-22 17:35:24 -0700625 try:
626 from sys import getwindowsversion
627 except ImportError:
628 return release, version, csd, ptype
Marc-André Lemburgdbd61a22008-03-20 17:31:36 +0000629 try:
Steve Dower044cde52015-09-22 17:25:30 -0700630 from winreg import OpenKeyEx, QueryValueEx, CloseKey, HKEY_LOCAL_MACHINE
Marc-André Lemburgdbd61a22008-03-20 17:31:36 +0000631 except ImportError:
Steve Dower044cde52015-09-22 17:25:30 -0700632 from _winreg import OpenKeyEx, QueryValueEx, CloseKey, HKEY_LOCAL_MACHINE
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000633
Steve Dower044cde52015-09-22 17:25:30 -0700634 winver = getwindowsversion()
635 maj, min, build = _get_real_winver(*winver[:3])
636 version = '{0}.{1}.{2}'.format(maj, min, build)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000637
Steve Dower044cde52015-09-22 17:25:30 -0700638 release = (_WIN32_CLIENT_RELEASES.get((maj, min)) or
639 _WIN32_CLIENT_RELEASES.get((maj, None)) or
640 release)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000641
Steve Dower044cde52015-09-22 17:25:30 -0700642 # getwindowsversion() reflect the compatibility mode Python is
643 # running under, and so the service pack value is only going to be
644 # valid if the versions match.
645 if winver[:2] == (maj, min):
Marc-André Lemburgdbd61a22008-03-20 17:31:36 +0000646 try:
Steve Dower044cde52015-09-22 17:25:30 -0700647 csd = 'SP{}'.format(winver.service_pack_major)
Marc-André Lemburgdbd61a22008-03-20 17:31:36 +0000648 except AttributeError:
Steve Dower044cde52015-09-22 17:25:30 -0700649 if csd[:13] == 'Service Pack ':
650 csd = 'SP' + csd[13:]
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000651
Steve Dower044cde52015-09-22 17:25:30 -0700652 # VER_NT_SERVER = 3
653 if getattr(winver, 'product_type', None) == 3:
654 release = (_WIN32_SERVER_RELEASES.get((maj, min)) or
655 _WIN32_SERVER_RELEASES.get((maj, None)) or
656 release)
Marc-André Lemburgcecaa652009-07-13 21:28:33 +0000657
Steve Dower044cde52015-09-22 17:25:30 -0700658 key = None
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000659 try:
Steve Dower044cde52015-09-22 17:25:30 -0700660 key = OpenKeyEx(HKEY_LOCAL_MACHINE,
661 r'SOFTWARE\Microsoft\Windows NT\CurrentVersion')
662 ptype = QueryValueEx(key, 'CurrentType')[0]
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000663 except:
Steve Dower044cde52015-09-22 17:25:30 -0700664 pass
665 finally:
666 if key:
667 CloseKey(key)
Tim Peters0eadaac2003-04-24 16:02:54 +0000668
Steve Dower044cde52015-09-22 17:25:30 -0700669 return release, version, csd, ptype
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000670
671def _mac_ver_lookup(selectors,default=None):
672
673 from gestalt import gestalt
Jack Jansena290e3d2003-08-11 11:08:49 +0000674 import MacOS
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000675 l = []
676 append = l.append
677 for selector in selectors:
678 try:
679 append(gestalt(selector))
Jack Jansena290e3d2003-08-11 11:08:49 +0000680 except (RuntimeError, MacOS.Error):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000681 append(default)
682 return l
683
684def _bcd2str(bcd):
685
686 return hex(bcd)[2:]
687
Ronald Oussoren3a04a252010-07-23 12:41:00 +0000688def _mac_ver_gestalt():
689 """
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000690 Thanks to Mark R. Levinson for mailing documentation links and
691 code examples for this function. Documentation for the
692 gestalt() API is available online at:
693
694 http://www.rgaros.nl/gestalt/
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000695 """
696 # Check whether the version info module is available
697 try:
698 import gestalt
Jack Jansena290e3d2003-08-11 11:08:49 +0000699 import MacOS
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000700 except ImportError:
Ronald Oussoren3a04a252010-07-23 12:41:00 +0000701 return None
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000702 # Get the infos
Ronald Oussoren9341ad22010-02-07 11:29:31 +0000703 sysv,sysa = _mac_ver_lookup(('sysv','sysa'))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000704 # Decode the infos
705 if sysv:
706 major = (sysv & 0xFF00) >> 8
707 minor = (sysv & 0x00F0) >> 4
708 patch = (sysv & 0x000F)
Ronald Oussorenc27b8b82008-05-08 10:34:39 +0000709
710 if (major, minor) >= (10, 4):
711 # the 'sysv' gestald cannot return patchlevels
712 # higher than 9. Apple introduced 3 new
713 # gestalt codes in 10.4 to deal with this
714 # issue (needed because patch levels can
715 # run higher than 9, such as 10.4.11)
716 major,minor,patch = _mac_ver_lookup(('sys1','sys2','sys3'))
717 release = '%i.%i.%i' %(major, minor, patch)
718 else:
719 release = '%s.%i.%i' % (_bcd2str(major),minor,patch)
Ronald Oussoren7a0f4c72008-05-18 20:54:47 +0000720
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000721 if sysa:
Tim Peters0eadaac2003-04-24 16:02:54 +0000722 machine = {0x1: '68k',
Ronald Oussoren749d0702006-04-17 13:37:15 +0000723 0x2: 'PowerPC',
724 0xa: 'i386'}.get(sysa,'')
Ronald Oussoren3a04a252010-07-23 12:41:00 +0000725
Ned Deily0ab67ee2011-07-13 15:05:31 -0700726 versioninfo=('', '', '')
Ronald Oussoren3a04a252010-07-23 12:41:00 +0000727 return release,versioninfo,machine
728
729def _mac_ver_xml():
730 fn = '/System/Library/CoreServices/SystemVersion.plist'
731 if not os.path.exists(fn):
732 return None
733
734 try:
735 import plistlib
736 except ImportError:
737 return None
738
739 pl = plistlib.readPlist(fn)
740 release = pl['ProductVersion']
741 versioninfo=('', '', '')
742 machine = os.uname()[4]
Ronald Oussoren22e3e692010-08-03 07:44:35 +0000743 if machine in ('ppc', 'Power Macintosh'):
Ronald Oussoren3a04a252010-07-23 12:41:00 +0000744 # for compatibility with the gestalt based code
745 machine = 'PowerPC'
746
747 return release,versioninfo,machine
748
749
750def mac_ver(release='',versioninfo=('','',''),machine=''):
751
752 """ Get MacOS version information and return it as tuple (release,
753 versioninfo, machine) with versioninfo being a tuple (version,
754 dev_stage, non_release_version).
755
Ezio Melottif5469cf2013-08-17 15:43:51 +0300756 Entries which cannot be determined are set to the parameter values
Ronald Oussoren3a04a252010-07-23 12:41:00 +0000757 which default to ''. All tuple entries are strings.
758 """
759
760 # First try reading the information from an XML file which should
761 # always be present
762 info = _mac_ver_xml()
763 if info is not None:
764 return info
765
766 # If that doesn't work for some reason fall back to reading the
767 # information using gestalt calls.
768 info = _mac_ver_gestalt()
769 if info is not None:
770 return info
771
772 # If that also doesn't work return the default values
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000773 return release,versioninfo,machine
774
Neal Norwitz9b924c62003-06-29 04:17:45 +0000775def _java_getprop(name,default):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000776
777 from java.lang import System
778 try:
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000779 value = System.getProperty(name)
780 if value is None:
781 return default
782 return value
783 except AttributeError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000784 return default
785
786def java_ver(release='',vendor='',vminfo=('','',''),osinfo=('','','')):
Tim Peters0eadaac2003-04-24 16:02:54 +0000787
Brett Cannon8ab27df2003-08-05 03:52:04 +0000788 """ Version interface for Jython.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000789
790 Returns a tuple (release,vendor,vminfo,osinfo) with vminfo being
791 a tuple (vm_name,vm_release,vm_vendor) and osinfo being a
792 tuple (os_name,os_version,os_arch).
793
794 Values which cannot be determined are set to the defaults
795 given as parameters (which all default to '').
796
797 """
798 # Import the needed APIs
799 try:
800 import java.lang
801 except ImportError:
802 return release,vendor,vminfo,osinfo
803
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000804 vendor = _java_getprop('java.vendor', vendor)
805 release = _java_getprop('java.version', release)
806 vm_name, vm_release, vm_vendor = vminfo
807 vm_name = _java_getprop('java.vm.name', vm_name)
808 vm_vendor = _java_getprop('java.vm.vendor', vm_vendor)
809 vm_release = _java_getprop('java.vm.version', vm_release)
810 vminfo = vm_name, vm_release, vm_vendor
811 os_name, os_version, os_arch = osinfo
812 os_arch = _java_getprop('java.os.arch', os_arch)
813 os_name = _java_getprop('java.os.name', os_name)
814 os_version = _java_getprop('java.os.version', os_version)
815 osinfo = os_name, os_version, os_arch
Tim Peters0eadaac2003-04-24 16:02:54 +0000816
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000817 return release, vendor, vminfo, osinfo
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000818
819### System name aliasing
820
821def system_alias(system,release,version):
822
823 """ Returns (system,release,version) aliased to common
824 marketing names used for some systems.
825
826 It also does some reordering of the information in some cases
827 where it would otherwise cause confusion.
828
829 """
830 if system == 'Rhapsody':
831 # Apple's BSD derivative
832 # XXX How can we determine the marketing release number ?
833 return 'MacOS X Server',system+release,version
834
835 elif system == 'SunOS':
836 # Sun's OS
837 if release < '5':
838 # These releases use the old name SunOS
839 return system,release,version
840 # Modify release (marketing release = SunOS release - 3)
841 l = string.split(release,'.')
842 if l:
843 try:
844 major = int(l[0])
845 except ValueError:
846 pass
847 else:
848 major = major - 3
849 l[0] = str(major)
850 release = string.join(l,'.')
851 if release < '6':
852 system = 'Solaris'
853 else:
854 # XXX Whatever the new SunOS marketing name is...
855 system = 'Solaris'
856
857 elif system == 'IRIX64':
858 # IRIX reports IRIX64 on platforms with 64-bit support; yet it
859 # is really a version and not a different platform, since 32-bit
860 # apps are also supported..
861 system = 'IRIX'
862 if version:
863 version = version + ' (64bit)'
864 else:
865 version = '64bit'
866
867 elif system in ('win32','win16'):
868 # In case one of the other tricks
869 system = 'Windows'
870
871 return system,release,version
872
873### Various internal helpers
874
875def _platform(*args):
876
877 """ Helper to format the platform string in a filename
878 compatible format e.g. "system-version-machine".
879 """
880 # Format the platform string
881 platform = string.join(
882 map(string.strip,
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000883 filter(len, args)),
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000884 '-')
885
886 # Cleanup some possible filename obstacles...
887 replace = string.replace
888 platform = replace(platform,' ','_')
889 platform = replace(platform,'/','-')
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
897 # No need to report 'unknown' information...
898 platform = replace(platform,'unknown','')
899
900 # Fold '--'s and remove trailing '-'
901 while 1:
902 cleaned = replace(platform,'--','-')
903 if cleaned == platform:
904 break
905 platform = cleaned
906 while platform[-1] == '-':
907 platform = platform[:-1]
908
909 return platform
910
911def _node(default=''):
912
913 """ Helper to determine the node name of this machine.
914 """
915 try:
916 import socket
917 except ImportError:
918 # No sockets...
919 return default
920 try:
921 return socket.gethostname()
922 except socket.error:
923 # Still not working...
924 return default
925
926# os.path.abspath is new in Python 1.5.2:
927if not hasattr(os.path,'abspath'):
928
929 def _abspath(path,
930
931 isabs=os.path.isabs,join=os.path.join,getcwd=os.getcwd,
932 normpath=os.path.normpath):
933
934 if not isabs(path):
935 path = join(getcwd(), path)
936 return normpath(path)
937
938else:
939
940 _abspath = os.path.abspath
941
942def _follow_symlinks(filepath):
943
944 """ In case filepath is a symlink, follow it until a
945 real file is reached.
946 """
947 filepath = _abspath(filepath)
948 while os.path.islink(filepath):
949 filepath = os.path.normpath(
Hirokazu Yamamoto171c4aa2008-09-04 11:15:14 +0000950 os.path.join(os.path.dirname(filepath),os.readlink(filepath)))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000951 return filepath
952
953def _syscmd_uname(option,default=''):
954
955 """ Interface to the system's uname command.
956 """
957 if sys.platform in ('dos','win32','win16','os2'):
958 # XXX Others too ?
959 return default
960 try:
Marc-André Lemburg19e5b3f2009-07-13 20:23:49 +0000961 f = os.popen('uname %s 2> %s' % (option, DEV_NULL))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000962 except (AttributeError,os.error):
963 return default
964 output = string.strip(f.read())
965 rc = f.close()
966 if not output or rc:
967 return default
968 else:
969 return output
970
971def _syscmd_file(target,default=''):
972
973 """ Interface to the system's file command.
974
975 The function uses the -b option of the file command to have it
976 ommit the filename in its output and if possible the -L option
977 to have the command follow symlinks. It returns default in
978 case the command should fail.
979
980 """
Jesus Ceadebda5d2012-10-04 15:14:56 +0200981
982 # We do the import here to avoid a bootstrap issue.
983 # See c73b90b6dadd changeset.
984 #
985 # [..]
986 # ranlib libpython2.7.a
987 # gcc -o python \
988 # Modules/python.o \
989 # libpython2.7.a -lsocket -lnsl -ldl -lm
990 # Traceback (most recent call last):
991 # File "./setup.py", line 8, in <module>
992 # from platform import machine as platform_machine
993 # File "[..]/build/Lib/platform.py", line 116, in <module>
994 # import sys,string,os,re,subprocess
995 # File "[..]/build/Lib/subprocess.py", line 429, in <module>
996 # import select
997 # ImportError: No module named select
998
999 import subprocess
1000
Hirokazu Yamamotoed8c6442008-09-01 14:32:58 +00001001 if sys.platform in ('dos','win32','win16','os2'):
1002 # XXX Others too ?
1003 return default
Jesus Cea3e94e142012-10-04 15:06:57 +02001004 target = _follow_symlinks(target)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001005 try:
Jesus Cea2699c9d2012-10-05 05:18:47 +02001006 proc = subprocess.Popen(['file', target],
1007 stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
Jesus Cea3e94e142012-10-04 15:06:57 +02001008
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001009 except (AttributeError,os.error):
1010 return default
Jesus Cea69e7c9b2012-10-05 04:50:17 +02001011 output = proc.communicate()[0]
Jesus Cea3e94e142012-10-04 15:06:57 +02001012 rc = proc.wait()
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001013 if not output or rc:
1014 return default
1015 else:
1016 return output
1017
1018### Information about the used architecture
1019
1020# Default values for architecture; non-empty strings override the
1021# defaults given as parameters
1022_default_architecture = {
1023 'win32': ('','WindowsPE'),
1024 'win16': ('','Windows'),
1025 'dos': ('','MSDOS'),
1026}
1027
Victor Stinner814b6c22010-04-18 18:22:25 +00001028_architecture_split = re.compile(r'[\s,]').split
1029
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +00001030def architecture(executable=sys.executable,bits='',linkage=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001031
1032 """ Queries the given executable (defaults to the Python interpreter
Brett Cannon8ab27df2003-08-05 03:52:04 +00001033 binary) for various architecture information.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001034
Brett Cannon8ab27df2003-08-05 03:52:04 +00001035 Returns a tuple (bits,linkage) which contains information about
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001036 the bit architecture and the linkage format used for the
1037 executable. Both values are returned as strings.
1038
1039 Values that cannot be determined are returned as given by the
1040 parameter presets. If bits is given as '', the sizeof(pointer)
1041 (or sizeof(long) on Python version < 1.5.2) is used as
1042 indicator for the supported pointer size.
1043
1044 The function relies on the system's "file" command to do the
1045 actual work. This is available on most if not all Unix
Brett Cannon8ab27df2003-08-05 03:52:04 +00001046 platforms. On some non-Unix platforms where the "file" command
1047 does not exist and the executable is set to the Python interpreter
1048 binary defaults from _default_architecture are used.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001049
1050 """
1051 # Use the sizeof(pointer) as default number of bits if nothing
1052 # else is given as default.
1053 if not bits:
1054 import struct
1055 try:
1056 size = struct.calcsize('P')
1057 except struct.error:
1058 # Older installations can only query longs
1059 size = struct.calcsize('l')
1060 bits = str(size*8) + 'bit'
Tim Peters0eadaac2003-04-24 16:02:54 +00001061
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001062 # Get data from the 'file' system command
Marc-André Lemburg3b8f60b2007-01-13 23:13:54 +00001063 if executable:
Victor Stinner814b6c22010-04-18 18:22:25 +00001064 output = _syscmd_file(executable, '')
Marc-André Lemburg3b8f60b2007-01-13 23:13:54 +00001065 else:
Victor Stinner814b6c22010-04-18 18:22:25 +00001066 output = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001067
Victor Stinner814b6c22010-04-18 18:22:25 +00001068 if not output and \
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001069 executable == sys.executable:
1070 # "file" command did not return anything; we'll try to provide
Tim Peters0eadaac2003-04-24 16:02:54 +00001071 # some sensible defaults then...
Florent Xicluna8d1da0f2010-04-01 18:17:09 +00001072 if sys.platform in _default_architecture:
1073 b, l = _default_architecture[sys.platform]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001074 if b:
1075 bits = b
1076 if l:
1077 linkage = l
Florent Xicluna8d1da0f2010-04-01 18:17:09 +00001078 return bits, linkage
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001079
Victor Stinner814b6c22010-04-18 18:22:25 +00001080 # Split the output into a list of strings omitting the filename
1081 fileout = _architecture_split(output)[1:]
1082
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001083 if 'executable' not in fileout:
1084 # Format not supported
1085 return bits,linkage
1086
1087 # Bits
1088 if '32-bit' in fileout:
1089 bits = '32bit'
1090 elif 'N32' in fileout:
1091 # On Irix only
1092 bits = 'n32bit'
1093 elif '64-bit' in fileout:
1094 bits = '64bit'
1095
1096 # Linkage
1097 if 'ELF' in fileout:
1098 linkage = 'ELF'
1099 elif 'PE' in fileout:
1100 # E.g. Windows uses this format
1101 if 'Windows' in fileout:
1102 linkage = 'WindowsPE'
1103 else:
1104 linkage = 'PE'
1105 elif 'COFF' in fileout:
1106 linkage = 'COFF'
1107 elif 'MS-DOS' in fileout:
1108 linkage = 'MSDOS'
1109 else:
1110 # XXX the A.OUT format also falls under this class...
1111 pass
1112
1113 return bits,linkage
1114
1115### Portable uname() interface
Tim Peters0eadaac2003-04-24 16:02:54 +00001116
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001117_uname_cache = None
1118
1119def uname():
1120
1121 """ Fairly portable uname interface. Returns a tuple
1122 of strings (system,node,release,version,machine,processor)
1123 identifying the underlying platform.
1124
1125 Note that unlike the os.uname function this also returns
Brett Cannon8ab27df2003-08-05 03:52:04 +00001126 possible processor information as an additional tuple entry.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001127
1128 Entries which cannot be determined are set to ''.
1129
1130 """
1131 global _uname_cache
Benjamin Peterson5c0be322008-06-13 15:11:50 +00001132 no_os_uname = 0
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001133
1134 if _uname_cache is not None:
1135 return _uname_cache
1136
Benjamin Peterson5c0be322008-06-13 15:11:50 +00001137 processor = ''
1138
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001139 # Get some infos from the builtin os.uname API...
1140 try:
1141 system,node,release,version,machine = os.uname()
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001142 except AttributeError:
Benjamin Peterson5c0be322008-06-13 15:11:50 +00001143 no_os_uname = 1
1144
1145 if no_os_uname or not filter(None, (system, node, release, version, machine)):
1146 # Hmm, no there is either no uname or uname has returned
1147 #'unknowns'... we'll have to poke around the system then.
1148 if no_os_uname:
1149 system = sys.platform
1150 release = ''
1151 version = ''
1152 node = _node()
1153 machine = ''
1154
Marc-André Lemburgcecaa652009-07-13 21:28:33 +00001155 use_syscmd_ver = 1
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001156
1157 # Try win32_ver() on win32 platforms
1158 if system == 'win32':
1159 release,version,csd,ptype = win32_ver()
1160 if release and version:
1161 use_syscmd_ver = 0
Marc-André Lemburgdbd61a22008-03-20 17:31:36 +00001162 # Try to use the PROCESSOR_* environment variables
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001163 # available on Win XP and later; see
1164 # http://support.microsoft.com/kb/888731 and
1165 # http://www.geocities.com/rick_lively/MANUALS/ENV/MSWIN/PROCESSI.HTM
Benjamin Peterson5c0be322008-06-13 15:11:50 +00001166 if not machine:
R. David Murrayc9d1a782010-03-22 15:55:09 +00001167 # WOW64 processes mask the native architecture
1168 if "PROCESSOR_ARCHITEW6432" in os.environ:
1169 machine = os.environ.get("PROCESSOR_ARCHITEW6432", '')
1170 else:
1171 machine = os.environ.get('PROCESSOR_ARCHITECTURE', '')
Benjamin Peterson5c0be322008-06-13 15:11:50 +00001172 if not processor:
1173 processor = os.environ.get('PROCESSOR_IDENTIFIER', machine)
Tim Peters0eadaac2003-04-24 16:02:54 +00001174
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001175 # Try the 'ver' system command available on some
1176 # platforms
1177 if use_syscmd_ver:
1178 system,release,version = _syscmd_ver(system)
Marc-André Lemburgcdc79232004-06-19 17:17:00 +00001179 # Normalize system to what win32_ver() normally returns
1180 # (_syscmd_ver() tends to return the vendor name as well)
1181 if system == 'Microsoft Windows':
1182 system = 'Windows'
Marc-André Lemburgb24cd0f2007-06-12 09:26:49 +00001183 elif system == 'Microsoft' and release == 'Windows':
1184 # Under Windows Vista and Windows Server 2008,
1185 # Microsoft changed the output of the ver command. The
1186 # release is no longer printed. This causes the
1187 # system and release to be misidentified.
1188 system = 'Windows'
1189 if '6.0' == version[:3]:
1190 release = 'Vista'
1191 else:
1192 release = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001193
1194 # In case we still don't know anything useful, we'll try to
1195 # help ourselves
1196 if system in ('win32','win16'):
1197 if not version:
1198 if system == 'win32':
1199 version = '32bit'
1200 else:
1201 version = '16bit'
1202 system = 'Windows'
1203
1204 elif system[:4] == 'java':
1205 release,vendor,vminfo,osinfo = java_ver()
1206 system = 'Java'
1207 version = string.join(vminfo,', ')
1208 if not version:
1209 version = vendor
1210
Benjamin Peterson5c0be322008-06-13 15:11:50 +00001211 # System specific extensions
1212 if system == 'OpenVMS':
1213 # OpenVMS seems to have release and version mixed up
1214 if not release or release == '0':
1215 release = version
1216 version = ''
1217 # Get processor information
1218 try:
1219 import vms_lib
1220 except ImportError:
1221 pass
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001222 else:
Benjamin Peterson5c0be322008-06-13 15:11:50 +00001223 csid, cpu_number = vms_lib.getsyi('SYI$_CPU',0)
1224 if (cpu_number >= 128):
1225 processor = 'Alpha'
1226 else:
1227 processor = 'VAX'
1228 if not processor:
1229 # Get processor information from the uname system command
1230 processor = _syscmd_uname('-p','')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001231
Benjamin Peterson5c0be322008-06-13 15:11:50 +00001232 #If any unknowns still exist, replace them with ''s, which are more portable
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001233 if system == 'unknown':
1234 system = ''
1235 if node == 'unknown':
1236 node = ''
1237 if release == 'unknown':
1238 release = ''
1239 if version == 'unknown':
1240 version = ''
1241 if machine == 'unknown':
1242 machine = ''
1243 if processor == 'unknown':
1244 processor = ''
Sean Reifscheiderf09597c2007-09-17 20:53:21 +00001245
1246 # normalize name
1247 if system == 'Microsoft' and release == 'Windows':
1248 system = 'Windows'
1249 release = 'Vista'
1250
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001251 _uname_cache = system,node,release,version,machine,processor
1252 return _uname_cache
1253
1254### Direct interfaces to some of the uname() return values
1255
1256def system():
1257
1258 """ Returns the system/OS name, e.g. 'Linux', 'Windows' or 'Java'.
1259
1260 An empty string is returned if the value cannot be determined.
1261
1262 """
1263 return uname()[0]
1264
1265def node():
1266
Brett Cannon8ab27df2003-08-05 03:52:04 +00001267 """ Returns the computer's network name (which may not be fully
1268 qualified)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001269
1270 An empty string is returned if the value cannot be determined.
1271
1272 """
1273 return uname()[1]
1274
1275def release():
1276
1277 """ Returns the system's release, e.g. '2.2.0' or 'NT'
1278
1279 An empty string is returned if the value cannot be determined.
1280
1281 """
1282 return uname()[2]
1283
1284def version():
1285
1286 """ Returns the system's release version, e.g. '#3 on degas'
1287
1288 An empty string is returned if the value cannot be determined.
1289
1290 """
1291 return uname()[3]
1292
1293def machine():
1294
1295 """ Returns the machine type, e.g. 'i386'
1296
1297 An empty string is returned if the value cannot be determined.
1298
1299 """
1300 return uname()[4]
1301
1302def processor():
1303
1304 """ Returns the (true) processor name, e.g. 'amdk6'
1305
1306 An empty string is returned if the value cannot be
1307 determined. Note that many platforms do not provide this
1308 information or simply return the same value as for machine(),
1309 e.g. NetBSD does this.
1310
1311 """
1312 return uname()[5]
1313
1314### Various APIs for extracting information from sys.version
1315
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001316_sys_version_parser = re.compile(
1317 r'([\w.+]+)\s*'
1318 '\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*'
1319 '\[([^\]]+)\]?')
1320
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001321_ironpython_sys_version_parser = re.compile(
1322 r'IronPython\s*'
1323 '([\d\.]+)'
1324 '(?: \(([\d\.]+)\))?'
1325 ' on (.NET [\d\.]+)')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001326
Ezio Melottibc385482013-10-21 03:03:32 +03001327# IronPython covering 2.6 and 2.7
1328_ironpython26_sys_version_parser = re.compile(
1329 r'([\d.]+)\s*'
1330 '\(IronPython\s*'
1331 '[\d.]+\s*'
1332 '\(([\d.]+)\) on ([\w.]+ [\d.]+(?: \(\d+-bit\))?)\)'
1333)
1334
Benjamin Peterson0ad9b772009-03-26 19:09:21 +00001335_pypy_sys_version_parser = re.compile(
1336 r'([\w.+]+)\s*'
1337 '\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*'
1338 '\[PyPy [^\]]+\]?')
1339
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001340_sys_version_cache = {}
1341
1342def _sys_version(sys_version=None):
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001343
1344 """ Returns a parsed version of Python's sys.version as tuple
Marc-André Lemburga519cfc2009-03-25 19:44:58 +00001345 (name, version, branch, revision, buildno, builddate, compiler)
1346 referring to the Python implementation name, version, branch,
1347 revision, build number, build date/time as string and the compiler
1348 identification string.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001349
1350 Note that unlike the Python sys.version, the returned value
1351 for the Python version will always include the patchlevel (it
1352 defaults to '.0').
1353
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001354 The function returns empty strings for tuple entries that
1355 cannot be determined.
1356
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001357 sys_version may be given to parse an alternative version
1358 string, e.g. if the version was read from a different Python
1359 interpreter.
1360
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001361 """
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001362 # Get the Python version
1363 if sys_version is None:
1364 sys_version = sys.version
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001365
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001366 # Try the cache first
1367 result = _sys_version_cache.get(sys_version, None)
1368 if result is not None:
1369 return result
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001370
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001371 # Parse it
Ezio Melottibc385482013-10-21 03:03:32 +03001372 if 'IronPython' in sys_version:
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001373 # IronPython
1374 name = 'IronPython'
Ezio Melottibc385482013-10-21 03:03:32 +03001375 if sys_version.startswith('IronPython'):
1376 match = _ironpython_sys_version_parser.match(sys_version)
1377 else:
1378 match = _ironpython26_sys_version_parser.match(sys_version)
1379
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001380 if match is None:
1381 raise ValueError(
1382 'failed to parse IronPython sys.version: %s' %
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001383 repr(sys_version))
Ezio Melottibc385482013-10-21 03:03:32 +03001384
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001385 version, alt_version, compiler = match.groups()
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001386 buildno = ''
1387 builddate = ''
1388
Ezio Melottibc385482013-10-21 03:03:32 +03001389 elif sys.platform.startswith('java'):
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001390 # Jython
1391 name = 'Jython'
Benjamin Petersonf521b8c2009-03-26 18:35:37 +00001392 match = _sys_version_parser.match(sys_version)
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001393 if match is None:
1394 raise ValueError(
1395 'failed to parse Jython sys.version: %s' %
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001396 repr(sys_version))
Benjamin Petersonf521b8c2009-03-26 18:35:37 +00001397 version, buildno, builddate, buildtime, _ = match.groups()
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001398 compiler = sys.platform
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001399
Benjamin Peterson0ad9b772009-03-26 19:09:21 +00001400 elif "PyPy" in sys_version:
1401 # PyPy
1402 name = "PyPy"
1403 match = _pypy_sys_version_parser.match(sys_version)
1404 if match is None:
1405 raise ValueError("failed to parse PyPy sys.version: %s" %
1406 repr(sys_version))
1407 version, buildno, builddate, buildtime = match.groups()
1408 compiler = ""
1409
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001410 else:
1411 # CPython
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001412 match = _sys_version_parser.match(sys_version)
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001413 if match is None:
1414 raise ValueError(
1415 'failed to parse CPython sys.version: %s' %
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001416 repr(sys_version))
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001417 version, buildno, builddate, buildtime, compiler = \
1418 match.groups()
Benjamin Petersonb457b892009-03-26 18:55:48 +00001419 name = 'CPython'
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001420 builddate = builddate + ' ' + buildtime
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001421
Benjamin Petersonb457b892009-03-26 18:55:48 +00001422 if hasattr(sys, 'subversion'):
1423 # sys.subversion was added in Python 2.5
1424 _, branch, revision = sys.subversion
1425 else:
1426 branch = ''
1427 revision = ''
1428
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001429 # Add the patchlevel version if missing
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001430 l = string.split(version, '.')
1431 if len(l) == 2:
1432 l.append('0')
1433 version = string.join(l, '.')
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001434
1435 # Build and cache the result
1436 result = (name, version, branch, revision, buildno, builddate, compiler)
1437 _sys_version_cache[sys_version] = result
1438 return result
1439
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001440def python_implementation():
1441
1442 """ Returns a string identifying the Python implementation.
1443
1444 Currently, the following implementations are identified:
Ezio Melotti6fa09472011-05-04 18:37:50 +03001445 'CPython' (C implementation of Python),
1446 'IronPython' (.NET implementation of Python),
1447 'Jython' (Java implementation of Python),
1448 'PyPy' (Python implementation of Python).
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001449
1450 """
1451 return _sys_version()[0]
1452
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001453def python_version():
1454
1455 """ Returns the Python version as string 'major.minor.patchlevel'
1456
1457 Note that unlike the Python sys.version, the returned value
1458 will always include the patchlevel (it defaults to 0).
1459
1460 """
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001461 return _sys_version()[1]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001462
1463def python_version_tuple():
1464
1465 """ Returns the Python version as tuple (major, minor, patchlevel)
1466 of strings.
1467
1468 Note that unlike the Python sys.version, the returned value
1469 will always include the patchlevel (it defaults to 0).
1470
1471 """
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001472 return tuple(string.split(_sys_version()[1], '.'))
1473
1474def python_branch():
1475
Neal Norwitz4b86f8b2007-01-13 21:22:37 +00001476 """ Returns a string identifying the Python implementation
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001477 branch.
1478
1479 For CPython this is the Subversion branch from which the
1480 Python binary was built.
1481
1482 If not available, an empty string is returned.
1483
1484 """
Tim Petersf733abb2007-01-30 03:03:46 +00001485
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001486 return _sys_version()[2]
1487
1488def python_revision():
1489
Neal Norwitz4b86f8b2007-01-13 21:22:37 +00001490 """ Returns a string identifying the Python implementation
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001491 revision.
1492
1493 For CPython this is the Subversion revision from which the
1494 Python binary was built.
1495
1496 If not available, an empty string is returned.
1497
1498 """
1499 return _sys_version()[3]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001500
1501def python_build():
1502
1503 """ Returns a tuple (buildno, builddate) stating the Python
1504 build number and date as strings.
1505
1506 """
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001507 return _sys_version()[4:6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001508
1509def python_compiler():
1510
1511 """ Returns a string identifying the compiler used for compiling
1512 Python.
1513
1514 """
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001515 return _sys_version()[6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001516
1517### The Opus Magnum of platform strings :-)
1518
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001519_platform_cache = {}
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001520
1521def platform(aliased=0, terse=0):
1522
1523 """ Returns a single string identifying the underlying platform
1524 with as much useful information as possible (but no more :).
Tim Peters0eadaac2003-04-24 16:02:54 +00001525
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001526 The output is intended to be human readable rather than
1527 machine parseable. It may look different on different
1528 platforms and this is intended.
1529
1530 If "aliased" is true, the function will use aliases for
1531 various platforms that report system names which differ from
1532 their common names, e.g. SunOS will be reported as
1533 Solaris. The system_alias() function is used to implement
1534 this.
1535
1536 Setting terse to true causes the function to return only the
1537 absolute minimum information needed to identify the platform.
1538
1539 """
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001540 result = _platform_cache.get((aliased, terse), None)
1541 if result is not None:
1542 return result
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001543
1544 # Get uname information and then apply platform specific cosmetics
1545 # to it...
1546 system,node,release,version,machine,processor = uname()
1547 if machine == processor:
1548 processor = ''
1549 if aliased:
1550 system,release,version = system_alias(system,release,version)
1551
1552 if system == 'Windows':
1553 # MS platforms
1554 rel,vers,csd,ptype = win32_ver(version)
1555 if terse:
1556 platform = _platform(system,release)
1557 else:
1558 platform = _platform(system,release,version,csd)
1559
1560 elif system in ('Linux',):
1561 # Linux based systems
1562 distname,distversion,distid = dist('')
1563 if distname and not terse:
1564 platform = _platform(system,release,machine,processor,
1565 'with',
1566 distname,distversion,distid)
1567 else:
1568 # If the distribution name is unknown check for libc vs. glibc
1569 libcname,libcversion = libc_ver(sys.executable)
1570 platform = _platform(system,release,machine,processor,
1571 'with',
1572 libcname+libcversion)
1573 elif system == 'Java':
1574 # Java platforms
1575 r,v,vminfo,(os_name,os_version,os_arch) = java_ver()
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001576 if terse or not os_name:
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001577 platform = _platform(system,release,version)
1578 else:
1579 platform = _platform(system,release,version,
1580 'on',
1581 os_name,os_version,os_arch)
1582
1583 elif system == 'MacOS':
1584 # MacOS platforms
1585 if terse:
1586 platform = _platform(system,release)
1587 else:
1588 platform = _platform(system,release,machine)
1589
1590 else:
1591 # Generic handler
1592 if terse:
1593 platform = _platform(system,release)
1594 else:
1595 bits,linkage = architecture(sys.executable)
1596 platform = _platform(system,release,machine,processor,bits,linkage)
Tim Peters0eadaac2003-04-24 16:02:54 +00001597
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001598 _platform_cache[(aliased, terse)] = platform
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001599 return platform
1600
1601### Command line interface
1602
1603if __name__ == '__main__':
1604 # Default is to print the aliased verbose platform string
Tim Peters0eadaac2003-04-24 16:02:54 +00001605 terse = ('terse' in sys.argv or '--terse' in sys.argv)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001606 aliased = (not 'nonaliased' in sys.argv and not '--nonaliased' in sys.argv)
1607 print platform(aliased,terse)
1608 sys.exit(0)