diff options
author | dec05eba <dec05eba@protonmail.com> | 2018-10-02 18:47:24 +0200 |
---|---|---|
committer | dec05eba <dec05eba@protonmail.com> | 2020-07-06 07:39:33 +0200 |
commit | cd98e64f462e650c9ec4cb673c2b77831396113b (patch) | |
tree | e66603d41e338b730b221660e0f5da5bbe7bb1d5 /scripts | |
parent | 1ffa0d60b0f253506a4e1e335f98c71bba3b866d (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')
-rwxr-xr-x | scripts/package.py | 79 |
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 |