-
Notifications
You must be signed in to change notification settings - Fork 280
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #668 from tiennou/fix/openssl-linkpath
Automatically package OpenSSL inside the framework
- Loading branch information
Showing
2 changed files
with
139 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |