]> git.saurik.com Git - wxWidgets.git/blob - wxPython/config.py
Adding the option to toggle between native and generic listctrl.
[wxWidgets.git] / wxPython / config.py
1 #----------------------------------------------------------------------
2 # Name: wx.build.config
3 # Purpose: Most of the contents of this module used to be located
4 # in wxPython's setup.py script. It was moved here so
5 # it would be installed with the rest of wxPython and
6 # could therefore be used by the setup.py for other
7 # projects that needed this same info and functionality
8 # (most likely in order to be compatible with wxPython.)
9 #
10 # This split from setup.py is still fairly rough, and
11 # some things may still get shuffled back and forth,
12 # refactored, etc. Please send me any comments and
13 # suggestions about this.
14 #
15 # Author: Robin Dunn
16 #
17 # Created: 23-March-2004
18 # RCS-ID: $Id$
19 # Copyright: (c) 2004 by Total Control Software
20 # Licence: wxWindows license
21 #----------------------------------------------------------------------
22
23 import sys, os, glob, fnmatch, tempfile
24 from distutils.core import setup, Extension
25 from distutils.file_util import copy_file
26 from distutils.dir_util import mkpath
27 from distutils.dep_util import newer
28 from distutils.spawn import spawn
29
30 import distutils.command.install
31 import distutils.command.install_data
32 import distutils.command.install_headers
33 import distutils.command.clean
34
35 #----------------------------------------------------------------------
36 # flags and values that affect this script
37 #----------------------------------------------------------------------
38
39 VER_MAJOR = 2 # The first three must match wxWidgets
40 VER_MINOR = 8
41 VER_RELEASE = 0
42 VER_SUBREL = 0 # wxPython release num for x.y.z release of wxWidgets
43 VER_FLAGS = "" # release flags, such as prerelease or RC num, etc.
44
45 DESCRIPTION = "Cross platform GUI toolkit for Python"
46 AUTHOR = "Robin Dunn"
47 AUTHOR_EMAIL = "Robin Dunn <robin@alldunn.com>"
48 URL = "http://wxPython.org/"
49 DOWNLOAD_URL = "http://wxPython.org/download.php"
50 LICENSE = "wxWidgets Library License (LGPL derivative)"
51 PLATFORMS = "WIN32,OSX,POSIX"
52 KEYWORDS = "GUI,wx,wxWindows,wxWidgets,cross-platform"
53
54 LONG_DESCRIPTION = """\
55 wxPython is a GUI toolkit for Python that is a wrapper around the
56 wxWidgets C++ GUI library. wxPython provides a large variety of
57 window types and controls, all implemented with a native look and
58 feel (by using the native widgets) on the platforms upon which it is
59 supported.
60 """
61
62 CLASSIFIERS = """\
63 Development Status :: 6 - Mature
64 Environment :: MacOS X :: Carbon
65 Environment :: Win32 (MS Windows)
66 Environment :: X11 Applications :: GTK
67 Intended Audience :: Developers
68 License :: OSI Approved
69 Operating System :: MacOS :: MacOS X
70 Operating System :: Microsoft :: Windows :: Windows 95/98/2000
71 Operating System :: POSIX
72 Programming Language :: Python
73 Topic :: Software Development :: User Interfaces
74 """
75
76 ## License :: OSI Approved :: wxWidgets Library Licence
77
78
79 # Config values below this point can be reset on the setup.py command line.
80
81 BUILD_GLCANVAS = 1 # If true, build the contrib/glcanvas extension module
82 BUILD_OGL = 0 # If true, build the contrib/ogl extension module
83 BUILD_STC = 1 # If true, build the contrib/stc extension module
84 BUILD_GIZMOS = 1 # Build a module for the gizmos contrib library
85 BUILD_DLLWIDGET = 0# Build a module that enables unknown wx widgets
86 # to be loaded from a DLL and to be used from Python.
87
88 # Internet Explorer wrapper (experimental)
89 BUILD_ACTIVEX = (os.name == 'nt') # new version of IEWIN and more
90
91
92 CORE_ONLY = 0 # if true, don't build any of the above
93
94 PREP_ONLY = 0 # Only run the prepatory steps, not the actual build.
95
96 USE_SWIG = 0 # Should we actually execute SWIG, or just use the
97 # files already in the distribution?
98
99 SWIG = "swig" # The swig executable to use.
100
101 BUILD_RENAMERS = 0 # Should we build the renamer modules too?
102
103 FULL_DOCS = 0 # Some docstrings are split into a basic docstring and a
104 # details string. Setting this flag to 1 will
105 # cause the two strings to be combined and output
106 # as the full docstring.
107
108 UNICODE = 0 # This will pass the 'wxUSE_UNICODE' flag to SWIG and
109 # will ensure that the right headers are found and the
110 # right libs are linked.
111
112 UNDEF_NDEBUG = 1 # Python 2.2 on Unix/Linux by default defines NDEBUG,
113 # and distutils will pick this up and use it on the
114 # compile command-line for the extensions. This could
115 # conflict with how wxWidgets was built. If NDEBUG is
116 # set then wxWidgets' __WXDEBUG__ setting will be turned
117 # off. If wxWidgets was actually built with it turned
118 # on then you end up with mismatched class structures,
119 # and wxPython will crash.
120
121 NO_SCRIPTS = 0 # Don't install the tool scripts
122 NO_HEADERS = 0 # Don't install the wxPython *.h and *.i files
123
124 INSTALL_MULTIVERSION = 1 # Install the packages such that multiple versions
125 # can co-exist. When turned on the wx and wxPython
126 # pacakges will be installed in a versioned subdir
127 # of site-packages, and a *.pth file will be
128 # created that adds that dir to the sys.path. In
129 # addition, a wxselect.py module will be installed
130 # to site-pacakges that will allow applications to
131 # choose a specific version if more than one is
132 # installed.
133
134 FLAVOUR = "" # Optional flavour string to be appended to VERSION
135 # in MULTIVERSION installs
136
137 EP_ADD_OPTS = 1 # When doing MULTIVERSION installs the wx port and
138 # ansi/unicode settings can optionally be added to the
139 # subdir path used in site-packages
140
141 EP_FULL_VER = 0 # When doing MULTIVERSION installs the default is to
142 # put only 2 or 3 (depending on stable/unstable) of
143 # the version compnonents into the "extra path"
144 # subdir of site-packages. Setting this option to
145 # 1 will cause the full 4 components of the version
146 # number to be used instead.
147
148 WX_CONFIG = None # Usually you shouldn't need to touch this, but you can set
149 # it to pass an alternate version of wx-config or alternate
150 # flags, eg. as required by the .deb in-tree build. By
151 # default a wx-config command will be assembled based on
152 # version, port, etc. and it will be looked for on the
153 # default $PATH.
154
155 SYS_WX_CONFIG = None # When installing an in tree build, setup.py uses wx-config
156 # for two different purposes. First, to determine the prefix
157 # where files will be installed, and secondly, to initialise
158 # build_options.py with the correct options for it.
159 # WX_CONFIG is used for the first task. SYS_WX_CONFIG may
160 # be set independently, to the value that should appear in
161 # build_options.py, if it is different to that. The default
162 # is to use the value of WX_CONFIG.
163
164 WXPORT = 'gtk2' # On Linux/Unix there are several ports of wxWidgets available.
165 # Setting this value lets you select which will be used for
166 # the wxPython build. Possibilites are 'gtk', 'gtk2' and
167 # 'x11'. Curently only gtk and gtk2 works.
168
169 BUILD_BASE = "build" # Directory to use for temporary build files.
170 # This name will be appended to if the WXPORT or
171 # the UNICODE flags are set to non-standard
172 # values. See below.
173
174
175 CONTRIBS_INC = "" # A dir to add as an -I flag when compiling the contribs
176
177
178 # Some MSW build settings
179
180 MONOLITHIC = 0 # The core wxWidgets lib can be built as either a
181 # single monolithic DLL or as a collection of DLLs.
182 # This flag controls which set of libs will be used
183 # on Windows. (For other platforms it is automatic
184 # via using wx-config.)
185
186 FINAL = 0 # Will use the release version of the wxWidgets libs on MSW.
187
188 HYBRID = 1 # Will use the "hybrid" version of the wxWidgets
189 # libs on MSW. A "hybrid" build is one that is
190 # basically a release build, but that also defines
191 # __WXDEBUG__ to activate the runtime checks and
192 # assertions in the library. When any of these is
193 # triggered it is turned into a Python exception so
194 # this is a very useful feature to have turned on.
195
196
197 # Version part of wxWidgets LIB/DLL names
198 WXDLLVER = '%d%d' % (VER_MAJOR, VER_MINOR)
199
200 WXPY_SRC = '.' # Assume we're in the source tree already, but allow the
201 # user to change it, particularly for extension building.
202
203
204 #----------------------------------------------------------------------
205
206 def msg(text):
207 if hasattr(sys, 'setup_is_main') and sys.setup_is_main:
208 print text
209
210
211 def opj(*args):
212 path = os.path.join(*args)
213 return os.path.normpath(path)
214
215
216 def libFlag():
217 if FINAL:
218 rv = ''
219 elif HYBRID:
220 rv = 'h'
221 else:
222 rv = 'd'
223 if UNICODE:
224 rv = 'u' + rv
225 return rv
226
227
228 #----------------------------------------------------------------------
229 # Some other globals
230 #----------------------------------------------------------------------
231
232 PKGDIR = 'wx'
233 wxpExtensions = []
234 DATA_FILES = []
235 CLEANUP = []
236
237 force = '--force' in sys.argv or '-f' in sys.argv
238 debug = '--debug' in sys.argv or '-g' in sys.argv
239 cleaning = 'clean' in sys.argv
240
241
242 # change the PORT default for wxMac
243 if sys.platform[:6] == "darwin":
244 WXPORT = 'mac'
245
246 # and do the same for wxMSW, just for consistency
247 if os.name == 'nt':
248 WXPORT = 'msw'
249
250 WXPYTHON_TYPE_TABLE = '_wxPython_table'
251
252 #----------------------------------------------------------------------
253 # Check for build flags on the command line
254 #----------------------------------------------------------------------
255
256 # Boolean (int) flags
257 for flag in [ 'BUILD_ACTIVEX', 'BUILD_DLLWIDGET',
258 'BUILD_GIZMOS', 'BUILD_GLCANVAS',
259 'BUILD_OGL', 'BUILD_STC',
260 'CORE_ONLY', 'PREP_ONLY', 'USE_SWIG', 'UNICODE',
261 'UNDEF_NDEBUG', 'NO_SCRIPTS', 'NO_HEADERS', 'BUILD_RENAMERS',
262 'FULL_DOCS', 'INSTALL_MULTIVERSION', 'EP_ADD_OPTS', 'EP_FULL_VER',
263 'MONOLITHIC', 'FINAL', 'HYBRID', ]:
264 for x in range(len(sys.argv)):
265 if sys.argv[x].find(flag) == 0:
266 pos = sys.argv[x].find('=') + 1
267 if pos > 0:
268 vars()[flag] = eval(sys.argv[x][pos:])
269 sys.argv[x] = ''
270
271 # String options
272 for option in ['WX_CONFIG', 'SYS_WX_CONFIG', 'WXDLLVER', 'BUILD_BASE',
273 'WXPORT', 'SWIG', 'CONTRIBS_INC', 'WXPY_SRC', 'FLAVOUR',
274 'VER_FLAGS',
275 ]:
276 for x in range(len(sys.argv)):
277 if sys.argv[x].find(option) == 0:
278 pos = sys.argv[x].find('=') + 1
279 if pos > 0:
280 vars()[option] = sys.argv[x][pos:]
281 sys.argv[x] = ''
282
283 sys.argv = filter(None, sys.argv)
284
285
286 #----------------------------------------------------------------------
287 # some helper functions
288 #----------------------------------------------------------------------
289
290 def Verify_WX_CONFIG():
291 """ Called below for the builds that need wx-config, if WX_CONFIG
292 is not set then determines the flags needed based on build
293 options and searches for wx-config on the PATH.
294 """
295 # if WX_CONFIG hasn't been set to an explicit value then construct one.
296 global WX_CONFIG
297 if WX_CONFIG is None:
298 WX_CONFIG='wx-config'
299 port = WXPORT
300 if port == "x11":
301 port = "x11univ"
302 flags = ' --toolkit=%s' % port
303 flags += ' --unicode=%s' % (UNICODE and 'yes' or 'no')
304 flags += ' --version=%s.%s' % (VER_MAJOR, VER_MINOR)
305
306 searchpath = os.environ["PATH"]
307 for p in searchpath.split(':'):
308 fp = os.path.join(p, 'wx-config')
309 if os.path.exists(fp) and os.access(fp, os.X_OK):
310 # success
311 msg("Found wx-config: " + fp)
312 msg(" Using flags: " + flags)
313 WX_CONFIG = fp + flags
314 if hasattr(sys, 'setup_is_main') and not sys.setup_is_main:
315 WX_CONFIG += " 2>/dev/null "
316 break
317 else:
318 msg("ERROR: WX_CONFIG not specified and wx-config not found on the $PATH")
319 # should we exit?
320
321 # TODO: execute WX_CONFIG --list and verify a matching config is found
322
323
324 def run_swig(files, dir, gendir, package, USE_SWIG, force, swig_args,
325 swig_deps=[], add_under=False):
326 """Run SWIG the way I want it done"""
327
328 if USE_SWIG and not os.path.exists(os.path.join(dir, gendir)):
329 os.mkdir(os.path.join(dir, gendir))
330
331 sources = []
332
333 if add_under: pre = '_'
334 else: pre = ''
335
336 for file in files:
337 basefile = os.path.splitext(file)[0]
338 i_file = os.path.join(dir, file)
339 py_file = os.path.join(dir, gendir, pre+basefile+'.py')
340 cpp_file = os.path.join(dir, gendir, pre+basefile+'_wrap.cpp')
341
342 if add_under:
343 interface = ['-interface', '_'+basefile+'_']
344 else:
345 interface = []
346
347 sources.append(cpp_file)
348
349 if not cleaning and USE_SWIG:
350 for dep in swig_deps:
351 # this may fail for external builds, but it's not
352 # a fatal error, so keep going.
353 try:
354 if newer(dep, py_file) or newer(dep, cpp_file):
355 force = 1
356 break
357 except:
358 pass
359
360 if force or newer(i_file, py_file) or newer(i_file, cpp_file):
361 ## we need forward slashes here, even on win32
362 #cpp_file = opj(cpp_file) #'/'.join(cpp_file.split('\\'))
363 #i_file = opj(i_file) #'/'.join(i_file.split('\\'))
364
365 if BUILD_RENAMERS:
366 xmltemp = tempfile.mktemp('.xml')
367
368 # First run swig to produce the XML file, adding
369 # an extra -D that prevents the old rename
370 # directives from being used
371 cmd = [ swig_cmd ] + swig_args + \
372 [ '-DBUILDING_RENAMERS', '-xmlout', xmltemp ] + \
373 ['-I'+dir, '-o', cpp_file, i_file]
374 msg(' '.join(cmd))
375 spawn(cmd)
376
377 # Next run build_renamers to process the XML
378 myRenamer = BuildRenamers()
379 myRenamer.run(dir, pre+basefile, xmltemp)
380 os.remove(xmltemp)
381
382 # Then run swig for real
383 cmd = [ swig_cmd ] + swig_args + interface + \
384 ['-I'+dir, '-o', cpp_file, i_file]
385 msg(' '.join(cmd))
386 spawn(cmd)
387
388
389 # copy the generated python file to the package directory
390 copy_file(py_file, package, update=not force, verbose=0)
391 CLEANUP.append(opj(package, os.path.basename(py_file)))
392
393 return sources
394
395
396 def swig_version():
397 # It may come on either stdout or stderr, depending on the
398 # version, so read both.
399 i, o, e = os.popen3(SWIG + ' -version', 't')
400 stext = o.read() + e.read()
401 import re
402 match = re.search(r'[0-9]+\.[0-9]+\.[0-9]+$', stext, re.MULTILINE)
403 if not match:
404 raise 'NotFound'
405 SVER = match.group(0)
406 return SVER
407
408
409 # Specializations of some distutils command classes
410 class wx_smart_install_data(distutils.command.install_data.install_data):
411 """need to change self.install_dir to the actual library dir"""
412 def run(self):
413 install_cmd = self.get_finalized_command('install')
414 self.install_dir = getattr(install_cmd, 'install_lib')
415 return distutils.command.install_data.install_data.run(self)
416
417
418 class wx_extra_clean(distutils.command.clean.clean):
419 """
420 Also cleans stuff that this setup.py copies itself. If the
421 --all flag was used also searches for .pyc, .pyd, .so files
422 """
423 def run(self):
424 from distutils import log
425 from distutils.filelist import FileList
426 global CLEANUP
427
428 distutils.command.clean.clean.run(self)
429
430 if self.all:
431 fl = FileList()
432 fl.include_pattern("*.pyc", 0)
433 fl.include_pattern("*.pyd", 0)
434 fl.include_pattern("*.so", 0)
435 CLEANUP += fl.files
436
437 for f in CLEANUP:
438 if os.path.isdir(f):
439 try:
440 if not self.dry_run and os.path.exists(f):
441 os.rmdir(f)
442 log.info("removing '%s'", f)
443 except IOError:
444 log.warning("unable to remove '%s'", f)
445
446 else:
447 try:
448 if not self.dry_run and os.path.exists(f):
449 os.remove(f)
450 log.info("removing '%s'", f)
451 except IOError:
452 log.warning("unable to remove '%s'", f)
453
454
455
456 class wx_install(distutils.command.install.install):
457 """
458 Turns off install_path_file
459 """
460 def initialize_options(self):
461 distutils.command.install.install.initialize_options(self)
462 self.install_path_file = 0
463
464
465 class wx_install_headers(distutils.command.install_headers.install_headers):
466 """
467 Install the header files to the WXPREFIX, with an extra dir per
468 filename too
469 """
470 def initialize_options(self):
471 self.root = None
472 distutils.command.install_headers.install_headers.initialize_options(self)
473
474 def finalize_options(self):
475 self.set_undefined_options('install', ('root', 'root'))
476 distutils.command.install_headers.install_headers.finalize_options(self)
477
478 def run(self):
479 if os.name == 'nt':
480 return
481 headers = self.distribution.headers
482 if not headers:
483 return
484
485 root = self.root
486 if root is None or WXPREFIX.startswith(root):
487 root = ''
488 for header, location in headers:
489 install_dir = os.path.normpath(root +
490 WXPREFIX +
491 '/include/wx-%d.%d/wx' % (VER_MAJOR, VER_MINOR) +
492 location)
493 self.mkpath(install_dir)
494 (out, _) = self.copy_file(header, install_dir)
495 self.outfiles.append(out)
496
497
498
499
500 def build_locale_dir(destdir, verbose=1):
501 """Build a locale dir under the wxPython package for MSW"""
502 moFiles = glob.glob(opj(WXDIR, 'locale', '*.mo'))
503 for src in moFiles:
504 lang = os.path.splitext(os.path.basename(src))[0]
505 #dest = opj(destdir, lang)
506 dest = opj(destdir, lang, 'LC_MESSAGES')
507 mkpath(dest, verbose=verbose)
508 copy_file(src, opj(dest, 'wxstd.mo'), update=1, verbose=verbose)
509 CLEANUP.append(opj(dest, 'wxstd.mo'))
510 CLEANUP.append(dest)
511
512
513 def build_locale_list(srcdir):
514 # get a list of all files under the srcdir, to be used for install_data
515 def walk_helper(lst, dirname, files):
516 for f in files:
517 filename = opj(dirname, f)
518 if not os.path.isdir(filename):
519 lst.append( (dirname, [filename]) )
520 file_list = []
521 os.path.walk(srcdir, walk_helper, file_list)
522 return file_list
523
524
525 def find_data_files(srcdir, *wildcards):
526 # get a list of all files under the srcdir matching wildcards,
527 # returned in a format to be used for install_data
528
529 def walk_helper(arg, dirname, files):
530 names = []
531 lst, wildcards = arg
532 for wc in wildcards:
533 for f in files:
534 filename = opj(dirname, f)
535 if fnmatch.fnmatch(filename, wc) and not os.path.isdir(filename):
536 names.append(filename)
537 if names:
538 lst.append( (dirname, names ) )
539
540 file_list = []
541 os.path.walk(srcdir, walk_helper, (file_list, wildcards))
542 return file_list
543
544
545 def makeLibName(name):
546 if os.name == 'posix':
547 libname = '%s_%s-%s' % (WXBASENAME, name, WXRELEASE)
548 elif name:
549 libname = 'wxmsw%s%s_%s' % (WXDLLVER, libFlag(), name)
550 else:
551 libname = 'wxmsw%s%s' % (WXDLLVER, libFlag())
552 return [libname]
553
554
555
556 def adjustCFLAGS(cflags, defines, includes):
557 '''Extract the raw -I, -D, and -U flags and put them into
558 defines and includes as needed.'''
559 newCFLAGS = []
560 for flag in cflags:
561 if flag[:2] == '-I':
562 includes.append(flag[2:])
563 elif flag[:2] == '-D':
564 flag = flag[2:]
565 if flag.find('=') == -1:
566 defines.append( (flag, None) )
567 else:
568 defines.append( tuple(flag.split('=')) )
569 elif flag[:2] == '-U':
570 defines.append( (flag[2:], ) )
571 else:
572 newCFLAGS.append(flag)
573 return newCFLAGS
574
575
576
577 def adjustLFLAGS(lflags, libdirs, libs):
578 '''Extract the -L and -l flags and put them in libdirs and libs as needed'''
579 newLFLAGS = []
580 for flag in lflags:
581 if flag[:2] == '-L':
582 libdirs.append(flag[2:])
583 elif flag[:2] == '-l':
584 libs.append(flag[2:])
585 else:
586 newLFLAGS.append(flag)
587
588 # remove any flags for universal binaries, we'll get those from
589 # distutils instead
590 return [flag for flag in newLFLAGS
591 if flag not in ['-isysroot', '-arch', 'ppc', 'i386'] and
592 not flag.startswith('/Developer') ]
593
594
595
596 def getExtraPath(shortVer=True, addOpts=False):
597 """Get the dirname that wxPython will be installed under."""
598
599 if shortVer:
600 # short version, just Major.Minor
601 ep = "wx-%d.%d" % (VER_MAJOR, VER_MINOR)
602
603 # plus release if minor is odd
604 if VER_MINOR % 2 == 1:
605 ep += ".%d" % VER_RELEASE
606
607 else:
608 # long version, full version
609 ep = "wx-%d.%d.%d.%d" % (VER_MAJOR, VER_MINOR, VER_RELEASE, VER_SUBREL)
610
611 if addOpts:
612 port = WXPORT
613 if port == "msw": port = "win32"
614 ep += "-%s-%s" % (WXPORT, (UNICODE and 'unicode' or 'ansi'))
615
616 if FLAVOUR:
617 ep += "-" + FLAVOUR
618
619 return ep
620
621 #----------------------------------------------------------------------
622 # sanity checks
623
624 if CORE_ONLY:
625 BUILD_GLCANVAS = 0
626 BUILD_OGL = 0
627 BUILD_STC = 0
628 BUILD_GIZMOS = 0
629 BUILD_DLLWIDGET = 0
630 BUILD_ACTIVEX = 0
631
632 if debug:
633 FINAL = 0
634 HYBRID = 0
635
636 if FINAL:
637 HYBRID = 0
638
639 if UNICODE and WXPORT not in ['msw', 'gtk2', 'mac']:
640 raise SystemExit, "UNICODE mode not currently supported on this WXPORT: "+WXPORT
641
642
643 if CONTRIBS_INC:
644 CONTRIBS_INC = [ CONTRIBS_INC ]
645 else:
646 CONTRIBS_INC = []
647
648
649 #----------------------------------------------------------------------
650 # Setup some platform specific stuff
651 #----------------------------------------------------------------------
652
653 if os.name == 'nt':
654 # Set compile flags and such for MSVC. These values are derived
655 # from the wxWidgets makefiles for MSVC, other compilers settings
656 # will probably vary...
657 if os.environ.has_key('WXWIN'):
658 WXDIR = os.environ['WXWIN']
659 else:
660 msg("WARNING: WXWIN not set in environment.")
661 WXDIR = '..' # assumes in CVS tree
662 WXPLAT = '__WXMSW__'
663 GENDIR = 'msw'
664
665 includes = ['include', 'src',
666 opj(WXDIR, 'lib', 'vc_dll', 'msw' + libFlag()),
667 opj(WXDIR, 'include'),
668 opj(WXDIR, 'contrib', 'include'),
669 ]
670
671 defines = [ ('WIN32', None),
672 ('_WINDOWS', None),
673
674 (WXPLAT, None),
675 ('WXUSINGDLL', '1'),
676
677 ('SWIG_TYPE_TABLE', WXPYTHON_TYPE_TABLE),
678 ('SWIG_PYTHON_OUTPUT_TUPLE', None),
679 ('WXP_USE_THREAD', '1'),
680 ]
681
682 if UNDEF_NDEBUG:
683 defines.append( ('NDEBUG',) ) # using a 1-tuple makes it do an undef
684
685 if HYBRID:
686 defines.append( ('__NO_VC_CRTDBG__', None) )
687
688 if not FINAL or HYBRID:
689 defines.append( ('__WXDEBUG__', None) )
690
691 if UNICODE:
692 defines.append( ('wxUSE_UNICODE', 1) )
693
694 libdirs = [ opj(WXDIR, 'lib', 'vc_dll') ]
695 if MONOLITHIC:
696 libs = makeLibName('')
697 else:
698 libs = [ 'wxbase' + WXDLLVER + libFlag(),
699 'wxbase' + WXDLLVER + libFlag() + '_net',
700 'wxbase' + WXDLLVER + libFlag() + '_xml',
701 makeLibName('core')[0],
702 makeLibName('adv')[0],
703 makeLibName('html')[0],
704 ]
705
706 libs = libs + ['kernel32', 'user32', 'gdi32', 'comdlg32',
707 'winspool', 'winmm', 'shell32', 'oldnames', 'comctl32',
708 'odbc32', 'ole32', 'oleaut32', 'uuid', 'rpcrt4',
709 'advapi32', 'wsock32']
710
711
712 cflags = [ '/Gy',
713 # '/GX-' # workaround for internal compiler error in MSVC on some machines
714 ]
715 lflags = None
716
717 # Other MSVC flags...
718 # Too bad I don't remember why I was playing with these, can they be removed?
719 if FINAL:
720 pass #cflags = cflags + ['/O1']
721 elif HYBRID :
722 pass #cflags = cflags + ['/Ox']
723 else:
724 pass # cflags = cflags + ['/Od', '/Z7']
725 # lflags = ['/DEBUG', ]
726
727
728
729 #----------------------------------------------------------------------
730
731 elif os.name == 'posix':
732 WXDIR = '..'
733 includes = ['include', 'src']
734 defines = [('SWIG_TYPE_TABLE', WXPYTHON_TYPE_TABLE),
735 ('SWIG_PYTHON_OUTPUT_TUPLE', None),
736 ('WXP_USE_THREAD', '1'),
737 ]
738 if UNDEF_NDEBUG:
739 defines.append( ('NDEBUG',) ) # using a 1-tuple makes it do an undef
740
741 Verify_WX_CONFIG()
742
743 libdirs = []
744 libs = []
745
746 # If you get unresolved symbol errors on Solaris and are using gcc, then
747 # uncomment this block to add the right flags to the link step and build
748 # again.
749 ## if os.uname()[0] == 'SunOS':
750 ## import commands
751 ## libs.append('gcc')
752 ## libdirs.append(commands.getoutput("gcc -print-search-dirs | grep '^install' | awk '{print $2}'")[:-1])
753
754 cflags = os.popen(WX_CONFIG + ' --cxxflags', 'r').read()[:-1]
755 cflags = cflags.split()
756 if debug:
757 cflags.append('-g')
758 cflags.append('-O0')
759 else:
760 cflags.append('-O3')
761
762 lflags = os.popen(WX_CONFIG + ' --libs', 'r').read()[:-1]
763 MONOLITHIC = (lflags.find("_xrc") == -1)
764 lflags = lflags.split()
765
766 WXBASENAME = os.popen(WX_CONFIG + ' --basename').read()[:-1]
767 WXRELEASE = os.popen(WX_CONFIG + ' --release').read()[:-1]
768 WXPREFIX = os.popen(WX_CONFIG + ' --prefix').read()[:-1]
769
770
771 if sys.platform[:6] == "darwin" and WXPORT == 'mac':
772 # Flags and such for a Darwin (Max OS X) build of Python
773 WXPLAT = '__WXMAC__'
774 GENDIR = 'mac'
775 libs = ['stdc++']
776 NO_SCRIPTS = 1
777
778
779 else:
780 # Set flags for other Unix type platforms
781 GENDIR = WXPORT
782
783 if WXPORT == 'gtk':
784 WXPLAT = '__WXGTK__'
785 portcfg = os.popen('gtk-config --cflags', 'r').read()[:-1]
786 elif WXPORT == 'gtk2':
787 WXPLAT = '__WXGTK__'
788 GENDIR = 'gtk' # no code differences so use the same generated sources
789 portcfg = os.popen('pkg-config gtk+-2.0 --cflags', 'r').read()[:-1]
790 BUILD_BASE = BUILD_BASE + '-' + WXPORT
791 elif WXPORT == 'x11':
792 WXPLAT = '__WXX11__'
793 portcfg = ''
794 BUILD_BASE = BUILD_BASE + '-' + WXPORT
795 else:
796 raise SystemExit, "Unknown WXPORT value: " + WXPORT
797
798 cflags += portcfg.split()
799
800 # Some distros (e.g. Mandrake) put libGLU in /usr/X11R6/lib, but
801 # wx-config doesn't output that for some reason. For now, just
802 # add it unconditionally but we should really check if the lib is
803 # really found there or wx-config should be fixed.
804 libdirs.append("/usr/X11R6/lib")
805
806
807 # Move the various -I, -D, etc. flags we got from the *config scripts
808 # into the distutils lists.
809 cflags = adjustCFLAGS(cflags, defines, includes)
810 lflags = adjustLFLAGS(lflags, libdirs, libs)
811
812
813 #----------------------------------------------------------------------
814 else:
815 raise 'Sorry, platform not supported...'
816
817
818 #----------------------------------------------------------------------
819 # build options file
820 #----------------------------------------------------------------------
821
822 if SYS_WX_CONFIG is None:
823 SYS_WX_CONFIG = WX_CONFIG
824
825 build_options_template = """
826 UNICODE=%d
827 UNDEF_NDEBUG=%d
828 INSTALL_MULTIVERSION=%d
829 FLAVOUR="%s"
830 EP_ADD_OPTS=%d
831 EP_FULL_VER=%d
832 WX_CONFIG="%s"
833 WXPORT="%s"
834 MONOLITHIC=%d
835 FINAL=%d
836 HYBRID=%d
837 """ % (UNICODE, UNDEF_NDEBUG, INSTALL_MULTIVERSION, FLAVOUR, EP_ADD_OPTS,
838 EP_FULL_VER, SYS_WX_CONFIG, WXPORT, MONOLITHIC, FINAL, HYBRID)
839
840 try:
841 from build_options import *
842 except:
843 build_options_file = os.path.join(os.path.dirname(__file__), "build_options.py")
844 if not os.path.exists(build_options_file):
845 try:
846 myfile = open(build_options_file, "w")
847 myfile.write(build_options_template)
848 myfile.close()
849 except:
850 print "WARNING: Unable to create build_options.py."
851
852
853 #----------------------------------------------------------------------
854 # post platform setup checks and tweaks, create the full version string
855 #----------------------------------------------------------------------
856
857 if UNICODE:
858 BUILD_BASE = BUILD_BASE + '.unicode'
859 ##VER_FLAGS += 'u'
860
861 if os.path.exists('DAILY_BUILD'):
862
863 VER_FLAGS += '-' + open('DAILY_BUILD').read().strip()
864
865 VERSION = "%s.%s.%s.%s%s" % (VER_MAJOR, VER_MINOR, VER_RELEASE,
866 VER_SUBREL, VER_FLAGS)
867
868
869 #----------------------------------------------------------------------
870 # SWIG defaults
871 #----------------------------------------------------------------------
872
873 # *.i files could live in the wxWidgets/wxPython/src dir, or in
874 # a subdirectory of the devel package. Let's specify both
875 # dirs as includes so we don't have to guess which is correct.
876
877 wxfilesdir = ""
878 i_subdir = opj("include", getExtraPath(), "wx", "wxPython", "i_files")
879 if os.name != "nt":
880 wxfilesdir = opj(WXPREFIX, i_subdir)
881 else:
882 wxfilesdir = opj(WXPY_SRC, i_subdir)
883
884 i_files_includes = [ '-I' + opj(WXPY_SRC, 'src'),
885 '-I' + wxfilesdir ]
886
887 swig_cmd = SWIG
888 swig_force = force
889 swig_args = ['-c++',
890 #'-Wall',
891 '-python',
892 '-new_repr',
893 '-modern',
894 '-D'+WXPLAT,
895 ] + i_files_includes
896
897 if USE_SWIG:
898 SVER = swig_version()
899 if int(SVER[-2:]) >= 29:
900 swig_args += [ '-fastdispatch',
901 '-fvirtual',
902 '-fastinit',
903 '-fastunpack',
904 #'-outputtuple', Currently setting this with a -D define above
905 ]
906
907 if UNICODE:
908 swig_args.append('-DwxUSE_UNICODE')
909
910 if FULL_DOCS:
911 swig_args.append('-D_DO_FULL_DOCS')
912
913
914 swig_deps = [ opj(WXPY_SRC, 'src/my_typemaps.i'),
915 opj(WXPY_SRC, 'src/pyfragments.swg'),
916 ]
917
918 depends = [ #'include/wx/wxPython/wxPython.h',
919 #'include/wx/wxPython/wxPython_int.h',
920 #'src/pyclasses.h',
921 ]
922
923 #----------------------------------------------------------------------
924
925 ####################################
926 # BuildRenamers
927 ####################################
928
929 import pprint, shutil
930 try:
931 import libxml2
932 FOUND_LIBXML2 = True
933 except ImportError:
934 FOUND_LIBXML2 = False
935
936 #---------------------------------------------------------------------------
937
938 renamerTemplateStart = """\
939 // A bunch of %rename directives generated by BuildRenamers in config.py
940 // in order to remove the wx prefix from all global scope names.
941
942 #ifndef BUILDING_RENAMERS
943
944 """
945
946 renamerTemplateEnd = """
947 #endif
948 """
949
950 wxPythonTemplateStart = """\
951 ## This file reverse renames symbols in the wx package to give
952 ## them their wx prefix again, for backwards compatibility.
953 ##
954 ## Generated by BuildRenamers in config.py
955
956 # This silly stuff here is so the wxPython.wx module doesn't conflict
957 # with the wx package. We need to import modules from the wx package
958 # here, then we'll put the wxPython.wx entry back in sys.modules.
959 import sys
960 _wx = None
961 if sys.modules.has_key('wxPython.wx'):
962 _wx = sys.modules['wxPython.wx']
963 del sys.modules['wxPython.wx']
964
965 import wx.%s
966
967 sys.modules['wxPython.wx'] = _wx
968 del sys, _wx
969
970
971 # Now assign all the reverse-renamed names:
972 """
973
974 wxPythonTemplateEnd = """
975
976 """
977
978
979
980 #---------------------------------------------------------------------------
981 class BuildRenamers:
982 def run(self, destdir, modname, xmlfile, wxPythonDir="wxPython"):
983
984 assert FOUND_LIBXML2, "The libxml2 module is required to use the BuildRenamers functionality."
985
986 if not os.path.exists(wxPythonDir):
987 os.mkdir(wxPythonDir)
988
989 swigDest = os.path.join(destdir, "_"+modname+"_rename.i")
990 pyDest = os.path.join(wxPythonDir, modname + '.py')
991
992 swigDestTemp = tempfile.mktemp('.tmp')
993 swigFile = open(swigDestTemp, "w")
994 swigFile.write(renamerTemplateStart)
995
996 pyDestTemp = tempfile.mktemp('.tmp')
997 pyFile = open(pyDestTemp, "w")
998 pyFile.write(wxPythonTemplateStart % modname)
999
1000 print "Parsing XML and building renamers..."
1001 self.processXML(xmlfile, modname, swigFile, pyFile)
1002
1003 self.checkOtherNames(pyFile, modname,
1004 os.path.join(destdir, '_'+modname+'_reverse.txt'))
1005 pyFile.write(wxPythonTemplateEnd)
1006 pyFile.close()
1007
1008 swigFile.write(renamerTemplateEnd)
1009 swigFile.close()
1010
1011 # Compare the files just created with the existing one and
1012 # blow away the old one if they are different.
1013 for dest, temp in [(swigDest, swigDestTemp),
1014 (pyDest, pyDestTemp)]:
1015 # NOTE: we don't use shutil.move() because it was introduced
1016 # in Python 2.3. Eventually we can switch to it when people
1017 # stop building using 2.2.
1018 if not os.path.exists(dest):
1019 shutil.copyfile(temp, dest)
1020 elif open(dest).read() != open(temp).read():
1021 os.unlink(dest)
1022 shutil.copyfile(temp, dest)
1023 else:
1024 print dest + " not changed."
1025 os.unlink(temp)
1026
1027 #---------------------------------------------------------------------------
1028
1029
1030 def GetAttr(self, node, name):
1031 path = "./attributelist/attribute[@name='%s']/@value" % name
1032 n = node.xpathEval2(path)
1033 if len(n):
1034 return n[0].content
1035 else:
1036 return None
1037
1038
1039 def processXML(self, xmlfile, modname, swigFile, pyFile):
1040
1041 topnode = libxml2.parseFile(xmlfile).children
1042
1043 # remove any import nodes as we don't need to do renamers for symbols found therein
1044 imports = topnode.xpathEval2("*/import")
1045 for n in imports:
1046 n.unlinkNode()
1047 n.freeNode()
1048
1049 # do a depth first iteration over what's left
1050 for node in topnode:
1051 doRename = False
1052 addWX = False
1053 revOnly = False
1054
1055
1056 if node.name == "class":
1057 lastClassName = name = self.GetAttr(node, "name")
1058 lastClassSymName = sym_name = self.GetAttr(node, "sym_name")
1059 doRename = True
1060 if sym_name != name:
1061 name = sym_name
1062 addWX = True
1063
1064 # renamed constructors
1065 elif node.name == "constructor":
1066 name = self.GetAttr(node, "name")
1067 sym_name = self.GetAttr(node, "sym_name")
1068 if sym_name != name:
1069 name = sym_name
1070 addWX = True
1071 doRename = True
1072
1073 # only enumitems at the top level
1074 elif node.name == "enumitem" and node.parent.parent.name == "include":
1075 name = self.GetAttr(node, "name")
1076 sym_name = self.GetAttr(node, "sym_name")
1077 doRename = True
1078
1079
1080 elif node.name in ["cdecl", "constant"]:
1081 name = self.GetAttr(node, "name")
1082 sym_name = self.GetAttr(node, "sym_name")
1083 toplevel = node.parent.name == "include"
1084
1085 # top-level functions
1086 if toplevel and self.GetAttr(node, "view") == "globalfunctionHandler":
1087 doRename = True
1088
1089 # top-level global vars
1090 elif toplevel and self.GetAttr(node, "feature_immutable") == "1":
1091 doRename = True
1092
1093 # static methods
1094 elif self.GetAttr(node, "view") == "staticmemberfunctionHandler":
1095 name = lastClassName + '_' + name
1096 sym_name = lastClassSymName + '_' + sym_name
1097 # only output the reverse renamer in this case
1098 doRename = revOnly = True
1099
1100 if doRename and name != sym_name:
1101 name = sym_name
1102 addWX = True
1103
1104
1105 if doRename and name:
1106 old = new = name
1107 if old.startswith('wx') and not old.startswith('wxEVT_'):
1108 # remove all wx prefixes except wxEVT_ and write a %rename directive for it
1109 new = old[2:]
1110 if not revOnly:
1111 swigFile.write("%%rename(%s) %35s;\n" % (new, old))
1112
1113 # Write assignments to import into the old wxPython namespace
1114 if addWX and not old.startswith('wx'):
1115 old = 'wx'+old
1116 pyFile.write("%s = wx.%s.%s\n" % (old, modname, new))
1117
1118
1119 #---------------------------------------------------------------------------
1120
1121 def checkOtherNames(self, pyFile, moduleName, filename):
1122 if os.path.exists(filename):
1123 prefixes = []
1124 for line in file(filename):
1125 if line.endswith('\n'):
1126 line = line[:-1]
1127 if line and not line.startswith('#'):
1128 if line.endswith('*'):
1129 prefixes.append(line[:-1])
1130 elif line.find('=') != -1:
1131 pyFile.write("%s\n" % line)
1132 else:
1133 wxname = 'wx' + line
1134 if line.startswith('wx') or line.startswith('WX') or line.startswith('EVT'):
1135 wxname = line
1136 pyFile.write("%s = wx.%s.%s\n" % (wxname, moduleName, line))
1137
1138 if prefixes:
1139 pyFile.write(
1140 "\n\nd = globals()\nfor k, v in wx.%s.__dict__.iteritems():"
1141 % moduleName)
1142 first = True
1143 for p in prefixes:
1144 if first:
1145 pyFile.write("\n if ")
1146 first = False
1147 else:
1148 pyFile.write("\n elif ")
1149 pyFile.write("k.startswith('%s'):\n d[k] = v" % p)
1150 pyFile.write("\ndel d, k, v\n\n")
1151
1152
1153 #---------------------------------------------------------------------------