-
-
Save nucleartide/14d672bed6d14acfe0e77f06eb66d998 to your computer and use it in GitHub Desktop.
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
require 'fileutils' | |
require 'optimist' | |
require 'plist' | |
def run(path, source_path) | |
process(path, source_path, '**/*.app', true) | |
process(path, source_path, '**/*.dylib', false) | |
end | |
def process(path, source_path, search_pattern, is_app) | |
binary_paths = Dir.glob(File.join(path, search_pattern)).sort | |
binary_paths.each do |binary_path| | |
dsym_path = File.join(path, "#{file_name_without_extension(binary_path)}.dSYM") | |
next unless File.exist?(dsym_path) | |
if is_app | |
binary_path_for_uuids = File.join(binary_path, 'Contents', 'MacOS', file_name_without_extension(binary_path)) | |
else | |
binary_path_for_uuids = binary_path | |
end | |
binary_uuids = get_uuids_of_dwarf(binary_path_for_uuids) | |
dsym_uuids = get_uuids_of_dwarf(dsym_path) | |
verify_uuids(binary_uuids, dsym_uuids) | |
build_source_path = find_source_path_to_map(binary_path_for_uuids) | |
generate_plist_for_dsym(binary_path, binary_uuids, dsym_path, source_path, build_source_path) | |
create_link_to_dsym(binary_path, dsym_path) | |
end | |
end | |
# https://gist.github.com/benasher44/fcf92fc12ff8b539bee7cc50fb52ed32 | |
def get_uuids_of_dwarf(binary_path) | |
lines = `dwarfdump --uuid "#{binary_path}"`.split("\n") | |
# | |
# An output line of the dwarfdump tool looks like this: | |
# "UUID: E29B1FB0-EBFE-3740-BF5F-5B65CE884713 (x86_64) /path/to/binary" | |
# | |
archs_to_uuids = {} | |
lines.each do |line| | |
elements = line.split(' ') | |
archs_to_uuids[elements[2].gsub(/[()]/, '')] = elements[1] if elements.length >= 4 | |
end | |
raise "Unable to obtain UUIDs from #{binary_path}" if archs_to_uuids.empty? | |
archs_to_uuids | |
end | |
def verify_uuids(binary_uuids, dsym_uuids) | |
binary_uuids.each do |arch, binary_uuid| | |
raise "Unable to find #{arch} architecture in dSYM" unless dsym_uuids.key? arch | |
next if binary_uuid == dsym_uuids[arch] | |
raise "uuid mismatch for arch #{arch}, binary uuid=#{binary_uuid}, dsym uuid=#{dsym_uuids[arch]}" | |
end | |
end | |
def find_source_path_to_map(binary_path) | |
lines = `nm -pa "#{binary_path}" | grep "SO /"`.split("\n") | |
lines.each do |line| | |
split_result = line.split | |
# A line looks like this | |
# 0000000000000000 - 00 0000 SO /potential/path/in/remote/machine | |
next if split_result.length < 6 | |
potential_original_path = split_result[5] | |
# doing some guessing here | |
# interesting, could be other stuff there, like /Users/mtrepka/Epic/UE4-Fortnite/Engine/.. | |
next unless potential_original_path.start_with?('/Users/build/') | |
# taking everything before /Engine/ | |
# in UE4 4.23 /Users/build/Build/++UE4/Sync/Engine/.. | |
# in UE4 4.25 /Users/build/Build/++UE4+Licensee/Sync/Engine/.. | |
potential_original_path_parts = potential_original_path.split(/\/Engine\//) | |
next unless potential_original_path_parts.count > 0 | |
return potential_original_path_parts.first | |
end | |
raise 'Unable to find path match, sorry :-( failing miserably!' | |
end | |
def generate_plist_for_dsym(binary_path, binary_uuids, dsym_path, source_path, build_source_path) | |
binary_uuids.each do |arch, uuid| | |
# DBGDSYMPath, DBGSymbolRichExecutable are not really needed for some reason. Works fine without them. | |
plist_dict = { | |
DBGArchitecture: arch, | |
DBGBuildSourcePath: build_source_path, | |
DBGSourcePath: source_path, | |
#DBGDSYMPath: dsym_path, | |
#DBGSymbolRichExecutable: binary_path | |
} | |
plist_dir = plist_dir_path(binary_path) | |
FileUtils.mkdir_p(plist_dir) unless Dir.exist?(plist_dir) | |
plist_path = File.join(plist_dir, "#{uuid}.plist") | |
File.write(plist_path, plist_dict.to_plist) | |
puts "Generated plist #{plist_path}" | |
end | |
end | |
def create_link_to_dsym(binary_path, dsym_path) | |
dsym_link_dir = dwarf_dir_path(binary_path) | |
FileUtils.mkdir_p(dsym_link_dir) unless Dir.exist?(dsym_link_dir) | |
# actually dsym link file name can be anything, dummy.xyz works fine as well. What the heck, lldb? | |
dsym_link_path = File.join(dsym_link_dir, File.basename(dsym_path)) | |
`ln -s "#{dsym_path}" "#{dsym_link_path}"` unless File.exist?(dsym_link_path) | |
puts "Created link #{dsym_link_path}" | |
end | |
def file_name_without_extension(file_path) | |
File.basename(file_path, File.extname(file_path)) | |
end | |
def plist_dir_path(binary_path) | |
File.join("#{binary_path}.dSYM", 'Contents', 'Resources') | |
end | |
def dwarf_dir_path(binary_path) | |
File.join(plist_dir_path(binary_path), 'DWARF') | |
end | |
options = Optimist.options do | |
opt :path, 'Path to the binaries and dSYMs (e.g. "/Users/Shared/Epic Games/UE_4.23/Engine/Binaries/Mac")', type: :string, default: '/Users/Shared/Epic Games/UE_4.23/Engine/Binaries/Mac'#, required: true | |
opt :source_path, 'Path to the local source directory (e.g. "/Users/Shared/Epic Games/UE_4.23")', type: :string, default: '/Users/Shared/Epic Games/UE_4.23'#, required: true | |
end | |
run options[:path], options[:source_path] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment