switching to python3 for creating Xcode project files from bakefile
moving fix_xcode_ids to python 3 and make it importable, the current AppleScript dictionary from Xcode makes it impossible to use it for our purpose
This commit is contained in:
@@ -17,23 +17,12 @@ import re
|
|||||||
USAGE = """fix_xcode_ids - Modifies an Xcode project in-place to use the same identifiers (based on name) instead of being different on each regeneration"
|
USAGE = """fix_xcode_ids - Modifies an Xcode project in-place to use the same identifiers (based on name) instead of being different on each regeneration"
|
||||||
Usage: fix_xcode_ids xcode_proj_dir"""
|
Usage: fix_xcode_ids xcode_proj_dir"""
|
||||||
|
|
||||||
if not testFixStage:
|
|
||||||
if len(sys.argv) < 2:
|
|
||||||
print USAGE
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
projectFile = sys.argv[1] + "/project.pbxproj"
|
|
||||||
fin = open(projectFile, "r")
|
|
||||||
strIn = fin.read()
|
|
||||||
fin.close()
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Xcode identifiers (IDs) consist of 24 hexadecimal digits
|
# Xcode identifiers (IDs) consist of 24 hexadecimal digits
|
||||||
idMask = "[A-Fa-f0-9]{24}"
|
idMask = "[A-Fa-f0-9]{24}"
|
||||||
|
|
||||||
idDict = {}
|
idDict = {}
|
||||||
|
|
||||||
|
|
||||||
# convert a name to an identifier for Xcode
|
# convert a name to an identifier for Xcode
|
||||||
def toUuid(name):
|
def toUuid(name):
|
||||||
from uuid import uuid3, UUID
|
from uuid import uuid3, UUID
|
||||||
@@ -41,13 +30,14 @@ def toUuid(name):
|
|||||||
|
|
||||||
# Some names can appear twice or even more (depending on number of
|
# Some names can appear twice or even more (depending on number of
|
||||||
# targets), make them unique
|
# targets), make them unique
|
||||||
while id in idDict.values() :
|
while id in idDict.values():
|
||||||
id = "%024X" % (int(id, 16) + 1)
|
id = "%024X" % (int(id, 16) + 1)
|
||||||
return id
|
return id
|
||||||
|
|
||||||
|
|
||||||
def insertBuildFileEntry(filePath, fileRefId):
|
def insertBuildFileEntry(filePath, fileRefId):
|
||||||
global strIn
|
global strIn
|
||||||
print "\tInsert PBXBuildFile for '%s'..." % filePath,
|
print("\tInsert PBXBuildFile for '%s'..." % filePath)
|
||||||
|
|
||||||
matchBuildFileSection = re.search("/\* Begin PBXBuildFile section \*/\n", strIn)
|
matchBuildFileSection = re.search("/\* Begin PBXBuildFile section \*/\n", strIn)
|
||||||
dirName, fileName = os.path.split(filePath)
|
dirName, fileName = os.path.split(filePath)
|
||||||
@@ -55,17 +45,18 @@ def insertBuildFileEntry(filePath, fileRefId):
|
|||||||
fileInSources = fileName + " in Sources"
|
fileInSources = fileName + " in Sources"
|
||||||
id = toUuid(fileInSources)
|
id = toUuid(fileInSources)
|
||||||
idDict[id] = id
|
idDict[id] = id
|
||||||
insert = "\t\t%s /* %s */ = {isa = PBXBuildFile; fileRef = %s /* %s */; };\n" % (id, fileInSources, fileRefId, fileName)
|
insert = "\t\t%s /* %s */ = {isa = PBXBuildFile; fileRef = %s /* %s */; };\n" % (
|
||||||
|
id, fileInSources, fileRefId, fileName)
|
||||||
|
|
||||||
strIn = strIn[:matchBuildFileSection.end()] + insert + strIn[matchBuildFileSection.end():]
|
strIn = strIn[:matchBuildFileSection.end()] + insert + strIn[matchBuildFileSection.end():]
|
||||||
|
|
||||||
print "OK"
|
print("OK")
|
||||||
return id
|
return id
|
||||||
|
|
||||||
|
|
||||||
def insertFileRefEntry(filePath, id = 0):
|
def insertFileRefEntry(filePath, id=0):
|
||||||
global strIn
|
global strIn
|
||||||
print "\tInsert PBXFileReference for '%s'..." % filePath,
|
print("\tInsert PBXFileReference for '%s'..." % filePath)
|
||||||
|
|
||||||
matchFileRefSection = re.search("/\* Begin PBXFileReference section \*/\n", strIn)
|
matchFileRefSection = re.search("/\* Begin PBXFileReference section \*/\n", strIn)
|
||||||
dirName, fileName = os.path.split(filePath)
|
dirName, fileName = os.path.split(filePath)
|
||||||
@@ -73,208 +64,232 @@ def insertFileRefEntry(filePath, id = 0):
|
|||||||
id = toUuid(fileName)
|
id = toUuid(fileName)
|
||||||
idDict[id] = id
|
idDict[id] = id
|
||||||
|
|
||||||
insert = "\t\t%s /* %s */ = {isa = PBXFileReference; lastKnownFileType = file; name = %s; path = %s; sourceTree = \"<group>\"; };\n" % (id, fileName, fileName, filePath)
|
insert = "\t\t%s /* %s */ = {isa = PBXFileReference; lastKnownFileType = file; name = %s; path = %s; sourceTree = \"<group>\"; };\n" % (
|
||||||
|
id, fileName, fileName, filePath)
|
||||||
strIn = strIn[:matchFileRefSection.end()] + insert + strIn[matchFileRefSection.end():]
|
strIn = strIn[:matchFileRefSection.end()] + insert + strIn[matchFileRefSection.end():]
|
||||||
|
|
||||||
print "OK"
|
print("OK")
|
||||||
return id
|
return id
|
||||||
|
|
||||||
|
|
||||||
def insertSourcesBuildPhaseEntry(id, fileName, insertBeforeFileName, startSearchPos = 0):
|
def insertSourcesBuildPhaseEntry(id, fileName, insertBeforeFileName, startSearchPos=0):
|
||||||
global strIn
|
global strIn
|
||||||
print "\tInsert PBXSourcesBuildPhase for '%s'..." % fileName,
|
print("\tInsert PBXSourcesBuildPhase for '%s'..." % fileName)
|
||||||
|
|
||||||
matchBuildPhase = re.compile(".+ /\* " + insertBeforeFileName + " in Sources \*/,") \
|
matchBuildPhase = re.compile(".+ /\* " + insertBeforeFileName + " in Sources \*/,") \
|
||||||
.search(strIn, startSearchPos)
|
.search(strIn, startSearchPos)
|
||||||
insert = "\t\t\t\t%s /* %s in Sources */,\n" % (id, fileName)
|
insert = "\t\t\t\t%s /* %s in Sources */,\n" % (id, fileName)
|
||||||
strIn = strIn[:matchBuildPhase.start()] \
|
strIn = strIn[:matchBuildPhase.start()] \
|
||||||
+ insert \
|
+ insert \
|
||||||
+ strIn[matchBuildPhase.start():]
|
+ strIn[matchBuildPhase.start():]
|
||||||
|
|
||||||
print "OK"
|
print("OK")
|
||||||
return matchBuildPhase.start() + len(insert) + len(matchBuildPhase.group(0))
|
return matchBuildPhase.start() + len(insert) + len(matchBuildPhase.group(0))
|
||||||
|
|
||||||
|
|
||||||
# Detect and fix errors in the project file that might have been introduced.
|
# Detect and fix errors in the project file that might have been introduced.
|
||||||
# Sometimes two source files are concatenated. These are spottable by
|
# Sometimes two source files are concatenated. These are spottable by
|
||||||
# looking for patterns such as "filename.cppsrc/html/"
|
# looking for patterns such as "filename.cppsrc/html/"
|
||||||
# Following is a stripped Xcode project containing several problems that
|
# Following is a stripped Xcode project containing several problems that
|
||||||
# are solved after finding the error.
|
# are solved after finding the error.
|
||||||
strTest = \
|
strTest = \
|
||||||
"""/* Begin PBXBuildFile section */
|
"""/* Begin PBXBuildFile section */
|
||||||
95DE8BAB1238EE1800B43069 /* m_fonts.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 95DE8BAA1238EE1700B43069 /* m_fonts.cpp */; };
|
95DE8BAB1238EE1800B43069 /* m_fonts.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 95DE8BAA1238EE1700B43069 /* m_fonts.cpp */; };
|
||||||
95DE8BAC1238EE1800B43069 /* m_fonts.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 95DE8BAA1238EE1700B43069 /* m_fonts.cpp */; };
|
95DE8BAC1238EE1800B43069 /* m_fonts.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 95DE8BAA1238EE1700B43069 /* m_fonts.cpp */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
95DE8BAA1238EE1700B43069 /* m_fonts.cpp */ = {isa = PBXFileReference; lastKnownFileType = file; name = m_fonts.cpp; path = ../../src/html/m_dflist.cppsrc/html/m_fonts.cpp; sourceTree = "<group>"; };
|
95DE8BAA1238EE1700B43069 /* m_fonts.cpp */ = {isa = PBXFileReference; lastKnownFileType = file; name = m_fonts.cpp; path = ../../src/html/m_dflist.cppsrc/html/m_fonts.cpp; sourceTree = "<group>"; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
/* Begin PBXGroup section */
|
/* Begin PBXGroup section */
|
||||||
95DE8B831238EE1000B43069 /* html */ = {
|
95DE8B831238EE1000B43069 /* html */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
95DE8B841238EE1000B43069 /* src/html */,
|
95DE8B841238EE1000B43069 /* src/html */,
|
||||||
95DE8BA91238EE1700B43069 /* src/html/m_dflist.cppsrc/html */,
|
95DE8BA91238EE1700B43069 /* src/html/m_dflist.cppsrc/html */,
|
||||||
95DE8BCE1238EE1F00B43069 /* src/generic */,
|
95DE8BCE1238EE1F00B43069 /* src/generic */,
|
||||||
);
|
);
|
||||||
name = html;
|
name = html;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
95DE8B841238EE1000B43069 /* src/html */ = {
|
95DE8B841238EE1000B43069 /* src/html */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
95DE8B851238EE1000B43069 /* chm.cpp */,
|
95DE8B851238EE1000B43069 /* chm.cpp */,
|
||||||
95DE8BAD1238EE1800B43069 /* m_hline.cpp */,
|
95DE8BAD1238EE1800B43069 /* m_hline.cpp */,
|
||||||
);
|
);
|
||||||
name = src/html;
|
name = src/html;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
|
||||||
95DE8BA91238EE1700B43069 /* src/html/m_dflist.cppsrc/html */ = {
|
95DE8BA91238EE1700B43069 /* src/html/m_dflist.cppsrc/html */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
95DE8BAA1238EE1700B43069 /* m_fonts.cpp */,
|
95DE8BAA1238EE1700B43069 /* m_fonts.cpp */,
|
||||||
);
|
);
|
||||||
name = src/html/m_dflist.cppsrc/html;
|
name = src/html/m_dflist.cppsrc/html;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
/* End PBXGroup section */
|
/* End PBXGroup section */
|
||||||
|
|
||||||
|
|
||||||
/* Begin PBXSourcesBuildPhase section */
|
/* Begin PBXSourcesBuildPhase section */
|
||||||
404BEE5E10EC83280080E2B8 /* Sources */ = {
|
404BEE5E10EC83280080E2B8 /* Sources */ = {
|
||||||
files = (
|
files = (
|
||||||
95DE8BAC1238EE1800B43069 /* m_fonts.cpp in Sources */,
|
95DE8BAC1238EE1800B43069 /* m_fonts.cpp in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
D2AAC0C405546C1D00DB518D /* Sources */ = {
|
D2AAC0C405546C1D00DB518D /* Sources */ = {
|
||||||
files = (
|
files = (
|
||||||
95DE8BAB1238EE1800B43069 /* m_fonts.cpp in Sources */,
|
95DE8BAB1238EE1800B43069 /* m_fonts.cpp in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* End PBXSourcesBuildPhase section */"""
|
/* End PBXSourcesBuildPhase section */"""
|
||||||
|
|
||||||
if testFixStage:
|
|
||||||
strIn = strTest
|
|
||||||
|
|
||||||
rc = re.compile(".+ (?P<path1>[\w/.]+(\.cpp|\.cxx|\.c))(?P<path2>\w+/[\w/.]+).+")
|
|
||||||
matchLine = rc.search(strIn)
|
|
||||||
while matchLine:
|
|
||||||
line = matchLine.group(0)
|
|
||||||
|
|
||||||
# is it a line from the PBXFileReference section containing 2 mixed paths?
|
|
||||||
# example:
|
|
||||||
# FEDCBA9876543210FEDCBA98 /* file2.cpp */ = {isa = PBXFileReference; lastKnownFileType = file; name = file2.cpp; path = ../../src/html/file1.cppsrc/html/file2.cpp; sourceTree = "<group>"; };
|
|
||||||
if line.endswith("};") :
|
|
||||||
path1 = matchLine.group('path1')
|
|
||||||
path2 = matchLine.group('path2')
|
|
||||||
print "Correcting mixed paths '%s' and '%s' at '%s':" % (path1, path2, line)
|
|
||||||
# if so, make note of the ID used (belongs to path2), remove the line
|
|
||||||
# and split the 2 paths inserting 2 new entries inside PBXFileReference
|
|
||||||
fileRefId2 = re.search(idMask, line).group(0)
|
|
||||||
|
|
||||||
print "\tDelete the offending PBXFileReference line...",
|
|
||||||
# delete the PBXFileReference line that was found and which contains 2 mixed paths
|
|
||||||
strIn = strIn[:matchLine.start()] + strIn[matchLine.end()+1:]
|
|
||||||
print "OK"
|
|
||||||
|
|
||||||
# insert corrected path1 entry in PBXFileReference
|
|
||||||
fileRefId1 = insertFileRefEntry(path1)
|
|
||||||
|
|
||||||
# do the same for path2 (which already had a ID)
|
|
||||||
path2Corrected = path2
|
|
||||||
if path2Corrected.startswith('src') :
|
|
||||||
path2Corrected = '../../' + path2Corrected
|
|
||||||
|
|
||||||
insertFileRefEntry(path2Corrected, fileRefId2)
|
|
||||||
|
|
||||||
|
|
||||||
buildPhaseId = {}
|
|
||||||
# insert a PBXBuildFile entry, 1 for each target
|
|
||||||
# path2 already has correct PBXBuildFile entries
|
|
||||||
targetCount = strIn.count("isa = PBXSourcesBuildPhase")
|
|
||||||
for i in range(0, targetCount):
|
|
||||||
buildPhaseId[i] = insertBuildFileEntry(path1, fileRefId1)
|
|
||||||
|
|
||||||
|
|
||||||
fileName1 = os.path.split(path1)[1]
|
|
||||||
dir2, fileName2 = os.path.split(path2)
|
|
||||||
|
|
||||||
# refer to each PBXBuildFile in each PBXSourcesBuildPhase
|
|
||||||
startSearchIndex = 0
|
|
||||||
for i in range(0, targetCount):
|
|
||||||
startSearchIndex = insertSourcesBuildPhaseEntry(buildPhaseId[i], fileName1, fileName2, startSearchIndex)
|
|
||||||
|
|
||||||
|
|
||||||
# insert both paths in the group they belong to
|
|
||||||
matchGroupStart = re.search("/\* %s \*/ = {" % dir2, strIn)
|
|
||||||
endGroupIndex = strIn.find("};", matchGroupStart.start())
|
|
||||||
|
|
||||||
for matchGroupLine in re.compile(".+" + idMask + " /\* (.+) \*/,").finditer(strIn, matchGroupStart.start(), endGroupIndex) :
|
|
||||||
if matchGroupLine.group(1) > fileName1:
|
|
||||||
print "\tInsert paths in PBXGroup '%s', just before '%s'..." % (dir2, matchGroupLine.group(1)),
|
|
||||||
strIn = strIn[:matchGroupLine.start()] \
|
|
||||||
+ "\t\t\t\t%s /* %s */,\n" % (fileRefId1, fileName1) \
|
|
||||||
+ "\t\t\t\t%s /* %s */,\n" % (fileRefId2, fileName2) \
|
|
||||||
+ strIn[matchGroupLine.start():]
|
|
||||||
print "OK"
|
|
||||||
|
|
||||||
break
|
|
||||||
|
|
||||||
elif line.endswith("*/ = {") :
|
|
||||||
print "Delete invalid PBXGroup starting at '%s'..." % line,
|
|
||||||
find = "};\n"
|
|
||||||
endGroupIndex = strIn.find(find, matchLine.start()) + len(find)
|
|
||||||
strIn = strIn[:matchLine.start()] + strIn[endGroupIndex:]
|
|
||||||
print "OK"
|
|
||||||
|
|
||||||
elif line.endswith(" */,") :
|
|
||||||
print "Delete invalid PBXGroup child '%s'..." % line,
|
|
||||||
strIn = strIn[:matchLine.start()] + strIn[matchLine.end()+1:]
|
|
||||||
print "OK"
|
|
||||||
|
|
||||||
matchLine = rc.search(strIn)
|
|
||||||
|
|
||||||
if testFixStage:
|
|
||||||
print "------------------------------------------"
|
|
||||||
print strIn
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
|
|
||||||
# key = original ID found in project
|
|
||||||
# value = ID it will be replaced by
|
|
||||||
idDict = {}
|
|
||||||
|
|
||||||
# some of the strings to match to find definitions of Xcode IDs:
|
|
||||||
|
|
||||||
# from PBXBuildFile section:
|
|
||||||
# 0123456789ABCDEF01234567 /* filename.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FEDCBA9876543210FEDCBA98 /* filename.cpp */; };
|
|
||||||
|
|
||||||
# from PBXFileReference section:
|
|
||||||
# FEDCBA9876543210FEDCBA98 /* filename.cpp */ = {isa = PBXFileReference; lastKnownFileType = file; name = any.cpp; path = ../../src/common/filename.cpp; sourceTree = "<group>"; };
|
|
||||||
|
|
||||||
# from remaining sections:
|
|
||||||
# 890123456789ABCDEF012345 /* Name */ = {
|
|
||||||
|
|
||||||
# Capture the first comment between /* and */ (file/section name) as a group
|
|
||||||
rc = re.compile("\s+(" + idMask + ") /\* (.+) \*/ = {.*$", re.MULTILINE)
|
|
||||||
dict = rc.findall(strIn)
|
|
||||||
|
|
||||||
for s in dict:
|
|
||||||
# s[0] is the original ID, s[1] is the name
|
|
||||||
assert(not s[0] in idDict)
|
|
||||||
idDict[s[0]] = toUuid(s[1])
|
|
||||||
|
|
||||||
|
|
||||||
# replace all found identifiers with the new ones
|
# replace all found identifiers with the new ones
|
||||||
def repl(match):
|
def repl(match):
|
||||||
return idDict[match.group(0)]
|
return idDict[match.group(0)]
|
||||||
|
|
||||||
strOut = re.sub(idMask, repl, strIn)
|
|
||||||
|
|
||||||
fout = open(projectFile, "w")
|
def processFile(projectFile):
|
||||||
fout.write(strOut)
|
global strIn
|
||||||
fout.close()
|
|
||||||
|
fin = open(projectFile, "r")
|
||||||
|
strIn = fin.read()
|
||||||
|
fin.close()
|
||||||
|
|
||||||
|
strOut = processContent()
|
||||||
|
|
||||||
|
fout = open(projectFile, "w")
|
||||||
|
fout.write(strOut)
|
||||||
|
fout.close()
|
||||||
|
|
||||||
|
|
||||||
|
def processContent():
|
||||||
|
global strIn
|
||||||
|
global idDict
|
||||||
|
|
||||||
|
rc = re.compile(".+ (?P<path1>[\w/.]+(\.cpp|\.cxx|\.c))(?P<path2>\w+/[\w/.]+).+")
|
||||||
|
matchLine = rc.search(strIn)
|
||||||
|
while matchLine:
|
||||||
|
line = matchLine.group(0)
|
||||||
|
|
||||||
|
# is it a line from the PBXFileReference section containing 2 mixed paths?
|
||||||
|
# example:
|
||||||
|
# FEDCBA9876543210FEDCBA98 /* file2.cpp */ = {isa = PBXFileReference; lastKnownFileType = file; name = file2.cpp; path = ../../src/html/file1.cppsrc/html/file2.cpp; sourceTree = "<group>"; };
|
||||||
|
if line.endswith("};"):
|
||||||
|
path1 = matchLine.group('path1')
|
||||||
|
path2 = matchLine.group('path2')
|
||||||
|
print("Correcting mixed paths '%s' and '%s' at '%s':" % (path1, path2, line))
|
||||||
|
# if so, make note of the ID used (belongs to path2), remove the line
|
||||||
|
# and split the 2 paths inserting 2 new entries inside PBXFileReference
|
||||||
|
fileRefId2 = re.search(idMask, line).group(0)
|
||||||
|
|
||||||
|
print("\tDelete the offending PBXFileReference line...")
|
||||||
|
# delete the PBXFileReference line that was found and which contains 2 mixed paths
|
||||||
|
strIn = strIn[:matchLine.start()] + strIn[matchLine.end() + 1:]
|
||||||
|
print("OK")
|
||||||
|
|
||||||
|
# insert corrected path1 entry in PBXFileReference
|
||||||
|
fileRefId1 = insertFileRefEntry(path1)
|
||||||
|
|
||||||
|
# do the same for path2 (which already had a ID)
|
||||||
|
path2Corrected = path2
|
||||||
|
if path2Corrected.startswith('src'):
|
||||||
|
path2Corrected = '../../' + path2Corrected
|
||||||
|
|
||||||
|
insertFileRefEntry(path2Corrected, fileRefId2)
|
||||||
|
|
||||||
|
buildPhaseId = {}
|
||||||
|
# insert a PBXBuildFile entry, 1 for each target
|
||||||
|
# path2 already has correct PBXBuildFile entries
|
||||||
|
targetCount = strIn.count("isa = PBXSourcesBuildPhase")
|
||||||
|
for i in range(0, targetCount):
|
||||||
|
buildPhaseId[i] = insertBuildFileEntry(path1, fileRefId1)
|
||||||
|
|
||||||
|
fileName1 = os.path.split(path1)[1]
|
||||||
|
dir2, fileName2 = os.path.split(path2)
|
||||||
|
|
||||||
|
# refer to each PBXBuildFile in each PBXSourcesBuildPhase
|
||||||
|
startSearchIndex = 0
|
||||||
|
for i in range(0, targetCount):
|
||||||
|
startSearchIndex = insertSourcesBuildPhaseEntry(buildPhaseId[i], fileName1, fileName2, startSearchIndex)
|
||||||
|
|
||||||
|
# insert both paths in the group they belong to
|
||||||
|
matchGroupStart = re.search("/\* %s \*/ = {" % dir2, strIn)
|
||||||
|
endGroupIndex = strIn.find("};", matchGroupStart.start())
|
||||||
|
|
||||||
|
for matchGroupLine in re.compile(".+" + idMask + " /\* (.+) \*/,").finditer(strIn, matchGroupStart.start(),
|
||||||
|
endGroupIndex):
|
||||||
|
if matchGroupLine.group(1) > fileName1:
|
||||||
|
print("\tInsert paths in PBXGroup '%s', just before '%s'..." % (dir2, matchGroupLine.group(1)))
|
||||||
|
strIn = strIn[:matchGroupLine.start()] \
|
||||||
|
+ "\t\t\t\t%s /* %s */,\n" % (fileRefId1, fileName1) \
|
||||||
|
+ "\t\t\t\t%s /* %s */,\n" % (fileRefId2, fileName2) \
|
||||||
|
+ strIn[matchGroupLine.start():]
|
||||||
|
print("OK")
|
||||||
|
|
||||||
|
break
|
||||||
|
|
||||||
|
elif line.endswith("*/ = {"):
|
||||||
|
print("Delete invalid PBXGroup starting at '%s'..." % line)
|
||||||
|
find = "};\n"
|
||||||
|
endGroupIndex = strIn.find(find, matchLine.start()) + len(find)
|
||||||
|
strIn = strIn[:matchLine.start()] + strIn[endGroupIndex:]
|
||||||
|
print("OK")
|
||||||
|
|
||||||
|
elif line.endswith(" */,"):
|
||||||
|
print("Delete invalid PBXGroup child '%s'..." % line)
|
||||||
|
strIn = strIn[:matchLine.start()] + strIn[matchLine.end() + 1:]
|
||||||
|
print("OK")
|
||||||
|
|
||||||
|
matchLine = rc.search(strIn)
|
||||||
|
|
||||||
|
# key = original ID found in project
|
||||||
|
# value = ID it will be replaced by
|
||||||
|
idDict = {}
|
||||||
|
|
||||||
|
# some of the strings to match to find definitions of Xcode IDs:
|
||||||
|
|
||||||
|
# from PBXBuildFile section:
|
||||||
|
# 0123456789ABCDEF01234567 /* filename.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FEDCBA9876543210FEDCBA98 /* filename.cpp */; };
|
||||||
|
|
||||||
|
# from PBXFileReference section:
|
||||||
|
# FEDCBA9876543210FEDCBA98 /* filename.cpp */ = {isa = PBXFileReference; lastKnownFileType = file; name = any.cpp; path = ../../src/common/filename.cpp; sourceTree = "<group>"; };
|
||||||
|
|
||||||
|
# from remaining sections:
|
||||||
|
# 890123456789ABCDEF012345 /* Name */ = {
|
||||||
|
|
||||||
|
# Capture the first comment between /* and */ (file/section name) as a group
|
||||||
|
rc = re.compile("\s+(" + idMask + ") /\* (.+) \*/ = {.*$", re.MULTILINE)
|
||||||
|
dict = rc.findall(strIn)
|
||||||
|
|
||||||
|
for s in dict:
|
||||||
|
# s[0] is the original ID, s[1] is the name
|
||||||
|
assert (not s[0] in idDict)
|
||||||
|
idDict[s[0]] = toUuid(s[1])
|
||||||
|
|
||||||
|
strOut = re.sub(idMask, repl, strIn)
|
||||||
|
return strOut
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
if not testFixStage:
|
||||||
|
if len(sys.argv) < 2:
|
||||||
|
print(USAGE)
|
||||||
|
sys.exit(1)
|
||||||
|
processFile(sys.argv[1] + "/project.pbxproj")
|
||||||
|
else:
|
||||||
|
strIn = strTest
|
||||||
|
print("------------------------------------------")
|
||||||
|
print(strIn)
|
||||||
|
strOut = processContent()
|
||||||
|
print("------------------------------------------")
|
||||||
|
print(strOut)
|
||||||
|
|
||||||
|
exit(1)
|
||||||
|
|||||||
109
build/osx/makeprojects.py
Normal file
109
build/osx/makeprojects.py
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
|
||||||
|
import xml.etree.ElementTree as ET
|
||||||
|
|
||||||
|
from pbxproj import XcodeProject
|
||||||
|
from pbxproj.pbxextensions import ProjectFiles
|
||||||
|
ProjectFiles._FILE_TYPES['.cxx'] = ('sourcecode.cpp.cpp', 'PBXSourcesBuildPhase')
|
||||||
|
|
||||||
|
from fix_xcode_ids import processFile
|
||||||
|
|
||||||
|
bklfiles = ["../bakefiles/files.bkl", "../bakefiles/zlib.bkl", "../bakefiles/regex.bkl", "../bakefiles/tiff.bkl",
|
||||||
|
"../bakefiles/png.bkl", "../bakefiles/jpeg.bkl", "../bakefiles/scintilla.bkl", "../bakefiles/expat.bkl"]
|
||||||
|
nodes = [
|
||||||
|
# xcode group, entries[], targets []
|
||||||
|
["base", ["$(BASE_SRC)"], ["dynamic", "static", "base"]],
|
||||||
|
["base", ["$(BASE_AND_GUI_SRC)"], ["dynamic", "static", "base", "core"]],
|
||||||
|
["core", ["$(CORE_SRC)"], ["dynamic", "static", "core"]],
|
||||||
|
["net", ["$(NET_SRC)"], ["dynamic", "static", "net"]],
|
||||||
|
["adv", ["$(ADVANCED_SRC)"], ["dynamic", "static", "adv"]],
|
||||||
|
["webview", ["$(WEBVIEW_SRC)"], ["dynamic", "static", "webview"]],
|
||||||
|
["media", ["$(MEDIA_SRC)"], ["dynamic", "static", "media"]],
|
||||||
|
["html", ["$(HTML_SRC)"], ["dynamic", "static", "html"]],
|
||||||
|
["xrc", ["$(XRC_SRC)"], ["dynamic", "static", "xrc"]],
|
||||||
|
["qa", ["$(QA_SRC)"], ["dynamic", "static", "qa"]],
|
||||||
|
["xml", ["$(XML_SRC)"], ["dynamic", "static", "xml"]],
|
||||||
|
["opengl", ["$(OPENGL_SRC)"], ["dynamic", "static", "gl"]],
|
||||||
|
["aui", ["$(AUI_SRC)"], ["dynamic", "static", "aui"]],
|
||||||
|
["ribbon", ["$(RIBBON_SRC)"], ["dynamic", "static", "ribbon"]],
|
||||||
|
["propgrid", ["$(PROPGRID_SRC)"], ["dynamic", "static", "propgrid"]],
|
||||||
|
["richtext", ["$(RICHTEXT_SRC)"], ["dynamic", "static", "richttext"]],
|
||||||
|
["stc", ["$(STC_SRC)"], ["dynamic", "static", "stc"]],
|
||||||
|
["libzlib", ["$(wxzlib)"], ["dynamic", "static", "wxzlib"]],
|
||||||
|
["libtiff", ["$(wxtiff)"], ["dynamic", "static", "wxtiff"]],
|
||||||
|
["libjpeg", ["$(wxjpeg)"], ["dynamic", "static", "wxjpeg"]],
|
||||||
|
["libpng", ["$(wxpng)"], ["dynamic", "static", "wxpng"]],
|
||||||
|
["libregex", ["$(wxregex)"], ["dynamic", "static", "wxregex"]],
|
||||||
|
["libscintilla", ["$(wxscintilla)"], ["dynamic", "static", "wxscintilla"]],
|
||||||
|
["libexpat", ["$(wxexpat)"], ["dynamic", "static", "wxexpat"]]
|
||||||
|
]
|
||||||
|
|
||||||
|
def addNode(project, groupName, entries, fileGroups, targets):
|
||||||
|
group = project.get_or_create_group(groupName)
|
||||||
|
for entry in entries:
|
||||||
|
if entry.startswith("$("):
|
||||||
|
varname = entry[2:-1]
|
||||||
|
addNode(project, groupName, fileGroups[varname], fileGroups, targets)
|
||||||
|
else:
|
||||||
|
project.add_file("../../"+entry, parent=group, target_name=targets)
|
||||||
|
|
||||||
|
|
||||||
|
def populateProject(projectfile, fileGroups, nodes):
|
||||||
|
project = XcodeProject.load(projectfile)
|
||||||
|
for node in nodes:
|
||||||
|
groupName = node[0]
|
||||||
|
entries = node[1]
|
||||||
|
targets = node[2]
|
||||||
|
addNode(project, groupName, entries, fileGroups, targets)
|
||||||
|
project.save()
|
||||||
|
|
||||||
|
|
||||||
|
def parseSources(theName, xmlNode, conditions, fileGroups):
|
||||||
|
files = xmlNode.text
|
||||||
|
for ifs in xmlNode.findall("if"):
|
||||||
|
condition = ifs.attrib['cond']
|
||||||
|
if condition in conditions:
|
||||||
|
files += ifs.text
|
||||||
|
fileList = files.split() if files != None else []
|
||||||
|
fileGroups[theName] = fileList
|
||||||
|
|
||||||
|
|
||||||
|
def parseFile(bklFile, conditions, fileGroups):
|
||||||
|
tree = ET.parse(os.path.join(osxBuildFolder, bklFile))
|
||||||
|
for elem in tree.iter():
|
||||||
|
if elem.tag == 'set':
|
||||||
|
theName = elem.attrib['var']
|
||||||
|
parseSources(theName, elem, conditions, fileGroups)
|
||||||
|
elif elem.tag == 'lib':
|
||||||
|
theName = elem.attrib['id']
|
||||||
|
parseSources(theName, elem.find("sources"), conditions, fileGroups)
|
||||||
|
|
||||||
|
|
||||||
|
def readFilesList(bklFileList, conditions):
|
||||||
|
fileGroups = {}
|
||||||
|
for bklFile in bklFileList:
|
||||||
|
parseFile(bklFile, conditions, fileGroups)
|
||||||
|
return fileGroups
|
||||||
|
|
||||||
|
|
||||||
|
def makeProject(projectName, conditions):
|
||||||
|
# make new copy from template
|
||||||
|
template = os.path.join(osxBuildFolder, projectName + "_in.xcodeproj")
|
||||||
|
projectFile = os.path.join(osxBuildFolder, projectName + ".xcodeproj")
|
||||||
|
if os.path.exists(projectFile):
|
||||||
|
shutil.rmtree(projectFile)
|
||||||
|
shutil.copytree(template, projectFile)
|
||||||
|
# read file list from bkls
|
||||||
|
fileGroups = readFilesList(bklfiles, conditions)
|
||||||
|
# create xcode project
|
||||||
|
populateProject(projectFile + "/project.pbxproj", fileGroups, nodes)
|
||||||
|
processFile(projectFile + "/project.pbxproj")
|
||||||
|
|
||||||
|
osxBuildFolder = os.getcwd()
|
||||||
|
|
||||||
|
makeProject("wxcocoa", ["PLATFORM_MACOSX=='1'", "TOOLKIT=='OSX_COCOA'", "WXUNIV=='0'", "USE_GUI=='1' and WXUNIV=='0'"])
|
||||||
|
makeProject("wxiphone", ["PLATFORM_MACOSX=='1'", "TOOLKIT=='OSX_IPHONE'", "WXUNIV=='0'", "USE_GUI=='1' and WXUNIV=='0'"])
|
||||||
Reference in New Issue
Block a user