123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125 |
- # This Source Code Form is subject to the terms of the Mozilla Public
- # License, v. 2.0. If a copy of the MPL was not distributed with this
- # file, You can obtain one at http://mozilla.org/MPL/2.0/.
- from __future__ import absolute_import
- import os
- import struct
- import subprocess
- from mozpack.errors import errors
- MACHO_SIGNATURES = [
- 0xfeedface, # mach-o 32-bits big endian
- 0xcefaedfe, # mach-o 32-bits little endian
- 0xfeedfacf, # mach-o 64-bits big endian
- 0xcffaedfe, # mach-o 64-bits little endian
- ]
- FAT_SIGNATURE = 0xcafebabe # mach-o FAT binary
- ELF_SIGNATURE = 0x7f454c46 # Elf binary
- UNKNOWN = 0
- MACHO = 1
- ELF = 2
- def get_type(path):
- '''
- Check the signature of the give file and returns what kind of executable
- matches.
- '''
- with open(path, 'rb') as f:
- signature = f.read(4)
- if len(signature) < 4:
- return UNKNOWN
- signature = struct.unpack('>L', signature)[0]
- if signature == ELF_SIGNATURE:
- return ELF
- if signature in MACHO_SIGNATURES:
- return MACHO
- if signature != FAT_SIGNATURE:
- return UNKNOWN
- # We have to sanity check the second four bytes, because Java class
- # files use the same magic number as Mach-O fat binaries.
- # This logic is adapted from file(1), which says that Mach-O uses
- # these bytes to count the number of architectures within, while
- # Java uses it for a version number. Conveniently, there are only
- # 18 labelled Mach-O architectures, and Java's first released
- # class format used the version 43.0.
- num = f.read(4)
- if len(num) < 4:
- return UNKNOWN
- num = struct.unpack('>L', num)[0]
- if num < 20:
- return MACHO
- return UNKNOWN
- def is_executable(path):
- '''
- Return whether a given file path points to an executable or a library,
- where an executable or library is identified by:
- - the file extension on OS/2 and WINNT
- - the file signature on OS/X and ELF systems (GNU/Linux, Android, BSD,
- Solaris)
- As this function is intended for use to choose between the ExecutableFile
- and File classes in FileFinder, and choosing ExecutableFile only matters
- on OS/2, OS/X, ELF and WINNT (in GCC build) systems, we don't bother
- detecting other kind of executables.
- '''
- from buildconfig import substs
- if not os.path.exists(path):
- return False
- if substs['OS_ARCH'] == 'WINNT':
- return path.lower().endswith((substs['DLL_SUFFIX'],
- substs['BIN_SUFFIX']))
- return get_type(path) != UNKNOWN
- def may_strip(path):
- '''
- Return whether strip() should be called
- '''
- from buildconfig import substs
- return not substs['PKG_SKIP_STRIP']
- def strip(path):
- '''
- Execute the STRIP command with STRIP_FLAGS on the given path.
- '''
- from buildconfig import substs
- strip = substs['STRIP']
- flags = substs['STRIP_FLAGS'].split() if 'STRIP_FLAGS' in substs else []
- cmd = [strip] + flags + [path]
- if subprocess.call(cmd) != 0:
- errors.fatal('Error executing ' + ' '.join(cmd))
- def may_elfhack(path):
- '''
- Return whether elfhack() should be called
- '''
- # elfhack only supports libraries. We should check the ELF header for
- # the right flag, but checking the file extension works too.
- from buildconfig import substs
- return ('USE_ELF_HACK' in substs and substs['USE_ELF_HACK'] and
- path.endswith(substs['DLL_SUFFIX']) and
- 'COMPILE_ENVIRONMENT' in substs and substs['COMPILE_ENVIRONMENT'])
- def elfhack(path):
- '''
- Execute the elfhack command on the given path.
- '''
- from buildconfig import topobjdir
- cmd = [os.path.join(topobjdir, 'build/unix/elfhack/elfhack'), path]
- if 'ELF_HACK_FLAGS' in os.environ:
- cmd[1:0] = os.environ['ELF_HACK_FLAGS'].split()
- if subprocess.call(cmd) != 0:
- errors.fatal('Error executing ' + ' '.join(cmd))
|