We maintain a few different branches of the lldb sources, e.g. to add swift
support, and the xcode project files have diverged over time from llvm.org to
our github repositories making git merging a real pain. The two biggest
sources of pain are the BuildFiles and FileReferences sections of the project
file, where we've managed to get the files in completely different orders
across our different branches.
I threw together a quick script to sort the files in these sections, and to
segregate the swift etc files that aren't on llvm.org into their own sections
so they don't cause merge headaches as often.
If anyone is maintaining a fork/branch of lldb where they've added files to the
xcode project file, this sorting will be need hand cleanup from them too. I
suspect that everyone outside apple would be using cmake and ignoring the xcode
project files -- but if this is a problem, please let me know and I'll delay.
Right now my cleanup script looks like this
#! /usr/bin/ruby
#
## Sort the BuildFile and FileReference sections of an Xcode project file,
## putting Apple/github-local files at the front to avoid merge conflicts.
#
## Run this in a directory with a project.pbxproj file. The sorted version
## is printed on standard output.
#
# Files with these words in the names will be sorted into a separate section;
# they are only present in some repositories and so having them intermixed
# can lead to merge failures.
segregated_filenames = ["Swift", "repl", "RPC"]
if !File.exists?("project.pbxproj")
puts "ERROR: project.pbxproj does not exist."
exit(1)
end
beginning = Array.new # All lines before "PBXBuildFile section"
files = Array.new # PBXBuildFile section lines -- sort these
middle = Array.new # All lines between PBXBuildFile and PBXFileReference sections
refs = Array.new # PBXFileReference section lines -- sort these
ending = Array.new # All lines after PBXFileReference section
all_lines = File.readlines 'project.pbxproj'
state = 1 # "begin"
all_lines.each do |l|
l.chomp
if state == 1 && l =~ /Begin PBXBuildFile section/
beginning.push(l)
state = 2
next
end
if state == 2 && l =~ /End PBXBuildFile section/
middle.push(l)
state = 3
next
end
if state == 3 && l =~ /Begin PBXFileReference section/
middle.push(l)
state = 4
next
end
if state == 4 && l =~ /End PBXFileReference section/
ending.push(l)
state = 5
next
end
if state == 1
beginning.push(l)
elsif state == 2
files.push(l)
elsif state == 3
middle.push(l)
elsif state == 4
refs.push(l)
else
ending.push(l)
end
end
######### Sort FILES by the filename, putting swift etc in front
# key is filename
# value is array of text lines for that filename in the FILES text
# (libraries like libz.dylib seem to occur multiple times, probably
# once each for different targets).
files_by_filename = Hash.new { |k, v| k[v] = Array.new }
files.each do |l|
# 2669421A1A6DC2AC0063BE93 /* MICmdCmdTarget.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 266941941A6DC2AC0063BE93 /* MICmdCmdTarget.cpp */; };
if l =~ /^\s+([A-F0-9]{24})\s+\/\*\s+(.*?)\sin.*?\*\/.*?fileRef = ([A-F0-9]{24})\s.*$/
uuid = $1
filename = $2
fileref = $3
files_by_filename[filename].push(l)
end
end
# clear the FILES array
files = Array.new
# add the lines in sorted order. First swift/etc, then everything else.
segregated_filenames.each do |keyword|
filenames = files_by_filename.keys
filenames.select {|l| l.include?(keyword) }.sort.each do |fn|
# re-add all the lines for the filename FN to our FILES array that we'll
# be outputting.
files_by_filename[fn].sort.each do |l|
files.push(l)
end
files_by_filename.delete(fn)
end
end
# All segregated filenames have been added to the FILES output array.
# Now add all the other lines, sorted by filename.
files_by_filename.keys.sort.each do |fn|
files_by_filename[fn].sort.each do |l|
files.push(l)
end
end
######### Sort REFS by the filename, putting swift etc in front
refs_by_filename = Hash.new { |k, v| k[v] = Array.new }
refs.each do |l|
# 2611FF12142D83060017FEA3 /* SBValue.i */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c.preprocessed; path = SBValue.i; sourceTree = "<group>"; };
if l =~ /^\s+([A-F0-9]{24})\s+\/\*\s+(.*?)\s\*\/.*$/
uuid = $1
filename = $2
refs_by_filename[filename].push(l)
end
end
# clear the refs array
refs = Array.new
# add the lines in sorted order. First swift/etc, then everything else.
segregated_filenames.each do |keyword|
filenames = refs_by_filename.keys
filenames.select {|l| l.include?(keyword) }.sort.each do |fn|
# re-add all the lines for the filename FN to our refs array that we'll
# be outputting.
refs_by_filename[fn].sort.each do |l|
refs.push(l)
end
refs_by_filename.delete(fn)
end
end
# All segregated filenames have been added to the refs output array.
# Now add all the other lines, sorted by filename.
refs_by_filename.keys.sort.each do |fn|
refs_by_filename[fn].sort.each do |l|
refs.push(l)
end
end
####### output the sorted pbxproj
[ beginning, files, middle, refs, ending ].each do |arr|
arr.each {|l| puts l}
end
I'll probably add something to fix up file UUIDs that have drifted over time
across the repositories (using the llvm.org project.pbxproj as the definitive
source) before I commit. But this is the general idea.
Jason
_______________________________________________
lldb-dev mailing list
lldb-dev@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-dev