]>
git.saurik.com Git - wxWidgets.git/blob - build/osx/fix_xcode_ids.py
3 ###############################################################################
4 # Name: build/osx/fix_xcode_ids.py
5 # Author: Dimitri Schoolwerth
7 # Copyright: (c) 2010 wxWidgets team
8 # Licence: wxWindows licence
9 ###############################################################################
17 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"
18 Usage: fix_xcode_ids xcode_proj_dir"""
25 projectFile
= sys
. argv
[ 1 ] + "/project.pbxproj"
26 fin
= open ( projectFile
, "r" )
32 # Xcode identifiers (IDs) consist of 24 hexadecimal digits
33 idMask
= "[A-Fa-f0-9] {24} "
37 # convert a name to an identifier for Xcode
39 from uuid
import uuid3
, UUID
40 id = uuid3 ( UUID ( "349f853c-91f8-4eba-b9b9-5e9f882e693c" ), name
). hex [: 24 ]. upper ()
42 # Some names can appear twice or even more (depending on number of
43 # targets), make them unique
44 while id in idDict
. values () :
45 id = " %0 24X" % ( int ( id , 16 ) + 1 )
48 def insertBuildFileEntry ( filePath
, fileRefId
):
50 print " \t Insert PBXBuildFile for ' %s '..." % filePath
,
52 matchBuildFileSection
= re
. search ( "/\* Begin PBXBuildFile section \*/ \n " , strIn
)
53 dirName
, fileName
= os
. path
. split ( filePath
)
55 fileInSources
= fileName
+ " in Sources"
56 id = toUuid ( fileInSources
)
58 insert
= " \t\t %s /* %s */ = {isa = PBXBuildFile; fileRef = %s /* %s */; } ; \n " % ( id , fileInSources
, fileRefId
, fileName
)
60 strIn
= strIn
[: matchBuildFileSection
. end ()] + insert
+ strIn
[ matchBuildFileSection
. end ():]
66 def insertFileRefEntry ( filePath
, id = 0 ):
68 print " \t Insert PBXFileReference for ' %s '..." % filePath
,
70 matchFileRefSection
= re
. search ( "/\* Begin PBXFileReference section \*/ \n " , strIn
)
71 dirName
, fileName
= os
. path
. split ( filePath
)
76 insert
= " \t\t %s /* %s */ = {isa = PBXFileReference; lastKnownFileType = file; name = %s; path = %s; sourceTree = \"<group>\"; } ; \n " % ( id , fileName
, fileName
, filePath
)
77 strIn
= strIn
[: matchFileRefSection
. end ()] + insert
+ strIn
[ matchFileRefSection
. end ():]
83 def insertSourcesBuildPhaseEntry ( id , fileName
, insertBeforeFileName
, startSearchPos
= 0 ):
85 print " \t Insert PBXSourcesBuildPhase for ' %s '..." % fileName
,
87 matchBuildPhase
= re
. compile ( ".+ /\* " + insertBeforeFileName
+ " in Sources \*/," ) \
88 . search ( strIn
, startSearchPos
)
89 insert
= " \t\t\t\t %s /* %s in Sources */, \n " % ( id , fileName
)
90 strIn
= strIn
[: matchBuildPhase
. start ()] \
92 + strIn
[ matchBuildPhase
. start ():]
95 return matchBuildPhase
. start () + len ( insert
) + len ( matchBuildPhase
. group ( 0 ))
97 # Detect and fix errors in the project file that might have been introduced.
98 # Sometimes two source files are concatenated. These are spottable by
99 # looking for patterns such as "filename.cppsrc/html/"
100 # Following is a stripped Xcode project containing several problems that
101 # are solved after finding the error.
103 """/* Begin PBXBuildFile section */
104 95DE8BAB1238EE1800B43069 /* m_fonts.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 95DE8BAA1238EE1700B43069 /* m_fonts.cpp */; } ;
105 95DE8BAC1238EE1800B43069 /* m_fonts.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 95DE8BAA1238EE1700B43069 /* m_fonts.cpp */; } ;
106 /* End PBXBuildFile section */
108 /* Begin PBXFileReference section */
109 95DE8BAA1238EE1700B43069 /* m_fonts.cpp */ = {isa = PBXFileReference; lastKnownFileType = file; name = m_fonts.cpp; path = ../../src/html/m_dflist.cppsrc/html/m_fonts.cpp; sourceTree = "<group>"; } ;
110 /* End PBXFileReference section */
112 /* Begin PBXGroup section */
113 95DE8B831238EE1000B43069 /* html */ = {
116 95DE8B841238EE1000B43069 /* src/html */,
117 95DE8BA91238EE1700B43069 /* src/html/m_dflist.cppsrc/html */,
118 95DE8BCE1238EE1F00B43069 /* src/generic */,
121 sourceTree = "<group>";
123 95DE8B841238EE1000B43069 /* src/html */ = {
126 95DE8B851238EE1000B43069 /* chm.cpp */,
127 95DE8BAD1238EE1800B43069 /* m_hline.cpp */,
130 sourceTree = "<group>";
133 95DE8BA91238EE1700B43069 /* src/html/m_dflist.cppsrc/html */ = {
136 95DE8BAA1238EE1700B43069 /* m_fonts.cpp */,
138 name = src/html/m_dflist.cppsrc/html;
139 sourceTree = "<group>";
141 /* End PBXGroup section */
144 /* Begin PBXSourcesBuildPhase section */
145 404BEE5E10EC83280080E2B8 /* Sources */ = {
147 95DE8BAC1238EE1800B43069 /* m_fonts.cpp in Sources */,
149 runOnlyForDeploymentPostprocessing = 0;
151 D2AAC0C405546C1D00DB518D /* Sources */ = {
153 95DE8BAB1238EE1800B43069 /* m_fonts.cpp in Sources */,
155 runOnlyForDeploymentPostprocessing = 0;
158 /* End PBXSourcesBuildPhase section */"""
163 rc
= re
. compile ( ".+ (?P<path1>[\w/.]+(\.cpp|\.cxx|\.c))(?P<path2>\w+/[\w/.]+).+" )
164 matchLine
= rc
. search ( strIn
)
166 line
= matchLine
. group ( 0 )
168 # is it a line from the PBXFileReference section containing 2 mixed paths?
170 # FEDCBA9876543210FEDCBA98 /* file2.cpp */ = {isa = PBXFileReference; lastKnownFileType = file; name = file2.cpp; path = ../../src/html/file1.cppsrc/html/file2.cpp; sourceTree = "<group>"; };
171 if line
. endswith ( "};" ) :
172 path1
= matchLine
. group ( 'path1' )
173 path2
= matchLine
. group ( 'path2' )
174 print "Correcting mixed paths ' %s ' and ' %s ' at ' %s ':" % ( path1
, path2
, line
)
175 # if so, make note of the ID used (belongs to path2), remove the line
176 # and split the 2 paths inserting 2 new entries inside PBXFileReference
177 fileRefId2
= re
. search ( idMask
, line
). group ( 0 )
179 print " \t Delete the offending PBXFileReference line..." ,
180 # delete the PBXFileReference line that was found and which contains 2 mixed paths
181 strIn
= strIn
[: matchLine
. start ()] + strIn
[ matchLine
. end ()+ 1 :]
184 # insert corrected path1 entry in PBXFileReference
185 fileRefId1
= insertFileRefEntry ( path1
)
187 # do the same for path2 (which already had a ID)
188 path2Corrected
= path2
189 if path2Corrected
. startswith ( 'src' ) :
190 path2Corrected
= '../../' + path2Corrected
192 insertFileRefEntry ( path2Corrected
, fileRefId2
)
196 # insert a PBXBuildFile entry, 1 for each target
197 # path2 already has correct PBXBuildFile entries
198 targetCount
= strIn
. count ( "isa = PBXSourcesBuildPhase" )
199 for i
in range ( 0 , targetCount
):
200 buildPhaseId
[ i
] = insertBuildFileEntry ( path1
, fileRefId1
)
203 fileName1
= os
. path
. split ( path1
)[ 1 ]
204 dir2
, fileName2
= os
. path
. split ( path2
)
206 # refer to each PBXBuildFile in each PBXSourcesBuildPhase
208 for i
in range ( 0 , targetCount
):
209 startSearchIndex
= insertSourcesBuildPhaseEntry ( buildPhaseId
[ i
], fileName1
, fileName2
, startSearchIndex
)
212 # insert both paths in the group they belong to
213 matchGroupStart
= re
. search ( "/\* %s \*/ = {" % dir2
, strIn
)
214 endGroupIndex
= strIn
. find ( "};" , matchGroupStart
. start ())
216 for matchGroupLine
in re
. compile ( ".+" + idMask
+ " /\* (.+) \*/," ). finditer ( strIn
, matchGroupStart
. start (), endGroupIndex
) :
217 if matchGroupLine
. group ( 1 ) > fileName1
:
218 print " \t Insert paths in PBXGroup ' %s ', just before ' %s '..." % ( dir2
, matchGroupLine
. group ( 1 )),
219 strIn
= strIn
[: matchGroupLine
. start ()] \
220 + " \t\t\t\t %s /* %s */, \n " % ( fileRefId1
, fileName1
) \
221 + " \t\t\t\t %s /* %s */, \n " % ( fileRefId2
, fileName2
) \
222 + strIn
[ matchGroupLine
. start ():]
227 elif line
. endswith ( "*/ = {" ) :
228 print "Delete invalid PBXGroup starting at ' %s '..." % line
,
230 endGroupIndex
= strIn
. find ( find
, matchLine
. start ()) + len ( find
)
231 strIn
= strIn
[: matchLine
. start ()] + strIn
[ endGroupIndex
:]
234 elif line
. endswith ( " */," ) :
235 print "Delete invalid PBXGroup child ' %s '..." % line
,
236 strIn
= strIn
[: matchLine
. start ()] + strIn
[ matchLine
. end ()+ 1 :]
239 matchLine
= rc
. search ( strIn
)
242 print "------------------------------------------"
247 # key = original ID found in project
248 # value = ID it will be replaced by
251 # some of the strings to match to find definitions of Xcode IDs:
253 # from PBXBuildFile section:
254 # 0123456789ABCDEF01234567 /* filename.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FEDCBA9876543210FEDCBA98 /* filename.cpp */; };
256 # from PBXFileReference section:
257 # FEDCBA9876543210FEDCBA98 /* filename.cpp */ = {isa = PBXFileReference; lastKnownFileType = file; name = any.cpp; path = ../../src/common/filename.cpp; sourceTree = "<group>"; };
259 # from remaining sections:
260 # 890123456789ABCDEF012345 /* Name */ = {
262 # Capture the first comment between /* and */ (file/section name) as a group
263 rc
= re
. compile ( "\s+(" + idMask
+ ") /\* (.+) \*/ = {.*$" , re
. MULTILINE
)
264 dict = rc
. findall ( strIn
)
267 # s[0] is the original ID, s[1] is the name
268 assert ( not s
[ 0 ] in idDict
)
269 idDict
[ s
[ 0 ]] = toUuid ( s
[ 1 ])
272 # replace all found identifiers with the new ones
274 return idDict
[ match
. group ( 0 )]
276 strOut
= re
. sub ( idMask
, repl
, strIn
)
278 fout
= open ( projectFile
, "w" )