python/mozbuild/mozpack/executables.py

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/python/mozbuild/mozpack/executables.py	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,121 @@
     1.4 +# This Source Code Form is subject to the terms of the Mozilla Public
     1.5 +# License, v. 2.0. If a copy of the MPL was not distributed with this
     1.6 +# file, You can obtain one at http://mozilla.org/MPL/2.0/.
     1.7 +
     1.8 +import os
     1.9 +import struct
    1.10 +import subprocess
    1.11 +from mozpack.errors import errors
    1.12 +
    1.13 +MACHO_SIGNATURES = [
    1.14 +    0xfeedface,  # mach-o 32-bits big endian
    1.15 +    0xcefaedfe,  # mach-o 32-bits little endian
    1.16 +    0xfeedfacf,  # mach-o 64-bits big endian
    1.17 +    0xcffaedfe,  # mach-o 64-bits little endian
    1.18 +]
    1.19 +
    1.20 +FAT_SIGNATURE = 0xcafebabe  # mach-o FAT binary
    1.21 +
    1.22 +ELF_SIGNATURE = 0x7f454c46  # Elf binary
    1.23 +
    1.24 +UNKNOWN = 0
    1.25 +MACHO = 1
    1.26 +ELF = 2
    1.27 +
    1.28 +def get_type(path):
    1.29 +    '''
    1.30 +    Check the signature of the give file and returns what kind of executable
    1.31 +    matches.
    1.32 +    '''
    1.33 +    with open(path, 'rb') as f:
    1.34 +        signature = f.read(4)
    1.35 +        if len(signature) < 4:
    1.36 +            return UNKNOWN
    1.37 +        signature = struct.unpack('>L', signature)[0]
    1.38 +        if signature == ELF_SIGNATURE:
    1.39 +            return ELF
    1.40 +        if signature in MACHO_SIGNATURES:
    1.41 +            return MACHO
    1.42 +        if signature != FAT_SIGNATURE:
    1.43 +            return UNKNOWN
    1.44 +        # We have to sanity check the second four bytes, because Java class
    1.45 +        # files use the same magic number as Mach-O fat binaries.
    1.46 +        # This logic is adapted from file(1), which says that Mach-O uses
    1.47 +        # these bytes to count the number of architectures within, while
    1.48 +        # Java uses it for a version number. Conveniently, there are only
    1.49 +        # 18 labelled Mach-O architectures, and Java's first released
    1.50 +        # class format used the version 43.0.
    1.51 +        num = f.read(4)
    1.52 +        if len(num) < 4:
    1.53 +            return UNKNOWN
    1.54 +        num = struct.unpack('>L', num)[0]
    1.55 +        if num < 20:
    1.56 +            return MACHO
    1.57 +        return UNKNOWN
    1.58 +
    1.59 +
    1.60 +def is_executable(path):
    1.61 +    '''
    1.62 +    Return whether a given file path points to an executable or a library,
    1.63 +    where an executable or library is identified by:
    1.64 +        - the file extension on OS/2 and WINNT
    1.65 +        - the file signature on OS/X and ELF systems (GNU/Linux, Android, BSD,
    1.66 +          Solaris)
    1.67 +
    1.68 +    As this function is intended for use to choose between the ExecutableFile
    1.69 +    and File classes in FileFinder, and choosing ExecutableFile only matters
    1.70 +    on OS/2, OS/X, ELF and WINNT (in GCC build) systems, we don't bother
    1.71 +    detecting other kind of executables.
    1.72 +    '''
    1.73 +    from buildconfig import substs
    1.74 +    if not os.path.exists(path):
    1.75 +        return False
    1.76 +
    1.77 +    if substs['OS_ARCH'] == 'WINNT':
    1.78 +        return path.lower().endswith((substs['DLL_SUFFIX'],
    1.79 +                                      substs['BIN_SUFFIX']))
    1.80 +
    1.81 +    return get_type(path) != UNKNOWN
    1.82 +
    1.83 +
    1.84 +def may_strip(path):
    1.85 +    '''
    1.86 +    Return whether strip() should be called
    1.87 +    '''
    1.88 +    from buildconfig import substs
    1.89 +    return not substs['PKG_SKIP_STRIP']
    1.90 +
    1.91 +
    1.92 +def strip(path):
    1.93 +    '''
    1.94 +    Execute the STRIP command with STRIP_FLAGS on the given path.
    1.95 +    '''
    1.96 +    from buildconfig import substs
    1.97 +    strip = substs['STRIP']
    1.98 +    flags = substs['STRIP_FLAGS'].split() if 'STRIP_FLAGS' in substs else []
    1.99 +    cmd = [strip] + flags + [path]
   1.100 +    if subprocess.call(cmd) != 0:
   1.101 +        errors.fatal('Error executing ' + ' '.join(cmd))
   1.102 +
   1.103 +
   1.104 +def may_elfhack(path):
   1.105 +    '''
   1.106 +    Return whether elfhack() should be called
   1.107 +    '''
   1.108 +    # elfhack only supports libraries. We should check the ELF header for
   1.109 +    # the right flag, but checking the file extension works too.
   1.110 +    from buildconfig import substs
   1.111 +    return 'USE_ELF_HACK' in substs and substs['USE_ELF_HACK'] and \
   1.112 +           path.endswith(substs['DLL_SUFFIX'])
   1.113 +
   1.114 +
   1.115 +def elfhack(path):
   1.116 +    '''
   1.117 +    Execute the elfhack command on the given path.
   1.118 +    '''
   1.119 +    from buildconfig import topobjdir
   1.120 +    cmd = [os.path.join(topobjdir, 'build/unix/elfhack/elfhack'), path]
   1.121 +    if 'ELF_HACK_FLAGS' in os.environ:
   1.122 +        cmd[1:0] = os.environ['ELF_HACK_FLAGS'].split()
   1.123 +    if subprocess.call(cmd) != 0:
   1.124 +        errors.fatal('Error executing ' + ' '.join(cmd))

mercurial