Back to index

enigmail  1.4.3
libstdcxx.py
Go to the documentation of this file.
00001 #!/usr/bin/python
00002 
00003 # This script find the version of libstdc++ and prints it as single number
00004 # with 8 bits per element. For example, GLIBCXX_3.4.10 becomes
00005 # 3 << 16 | 4 << 8 | 10 = 197642. This format is easy to use
00006 # in the C preprocessor.
00007 
00008 # We find out both the host and target versions. Since the output
00009 # will be used from shell, we just print the two assignments and evaluate
00010 # them from shell.
00011 
00012 import os
00013 import subprocess
00014 import re
00015 import sys
00016 
00017 re_for_ld = re.compile('.*\((.*)\).*')
00018 
00019 def parse_readelf_line(x):
00020     """Return the version from a readelf line that looks like:
00021     0x00ec: Rev: 1  Flags: none  Index: 8  Cnt: 2  Name: GLIBCXX_3.4.6
00022     """
00023     return x.split(':')[-1].split('_')[-1].strip()
00024 
00025 def parse_ld_line(x):
00026     """Parse a line from the output of ld -t. The output of gold is just
00027     the full path, gnu ld prints "-lstdc++ (path)".
00028     """
00029     t = re_for_ld.match(x)
00030     if t:
00031         return t.groups()[0].strip()
00032     return x.strip()
00033 
00034 def split_ver(v):
00035     """Covert the string '1.2.3' into the list [1,2,3]
00036     """
00037     return [int(x) for x in v.split('.')]
00038 
00039 def cmp_ver(a, b):
00040     """Compare versions in the form 'a.b.c'
00041     """
00042     for (i, j) in zip(split_ver(a), split_ver(b)):
00043         if i != j:
00044             return i - j
00045     return 0
00046 
00047 def encode_ver(v):
00048     """Encode the version as a single number.
00049     """
00050     t = split_ver(v)
00051     return t[0] << 16 | t[1] << 8 | t[2]
00052 
00053 def find_version(e):
00054     """Given the value of environment variable CXX or HOST_CXX, find the
00055     version of the libstdc++ it uses.
00056     """
00057     args = e.split()
00058     args +=  ['-shared', '-Wl,-t']
00059     p = subprocess.Popen(args, stderr=subprocess.STDOUT, stdout=subprocess.PIPE)
00060     candidates = [x for x in p.stdout if 'libstdc++.so' in x]
00061     assert len(candidates) == 1
00062     libstdcxx = parse_ld_line(candidates[-1])
00063 
00064     p = subprocess.Popen(['readelf', '-V', libstdcxx], stdout=subprocess.PIPE)
00065     versions = [parse_readelf_line(x)
00066                 for x in p.stdout.readlines() if 'Name: GLIBCXX' in x]
00067     last_version = sorted(versions, cmp = cmp_ver)[-1]
00068     return encode_ver(last_version)
00069 
00070 if __name__ == '__main__':
00071     if os.uname()[0] == 'Darwin':
00072         sdk_dir = os.environ['MACOS_SDK_DIR']
00073         if 'MacOSX10.5.sdk' in sdk_dir:
00074             target_ver = 0
00075             host_ver = 0
00076         else:
00077             target_ver = encode_ver('3.4.9')
00078             host_ver = encode_ver('3.4.9')
00079     else:
00080         cxx_env = os.environ['CXX']
00081         target_ver = find_version(cxx_env)
00082         host_cxx_env = os.environ.get('HOST_CXX', cxx_env)
00083         host_ver = find_version(host_cxx_env)
00084 
00085     print 'MOZ_LIBSTDCXX_TARGET_VERSION=%s' % target_ver
00086     print 'MOZ_LIBSTDCXX_HOST_VERSION=%s' % host_ver