X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/862b53623ba193fd91e86f4f22d367b1e08e2816..1d88e73a3f25f16ad845b114153edd603d4970be:/wxPython/config.py diff --git a/wxPython/config.py b/wxPython/config.py index baa5c9dfa2..35032e2fcd 100644 --- a/wxPython/config.py +++ b/wxPython/config.py @@ -27,6 +27,7 @@ from distutils.dir_util import mkpath from distutils.dep_util import newer from distutils.spawn import spawn +import distutils.command.install import distutils.command.install_data import distutils.command.install_headers import distutils.command.clean @@ -36,10 +37,10 @@ import distutils.command.clean #---------------------------------------------------------------------- VER_MAJOR = 2 # The first three must match wxWidgets -VER_MINOR = 5 -VER_RELEASE = 1 -VER_SUBREL = 6 # wxPython release num for x.y.z release of wxWidgets -VER_FLAGS = "p" # release flags, such as prerelease num, unicode, etc. +VER_MINOR = 7 +VER_RELEASE = 0 +VER_SUBREL = 0 # wxPython release num for x.y.z release of wxWidgets +VER_FLAGS = "pre" # release flags, such as prerelease or RC num, etc. DESCRIPTION = "Cross platform GUI toolkit for Python" AUTHOR = "Robin Dunn" @@ -54,8 +55,8 @@ LONG_DESCRIPTION = """\ wxPython is a GUI toolkit for Python that is a wrapper around the wxWidgets C++ GUI library. wxPython provides a large variety of window types and controls, all implemented with a native look and -feel (by using the native widgets) on the platforms it is supported -on. +feel (by using the native widgets) on the platforms upon which it is +supported. """ CLASSIFIERS = """\ @@ -78,16 +79,15 @@ Topic :: Software Development :: User Interfaces # Config values below this point can be reset on the setup.py command line. BUILD_GLCANVAS = 1 # If true, build the contrib/glcanvas extension module -BUILD_OGL = 1 # If true, build the contrib/ogl extension module +BUILD_OGL = 0 # If true, build the contrib/ogl extension module BUILD_STC = 1 # If true, build the contrib/stc extension module -BUILD_XRC = 1 # XML based resource system BUILD_GIZMOS = 1 # Build a module for the gizmos contrib library +BUILD_ANIMATE = 1 # Build a module for the animate contrib library BUILD_DLLWIDGET = 0# Build a module that enables unknown wx widgets # to be loaded from a DLL and to be used from Python. # Internet Explorer wrapper (experimental) -BUILD_IEWIN = (os.name == 'nt') -BUILD_ACTIVEX = (os.name == 'nt') # new version of IEWIN +BUILD_ACTIVEX = (os.name == 'nt') # new version of IEWIN and more CORE_ONLY = 0 # if true, don't build any of the above @@ -101,6 +101,11 @@ SWIG = "swig" # The swig executable to use. BUILD_RENAMERS = 1 # Should we build the renamer modules too? +FULL_DOCS = 0 # Some docstrings are split into a basic docstring and a + # details string. Setting this flag to 1 will + # cause the two strings to be combined and output + # as the full docstring. + UNICODE = 0 # This will pass the 'wxUSE_UNICODE' flag to SWIG and # will ensure that the right headers are found and the # right libs are linked. @@ -117,6 +122,30 @@ UNDEF_NDEBUG = 1 # Python 2.2 on Unix/Linux by default defines NDEBUG, NO_SCRIPTS = 0 # Don't install the tool scripts NO_HEADERS = 0 # Don't install the wxPython *.h and *.i files +INSTALL_MULTIVERSION = 1 # Install the packages such that multiple versions + # can co-exist. When turned on the wx and wxPython + # pacakges will be installed in a versioned subdir + # of site-packages, and a *.pth file will be + # created that adds that dir to the sys.path. In + # addition, a wxselect.py module will be installed + # to site-pacakges that will allow applications to + # choose a specific version if more than one is + # installed. + +FLAVOUR = "" # Optional flavour string to be appended to VERSION + # in MULTIVERSION installs + +EP_ADD_OPTS = 1 # When doing MULTIVERSION installs the wx port and + # ansi/unicode settings can optionally be added to the + # subdir path used in site-packages + +EP_FULL_VER = 0 # When doing MULTIVERSION installs the default is to + # put only 2 or 3 (depending on stable/unstable) of + # the version compnonents into the "extra path" + # subdir of site-packages. Setting this option to + # 1 will cause the full 4 components of the version + # number to be used instead. + WX_CONFIG = None # Usually you shouldn't need to touch this, but you can set # it to pass an alternate version of wx-config or alternate # flags, eg. as required by the .deb in-tree build. By @@ -124,7 +153,16 @@ WX_CONFIG = None # Usually you shouldn't need to touch this, but you can set # version, port, etc. and it will be looked for on the # default $PATH. -WXPORT = 'gtk' # On Linux/Unix there are several ports of wxWidgets available. +SYS_WX_CONFIG = None # When installing an in tree build, setup.py uses wx-config + # for two different purposes. First, to determine the prefix + # where files will be installed, and secondly, to initialise + # build_options.py with the correct options for it. + # WX_CONFIG is used for the first task. SYS_WX_CONFIG may + # be set independently, to the value that should appear in + # build_options.py, if it is different to that. The default + # is to use the value of WX_CONFIG. + +WXPORT = 'gtk2' # On Linux/Unix there are several ports of wxWidgets available. # Setting this value lets you select which will be used for # the wxPython build. Possibilites are 'gtk', 'gtk2' and # 'x11'. Curently only gtk and gtk2 works. @@ -140,30 +178,39 @@ CONTRIBS_INC = "" # A dir to add as an -I flag when compiling the contribs # Some MSW build settings -FINAL = 0 # Mirrors use of same flag in wx makefiles, - # (0 or 1 only) should probably find a way to - # autodetect this... +MONOLITHIC = 1 # The core wxWidgets lib can be built as either a + # single monolithic DLL or as a collection of DLLs. + # This flag controls which set of libs will be used + # on Windows. (For other platforms it is automatic + # via using wx-config.) + +FINAL = 0 # Will use the release version of the wxWidgets libs on MSW. + +HYBRID = 1 # Will use the "hybrid" version of the wxWidgets + # libs on MSW. A "hybrid" build is one that is + # basically a release build, but that also defines + # __WXDEBUG__ to activate the runtime checks and + # assertions in the library. When any of these is + # triggered it is turned into a Python exception so + # this is a very useful feature to have turned on. -HYBRID = 1 # If set and not debug or FINAL, then build a - # hybrid extension that can be used by the - # non-debug version of python, but contains - # debugging symbols for wxWidgets and wxPython. - # wxWidgets must have been built with /MD, not /MDd - # (using FINAL=hybrid will do it.) # Version part of wxWidgets LIB/DLL names WXDLLVER = '%d%d' % (VER_MAJOR, VER_MINOR) +WXPY_SRC = '.' # Assume we're in the source tree already, but allow the + # user to change it, particularly for extension building. + #---------------------------------------------------------------------- def msg(text): - if sys.setup_is_main: + if hasattr(sys, 'setup_is_main') and sys.setup_is_main: print text def opj(*args): - path = apply(os.path.join, args) + path = os.path.join(*args) return os.path.normpath(path) @@ -201,17 +248,20 @@ if sys.platform[:6] == "darwin": if os.name == 'nt': WXPORT = 'msw' +WXPYTHON_TYPE_TABLE = '_wxPython_table' #---------------------------------------------------------------------- # Check for build flags on the command line #---------------------------------------------------------------------- # Boolean (int) flags -for flag in ['BUILD_GLCANVAS', 'BUILD_OGL', 'BUILD_STC', 'BUILD_XRC', - 'BUILD_GIZMOS', 'BUILD_DLLWIDGET', 'BUILD_IEWIN', 'BUILD_ACTIVEX', +for flag in [ 'BUILD_ACTIVEX', 'BUILD_ANIMATE', 'BUILD_DLLWIDGET', + 'BUILD_GIZMOS', 'BUILD_GLCANVAS', + 'BUILD_OGL', 'BUILD_STC', 'CORE_ONLY', 'PREP_ONLY', 'USE_SWIG', 'UNICODE', 'UNDEF_NDEBUG', 'NO_SCRIPTS', 'NO_HEADERS', 'BUILD_RENAMERS', - 'FINAL', 'HYBRID', ]: + 'FULL_DOCS', 'INSTALL_MULTIVERSION', 'EP_ADD_OPTS', 'EP_FULL_VER', + 'MONOLITHIC', 'FINAL', 'HYBRID', ]: for x in range(len(sys.argv)): if sys.argv[x].find(flag) == 0: pos = sys.argv[x].find('=') + 1 @@ -220,8 +270,9 @@ for flag in ['BUILD_GLCANVAS', 'BUILD_OGL', 'BUILD_STC', 'BUILD_XRC', sys.argv[x] = '' # String options -for option in ['WX_CONFIG', 'WXDLLVER', 'BUILD_BASE', 'WXPORT', 'SWIG', - 'CONTRIBS_INC']: +for option in ['WX_CONFIG', 'SYS_WX_CONFIG', 'WXDLLVER', 'BUILD_BASE', + 'WXPORT', 'SWIG', 'CONTRIBS_INC', 'WXPY_SRC', 'FLAVOUR', + ]: for x in range(len(sys.argv)): if sys.argv[x].find(option) == 0: pos = sys.argv[x].find('=') + 1 @@ -232,81 +283,121 @@ for option in ['WX_CONFIG', 'WXDLLVER', 'BUILD_BASE', 'WXPORT', 'SWIG', sys.argv = filter(None, sys.argv) +#---------------------------------------------------------------------- +# build options file +#---------------------------------------------------------------------- + +if SYS_WX_CONFIG is None: + SYS_WX_CONFIG = WX_CONFIG + +build_options_template = """ +UNICODE=%d +UNDEF_NDEBUG=%d +INSTALL_MULTIVERSION=%d +FLAVOUR="%s" +EP_ADD_OPTS=%d +EP_FULL_VER=%d +WX_CONFIG="%s" +WXPORT="%s" +MONOLITHIC=%d +FINAL=%d +HYBRID=%d +""" % (UNICODE, UNDEF_NDEBUG, INSTALL_MULTIVERSION, FLAVOUR, EP_ADD_OPTS, + EP_FULL_VER, SYS_WX_CONFIG, WXPORT, MONOLITHIC, FINAL, HYBRID) + +try: + from build_options import * +except: + build_options_file = os.path.join(os.path.dirname(__file__), "build_options.py") + if not os.path.exists(build_options_file): + try: + myfile = open(build_options_file, "w") + myfile.write(build_options_template) + myfile.close() + except: + print "WARNING: Unable to create build_options.py." + + #---------------------------------------------------------------------- # some helper functions #---------------------------------------------------------------------- def Verify_WX_CONFIG(): - """ Called below for the builds that need wx-config, - if WX_CONFIG is not set then tries to select the specific - wx*-config script based on build options. If not found - then it defaults to 'wx-config'. + """ Called below for the builds that need wx-config, if WX_CONFIG + is not set then determines the flags needed based on build + options and searches for wx-config on the PATH. """ # if WX_CONFIG hasn't been set to an explicit value then construct one. global WX_CONFIG if WX_CONFIG is None: - if debug: # TODO: Fix this. wxPython's --debug shouldn't be tied to wxWidgets... - df = 'd' - else: - df = '' - if UNICODE: - uf = 'u' - else: - uf = '' - ver2 = "%s.%s" % (VER_MAJOR, VER_MINOR) + WX_CONFIG='wx-config' port = WXPORT if port == "x11": port = "x11univ" - WX_CONFIG = 'wx%s%s%s-%s-config' % (port, uf, df, ver2) + flags = ' --toolkit=%s' % port + flags += ' --unicode=%s' % (UNICODE and 'yes' or 'no') + flags += ' --version=%s.%s' % (VER_MAJOR, VER_MINOR) searchpath = os.environ["PATH"] for p in searchpath.split(':'): - fp = os.path.join(p, WX_CONFIG) + fp = os.path.join(p, 'wx-config') if os.path.exists(fp) and os.access(fp, os.X_OK): # success msg("Found wx-config: " + fp) - WX_CONFIG = fp + msg(" Using flags: " + flags) + WX_CONFIG = fp + flags + if hasattr(sys, 'setup_is_main') and not sys.setup_is_main: + WX_CONFIG += " 2>/dev/null " break else: - msg("WX_CONFIG not specified and %s not found on $PATH " - "defaulting to \"wx-config\"" % WX_CONFIG) - WX_CONFIG = 'wx-config' + msg("ERROR: WX_CONFIG not specified and wx-config not found on the $PATH") + # should we exit? + # TODO: execute WX_CONFIG --list and verify a matching config is found + - -def run_swig(files, dir, gendir, package, USE_SWIG, force, swig_args, swig_deps=[]): +def run_swig(files, dir, gendir, package, USE_SWIG, force, swig_args, + swig_deps=[], add_under=False): """Run SWIG the way I want it done""" if USE_SWIG and not os.path.exists(os.path.join(dir, gendir)): os.mkdir(os.path.join(dir, gendir)) - if USE_SWIG and not os.path.exists(os.path.join("docs", "xml-raw")): - os.mkdir(os.path.join("docs", "xml-raw")) - sources = [] + if add_under: pre = '_' + else: pre = '' + for file in files: basefile = os.path.splitext(file)[0] 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') + py_file = os.path.join(dir, gendir, pre+basefile+'.py') + cpp_file = os.path.join(dir, gendir, pre+basefile+'_wrap.cpp') + if add_under: + interface = ['-interface', '_'+basefile+'_'] + else: + interface = [] + sources.append(cpp_file) if not cleaning and USE_SWIG: for dep in swig_deps: - if newer(dep, py_file) or newer(dep, cpp_file): - force = 1 - break + # this may fail for external builds, but it's not + # a fatal error, so keep going. + try: + if newer(dep, py_file) or newer(dep, cpp_file): + force = 1 + break + except: + pass if force or newer(i_file, py_file) or newer(i_file, cpp_file): - ## we need forward slashes here even on win32 + ## we need forward slashes here, even on win32 #cpp_file = opj(cpp_file) #'/'.join(cpp_file.split('\\')) #i_file = opj(i_file) #'/'.join(i_file.split('\\')) if BUILD_RENAMERS: - #tempfile.tempdir = sourcePath xmltemp = tempfile.mktemp('.xml') # First run swig to produce the XML file, adding @@ -319,15 +410,13 @@ def run_swig(files, dir, gendir, package, USE_SWIG, force, swig_args, swig_deps= spawn(cmd) # Next run build_renamers to process the XML - cmd = [ sys.executable, '-u', - './distrib/build_renamers.py', dir, basefile, xmltemp] - msg(' '.join(cmd)) - spawn(cmd) + myRenamer = BuildRenamers() + myRenamer.run(dir, pre+basefile, xmltemp) os.remove(xmltemp) # Then run swig for real - cmd = [ swig_cmd ] + swig_args + ['-I'+dir, '-o', cpp_file, - '-xmlout', xml_file, i_file] + cmd = [ swig_cmd ] + swig_args + interface + \ + ['-I'+dir, '-o', cpp_file, i_file] msg(' '.join(cmd)) spawn(cmd) @@ -339,6 +428,18 @@ def run_swig(files, dir, gendir, package, USE_SWIG, force, swig_args, swig_deps= return sources +def swig_version(): + # It may come on either stdout or stderr, depending on the + # version, so read both. + i, o, e = os.popen3(SWIG + ' -version', 't') + stext = o.read() + e.read() + import re + match = re.search(r'[0-9]+\.[0-9]+\.[0-9]+$', stext, re.MULTILINE) + if not match: + raise 'NotFound' + SVER = match.group(0) + return SVER + # Specializations of some distutils command classes class wx_smart_install_data(distutils.command.install_data.install_data): @@ -387,16 +488,25 @@ class wx_extra_clean(distutils.command.clean.clean): +class wx_install(distutils.command.install.install): + """ + Turns off install_path_file + """ + def initialize_options(self): + distutils.command.install.install.initialize_options(self) + self.install_path_file = 0 + + class wx_install_headers(distutils.command.install_headers.install_headers): """ Install the header files to the WXPREFIX, with an extra dir per filename too """ - def initialize_options (self): + def initialize_options(self): self.root = None distutils.command.install_headers.install_headers.initialize_options(self) - def finalize_options (self): + def finalize_options(self): self.set_undefined_options('install', ('root', 'root')) distutils.command.install_headers.install_headers.finalize_options(self) @@ -411,7 +521,10 @@ class wx_install_headers(distutils.command.install_headers.install_headers): if root is None or WXPREFIX.startswith(root): root = '' for header, location in headers: - install_dir = os.path.normpath(root + WXPREFIX + location) + install_dir = os.path.normpath(root + + WXPREFIX + + '/include/wx-%d.%d/wx' % (VER_MAJOR, VER_MINOR) + + location) self.mkpath(install_dir) (out, _) = self.copy_file(header, install_dir) self.outfiles.append(out) @@ -466,15 +579,16 @@ def find_data_files(srcdir, *wildcards): def makeLibName(name): if os.name == 'posix': libname = '%s_%s-%s' % (WXBASENAME, name, WXRELEASE) - else: + elif name: libname = 'wxmsw%s%s_%s' % (WXDLLVER, libFlag(), name) - + else: + libname = 'wxmsw%s%s' % (WXDLLVER, libFlag()) return [libname] def adjustCFLAGS(cflags, defines, includes): - '''Extrace the raw -I, -D, and -U flags and put them into + '''Extract the raw -I, -D, and -U flags and put them into defines and includes as needed.''' newCFLAGS = [] for flag in cflags: @@ -495,7 +609,7 @@ def adjustCFLAGS(cflags, defines, includes): def adjustLFLAGS(lfags, libdirs, libs): - '''Extrace the -L and -l flags and put them in libdirs and libs as needed''' + '''Extract the -L and -l flags and put them in libdirs and libs as needed''' newLFLAGS = [] for flag in lflags: if flag[:2] == '-L': @@ -507,6 +621,33 @@ def adjustLFLAGS(lfags, libdirs, libs): return newLFLAGS + + +def getExtraPath(shortVer=True, addOpts=False): + """Get the dirname that wxPython will be installed under.""" + + if shortVer: + # short version, just Major.Minor + ep = "wx-%d.%d" % (VER_MAJOR, VER_MINOR) + + # plus release if minor is odd + if VER_MINOR % 2 == 1: + ep += ".%d" % VER_RELEASE + + else: + # long version, full version + ep = "wx-%d.%d.%d.%d" % (VER_MAJOR, VER_MINOR, VER_RELEASE, VER_SUBREL) + + if addOpts: + port = WXPORT + if port == "msw": port = "win32" + ep += "-%s-%s" % (WXPORT, (UNICODE and 'unicode' or 'ansi')) + + if FLAVOUR: + ep += "-" + FLAVOUR + + return ep + #---------------------------------------------------------------------- # sanity checks @@ -514,11 +655,10 @@ if CORE_ONLY: BUILD_GLCANVAS = 0 BUILD_OGL = 0 BUILD_STC = 0 - BUILD_XRC = 0 BUILD_GIZMOS = 0 BUILD_DLLWIDGET = 0 - BUILD_IEWIN = 0 BUILD_ACTIVEX = 0 + BUILD_ANIMATE = 0 if debug: FINAL = 0 @@ -527,7 +667,7 @@ if debug: if FINAL: HYBRID = 0 -if UNICODE and WXPORT not in ['msw', 'gtk2']: +if UNICODE and WXPORT not in ['msw', 'gtk2', 'mac']: raise SystemExit, "UNICODE mode not currently supported on this WXPORT: "+WXPORT @@ -565,7 +705,8 @@ if os.name == 'nt': (WXPLAT, None), ('WXUSINGDLL', '1'), - ('SWIG_GLOBAL', None), + ('SWIG_TYPE_TABLE', WXPYTHON_TYPE_TABLE), + ('SWIG_PYTHON_OUTPUT_TUPLE', None), ('WXP_USE_THREAD', '1'), ] @@ -578,14 +719,21 @@ if os.name == 'nt': if not FINAL or HYBRID: defines.append( ('__WXDEBUG__', None) ) + if UNICODE: + defines.append( ('wxUSE_UNICODE', 1) ) + libdirs = [ opj(WXDIR, 'lib', 'vc_dll') ] - libs = [ 'wxbase' + WXDLLVER + libFlag(), # TODO: trim this down to what is really needed for the core - 'wxbase' + WXDLLVER + libFlag() + '_net', - 'wxbase' + WXDLLVER + libFlag() + '_xml', - makeLibName('core')[0], - makeLibName('adv')[0], - makeLibName('html')[0], - ] + if MONOLITHIC: + libs = makeLibName('') + else: + libs = [ 'wxbase' + WXDLLVER + libFlag(), + 'wxbase' + WXDLLVER + libFlag() + '_net', + 'wxbase' + WXDLLVER + libFlag() + '_xml', + makeLibName('core')[0], + makeLibName('adv')[0], + makeLibName('html')[0], + makeLibName('xrc')[0], + ] libs = libs + ['kernel32', 'user32', 'gdi32', 'comdlg32', 'winspool', 'winmm', 'shell32', 'oldnames', 'comctl32', @@ -615,8 +763,8 @@ if os.name == 'nt': elif os.name == 'posix': WXDIR = '..' includes = ['include', 'src'] - defines = [('SWIG_GLOBAL', None), - ('HAVE_CONFIG_H', None), + defines = [('SWIG_TYPE_TABLE', WXPYTHON_TYPE_TABLE), + ('SWIG_PYTHON_OUTPUT_TUPLE', None), ('WXP_USE_THREAD', '1'), ] if UNDEF_NDEBUG: @@ -631,6 +779,7 @@ elif os.name == 'posix': # uncomment this block to add the right flags to the link step and build # again. ## if os.uname()[0] == 'SunOS': + ## import commands ## libs.append('gcc') ## libdirs.append(commands.getoutput("gcc -print-search-dirs | grep '^install' | awk '{print $2}'")[:-1]) @@ -650,7 +799,7 @@ elif os.name == 'posix': WXPREFIX = os.popen(WX_CONFIG + ' --prefix').read()[:-1] - if sys.platform[:6] == "darwin": + if sys.platform[:6] == "darwin" and WXPORT == 'mac': # Flags and such for a Darwin (Max OS X) build of Python WXPLAT = '__WXMAC__' GENDIR = 'mac' @@ -703,8 +852,11 @@ else: if UNICODE: BUILD_BASE = BUILD_BASE + '.unicode' - VER_FLAGS += 'u' + ##VER_FLAGS += 'u' +if os.path.exists('DAILY_BUILD'): + + VER_FLAGS += '.' + open('DAILY_BUILD').read().strip() VERSION = "%s.%s.%s.%s%s" % (VER_MAJOR, VER_MINOR, VER_RELEASE, VER_SUBREL, VER_FLAGS) @@ -714,27 +866,49 @@ VERSION = "%s.%s.%s.%s%s" % (VER_MAJOR, VER_MINOR, VER_RELEASE, # SWIG defaults #---------------------------------------------------------------------- +# *.i files could live in the wxWidgets/wxPython/src dir, or in +# a subdirectory of the devel package. Let's specify both +# dirs as includes so we don't have to guess which is correct. + +wxfilesdir = "" +i_subdir = opj("include", getExtraPath(), "wx", "wxPython", "i_files") +if os.name != "nt": + wxfilesdir = opj(WXPREFIX, i_subdir) +else: + wxfilesdir = opj(WXPY_SRC, i_subdir) + +i_files_includes = [ '-I' + opj(WXPY_SRC, 'src'), + '-I' + wxfilesdir ] + swig_cmd = SWIG swig_force = force swig_args = ['-c++', - '-Wall', - '-nodefault', - + #'-Wall', '-python', - '-keyword', '-new_repr', '-modern', - - '-I./src', '-D'+WXPLAT, - '-noruntime' - ] + ] + i_files_includes + +if USE_SWIG: + SVER = swig_version() + if int(SVER[-2:]) >= 29: + swig_args += [ '-fastdispatch', + '-fvirtual', + '-fastinit', + '-fastunpack', + #'-outputtuple', Currently setting this with a -D define above + ] + if UNICODE: swig_args.append('-DwxUSE_UNICODE') -swig_deps = [ 'src/my_typemaps.i', - 'src/common.swg', - 'src/pyrun.swg', +if FULL_DOCS: + swig_args.append('-D_DO_FULL_DOCS') + + +swig_deps = [ opj(WXPY_SRC, 'src/my_typemaps.i'), + opj(WXPY_SRC, 'src/pyfragments.swg'), ] depends = [ #'include/wx/wxPython/wxPython.h', @@ -743,3 +917,233 @@ depends = [ #'include/wx/wxPython/wxPython.h', ] #---------------------------------------------------------------------- + +#################################### +# BuildRenamers +#################################### + +import pprint, shutil +try: + import libxml2 + FOUND_LIBXML2 = True +except ImportError: + FOUND_LIBXML2 = False + +#--------------------------------------------------------------------------- + +renamerTemplateStart = """\ +// A bunch of %rename directives generated by BuildRenamers in config.py +// in order to remove the wx prefix from all global scope names. + +#ifndef BUILDING_RENAMERS + +""" + +renamerTemplateEnd = """ +#endif +""" + +wxPythonTemplateStart = """\ +## This file reverse renames symbols in the wx package to give +## them their wx prefix again, for backwards compatibility. +## +## Generated by BuildRenamers in config.py + +# This silly stuff here is so the wxPython.wx module doesn't conflict +# with the wx package. We need to import modules from the wx package +# here, then we'll put the wxPython.wx entry back in sys.modules. +import sys +_wx = None +if sys.modules.has_key('wxPython.wx'): + _wx = sys.modules['wxPython.wx'] + del sys.modules['wxPython.wx'] + +import wx.%s + +sys.modules['wxPython.wx'] = _wx +del sys, _wx + + +# Now assign all the reverse-renamed names: +""" + +wxPythonTemplateEnd = """ + +""" + + + +#--------------------------------------------------------------------------- +class BuildRenamers: + def run(self, destdir, modname, xmlfile, wxPythonDir="wxPython"): + + assert FOUND_LIBXML2, "The libxml2 module is required to use the BuildRenamers functionality." + + if not os.path.exists(wxPythonDir): + os.mkdir(wxPythonDir) + + 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) + + pyDestTemp = tempfile.mktemp('.tmp') + pyFile = open(pyDestTemp, "w") + pyFile.write(wxPythonTemplateStart % modname) + + print "Parsing XML and building renamers..." + self.processXML(xmlfile, modname, swigFile, pyFile) + + self.checkOtherNames(pyFile, modname, + os.path.join(destdir, '_'+modname+'_reverse.txt')) + pyFile.write(wxPythonTemplateEnd) + pyFile.close() + + swigFile.write(renamerTemplateEnd) + swigFile.close() + + # Compare the files just created with the existing one and + # blow away the old one if they are different. + for dest, temp in [(swigDest, swigDestTemp), + (pyDest, pyDestTemp)]: + # NOTE: we don't use shutil.move() because it was introduced + # in Python 2.3. Eventually we can switch to it when people + # stop building using 2.2. + if not os.path.exists(dest): + shutil.copyfile(temp, dest) + elif open(dest).read() != open(temp).read(): + os.unlink(dest) + shutil.copyfile(temp, dest) + else: + print dest + " not changed." + os.unlink(temp) + + #--------------------------------------------------------------------------- + + + def GetAttr(self, node, name): + path = "./attributelist/attribute[@name='%s']/@value" % name + n = node.xpathEval2(path) + if len(n): + return n[0].content + else: + return None + + + def processXML(self, xmlfile, modname, swigFile, pyFile): + + topnode = libxml2.parseFile(xmlfile).children + + # remove any import nodes as we don't need to do renamers for symbols found therein + imports = topnode.xpathEval2("*/import") + for n in imports: + n.unlinkNode() + n.freeNode() + + # do a depth first iteration over what's left + for node in topnode: + doRename = False + addWX = False + revOnly = False + + + if node.name == "class": + lastClassName = name = self.GetAttr(node, "name") + lastClassSymName = sym_name = self.GetAttr(node, "sym_name") + doRename = True + if sym_name != name: + name = sym_name + addWX = True + + # renamed constructors + elif node.name == "constructor": + name = self.GetAttr(node, "name") + sym_name = self.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 = self.GetAttr(node, "name") + sym_name = self.GetAttr(node, "sym_name") + doRename = True + + + elif node.name in ["cdecl", "constant"]: + name = self.GetAttr(node, "name") + sym_name = self.GetAttr(node, "sym_name") + toplevel = node.parent.name == "include" + + # top-level functions + if toplevel and self.GetAttr(node, "view") == "globalfunctionHandler": + doRename = True + + # top-level global vars + elif toplevel and self.GetAttr(node, "feature_immutable") == "1": + doRename = True + + # static methods + elif self.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 and name: + 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)) + + + #--------------------------------------------------------------------------- + + def checkOtherNames(self, pyFile, moduleName, filename): + if os.path.exists(filename): + prefixes = [] + for line in file(filename): + if line.endswith('\n'): + line = line[:-1] + if line and not line.startswith('#'): + if line.endswith('*'): + prefixes.append(line[:-1]) + elif line.find('=') != -1: + pyFile.write("%s\n" % line) + else: + wxname = 'wx' + line + if line.startswith('wx') or line.startswith('WX') or line.startswith('EVT'): + wxname = line + pyFile.write("%s = wx.%s.%s\n" % (wxname, moduleName, line)) + + if prefixes: + pyFile.write( + "\n\nd = globals()\nfor k, v in wx.%s.__dict__.iteritems():" + % moduleName) + first = True + for p in prefixes: + if first: + pyFile.write("\n if ") + first = False + else: + pyFile.write("\n elif ") + pyFile.write("k.startswith('%s'):\n d[k] = v" % p) + pyFile.write("\ndel d, k, v\n\n") + + +#---------------------------------------------------------------------------