diff --git a/build/osx/fix_xcode_ids.py b/build/osx/fix_xcode_ids.py index 180f0ab536..f1d5e74485 100755 --- a/build/osx/fix_xcode_ids.py +++ b/build/osx/fix_xcode_ids.py @@ -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 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 idMask = "[A-Fa-f0-9]{24}" idDict = {} + # convert a name to an identifier for Xcode def toUuid(name): from uuid import uuid3, UUID @@ -41,13 +30,14 @@ def toUuid(name): # Some names can appear twice or even more (depending on number of # targets), make them unique - while id in idDict.values() : + while id in idDict.values(): id = "%024X" % (int(id, 16) + 1) return id + def insertBuildFileEntry(filePath, fileRefId): global strIn - print "\tInsert PBXBuildFile for '%s'..." % filePath, + print("\tInsert PBXBuildFile for '%s'..." % filePath) matchBuildFileSection = re.search("/\* Begin PBXBuildFile section \*/\n", strIn) dirName, fileName = os.path.split(filePath) @@ -55,17 +45,18 @@ def insertBuildFileEntry(filePath, fileRefId): fileInSources = fileName + " in Sources" id = toUuid(fileInSources) 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():] - print "OK" + print("OK") return id -def insertFileRefEntry(filePath, id = 0): +def insertFileRefEntry(filePath, id=0): global strIn - print "\tInsert PBXFileReference for '%s'..." % filePath, + print("\tInsert PBXFileReference for '%s'..." % filePath) matchFileRefSection = re.search("/\* Begin PBXFileReference section \*/\n", strIn) dirName, fileName = os.path.split(filePath) @@ -73,208 +64,232 @@ def insertFileRefEntry(filePath, id = 0): id = toUuid(fileName) idDict[id] = id - insert = "\t\t%s /* %s */ = {isa = PBXFileReference; lastKnownFileType = file; name = %s; path = %s; sourceTree = \"\"; };\n" % (id, fileName, fileName, filePath) + insert = "\t\t%s /* %s */ = {isa = PBXFileReference; lastKnownFileType = file; name = %s; path = %s; sourceTree = \"\"; };\n" % ( + id, fileName, fileName, filePath) strIn = strIn[:matchFileRefSection.end()] + insert + strIn[matchFileRefSection.end():] - print "OK" + print("OK") return id -def insertSourcesBuildPhaseEntry(id, fileName, insertBeforeFileName, startSearchPos = 0): +def insertSourcesBuildPhaseEntry(id, fileName, insertBeforeFileName, startSearchPos=0): global strIn - print "\tInsert PBXSourcesBuildPhase for '%s'..." % fileName, + print("\tInsert PBXSourcesBuildPhase for '%s'..." % fileName) matchBuildPhase = re.compile(".+ /\* " + insertBeforeFileName + " in Sources \*/,") \ .search(strIn, startSearchPos) insert = "\t\t\t\t%s /* %s in Sources */,\n" % (id, fileName) strIn = strIn[:matchBuildPhase.start()] \ - + insert \ - + strIn[matchBuildPhase.start():] + + insert \ + + strIn[matchBuildPhase.start():] - print "OK" + print("OK") return matchBuildPhase.start() + len(insert) + len(matchBuildPhase.group(0)) + # Detect and fix errors in the project file that might have been introduced. # Sometimes two source files are concatenated. These are spottable by # looking for patterns such as "filename.cppsrc/html/" # Following is a stripped Xcode project containing several problems that # are solved after finding the error. strTest = \ -"""/* Begin PBXBuildFile section */ - 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 */; }; -/* End PBXBuildFile section */ + """/* Begin PBXBuildFile section */ + 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 */; }; + /* End PBXBuildFile 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 = ""; }; -/* End 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 = ""; }; + /* End PBXFileReference section */ -/* Begin PBXGroup section */ - 95DE8B831238EE1000B43069 /* html */ = { - isa = PBXGroup; - children = ( - 95DE8B841238EE1000B43069 /* src/html */, - 95DE8BA91238EE1700B43069 /* src/html/m_dflist.cppsrc/html */, - 95DE8BCE1238EE1F00B43069 /* src/generic */, - ); - name = html; - sourceTree = ""; - }; - 95DE8B841238EE1000B43069 /* src/html */ = { - isa = PBXGroup; - children = ( - 95DE8B851238EE1000B43069 /* chm.cpp */, - 95DE8BAD1238EE1800B43069 /* m_hline.cpp */, - ); - name = src/html; - sourceTree = ""; - }; + /* Begin PBXGroup section */ + 95DE8B831238EE1000B43069 /* html */ = { + isa = PBXGroup; + children = ( + 95DE8B841238EE1000B43069 /* src/html */, + 95DE8BA91238EE1700B43069 /* src/html/m_dflist.cppsrc/html */, + 95DE8BCE1238EE1F00B43069 /* src/generic */, + ); + name = html; + sourceTree = ""; + }; + 95DE8B841238EE1000B43069 /* src/html */ = { + isa = PBXGroup; + children = ( + 95DE8B851238EE1000B43069 /* chm.cpp */, + 95DE8BAD1238EE1800B43069 /* m_hline.cpp */, + ); + name = src/html; + sourceTree = ""; + }; - 95DE8BA91238EE1700B43069 /* src/html/m_dflist.cppsrc/html */ = { - isa = PBXGroup; - children = ( - 95DE8BAA1238EE1700B43069 /* m_fonts.cpp */, - ); - name = src/html/m_dflist.cppsrc/html; - sourceTree = ""; - }; -/* End PBXGroup section */ + 95DE8BA91238EE1700B43069 /* src/html/m_dflist.cppsrc/html */ = { + isa = PBXGroup; + children = ( + 95DE8BAA1238EE1700B43069 /* m_fonts.cpp */, + ); + name = src/html/m_dflist.cppsrc/html; + sourceTree = ""; + }; + /* End PBXGroup section */ -/* Begin PBXSourcesBuildPhase section */ - 404BEE5E10EC83280080E2B8 /* Sources */ = { - files = ( - 95DE8BAC1238EE1800B43069 /* m_fonts.cpp in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - D2AAC0C405546C1D00DB518D /* Sources */ = { - files = ( - 95DE8BAB1238EE1800B43069 /* m_fonts.cpp in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; + /* Begin PBXSourcesBuildPhase section */ + 404BEE5E10EC83280080E2B8 /* Sources */ = { + files = ( + 95DE8BAC1238EE1800B43069 /* m_fonts.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D2AAC0C405546C1D00DB518D /* Sources */ = { + files = ( + 95DE8BAB1238EE1800B43069 /* m_fonts.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; -/* End PBXSourcesBuildPhase section */""" - -if testFixStage: - strIn = strTest - -rc = re.compile(".+ (?P[\w/.]+(\.cpp|\.cxx|\.c))(?P\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 = ""; }; - 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 = ""; }; - -# 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]) + /* End PBXSourcesBuildPhase section */""" # replace all found identifiers with the new ones def repl(match): return idDict[match.group(0)] -strOut = re.sub(idMask, repl, strIn) -fout = open(projectFile, "w") -fout.write(strOut) -fout.close() +def processFile(projectFile): + global strIn + + 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[\w/.]+(\.cpp|\.cxx|\.c))(?P\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 = ""; }; + 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 = ""; }; + + # 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) diff --git a/build/osx/makeprojects.py b/build/osx/makeprojects.py new file mode 100644 index 0000000000..b3750122d5 --- /dev/null +++ b/build/osx/makeprojects.py @@ -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'"])