forked from OpenShot/openshot-qt
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfix_qt5_rpath.py
118 lines (97 loc) · 5.72 KB
/
fix_qt5_rpath.py
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
"""Methods to fix Mac OS X @rpath and /usr/local dependencies, and analyze the
app bundle for OpenShot to find all external dependencies"""
import os
import subprocess
from subprocess import call
import re
import shutil
# Ignore non library/executable extensions
non_executables = [".py", ".svg", ".png", ".blend", ".a", ".pak", ".qm", ".pyc", ".txt",
".jpg", ".zip", ".dat", ".conf", ".xml", ".h", ".ui", ".json", ".exe"]
def fix_rpath(PATH):
"""FIX broken @rpath on Qt, PyQt, and /usr/local/ dependencies with no @rpath"""
# Cleanup duplicate folder and files (that cx_freeze creates)
duplicate_path = os.path.join(PATH, "lib", "openshot_qt")
if os.path.exists(duplicate_path):
shutil.rmtree(duplicate_path)
# Find files matching patterns
for root, dirs, files in os.walk(PATH):
for basename in files:
file_path = os.path.join(root, basename)
relative_path = os.path.relpath(root, PATH)
# Skip common file extensions (speed things up)
if os.path.splitext(file_path)[-1] in non_executables or basename.startswith("."):
continue
# Build exe path (relative from the app dir)
executable_path = os.path.join("@executable_path", relative_path, basename)
if relative_path == ".":
executable_path = os.path.join("@executable_path", basename)
# Change ID path of library files
# Sometimes, the ID has an absolute path or invalid @rpath embedded in it, which breaks our frozen exe
print ("ID: %s: install_name_tool %s -id %s" % (basename, file_path, executable_path))
call(["install_name_tool", file_path, "-id", executable_path])
# Loop through all dependencies of each library/executable
raw_output = subprocess.Popen(["oTool", "-L", file_path], stdout=subprocess.PIPE).communicate()[0].decode('utf-8')
for output in raw_output.split("\n")[1:-1]:
if output and "is not an object file" not in output and ".o):" not in output:
dependency_path = output.split('\t')[1].split(' ')[0]
dependency_version = output.split('\t')[1].split(' (')[1].replace(')', '')
dependency_base_path, dependency_name = os.path.split(dependency_path)
# If @rpath or /usr/local found in dependency path, update with @executable_path instead
if "/usr/local" in dependency_path or "@rpath" in dependency_path:
dependency_exe_path = os.path.join("@executable_path", dependency_name)
if not os.path.exists(os.path.join(PATH, dependency_name)):
print("ERROR: /usr/local PATH not found in EXE folder: %s" % dependency_path)
else:
print('-- Dependency: %s: install_name_tool "%s" -change "%s" "%s"' % (dependency_name, file_path, dependency_path, dependency_exe_path))
call(["install_name_tool", file_path, "-change", dependency_path, dependency_exe_path])
def print_min_versions(PATH):
"""Print ALL MINIMUM and SDK VERSIONS for files in OpenShot build folder.
This does not list all dependent libraries though, and sometimes one of those can cause issues."""
# Use 2 different matches, due to different output from different libraries (depending on compiler)
REGEX_SDK_MATCH = re.compile(r'.*(LC_VERSION_MIN_MACOSX).*version (\d+\.\d+).*sdk (\d+\.\d+).*(cmd)', re.DOTALL)
REGEX_SDK_MATCH2 = re.compile(r'.*sdk\s(.*)\s*minos\s(.*)')
VERSIONS = {}
# Find files matching patterns
for root, dirs, files in os.walk(PATH):
for basename in files:
file_path = os.path.join(root, basename)
file_parts = file_path.split("/")
# Skip common file extensions (speed things up)
if os.path.splitext(file_path)[-1] in non_executables or basename.startswith("."):
continue
raw_output = subprocess.Popen(["oTool", "-l", file_path], stdout=subprocess.PIPE).communicate()[0].decode('utf-8')
matches = REGEX_SDK_MATCH.findall(raw_output)
matches2 = REGEX_SDK_MATCH2.findall(raw_output)
min_version = None
sdk_version = None
if matches and len(matches[0]) == 4:
min_version = matches[0][1]
sdk_version = matches[0][2]
elif matches2 and len(matches2[0]) == 2:
sdk_version = matches2[0][0]
min_version = matches2[0][1]
if min_version and sdk_version:
print("... scanning %s for min version (min: %s, sdk: %s)" % (file_path.replace(PATH, ""),
min_version, sdk_version))
# Organize by MIN version
if min_version in VERSIONS:
if file_path not in VERSIONS[min_version]:
VERSIONS[min_version].append(file_path)
else:
VERSIONS[min_version] = [file_path]
if min_version in ['11.0']:
print("ERROR!!!! Minimum OS X version not met for %s" % file_path)
print("\nSummary of Minimum Mac SDKs for Dependencies:")
for key in sorted(VERSIONS.keys()):
print("\n%s" % key)
for file_path in VERSIONS[key]:
print(" %s" % file_path)
print("\nCount of Minimum Mac SDKs for Dependencies:")
for key in sorted(VERSIONS.keys()):
print("%s (%d)" % (key, len(VERSIONS[key])))
if __name__ == "__main__":
"""Run these methods manually for testing"""
PATH = "/Users/jonathanthomas/apps/openshot-qt/build/exe.macosx-10.15-x86_64-3.7"
fix_rpath(PATH)
print_min_versions(PATH)