From 8994c3c20cae2b27f479fefe8d4190d9bffb8cad Mon Sep 17 00:00:00 2001 From: Robin Dunn Date: Thu, 11 Dec 2003 20:03:42 +0000 Subject: [PATCH] Run swig from the main setup.py when building the renamer's XML instead of from build_renamers.py. This makes it easy to ensure that the same flags are used. Also, use the new swig flag to generate the XML after the python language module has run, rather than instead of. This gives us more info in the xml output. Updated build_renamers.py to expect the xml file to already be generated, and also allow it to run with a xml doc tree from libxml2 rather than the xml.sax module. This makes the extraction of info much cleaner and logical since we usually need info from child or grandchild nodes. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@24780 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- wxPython/distrib/build_renamers.py | 217 +++++++++++++++++++---------- wxPython/setup.py | 28 +++- 2 files changed, 164 insertions(+), 81 deletions(-) diff --git a/wxPython/distrib/build_renamers.py b/wxPython/distrib/build_renamers.py index 03f043a8d6..022051b8dc 100755 --- a/wxPython/distrib/build_renamers.py +++ b/wxPython/distrib/build_renamers.py @@ -1,12 +1,12 @@ #!/usr/bin/env python #--------------------------------------------------------------------------- """ -Usage: build_renamers.py filename.i +Usage: build_renamers.py destdir modulename filename.xml -Run SWIG on file.i using the XML language module and then scan the XML -file produced and generate the %rename directives needed to implement -the new wx namespace. The rename directives are output in a file -named _filename_rename.i in the same dir as filename.i. +Scans the XML file produced by SWIG (see setup.py) and generate the +%rename directives needed to implement the new wx namespace. The +rename directives are output in a file named _modulename_rename.i in +the destdir given. Also output a reverse 'renamer' Python module located in wxPython/filename.py (relative the the current dir) to make a @@ -14,37 +14,25 @@ backwards compatibility interface for the old wxPython packages. """ import sys, os, tempfile, pprint -import xml.sax +import xml.sax from distutils.spawn import spawn - - -#--------------------------------------------------------------------------- - -DO_UNLINK = True +try: + import libxml2 + USE_LIBXML2 = True +except ImportError: + USE_LIBXML2 = False wxPythonDir = "wxPython" -swig_cmd = "/opt/swig/bin/swig" -if os.name == 'nt': - swig_cmd = 'e:/projects/SWIG-cvs/swig.exe' -swig_args = ['-c++', - '-Wall', - '-nodefault', - - '-xml', - '-xmllite', - - '-I./src', - '-noruntime' - ] +#--------------------------------------------------------------------------- renamerTemplateStart = """\ // A bunch of %%rename directives generated by %s // in order to remove the wx prefix from all global scope names. -#ifndef SWIGXML +#ifndef BUILDING_RENAMERS """ @@ -86,7 +74,7 @@ wxPythonTemplateEnd = """ def main(args): # check args - if len(args) < 1: + if len(args) < 3: print __doc__ sys.exit(1) @@ -97,70 +85,148 @@ def main(args): sys.exit(1) - source = args[0] - sourcePath, sourceBase = os.path.split(source) - sourceBase = os.path.splitext(sourceBase)[0] - - tempfile.tempdir = sourcePath - xmlDest = tempfile.mktemp('.xml') - swigDest = os.path.join(sourcePath, "_"+sourceBase+"_rename.i") - pyDest = os.path.join(wxPythonDir, sourceBase + '.py') - - #print "source: ", source - #print "xmlDest: ", xmlDest - #print "swigDest: ", swigDest - #print "pyDest: ", pyDest - - cmd = [ swig_cmd ] + swig_args + args[1:] + ['-I'+sourcePath, '-o', xmlDest, source] - print ' '.join(cmd) - spawn(cmd) + destdir = args[0] + modname = args[1] + xmlfile = args[2] + + swigDest = os.path.join(destdir, "_"+modname+"_rename.i") + pyDest = os.path.join(wxPythonDir, modname + '.py') swigDestTemp = tempfile.mktemp('.tmp') swigFile = open(swigDestTemp, "w") swigFile.write(renamerTemplateStart % sys.argv[0]) - pyFile = open(pyDest, "w") - pyFile.write(wxPythonTemplateStart % (sys.argv[0], sourceBase)) - - print "Parsing and building renamers", + pyDestTemp = tempfile.mktemp('.tmp') + pyFile = open(pyDestTemp, "w") + pyFile.write(wxPythonTemplateStart % (sys.argv[0], modname)) + try: -## try: -## import libxml2 -## print "using libxml2..." -## ctxt = libxml2.createPushParser(ContentHandler(source, sourceBase, swigFile, pyFile), -## '', 0, xmlDest) -## for line in file(xmlDest): -## if not line: -## ctxt.parseChunck('', 0, 1) -## break -## ctxt.parseChunk(line, len(line), 0) - -## except ImportError: - print "using xml.sax..." - xml.sax.parse(xmlDest, ContentHandler(source, sourceBase, swigFile, pyFile)) + print "Parsing and building renamers", + if USE_LIBXML2: + processXML(xmlfile, modname, swigFile, pyFile) + else: + print "using xml.sax..." + xml.sax.parse(xmlfile, ContentHandler(modname, swigFile, pyFile)) finally: - checkOtherNames(pyFile, sourceBase, - os.path.join(sourcePath, '_'+sourceBase+'_reverse.txt')) + + checkOtherNames(pyFile, modname, + os.path.join(destdir, '_'+modname+'_reverse.txt')) pyFile.write(wxPythonTemplateEnd) pyFile.close() swigFile.write(renamerTemplateEnd) swigFile.close() - # Compare the file just created with the existing one and + # Compare the files just created with the existing one and # blow away the old one if they are different. - if open(swigDest).read() != open(swigDestTemp).read(): - os.unlink(swigDest) - os.rename(swigDestTemp, swigDest) - else: - print swigDest + " not changed." - os.unlink(swigDestTemp) + for dest, temp in [(swigDest, swigDestTemp), + (pyDest, pyDestTemp)]: + if open(dest).read() != open(temp).read(): + os.unlink(dest) + os.rename(temp, dest) + else: + print dest + " not changed." + os.unlink(temp) - if DO_UNLINK: - os.unlink(xmlDest) +#--------------------------------------------------------------------------- +def GetAttr(node, name): + path = "./attributelist/attribute[@name='%s']/@value" % name + n = node.xpathEval(path) + if len(n): + return n[0].content + else: + return None + + +def processXML(xmlfile, modname, swigFile, pyFile): + import libxml2 + print "using libxml2..." + + topnode = libxml2.parseFile(xmlfile).children + + # remove any import nodes as we don't need to do renamers for symbols found therein + imports = topnode.xpathEval("*/import") + for n in imports: + n.unlinkNode() + n.freeNode() + + # do a depth first iteration over what's left + for node in topnode: + doRename = False + doPtr = False + addWX = False + revOnly = False + + + if node.name == "class": + lastClassName = name = GetAttr(node, "name") + lastClassSymName = sym_name = GetAttr(node, "sym_name") + doRename = True + doPtr = True + if sym_name != name: + name = sym_name + addWX = True + + # renamed constructors + elif node.name == "constructor": + name = GetAttr(node, "name") + sym_name = GetAttr(node, "sym_name") + if sym_name != name: + name = sym_name + addWX = True + doRename = True + + # only enumitems at the top level + elif node.name == "enumitem" and node.parent.parent.name == "include": + name = GetAttr(node, "name") + sym_name = GetAttr(node, "sym_name") + doRename = True + + + elif node.name in ["cdecl", "constant"]: + name = GetAttr(node, "name") + sym_name = GetAttr(node, "sym_name") + toplevel = node.parent.name == "include" + + # top-level functions + if toplevel and GetAttr(node, "view") == "globalfunctionHandler": + doRename = True + + # top-level global vars + elif toplevel and GetAttr(node, "feature_immutable") == "1": + doRename = True + + # static methods + elif GetAttr(node, "view") == "staticmemberfunctionHandler": + name = lastClassName + '_' + name + sym_name = lastClassSymName + '_' + sym_name + # only output the reverse renamer in this case + doRename = revOnly = True + + if doRename and name != sym_name: + name = sym_name + addWX = True + + + if doRename: + old = new = name + if old.startswith('wx') and not old.startswith('wxEVT_'): + # remove all wx prefixes except wxEVT_ and write a %rename directive for it + new = old[2:] + if not revOnly: + swigFile.write("%%rename(%s) %35s;\n" % (new, old)) + + # Write assignments to import into the old wxPython namespace + if addWX and not old.startswith('wx'): + old = 'wx'+old + pyFile.write("%s = wx.%s.%s\n" % (old, modname, new)) + if doPtr: + pyFile.write("%sPtr = wx.%s.%sPtr\n" % (old, modname, new)) + + #--------------------------------------------------------------------------- def checkOtherNames(pyFile, moduleName, filename): @@ -304,10 +370,9 @@ class Element: #--------------------------------------------------------------------------- class ContentHandler(xml.sax.ContentHandler): - def __init__(self, source, sourceBase, swigFile, pyFile): + def __init__(self, modname, swigFile, pyFile): xml.sax.ContentHandler.__init__(self) - self.source = source - self.sourceBase = sourceBase + self.modname = modname self.swigFile = swigFile self.pyFile = pyFile self.elements = [] @@ -398,7 +463,7 @@ class ContentHandler(xml.sax.ContentHandler): if self.imports == 0: # only write for items that are in this file, not imported - ce.write(self.sourceBase, self.swigFile, self.pyFile) + ce.write(self.modname, self.swigFile, self.pyFile) if name == 'import': self.imports -= 1 diff --git a/wxPython/setup.py b/wxPython/setup.py index 09b44e2192..ba32bc46af 100755 --- a/wxPython/setup.py +++ b/wxPython/setup.py @@ -246,6 +246,9 @@ def run_swig(files, dir, gendir, package, USE_SWIG, force, swig_args, swig_deps= if not os.path.exists(os.path.join(dir, gendir)): os.mkdir(os.path.join(dir, gendir)) + if not os.path.exists(os.path.join("docs", "xml-raw")): + os.mkdir(os.path.join("docs", "xml-raw")) + sources = [] for file in files: @@ -253,6 +256,7 @@ def run_swig(files, dir, gendir, package, USE_SWIG, force, swig_args, swig_deps= i_file = os.path.join(dir, file) py_file = os.path.join(dir, gendir, basefile+'.py') cpp_file = os.path.join(dir, gendir, basefile+'_wrap.cpp') + xml_file = os.path.join("docs", "xml-raw", basefile+'_swig.xml') sources.append(cpp_file) @@ -268,14 +272,28 @@ def run_swig(files, dir, gendir, package, USE_SWIG, force, swig_args, swig_deps= #i_file = opj(i_file) #'/'.join(i_file.split('\\')) if BUILD_RENAMERS: - # first run build_renamers - cmd = [ sys.executable, '-u', - './distrib/build_renamers.py', - i_file, '-D'+WXPLAT, ] + \ - [x for x in swig_args if x.startswith('-I')] + #info_file = "./distrib/swig_info" + #info_dict = { 'cmd' : swig_cmd, + # 'args' : swig_args + ['-I'+dir] + # } + #open(info_file, "w").write(str(args_dict)) + + # First run swig to produce the XML file, adding + # an extra -D that prevents the old rename + # directives from being used + cmd = [ swig_cmd ] + swig_args + \ + [ '-DBUILDING_RENAMERS', '-xmlout', xml_file ] + \ + ['-I'+dir, '-o', cpp_file, i_file] msg(' '.join(cmd)) spawn(cmd) + # Next run build_renamers to process the XML + cmd = [ sys.executable, '-u', + './distrib/build_renamers.py', dir, basefile, xml_file] + msg(' '.join(cmd)) + spawn(cmd) + #os.remove(info_file) + # Then run swig for real cmd = [ swig_cmd ] + swig_args + ['-I'+dir, '-o', cpp_file, i_file] msg(' '.join(cmd))