aboutsummaryrefslogtreecommitdiff
path: root/scripts/package.py
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2018-10-02 18:47:24 +0200
committerdec05eba <dec05eba@protonmail.com>2020-07-06 07:39:33 +0200
commitcd98e64f462e650c9ec4cb673c2b77831396113b (patch)
treee66603d41e338b730b221660e0f5da5bbe7bb1d5 /scripts/package.py
parent1ffa0d60b0f253506a4e1e335f98c71bba3b866d (diff)
Add bundle command to sibs package
Bundle command copies all dynamic library dependencies to one location and creates an archive that can be distributed. Currently only for linux. In testing phase...
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