blob: c58c3fdcaa99ff05b88e3062801961855ba9803a [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=''):
625 from sys import getwindowsversion
Marc-André Lemburgdbd61a22008-03-20 17:31:36 +0000626 try:
Steve Dower044cde52015-09-22 17:25:30 -0700627 from winreg import OpenKeyEx, QueryValueEx, CloseKey, HKEY_LOCAL_MACHINE
Marc-André Lemburgdbd61a22008-03-20 17:31:36 +0000628 except ImportError:
Steve Dower044cde52015-09-22 17:25:30 -0700629 from _winreg import OpenKeyEx, QueryValueEx, CloseKey, HKEY_LOCAL_MACHINE
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000630
Steve Dower044cde52015-09-22 17:25:30 -0700631 winver = getwindowsversion()
632 maj, min, build = _get_real_winver(*winver[:3])
633 version = '{0}.{1}.{2}'.format(maj, min, build)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000634
Steve Dower044cde52015-09-22 17:25:30 -0700635 release = (_WIN32_CLIENT_RELEASES.get((maj, min)) or
636 _WIN32_CLIENT_RELEASES.get((maj, None)) or
637 release)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000638
Steve Dower044cde52015-09-22 17:25:30 -0700639 # getwindowsversion() reflect the compatibility mode Python is
640 # running under, and so the service pack value is only going to be
641 # valid if the versions match.
642 if winver[:2] == (maj, min):
Marc-André Lemburgdbd61a22008-03-20 17:31:36 +0000643 try:
Steve Dower044cde52015-09-22 17:25:30 -0700644 csd = 'SP{}'.format(winver.service_pack_major)
Marc-André Lemburgdbd61a22008-03-20 17:31:36 +0000645 except AttributeError:
Steve Dower044cde52015-09-22 17:25:30 -0700646 if csd[:13] == 'Service Pack ':
647 csd = 'SP' + csd[13:]
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000648
Steve Dower044cde52015-09-22 17:25:30 -0700649 # VER_NT_SERVER = 3
650 if getattr(winver, 'product_type', None) == 3:
651 release = (_WIN32_SERVER_RELEASES.get((maj, min)) or
652 _WIN32_SERVER_RELEASES.get((maj, None)) or
653 release)
Marc-André Lemburgcecaa652009-07-13 21:28:33 +0000654
Steve Dower044cde52015-09-22 17:25:30 -0700655 key = None
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000656 try:
Steve Dower044cde52015-09-22 17:25:30 -0700657 key = OpenKeyEx(HKEY_LOCAL_MACHINE,
658 r'SOFTWARE\Microsoft\Windows NT\CurrentVersion')
659 ptype = QueryValueEx(key, 'CurrentType')[0]
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000660 except:
Steve Dower044cde52015-09-22 17:25:30 -0700661 pass
662 finally:
663 if key:
664 CloseKey(key)
Tim Peters0eadaac2003-04-24 16:02:54 +0000665
Steve Dower044cde52015-09-22 17:25:30 -0700666 return release, version, csd, ptype
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000667
668def _mac_ver_lookup(selectors,default=None):
669
670 from gestalt import gestalt
Jack Jansena290e3d2003-08-11 11:08:49 +0000671 import MacOS
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000672 l = []
673 append = l.append
674 for selector in selectors:
675 try:
676 append(gestalt(selector))
Jack Jansena290e3d2003-08-11 11:08:49 +0000677 except (RuntimeError, MacOS.Error):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000678 append(default)
679 return l
680
681def _bcd2str(bcd):
682
683 return hex(bcd)[2:]
684
Ronald Oussoren3a04a252010-07-23 12:41:00 +0000685def _mac_ver_gestalt():
686 """
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000687 Thanks to Mark R. Levinson for mailing documentation links and
688 code examples for this function. Documentation for the
689 gestalt() API is available online at:
690
691 http://www.rgaros.nl/gestalt/
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000692 """
693 # Check whether the version info module is available
694 try:
695 import gestalt
Jack Jansena290e3d2003-08-11 11:08:49 +0000696 import MacOS
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000697 except ImportError:
Ronald Oussoren3a04a252010-07-23 12:41:00 +0000698 return None
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000699 # Get the infos
Ronald Oussoren9341ad22010-02-07 11:29:31 +0000700 sysv,sysa = _mac_ver_lookup(('sysv','sysa'))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000701 # Decode the infos
702 if sysv:
703 major = (sysv & 0xFF00) >> 8
704 minor = (sysv & 0x00F0) >> 4
705 patch = (sysv & 0x000F)
Ronald Oussorenc27b8b82008-05-08 10:34:39 +0000706
707 if (major, minor) >= (10, 4):
708 # the 'sysv' gestald cannot return patchlevels
709 # higher than 9. Apple introduced 3 new
710 # gestalt codes in 10.4 to deal with this
711 # issue (needed because patch levels can
712 # run higher than 9, such as 10.4.11)
713 major,minor,patch = _mac_ver_lookup(('sys1','sys2','sys3'))
714 release = '%i.%i.%i' %(major, minor, patch)
715 else:
716 release = '%s.%i.%i' % (_bcd2str(major),minor,patch)
Ronald Oussoren7a0f4c72008-05-18 20:54:47 +0000717
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000718 if sysa:
Tim Peters0eadaac2003-04-24 16:02:54 +0000719 machine = {0x1: '68k',
Ronald Oussoren749d0702006-04-17 13:37:15 +0000720 0x2: 'PowerPC',
721 0xa: 'i386'}.get(sysa,'')
Ronald Oussoren3a04a252010-07-23 12:41:00 +0000722
Ned Deily0ab67ee2011-07-13 15:05:31 -0700723 versioninfo=('', '', '')
Ronald Oussoren3a04a252010-07-23 12:41:00 +0000724 return release,versioninfo,machine
725
726def _mac_ver_xml():
727 fn = '/System/Library/CoreServices/SystemVersion.plist'
728 if not os.path.exists(fn):
729 return None
730
731 try:
732 import plistlib
733 except ImportError:
734 return None
735
736 pl = plistlib.readPlist(fn)
737 release = pl['ProductVersion']
738 versioninfo=('', '', '')
739 machine = os.uname()[4]
Ronald Oussoren22e3e692010-08-03 07:44:35 +0000740 if machine in ('ppc', 'Power Macintosh'):
Ronald Oussoren3a04a252010-07-23 12:41:00 +0000741 # for compatibility with the gestalt based code
742 machine = 'PowerPC'
743
744 return release,versioninfo,machine
745
746
747def mac_ver(release='',versioninfo=('','',''),machine=''):
748
749 """ Get MacOS version information and return it as tuple (release,
750 versioninfo, machine) with versioninfo being a tuple (version,
751 dev_stage, non_release_version).
752
Ezio Melottif5469cf2013-08-17 15:43:51 +0300753 Entries which cannot be determined are set to the parameter values
Ronald Oussoren3a04a252010-07-23 12:41:00 +0000754 which default to ''. All tuple entries are strings.
755 """
756
757 # First try reading the information from an XML file which should
758 # always be present
759 info = _mac_ver_xml()
760 if info is not None:
761 return info
762
763 # If that doesn't work for some reason fall back to reading the
764 # information using gestalt calls.
765 info = _mac_ver_gestalt()
766 if info is not None:
767 return info
768
769 # If that also doesn't work return the default values
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000770 return release,versioninfo,machine
771
Neal Norwitz9b924c62003-06-29 04:17:45 +0000772def _java_getprop(name,default):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000773
774 from java.lang import System
775 try:
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000776 value = System.getProperty(name)
777 if value is None:
778 return default
779 return value
780 except AttributeError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000781 return default
782
783def java_ver(release='',vendor='',vminfo=('','',''),osinfo=('','','')):
Tim Peters0eadaac2003-04-24 16:02:54 +0000784
Brett Cannon8ab27df2003-08-05 03:52:04 +0000785 """ Version interface for Jython.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000786
787 Returns a tuple (release,vendor,vminfo,osinfo) with vminfo being
788 a tuple (vm_name,vm_release,vm_vendor) and osinfo being a
789 tuple (os_name,os_version,os_arch).
790
791 Values which cannot be determined are set to the defaults
792 given as parameters (which all default to '').
793
794 """
795 # Import the needed APIs
796 try:
797 import java.lang
798 except ImportError:
799 return release,vendor,vminfo,osinfo
800
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000801 vendor = _java_getprop('java.vendor', vendor)
802 release = _java_getprop('java.version', release)
803 vm_name, vm_release, vm_vendor = vminfo
804 vm_name = _java_getprop('java.vm.name', vm_name)
805 vm_vendor = _java_getprop('java.vm.vendor', vm_vendor)
806 vm_release = _java_getprop('java.vm.version', vm_release)
807 vminfo = vm_name, vm_release, vm_vendor
808 os_name, os_version, os_arch = osinfo
809 os_arch = _java_getprop('java.os.arch', os_arch)
810 os_name = _java_getprop('java.os.name', os_name)
811 os_version = _java_getprop('java.os.version', os_version)
812 osinfo = os_name, os_version, os_arch
Tim Peters0eadaac2003-04-24 16:02:54 +0000813
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000814 return release, vendor, vminfo, osinfo
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000815
816### System name aliasing
817
818def system_alias(system,release,version):
819
820 """ Returns (system,release,version) aliased to common
821 marketing names used for some systems.
822
823 It also does some reordering of the information in some cases
824 where it would otherwise cause confusion.
825
826 """
827 if system == 'Rhapsody':
828 # Apple's BSD derivative
829 # XXX How can we determine the marketing release number ?
830 return 'MacOS X Server',system+release,version
831
832 elif system == 'SunOS':
833 # Sun's OS
834 if release < '5':
835 # These releases use the old name SunOS
836 return system,release,version
837 # Modify release (marketing release = SunOS release - 3)
838 l = string.split(release,'.')
839 if l:
840 try:
841 major = int(l[0])
842 except ValueError:
843 pass
844 else:
845 major = major - 3
846 l[0] = str(major)
847 release = string.join(l,'.')
848 if release < '6':
849 system = 'Solaris'
850 else:
851 # XXX Whatever the new SunOS marketing name is...
852 system = 'Solaris'
853
854 elif system == 'IRIX64':
855 # IRIX reports IRIX64 on platforms with 64-bit support; yet it
856 # is really a version and not a different platform, since 32-bit
857 # apps are also supported..
858 system = 'IRIX'
859 if version:
860 version = version + ' (64bit)'
861 else:
862 version = '64bit'
863
864 elif system in ('win32','win16'):
865 # In case one of the other tricks
866 system = 'Windows'
867
868 return system,release,version
869
870### Various internal helpers
871
872def _platform(*args):
873
874 """ Helper to format the platform string in a filename
875 compatible format e.g. "system-version-machine".
876 """
877 # Format the platform string
878 platform = string.join(
879 map(string.strip,
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000880 filter(len, args)),
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000881 '-')
882
883 # Cleanup some possible filename obstacles...
884 replace = string.replace
885 platform = replace(platform,' ','_')
886 platform = replace(platform,'/','-')
887 platform = replace(platform,'\\','-')
888 platform = replace(platform,':','-')
889 platform = replace(platform,';','-')
890 platform = replace(platform,'"','-')
891 platform = replace(platform,'(','-')
892 platform = replace(platform,')','-')
893
894 # No need to report 'unknown' information...
895 platform = replace(platform,'unknown','')
896
897 # Fold '--'s and remove trailing '-'
898 while 1:
899 cleaned = replace(platform,'--','-')
900 if cleaned == platform:
901 break
902 platform = cleaned
903 while platform[-1] == '-':
904 platform = platform[:-1]
905
906 return platform
907
908def _node(default=''):
909
910 """ Helper to determine the node name of this machine.
911 """
912 try:
913 import socket
914 except ImportError:
915 # No sockets...
916 return default
917 try:
918 return socket.gethostname()
919 except socket.error:
920 # Still not working...
921 return default
922
923# os.path.abspath is new in Python 1.5.2:
924if not hasattr(os.path,'abspath'):
925
926 def _abspath(path,
927
928 isabs=os.path.isabs,join=os.path.join,getcwd=os.getcwd,
929 normpath=os.path.normpath):
930
931 if not isabs(path):
932 path = join(getcwd(), path)
933 return normpath(path)
934
935else:
936
937 _abspath = os.path.abspath
938
939def _follow_symlinks(filepath):
940
941 """ In case filepath is a symlink, follow it until a
942 real file is reached.
943 """
944 filepath = _abspath(filepath)
945 while os.path.islink(filepath):
946 filepath = os.path.normpath(
Hirokazu Yamamoto171c4aa2008-09-04 11:15:14 +0000947 os.path.join(os.path.dirname(filepath),os.readlink(filepath)))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000948 return filepath
949
950def _syscmd_uname(option,default=''):
951
952 """ Interface to the system's uname command.
953 """
954 if sys.platform in ('dos','win32','win16','os2'):
955 # XXX Others too ?
956 return default
957 try:
Marc-André Lemburg19e5b3f2009-07-13 20:23:49 +0000958 f = os.popen('uname %s 2> %s' % (option, DEV_NULL))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000959 except (AttributeError,os.error):
960 return default
961 output = string.strip(f.read())
962 rc = f.close()
963 if not output or rc:
964 return default
965 else:
966 return output
967
968def _syscmd_file(target,default=''):
969
970 """ Interface to the system's file command.
971
972 The function uses the -b option of the file command to have it
973 ommit the filename in its output and if possible the -L option
974 to have the command follow symlinks. It returns default in
975 case the command should fail.
976
977 """
Jesus Ceadebda5d2012-10-04 15:14:56 +0200978
979 # We do the import here to avoid a bootstrap issue.
980 # See c73b90b6dadd changeset.
981 #
982 # [..]
983 # ranlib libpython2.7.a
984 # gcc -o python \
985 # Modules/python.o \
986 # libpython2.7.a -lsocket -lnsl -ldl -lm
987 # Traceback (most recent call last):
988 # File "./setup.py", line 8, in <module>
989 # from platform import machine as platform_machine
990 # File "[..]/build/Lib/platform.py", line 116, in <module>
991 # import sys,string,os,re,subprocess
992 # File "[..]/build/Lib/subprocess.py", line 429, in <module>
993 # import select
994 # ImportError: No module named select
995
996 import subprocess
997
Hirokazu Yamamotoed8c6442008-09-01 14:32:58 +0000998 if sys.platform in ('dos','win32','win16','os2'):
999 # XXX Others too ?
1000 return default
Jesus Cea3e94e142012-10-04 15:06:57 +02001001 target = _follow_symlinks(target)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001002 try:
Jesus Cea2699c9d2012-10-05 05:18:47 +02001003 proc = subprocess.Popen(['file', target],
1004 stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
Jesus Cea3e94e142012-10-04 15:06:57 +02001005
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001006 except (AttributeError,os.error):
1007 return default
Jesus Cea69e7c9b2012-10-05 04:50:17 +02001008 output = proc.communicate()[0]
Jesus Cea3e94e142012-10-04 15:06:57 +02001009 rc = proc.wait()
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001010 if not output or rc:
1011 return default
1012 else:
1013 return output
1014
1015### Information about the used architecture
1016
1017# Default values for architecture; non-empty strings override the
1018# defaults given as parameters
1019_default_architecture = {
1020 'win32': ('','WindowsPE'),
1021 'win16': ('','Windows'),
1022 'dos': ('','MSDOS'),
1023}
1024
Victor Stinner814b6c22010-04-18 18:22:25 +00001025_architecture_split = re.compile(r'[\s,]').split
1026
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +00001027def architecture(executable=sys.executable,bits='',linkage=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001028
1029 """ Queries the given executable (defaults to the Python interpreter
Brett Cannon8ab27df2003-08-05 03:52:04 +00001030 binary) for various architecture information.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001031
Brett Cannon8ab27df2003-08-05 03:52:04 +00001032 Returns a tuple (bits,linkage) which contains information about
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001033 the bit architecture and the linkage format used for the
1034 executable. Both values are returned as strings.
1035
1036 Values that cannot be determined are returned as given by the
1037 parameter presets. If bits is given as '', the sizeof(pointer)
1038 (or sizeof(long) on Python version < 1.5.2) is used as
1039 indicator for the supported pointer size.
1040
1041 The function relies on the system's "file" command to do the
1042 actual work. This is available on most if not all Unix
Brett Cannon8ab27df2003-08-05 03:52:04 +00001043 platforms. On some non-Unix platforms where the "file" command
1044 does not exist and the executable is set to the Python interpreter
1045 binary defaults from _default_architecture are used.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001046
1047 """
1048 # Use the sizeof(pointer) as default number of bits if nothing
1049 # else is given as default.
1050 if not bits:
1051 import struct
1052 try:
1053 size = struct.calcsize('P')
1054 except struct.error:
1055 # Older installations can only query longs
1056 size = struct.calcsize('l')
1057 bits = str(size*8) + 'bit'
Tim Peters0eadaac2003-04-24 16:02:54 +00001058
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001059 # Get data from the 'file' system command
Marc-André Lemburg3b8f60b2007-01-13 23:13:54 +00001060 if executable:
Victor Stinner814b6c22010-04-18 18:22:25 +00001061 output = _syscmd_file(executable, '')
Marc-André Lemburg3b8f60b2007-01-13 23:13:54 +00001062 else:
Victor Stinner814b6c22010-04-18 18:22:25 +00001063 output = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001064
Victor Stinner814b6c22010-04-18 18:22:25 +00001065 if not output and \
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001066 executable == sys.executable:
1067 # "file" command did not return anything; we'll try to provide
Tim Peters0eadaac2003-04-24 16:02:54 +00001068 # some sensible defaults then...
Florent Xicluna8d1da0f2010-04-01 18:17:09 +00001069 if sys.platform in _default_architecture:
1070 b, l = _default_architecture[sys.platform]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001071 if b:
1072 bits = b
1073 if l:
1074 linkage = l
Florent Xicluna8d1da0f2010-04-01 18:17:09 +00001075 return bits, linkage
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001076
Victor Stinner814b6c22010-04-18 18:22:25 +00001077 # Split the output into a list of strings omitting the filename
1078 fileout = _architecture_split(output)[1:]
1079
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001080 if 'executable' not in fileout:
1081 # Format not supported
1082 return bits,linkage
1083
1084 # Bits
1085 if '32-bit' in fileout:
1086 bits = '32bit'
1087 elif 'N32' in fileout:
1088 # On Irix only
1089 bits = 'n32bit'
1090 elif '64-bit' in fileout:
1091 bits = '64bit'
1092
1093 # Linkage
1094 if 'ELF' in fileout:
1095 linkage = 'ELF'
1096 elif 'PE' in fileout:
1097 # E.g. Windows uses this format
1098 if 'Windows' in fileout:
1099 linkage = 'WindowsPE'
1100 else:
1101 linkage = 'PE'
1102 elif 'COFF' in fileout:
1103 linkage = 'COFF'
1104 elif 'MS-DOS' in fileout:
1105 linkage = 'MSDOS'
1106 else:
1107 # XXX the A.OUT format also falls under this class...
1108 pass
1109
1110 return bits,linkage
1111
1112### Portable uname() interface
Tim Peters0eadaac2003-04-24 16:02:54 +00001113
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001114_uname_cache = None
1115
1116def uname():
1117
1118 """ Fairly portable uname interface. Returns a tuple
1119 of strings (system,node,release,version,machine,processor)
1120 identifying the underlying platform.
1121
1122 Note that unlike the os.uname function this also returns
Brett Cannon8ab27df2003-08-05 03:52:04 +00001123 possible processor information as an additional tuple entry.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001124
1125 Entries which cannot be determined are set to ''.
1126
1127 """
1128 global _uname_cache
Benjamin Peterson5c0be322008-06-13 15:11:50 +00001129 no_os_uname = 0
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001130
1131 if _uname_cache is not None:
1132 return _uname_cache
1133
Benjamin Peterson5c0be322008-06-13 15:11:50 +00001134 processor = ''
1135
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001136 # Get some infos from the builtin os.uname API...
1137 try:
1138 system,node,release,version,machine = os.uname()
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001139 except AttributeError:
Benjamin Peterson5c0be322008-06-13 15:11:50 +00001140 no_os_uname = 1
1141
1142 if no_os_uname or not filter(None, (system, node, release, version, machine)):
1143 # Hmm, no there is either no uname or uname has returned
1144 #'unknowns'... we'll have to poke around the system then.
1145 if no_os_uname:
1146 system = sys.platform
1147 release = ''
1148 version = ''
1149 node = _node()
1150 machine = ''
1151
Marc-André Lemburgcecaa652009-07-13 21:28:33 +00001152 use_syscmd_ver = 1
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001153
1154 # Try win32_ver() on win32 platforms
1155 if system == 'win32':
1156 release,version,csd,ptype = win32_ver()
1157 if release and version:
1158 use_syscmd_ver = 0
Marc-André Lemburgdbd61a22008-03-20 17:31:36 +00001159 # Try to use the PROCESSOR_* environment variables
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001160 # available on Win XP and later; see
1161 # http://support.microsoft.com/kb/888731 and
1162 # http://www.geocities.com/rick_lively/MANUALS/ENV/MSWIN/PROCESSI.HTM
Benjamin Peterson5c0be322008-06-13 15:11:50 +00001163 if not machine:
R. David Murrayc9d1a782010-03-22 15:55:09 +00001164 # WOW64 processes mask the native architecture
1165 if "PROCESSOR_ARCHITEW6432" in os.environ:
1166 machine = os.environ.get("PROCESSOR_ARCHITEW6432", '')
1167 else:
1168 machine = os.environ.get('PROCESSOR_ARCHITECTURE', '')
Benjamin Peterson5c0be322008-06-13 15:11:50 +00001169 if not processor:
1170 processor = os.environ.get('PROCESSOR_IDENTIFIER', machine)
Tim Peters0eadaac2003-04-24 16:02:54 +00001171
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001172 # Try the 'ver' system command available on some
1173 # platforms
1174 if use_syscmd_ver:
1175 system,release,version = _syscmd_ver(system)
Marc-André Lemburgcdc79232004-06-19 17:17:00 +00001176 # Normalize system to what win32_ver() normally returns
1177 # (_syscmd_ver() tends to return the vendor name as well)
1178 if system == 'Microsoft Windows':
1179 system = 'Windows'
Marc-André Lemburgb24cd0f2007-06-12 09:26:49 +00001180 elif system == 'Microsoft' and release == 'Windows':
1181 # Under Windows Vista and Windows Server 2008,
1182 # Microsoft changed the output of the ver command. The
1183 # release is no longer printed. This causes the
1184 # system and release to be misidentified.
1185 system = 'Windows'
1186 if '6.0' == version[:3]:
1187 release = 'Vista'
1188 else:
1189 release = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001190
1191 # In case we still don't know anything useful, we'll try to
1192 # help ourselves
1193 if system in ('win32','win16'):
1194 if not version:
1195 if system == 'win32':
1196 version = '32bit'
1197 else:
1198 version = '16bit'
1199 system = 'Windows'
1200
1201 elif system[:4] == 'java':
1202 release,vendor,vminfo,osinfo = java_ver()
1203 system = 'Java'
1204 version = string.join(vminfo,', ')
1205 if not version:
1206 version = vendor
1207
Benjamin Peterson5c0be322008-06-13 15:11:50 +00001208 # System specific extensions
1209 if system == 'OpenVMS':
1210 # OpenVMS seems to have release and version mixed up
1211 if not release or release == '0':
1212 release = version
1213 version = ''
1214 # Get processor information
1215 try:
1216 import vms_lib
1217 except ImportError:
1218 pass
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001219 else:
Benjamin Peterson5c0be322008-06-13 15:11:50 +00001220 csid, cpu_number = vms_lib.getsyi('SYI$_CPU',0)
1221 if (cpu_number >= 128):
1222 processor = 'Alpha'
1223 else:
1224 processor = 'VAX'
1225 if not processor:
1226 # Get processor information from the uname system command
1227 processor = _syscmd_uname('-p','')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001228
Benjamin Peterson5c0be322008-06-13 15:11:50 +00001229 #If any unknowns still exist, replace them with ''s, which are more portable
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001230 if system == 'unknown':
1231 system = ''
1232 if node == 'unknown':
1233 node = ''
1234 if release == 'unknown':
1235 release = ''
1236 if version == 'unknown':
1237 version = ''
1238 if machine == 'unknown':
1239 machine = ''
1240 if processor == 'unknown':
1241 processor = ''
Sean Reifscheiderf09597c2007-09-17 20:53:21 +00001242
1243 # normalize name
1244 if system == 'Microsoft' and release == 'Windows':
1245 system = 'Windows'
1246 release = 'Vista'
1247
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001248 _uname_cache = system,node,release,version,machine,processor
1249 return _uname_cache
1250
1251### Direct interfaces to some of the uname() return values
1252
1253def system():
1254
1255 """ Returns the system/OS name, e.g. 'Linux', 'Windows' or 'Java'.
1256
1257 An empty string is returned if the value cannot be determined.
1258
1259 """
1260 return uname()[0]
1261
1262def node():
1263
Brett Cannon8ab27df2003-08-05 03:52:04 +00001264 """ Returns the computer's network name (which may not be fully
1265 qualified)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001266
1267 An empty string is returned if the value cannot be determined.
1268
1269 """
1270 return uname()[1]
1271
1272def release():
1273
1274 """ Returns the system's release, e.g. '2.2.0' or 'NT'
1275
1276 An empty string is returned if the value cannot be determined.
1277
1278 """
1279 return uname()[2]
1280
1281def version():
1282
1283 """ Returns the system's release version, e.g. '#3 on degas'
1284
1285 An empty string is returned if the value cannot be determined.
1286
1287 """
1288 return uname()[3]
1289
1290def machine():
1291
1292 """ Returns the machine type, e.g. 'i386'
1293
1294 An empty string is returned if the value cannot be determined.
1295
1296 """
1297 return uname()[4]
1298
1299def processor():
1300
1301 """ Returns the (true) processor name, e.g. 'amdk6'
1302
1303 An empty string is returned if the value cannot be
1304 determined. Note that many platforms do not provide this
1305 information or simply return the same value as for machine(),
1306 e.g. NetBSD does this.
1307
1308 """
1309 return uname()[5]
1310
1311### Various APIs for extracting information from sys.version
1312
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001313_sys_version_parser = re.compile(
1314 r'([\w.+]+)\s*'
1315 '\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*'
1316 '\[([^\]]+)\]?')
1317
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001318_ironpython_sys_version_parser = re.compile(
1319 r'IronPython\s*'
1320 '([\d\.]+)'
1321 '(?: \(([\d\.]+)\))?'
1322 ' on (.NET [\d\.]+)')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001323
Ezio Melottibc385482013-10-21 03:03:32 +03001324# IronPython covering 2.6 and 2.7
1325_ironpython26_sys_version_parser = re.compile(
1326 r'([\d.]+)\s*'
1327 '\(IronPython\s*'
1328 '[\d.]+\s*'
1329 '\(([\d.]+)\) on ([\w.]+ [\d.]+(?: \(\d+-bit\))?)\)'
1330)
1331
Benjamin Peterson0ad9b772009-03-26 19:09:21 +00001332_pypy_sys_version_parser = re.compile(
1333 r'([\w.+]+)\s*'
1334 '\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*'
1335 '\[PyPy [^\]]+\]?')
1336
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001337_sys_version_cache = {}
1338
1339def _sys_version(sys_version=None):
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001340
1341 """ Returns a parsed version of Python's sys.version as tuple
Marc-André Lemburga519cfc2009-03-25 19:44:58 +00001342 (name, version, branch, revision, buildno, builddate, compiler)
1343 referring to the Python implementation name, version, branch,
1344 revision, build number, build date/time as string and the compiler
1345 identification string.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001346
1347 Note that unlike the Python sys.version, the returned value
1348 for the Python version will always include the patchlevel (it
1349 defaults to '.0').
1350
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001351 The function returns empty strings for tuple entries that
1352 cannot be determined.
1353
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001354 sys_version may be given to parse an alternative version
1355 string, e.g. if the version was read from a different Python
1356 interpreter.
1357
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001358 """
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001359 # Get the Python version
1360 if sys_version is None:
1361 sys_version = sys.version
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001362
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001363 # Try the cache first
1364 result = _sys_version_cache.get(sys_version, None)
1365 if result is not None:
1366 return result
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001367
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001368 # Parse it
Ezio Melottibc385482013-10-21 03:03:32 +03001369 if 'IronPython' in sys_version:
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001370 # IronPython
1371 name = 'IronPython'
Ezio Melottibc385482013-10-21 03:03:32 +03001372 if sys_version.startswith('IronPython'):
1373 match = _ironpython_sys_version_parser.match(sys_version)
1374 else:
1375 match = _ironpython26_sys_version_parser.match(sys_version)
1376
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001377 if match is None:
1378 raise ValueError(
1379 'failed to parse IronPython sys.version: %s' %
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001380 repr(sys_version))
Ezio Melottibc385482013-10-21 03:03:32 +03001381
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001382 version, alt_version, compiler = match.groups()
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001383 buildno = ''
1384 builddate = ''
1385
Ezio Melottibc385482013-10-21 03:03:32 +03001386 elif sys.platform.startswith('java'):
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001387 # Jython
1388 name = 'Jython'
Benjamin Petersonf521b8c2009-03-26 18:35:37 +00001389 match = _sys_version_parser.match(sys_version)
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001390 if match is None:
1391 raise ValueError(
1392 'failed to parse Jython sys.version: %s' %
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001393 repr(sys_version))
Benjamin Petersonf521b8c2009-03-26 18:35:37 +00001394 version, buildno, builddate, buildtime, _ = match.groups()
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001395 compiler = sys.platform
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001396
Benjamin Peterson0ad9b772009-03-26 19:09:21 +00001397 elif "PyPy" in sys_version:
1398 # PyPy
1399 name = "PyPy"
1400 match = _pypy_sys_version_parser.match(sys_version)
1401 if match is None:
1402 raise ValueError("failed to parse PyPy sys.version: %s" %
1403 repr(sys_version))
1404 version, buildno, builddate, buildtime = match.groups()
1405 compiler = ""
1406
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001407 else:
1408 # CPython
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001409 match = _sys_version_parser.match(sys_version)
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001410 if match is None:
1411 raise ValueError(
1412 'failed to parse CPython sys.version: %s' %
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001413 repr(sys_version))
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001414 version, buildno, builddate, buildtime, compiler = \
1415 match.groups()
Benjamin Petersonb457b892009-03-26 18:55:48 +00001416 name = 'CPython'
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001417 builddate = builddate + ' ' + buildtime
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001418
Benjamin Petersonb457b892009-03-26 18:55:48 +00001419 if hasattr(sys, 'subversion'):
1420 # sys.subversion was added in Python 2.5
1421 _, branch, revision = sys.subversion
1422 else:
1423 branch = ''
1424 revision = ''
1425
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001426 # Add the patchlevel version if missing
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001427 l = string.split(version, '.')
1428 if len(l) == 2:
1429 l.append('0')
1430 version = string.join(l, '.')
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001431
1432 # Build and cache the result
1433 result = (name, version, branch, revision, buildno, builddate, compiler)
1434 _sys_version_cache[sys_version] = result
1435 return result
1436
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001437def python_implementation():
1438
1439 """ Returns a string identifying the Python implementation.
1440
1441 Currently, the following implementations are identified:
Ezio Melotti6fa09472011-05-04 18:37:50 +03001442 'CPython' (C implementation of Python),
1443 'IronPython' (.NET implementation of Python),
1444 'Jython' (Java implementation of Python),
1445 'PyPy' (Python implementation of Python).
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001446
1447 """
1448 return _sys_version()[0]
1449
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001450def python_version():
1451
1452 """ Returns the Python version as string 'major.minor.patchlevel'
1453
1454 Note that unlike the Python sys.version, the returned value
1455 will always include the patchlevel (it defaults to 0).
1456
1457 """
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001458 return _sys_version()[1]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001459
1460def python_version_tuple():
1461
1462 """ Returns the Python version as tuple (major, minor, patchlevel)
1463 of strings.
1464
1465 Note that unlike the Python sys.version, the returned value
1466 will always include the patchlevel (it defaults to 0).
1467
1468 """
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001469 return tuple(string.split(_sys_version()[1], '.'))
1470
1471def python_branch():
1472
Neal Norwitz4b86f8b2007-01-13 21:22:37 +00001473 """ Returns a string identifying the Python implementation
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001474 branch.
1475
1476 For CPython this is the Subversion branch from which the
1477 Python binary was built.
1478
1479 If not available, an empty string is returned.
1480
1481 """
Tim Petersf733abb2007-01-30 03:03:46 +00001482
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001483 return _sys_version()[2]
1484
1485def python_revision():
1486
Neal Norwitz4b86f8b2007-01-13 21:22:37 +00001487 """ Returns a string identifying the Python implementation
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001488 revision.
1489
1490 For CPython this is the Subversion revision from which the
1491 Python binary was built.
1492
1493 If not available, an empty string is returned.
1494
1495 """
1496 return _sys_version()[3]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001497
1498def python_build():
1499
1500 """ Returns a tuple (buildno, builddate) stating the Python
1501 build number and date as strings.
1502
1503 """
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001504 return _sys_version()[4:6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001505
1506def python_compiler():
1507
1508 """ Returns a string identifying the compiler used for compiling
1509 Python.
1510
1511 """
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001512 return _sys_version()[6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001513
1514### The Opus Magnum of platform strings :-)
1515
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001516_platform_cache = {}
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001517
1518def platform(aliased=0, terse=0):
1519
1520 """ Returns a single string identifying the underlying platform
1521 with as much useful information as possible (but no more :).
Tim Peters0eadaac2003-04-24 16:02:54 +00001522
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001523 The output is intended to be human readable rather than
1524 machine parseable. It may look different on different
1525 platforms and this is intended.
1526
1527 If "aliased" is true, the function will use aliases for
1528 various platforms that report system names which differ from
1529 their common names, e.g. SunOS will be reported as
1530 Solaris. The system_alias() function is used to implement
1531 this.
1532
1533 Setting terse to true causes the function to return only the
1534 absolute minimum information needed to identify the platform.
1535
1536 """
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001537 result = _platform_cache.get((aliased, terse), None)
1538 if result is not None:
1539 return result
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001540
1541 # Get uname information and then apply platform specific cosmetics
1542 # to it...
1543 system,node,release,version,machine,processor = uname()
1544 if machine == processor:
1545 processor = ''
1546 if aliased:
1547 system,release,version = system_alias(system,release,version)
1548
1549 if system == 'Windows':
1550 # MS platforms
1551 rel,vers,csd,ptype = win32_ver(version)
1552 if terse:
1553 platform = _platform(system,release)
1554 else:
1555 platform = _platform(system,release,version,csd)
1556
1557 elif system in ('Linux',):
1558 # Linux based systems
1559 distname,distversion,distid = dist('')
1560 if distname and not terse:
1561 platform = _platform(system,release,machine,processor,
1562 'with',
1563 distname,distversion,distid)
1564 else:
1565 # If the distribution name is unknown check for libc vs. glibc
1566 libcname,libcversion = libc_ver(sys.executable)
1567 platform = _platform(system,release,machine,processor,
1568 'with',
1569 libcname+libcversion)
1570 elif system == 'Java':
1571 # Java platforms
1572 r,v,vminfo,(os_name,os_version,os_arch) = java_ver()
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001573 if terse or not os_name:
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001574 platform = _platform(system,release,version)
1575 else:
1576 platform = _platform(system,release,version,
1577 'on',
1578 os_name,os_version,os_arch)
1579
1580 elif system == 'MacOS':
1581 # MacOS platforms
1582 if terse:
1583 platform = _platform(system,release)
1584 else:
1585 platform = _platform(system,release,machine)
1586
1587 else:
1588 # Generic handler
1589 if terse:
1590 platform = _platform(system,release)
1591 else:
1592 bits,linkage = architecture(sys.executable)
1593 platform = _platform(system,release,machine,processor,bits,linkage)
Tim Peters0eadaac2003-04-24 16:02:54 +00001594
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001595 _platform_cache[(aliased, terse)] = platform
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001596 return platform
1597
1598### Command line interface
1599
1600if __name__ == '__main__':
1601 # Default is to print the aliased verbose platform string
Tim Peters0eadaac2003-04-24 16:02:54 +00001602 terse = ('terse' in sys.argv or '--terse' in sys.argv)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001603 aliased = (not 'nonaliased' in sys.argv and not '--nonaliased' in sys.argv)
1604 print platform(aliased,terse)
1605 sys.exit(0)