python/mozbuild/mozpack/executables.py

Fri, 16 Jan 2015 18:13:44 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 18:13:44 +0100
branch
TOR_BUG_9701
changeset 14
925c144e1f1f
permissions
-rw-r--r--

Integrate suggestion from review to improve consistency with existing code.

     1 # This Source Code Form is subject to the terms of the Mozilla Public
     2 # License, v. 2.0. If a copy of the MPL was not distributed with this
     3 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
     5 import os
     6 import struct
     7 import subprocess
     8 from mozpack.errors import errors
    10 MACHO_SIGNATURES = [
    11     0xfeedface,  # mach-o 32-bits big endian
    12     0xcefaedfe,  # mach-o 32-bits little endian
    13     0xfeedfacf,  # mach-o 64-bits big endian
    14     0xcffaedfe,  # mach-o 64-bits little endian
    15 ]
    17 FAT_SIGNATURE = 0xcafebabe  # mach-o FAT binary
    19 ELF_SIGNATURE = 0x7f454c46  # Elf binary
    21 UNKNOWN = 0
    22 MACHO = 1
    23 ELF = 2
    25 def get_type(path):
    26     '''
    27     Check the signature of the give file and returns what kind of executable
    28     matches.
    29     '''
    30     with open(path, 'rb') as f:
    31         signature = f.read(4)
    32         if len(signature) < 4:
    33             return UNKNOWN
    34         signature = struct.unpack('>L', signature)[0]
    35         if signature == ELF_SIGNATURE:
    36             return ELF
    37         if signature in MACHO_SIGNATURES:
    38             return MACHO
    39         if signature != FAT_SIGNATURE:
    40             return UNKNOWN
    41         # We have to sanity check the second four bytes, because Java class
    42         # files use the same magic number as Mach-O fat binaries.
    43         # This logic is adapted from file(1), which says that Mach-O uses
    44         # these bytes to count the number of architectures within, while
    45         # Java uses it for a version number. Conveniently, there are only
    46         # 18 labelled Mach-O architectures, and Java's first released
    47         # class format used the version 43.0.
    48         num = f.read(4)
    49         if len(num) < 4:
    50             return UNKNOWN
    51         num = struct.unpack('>L', num)[0]
    52         if num < 20:
    53             return MACHO
    54         return UNKNOWN
    57 def is_executable(path):
    58     '''
    59     Return whether a given file path points to an executable or a library,
    60     where an executable or library is identified by:
    61         - the file extension on OS/2 and WINNT
    62         - the file signature on OS/X and ELF systems (GNU/Linux, Android, BSD,
    63           Solaris)
    65     As this function is intended for use to choose between the ExecutableFile
    66     and File classes in FileFinder, and choosing ExecutableFile only matters
    67     on OS/2, OS/X, ELF and WINNT (in GCC build) systems, we don't bother
    68     detecting other kind of executables.
    69     '''
    70     from buildconfig import substs
    71     if not os.path.exists(path):
    72         return False
    74     if substs['OS_ARCH'] == 'WINNT':
    75         return path.lower().endswith((substs['DLL_SUFFIX'],
    76                                       substs['BIN_SUFFIX']))
    78     return get_type(path) != UNKNOWN
    81 def may_strip(path):
    82     '''
    83     Return whether strip() should be called
    84     '''
    85     from buildconfig import substs
    86     return not substs['PKG_SKIP_STRIP']
    89 def strip(path):
    90     '''
    91     Execute the STRIP command with STRIP_FLAGS on the given path.
    92     '''
    93     from buildconfig import substs
    94     strip = substs['STRIP']
    95     flags = substs['STRIP_FLAGS'].split() if 'STRIP_FLAGS' in substs else []
    96     cmd = [strip] + flags + [path]
    97     if subprocess.call(cmd) != 0:
    98         errors.fatal('Error executing ' + ' '.join(cmd))
   101 def may_elfhack(path):
   102     '''
   103     Return whether elfhack() should be called
   104     '''
   105     # elfhack only supports libraries. We should check the ELF header for
   106     # the right flag, but checking the file extension works too.
   107     from buildconfig import substs
   108     return 'USE_ELF_HACK' in substs and substs['USE_ELF_HACK'] and \
   109            path.endswith(substs['DLL_SUFFIX'])
   112 def elfhack(path):
   113     '''
   114     Execute the elfhack command on the given path.
   115     '''
   116     from buildconfig import topobjdir
   117     cmd = [os.path.join(topobjdir, 'build/unix/elfhack/elfhack'), path]
   118     if 'ELF_HACK_FLAGS' in os.environ:
   119         cmd[1:0] = os.environ['ELF_HACK_FLAGS'].split()
   120     if subprocess.call(cmd) != 0:
   121         errors.fatal('Error executing ' + ' '.join(cmd))

mercurial