aboutsummaryrefslogtreecommitdiff
path: root/scripts/package.py
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/package.py')
-rwxr-xr-xscripts/package.py79
1 files changed, 79 insertions, 0 deletions
diff --git a/scripts/package.py b/scripts/package.py
new file mode 100755
index 0000000..3de3448
--- /dev/null
+++ b/scripts/package.py
@@ -0,0 +1,79 @@
+#!/usr/bin/env python3
+
+import subprocess
+import sys
+import os
+import shutil
+import re
+import stat
+import tarfile
+
+def get_executable_dynamic_libraries(filepath):
+ libs = []
+ process = subprocess.Popen(["ldd", filepath], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ (stdout, stderr) = process.communicate()
+ if process.returncode != 0:
+ raise RuntimeError("Failed to execute ldd on executable %s, error:\n%s" % (filepath, stderr))
+ lines = stdout.splitlines()
+ for line in lines:
+ s = line.split()
+ if b"=>" in s:
+ if len(s) >= 3:
+ libs.append(os.path.realpath(s[2].decode("UTF-8")))
+ return libs
+
+def make_executable(filepath):
+ mode = os.stat(filepath).st_mode
+ os.chmod(filepath, mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
+
+def main():
+ if len(sys.argv) <= 2:
+ print("usage: %s executable_path destination_path" % sys.argv[0])
+ exit(1)
+
+ os.makedirs(sys.argv[2], exist_ok=True)
+ libs = get_executable_dynamic_libraries(sys.argv[1])
+
+ so_loader_pattern = re.compile("ld-[0-9.]+\\.so.*")
+ so_loader = None
+ for lib in libs:
+ lib_filename = os.path.basename(lib)
+ if so_loader_pattern.match(lib_filename):
+ if so_loader != None:
+ print("Unexpected error: found multiple so loaders, unable to recover")
+ exit(2)
+ so_loader = lib_filename
+
+ executable_filename = os.path.basename(sys.argv[1])
+ new_executable_path = os.path.join(sys.argv[2], executable_filename)
+ shutil.copyfile(sys.argv[1], new_executable_path)
+ make_executable(new_executable_path)
+
+ print("Patching executable")
+ process = subprocess.Popen(["patchelf", "--set-interpreter", so_loader, new_executable_path], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ (stdout, stderr) = process.communicate()
+ if process.returncode != 0:
+ print("Failed to execute patchelf --set-interpreter on executable %s, error: %s" % (new_executable_path, stderr))
+ exit(3)
+
+ process = subprocess.Popen(["patchelf", "--set-rpath", ".", new_executable_path], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ (stdout, stderr) = process.communicate()
+ if process.returncode != 0:
+ print("Failed to execute patchelf --set-rpath on executable %s, error: %s" % (new_executable_path, stderr))
+ exit(4)
+
+ package_name = new_executable_path + ".tar.gz"
+ print("Creating package %s" % os.path.basename(package_name))
+ with tarfile.open(package_name, "w:gz") as tar:
+ for lib in libs:
+ print("Adding shared library %s to tar" % lib)
+ tar.add(lib, arcname=os.path.basename(lib))
+ print("Adding executable %s to tar" % sys.argv[1])
+ tar.add(new_executable_path, arcname=os.path.basename(new_executable_path))
+
+ print("Removing temporary file %s" % new_executable_path)
+ os.remove(new_executable_path)
+ print("Package has been created at %s" % package_name)
+
+if __name__ == "__main__":
+ main() \ No newline at end of file