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
This commit is contained in:
Robin Dunn 2003-12-11 20:03:42 +00:00
parent 7cb55566ba
commit 8994c3c20c
2 changed files with 164 additions and 81 deletions

View File

@ -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

View File

@ -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))