1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195
|
#!/usr/bin/env python3
import os
import sys
import shutil
import subprocess
strip = False
rpath = False
no_copy = False
# steam_runtime = os.getenv("STEAM_RUNTIME", "")
steam_runtime = os.getenv("STEAMOS", "")
def fix_binary(path):
changes = 0
if os.path.exists(path + ".standalone"):
return changes
if not os.path.exists(path):
raise Exception("could not find " + repr(path))
# find library locations
args = ["ldd", path]
p = subprocess.Popen(args, stdout=subprocess.PIPE)
# noinspection PyUnresolvedReferences
data = p.stdout.read().decode("UTF-8")
if p.wait() != 0:
return 0
print("fixing", path, "no_copy =", no_copy)
library_locations = {}
for line in data.split("\n"):
line = line.strip()
if "=>" not in line:
continue
library_locations[line.split(" ")[0]] = line.split(" ")[2]
# find direct dependencies
args = ["objdump", "-p", path]
p = subprocess.Popen(args, stdout=subprocess.PIPE)
# noinspection PyUnresolvedReferences
data = p.stdout.read().decode("UTF-8")
if p.wait() != 0:
return 0
for line in data.split("\n"):
line = line.strip()
# print(line)
if not line.startswith("NEEDED"):
continue
print(line)
library = line.split(" ")[-1]
print(library)
if ignore_library(library):
continue
library_source = library_locations[library]
library_source = os.path.normpath(library_source)
print(library, library_source)
# if steam_runtime and library_source.startswith(steam_runtime):
# if steam_runtime and not library_source.startswith("/usr/local"):
if steam_runtime and not library_source.startswith("/home"):
print("skipping steam runtime library")
continue
if no_copy:
print("no_copy is set")
continue
dst = os.path.join(os.path.dirname(path), library)
if not os.path.exists(dst):
print("copying", library)
shutil.copy(library_source, dst)
os.chmod(dst, 0o644)
changes += 1
if strip:
# strip does not work after patchelf has been run
command = "strip '{}'".format(path)
print(command)
os.system(command)
if rpath:
command = "patchelf --set-rpath '{}' '{}'".format(rpath, path)
print(command)
assert os.system(command) == 0
# to make sure strip is not run again
os.system("touch '{}.standalone'".format(path))
return changes
def ignore_library(name):
if name.startswith("libgpg-error.so"):
raise Exception(
"Bundling libgpg-error (libgcrypt?) breaks Intel GL driver")
if name.startswith("linux-gate.so"):
return True
if name.startswith("linux-vdso.so"):
return True
if name.startswith("ld-linux.so.2"):
return True
if name.startswith("ld-linux-x86-64.so"):
return True
if name.startswith("ld-linux-aarch64.so.1"):
return True
if name.startswith("libc.so"):
return True
if name.startswith("libstdc++.so"):
# Including libstdc++.sp breaks libGL loading with Intel on Ubuntu 16.10
# libGL error: unable to load driver: i965_dri.so
return True
if name.startswith("libgcc_s.so"):
# Might as well skip this one also, to avoid potential similar problems.
return True
if name.startswith("libpthread.so"):
return True
if name.startswith("libm.so"):
return True
if name.startswith("libdl.so"):
return True
if name.startswith("libresolv.so"):
return True
if name.startswith("librt.so"):
return True
if name.startswith("libutil.so"):
return True
# if name.startswith("libpcre.so"):
# # Problem with OpenAL on Ubuntu 16.04 if this is included.
# return True
if name.startswith("libGL.so"):
return True
if name.startswith("libGLU.so"):
return True
if name.startswith("libEGL.so"):
return True
if name.startswith("libasound.so"):
# Alsa library is in LSB, looks like only "old" interfaces are used
# by SDL2.
return True
if name.startswith("libX11.so"):
return True
if name.startswith("libXext.so"):
return True
if name.startswith("libXcursor.so"):
return True
if name.startswith("libXinerama.so"):
return True
if name.startswith("libXi.so"):
return True
if name.startswith("libXrandr.so"):
return True
if name.startswith("libXss.so"):
return True
if name.startswith("libXxf86vm.so"):
return True
# if name.startswith("libxkbcommon.so"):
# return True
if name.startswith("libxcb.so"):
return True
return False
def fix_iteration(app):
binaries = []
binaries_dir = app
for name in os.listdir(binaries_dir):
binaries.append(os.path.join(binaries_dir, name))
changes = 0
for binary in binaries:
changes += fix_binary(binary)
return changes
def main():
global no_copy, strip, rpath
for arg in list(sys.argv):
if arg.startswith("--rpath="):
sys.argv.remove(arg)
rpath = arg[8:]
elif arg == "--no-copy":
sys.argv.remove("--no-copy")
no_copy = True
elif arg == "--strip":
sys.argv.remove("--strip")
strip = True
app = sys.argv[1]
while True:
changes = fix_iteration(app)
if changes == 0:
break
for name in os.listdir(app):
if name.endswith(".standalone"):
os.remove(os.path.join(app, name))
if __name__ == "__main__":
main()
|