summaryrefslogtreecommitdiffstats
path: root/python/mozbuild/mozpack/executables.py
diff options
context:
space:
mode:
Diffstat (limited to 'python/mozbuild/mozpack/executables.py')
-rw-r--r--python/mozbuild/mozpack/executables.py124
1 files changed, 124 insertions, 0 deletions
diff --git a/python/mozbuild/mozpack/executables.py b/python/mozbuild/mozpack/executables.py
new file mode 100644
index 000000000..c943564fa
--- /dev/null
+++ b/python/mozbuild/mozpack/executables.py
@@ -0,0 +1,124 @@
+# 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))