Skip to content

Commit fd12f0f

Browse files
authored
Merge pull request #668 from tiennou/fix/openssl-linkpath
Automatically package OpenSSL inside the framework
2 parents 8927e23 + da034f6 commit fd12f0f

File tree

2 files changed

+139
-0
lines changed

2 files changed

+139
-0
lines changed

ObjectiveGitFramework.xcodeproj/project.pbxproj

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1225,6 +1225,7 @@
12251225
79262F0F13C697BE00A4B1EA /* Copy git2 Headers */,
12261226
BEF7E4DF1A3A47450035BB8E /* Copy git2 Headers again */,
12271227
8DC2EF500486A6940098B216 /* Headers */,
1228+
4D751E9D215D765D003CD3CE /* Package external libraries */,
12281229
);
12291230
buildRules = (
12301231
);
@@ -1356,6 +1357,20 @@
13561357
/* End PBXResourcesBuildPhase section */
13571358

13581359
/* Begin PBXShellScriptBuildPhase section */
1360+
4D751E9D215D765D003CD3CE /* Package external libraries */ = {
1361+
isa = PBXShellScriptBuildPhase;
1362+
buildActionMask = 2147483647;
1363+
files = (
1364+
);
1365+
inputPaths = (
1366+
);
1367+
name = "Package external libraries";
1368+
outputPaths = (
1369+
);
1370+
runOnlyForDeploymentPostprocessing = 0;
1371+
shellPath = /bin/sh;
1372+
shellScript = "./script/repackage-dylibs.rb";
1373+
};
13591374
6A28265317C69CB400C6A948 /* OpenSSL-iOS */ = {
13601375
isa = PBXShellScriptBuildPhase;
13611376
buildActionMask = 2147483647;

script/repackage-dylibs.rb

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
#!/usr/bin/ruby
2+
3+
# This script looks up an executable's list of shared libraries, copies
4+
# non-standard ones (ie. anything not under /usr or /System/) into the target's
5+
# bundle and updates the executable install_name to point to the "packaged"
6+
# version.
7+
8+
# Usage:
9+
# Add the script as a Run Script build phase in the target using Xcode.
10+
11+
# FIXMEs:
12+
# - only handles dylibs
13+
# - only tested against a framework target
14+
# - doesn't care about codesigning
15+
16+
17+
require 'fileutils'
18+
require 'ostruct'
19+
20+
def err(msg)
21+
puts "error: " + msg
22+
exit 1
23+
end
24+
25+
def warn(msg)
26+
puts "warning: " + msg
27+
end
28+
29+
def note(msg)
30+
puts "note: " + msg
31+
end
32+
33+
envvars = %w(
34+
TARGET_BUILD_DIR
35+
EXECUTABLE_PATH
36+
FRAMEWORKS_FOLDER_PATH
37+
)
38+
39+
envvars.each do |var|
40+
raise "Must be run in an Xcode Run Phase" unless ENV[var]
41+
Kernel.const_set var, ENV[var]
42+
end
43+
44+
TARGET_EXECUTABLE_PATH = File.join(TARGET_BUILD_DIR, EXECUTABLE_PATH)
45+
TARGET_FRAMEWORKS_PATH = File.join(TARGET_BUILD_DIR, FRAMEWORKS_FOLDER_PATH)
46+
47+
def extract_link_dependencies(executable)
48+
deps = `otool -L #{executable}`
49+
50+
lines = deps.split("\n").map(&:strip)
51+
lines.shift
52+
# lines.shift
53+
lines.map do |dep|
54+
path, compat, current = /^(.*) \(compatibility version (.*), current version (.*)\)$/.match(dep)[1..3]
55+
err "Failed to parse #{dep}" if path.nil?
56+
57+
dep = OpenStruct.new
58+
dep.is_self = (File.basename(path) == File.basename(executable))
59+
dep.executable = executable
60+
dep.install_name = path
61+
dep.current_version = current
62+
dep.compat_version = compat
63+
dep.type = File.extname(path)
64+
dep.name = File.basename(path)
65+
dep.is_packaged = !!(dep.install_name =~ /^@rpath/)
66+
dep.path = if dep.install_name =~ /^@rpath/
67+
File.join(TARGET_FRAMEWORKS_PATH, dep.name)
68+
else
69+
dep.install_name
70+
end
71+
72+
dep
73+
end
74+
end
75+
76+
def repackage_dependency(dep)
77+
return if dep.is_self or dep.is_packaged or dep.path =~ /^(\/usr\/lib|\/System\/Library)/
78+
79+
note "Packaging #{dep.name}…"
80+
81+
FileUtils.mkdir(TARGET_FRAMEWORKS_PATH) unless Dir.exist?(TARGET_FRAMEWORKS_PATH)
82+
packaged_path = File.join(TARGET_FRAMEWORKS_PATH, dep.name)
83+
84+
case dep.type
85+
when ".dylib"
86+
if File.exist? packaged_path
87+
warn "#{dep.path} already in Frameworks directory, removing"
88+
FileUtils.rm packaged_path
89+
end
90+
91+
note "Copying #{dep[:path]} to TARGET_FRAMEWORKS_PATH"
92+
FileUtils.cp dep[:path], TARGET_FRAMEWORKS_PATH
93+
FileUtils.chmod "u=rw", packaged_path
94+
95+
out = `install_name_tool -change #{dep.path} "@rpath/#{dep.name}" #{dep.executable}`
96+
if $? != 0
97+
err "install_name_tool failed with error #{$?}:\n#{out}"
98+
end
99+
100+
dep.path = packaged_path
101+
dep.install_name = "@rpath/#{dep.name}"
102+
dep.is_packaged = true
103+
else
104+
warn "Unhandled type #{dep.type} for #{dep.path}, ignoring"
105+
end
106+
end
107+
108+
def fix_install_id(dep)
109+
note "Fixing #{dep.name} install_name id…"
110+
out = `install_name_tool -id @rpath/#{dep.name} #{dep.executable}`
111+
if $? != 0
112+
err "install_name_tool failed with error #{$?}:\n#{out}"
113+
end
114+
end
115+
116+
deps = extract_link_dependencies(TARGET_EXECUTABLE_PATH)
117+
while (dep = deps.shift) do
118+
repackage_dependency dep
119+
fix_install_id dep if dep.is_self and dep.executable != TARGET_EXECUTABLE_PATH
120+
deps += extract_link_dependencies(dep[:path]) if dep.is_packaged and not dep.is_self
121+
end
122+
123+
note "Packaging done"
124+
exit 0

0 commit comments

Comments
 (0)