Skip to content

Commit

Permalink
Merge pull request #668 from tiennou/fix/openssl-linkpath
Browse files Browse the repository at this point in the history
Automatically package OpenSSL inside the framework
  • Loading branch information
tiennou authored Jan 30, 2019
2 parents 8927e23 + da034f6 commit fd12f0f
Show file tree
Hide file tree
Showing 2 changed files with 139 additions and 0 deletions.
15 changes: 15 additions & 0 deletions ObjectiveGitFramework.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -1225,6 +1225,7 @@
79262F0F13C697BE00A4B1EA /* Copy git2 Headers */,
BEF7E4DF1A3A47450035BB8E /* Copy git2 Headers again */,
8DC2EF500486A6940098B216 /* Headers */,
4D751E9D215D765D003CD3CE /* Package external libraries */,
);
buildRules = (
);
Expand Down Expand Up @@ -1356,6 +1357,20 @@
/* End PBXResourcesBuildPhase section */

/* Begin PBXShellScriptBuildPhase section */
4D751E9D215D765D003CD3CE /* Package external libraries */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Package external libraries";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "./script/repackage-dylibs.rb";
};
6A28265317C69CB400C6A948 /* OpenSSL-iOS */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
Expand Down
124 changes: 124 additions & 0 deletions script/repackage-dylibs.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
#!/usr/bin/ruby

# This script looks up an executable's list of shared libraries, copies
# non-standard ones (ie. anything not under /usr or /System/) into the target's
# bundle and updates the executable install_name to point to the "packaged"
# version.

# Usage:
# Add the script as a Run Script build phase in the target using Xcode.

# FIXMEs:
# - only handles dylibs
# - only tested against a framework target
# - doesn't care about codesigning


require 'fileutils'
require 'ostruct'

def err(msg)
puts "error: " + msg
exit 1
end

def warn(msg)
puts "warning: " + msg
end

def note(msg)
puts "note: " + msg
end

envvars = %w(
TARGET_BUILD_DIR
EXECUTABLE_PATH
FRAMEWORKS_FOLDER_PATH
)

envvars.each do |var|
raise "Must be run in an Xcode Run Phase" unless ENV[var]
Kernel.const_set var, ENV[var]
end

TARGET_EXECUTABLE_PATH = File.join(TARGET_BUILD_DIR, EXECUTABLE_PATH)
TARGET_FRAMEWORKS_PATH = File.join(TARGET_BUILD_DIR, FRAMEWORKS_FOLDER_PATH)

def extract_link_dependencies(executable)
deps = `otool -L #{executable}`

lines = deps.split("\n").map(&:strip)
lines.shift
# lines.shift
lines.map do |dep|
path, compat, current = /^(.*) \(compatibility version (.*), current version (.*)\)$/.match(dep)[1..3]
err "Failed to parse #{dep}" if path.nil?

dep = OpenStruct.new
dep.is_self = (File.basename(path) == File.basename(executable))
dep.executable = executable
dep.install_name = path
dep.current_version = current
dep.compat_version = compat
dep.type = File.extname(path)
dep.name = File.basename(path)
dep.is_packaged = !!(dep.install_name =~ /^@rpath/)
dep.path = if dep.install_name =~ /^@rpath/
File.join(TARGET_FRAMEWORKS_PATH, dep.name)
else
dep.install_name
end

dep
end
end

def repackage_dependency(dep)
return if dep.is_self or dep.is_packaged or dep.path =~ /^(\/usr\/lib|\/System\/Library)/

note "Packaging #{dep.name}…"

FileUtils.mkdir(TARGET_FRAMEWORKS_PATH) unless Dir.exist?(TARGET_FRAMEWORKS_PATH)
packaged_path = File.join(TARGET_FRAMEWORKS_PATH, dep.name)

case dep.type
when ".dylib"
if File.exist? packaged_path
warn "#{dep.path} already in Frameworks directory, removing"
FileUtils.rm packaged_path
end

note "Copying #{dep[:path]} to TARGET_FRAMEWORKS_PATH"
FileUtils.cp dep[:path], TARGET_FRAMEWORKS_PATH
FileUtils.chmod "u=rw", packaged_path

out = `install_name_tool -change #{dep.path} "@rpath/#{dep.name}" #{dep.executable}`
if $? != 0
err "install_name_tool failed with error #{$?}:\n#{out}"
end

dep.path = packaged_path
dep.install_name = "@rpath/#{dep.name}"
dep.is_packaged = true
else
warn "Unhandled type #{dep.type} for #{dep.path}, ignoring"
end
end

def fix_install_id(dep)
note "Fixing #{dep.name} install_name id…"
out = `install_name_tool -id @rpath/#{dep.name} #{dep.executable}`
if $? != 0
err "install_name_tool failed with error #{$?}:\n#{out}"
end
end

deps = extract_link_dependencies(TARGET_EXECUTABLE_PATH)
while (dep = deps.shift) do
repackage_dependency dep
fix_install_id dep if dep.is_self and dep.executable != TARGET_EXECUTABLE_PATH
deps += extract_link_dependencies(dep[:path]) if dep.is_packaged and not dep.is_self
end

note "Packaging done"
exit 0

0 comments on commit fd12f0f

Please sign in to comment.