diff --git a/.gitignore b/.gitignore index 2f052163..fdbf8f77 100644 --- a/.gitignore +++ b/.gitignore @@ -3,12 +3,15 @@ *.pyd *.pdb *.dll +.waf-* +.lock-waf* # / /.hg /.hgignore /build +/build_waf /tmp /dist /license diff --git a/buildtools/config.py b/buildtools/config.py index 353d24ce..1a29ec30 100644 --- a/buildtools/config.py +++ b/buildtools/config.py @@ -129,10 +129,20 @@ class Configuration(object): ] if noWxConfig: - # this is as far as we go + # this is as far as we go for now return + # otherwise do the rest of it + self.finishSetup() + + def finishSetup(self, wx_config=None, debug=None): + if wx_config is not None: + self.WX_CONFIG = wx_config + + if debug is not None: + self.debug = debug + #--------------------------------------- # MSW specific settings if os.name == 'nt' and self.COMPILER == 'msvc': @@ -157,7 +167,7 @@ class Configuration(object): (self.WXPLAT, None), ('WXUSINGDLL', '1'), ('ISOLATION_AWARE_ENABLED', None), - ('NDEBUG',), # using a 1-tuple makes it do an undef + #('NDEBUG',), # using a 1-tuple makes it do an undef ] self.libs = [] @@ -178,7 +188,8 @@ class Configuration(object): 'odbc32', 'ole32', 'oleaut32', 'uuid', 'rpcrt4', 'advapi32', 'wsock32'] - self.cflags = [ '/Gy', + self.cflags = [ '/UNDEBUG', + '/Gy', '/EHsc', # '/GX-' # workaround for internal compiler error in MSVC on some machines ] @@ -195,7 +206,7 @@ class Configuration(object): elif os.name == 'posix' or COMPILER == 'mingw32': self.Verify_WX_CONFIG() self.includes += ['include'] - self.defines = [ ('NDEBUG',), # using a 1-tuple makes it do an undef + self.defines = [ #('NDEBUG',), # using a 1-tuple makes it do an undef ] self.libdirs = [] self.libs = [] @@ -233,9 +244,10 @@ class Configuration(object): self.lflags.append("-arch") self.lflags.append(self.ARCH) + self.CC = self.CXX = None if not os.environ.get('CC') or not os.environ.get('CXX'): - os.environ["CXX"] = self.getWxConfigValue('--cxx') - os.environ["CC"] = self.getWxConfigValue('--cc') + self.CC = os.environ["CC"] = self.getWxConfigValue('--cc') + self.CXX = os.environ["CXX"] = self.getWxConfigValue('--cxx') # wxGTK settings else: @@ -272,10 +284,22 @@ class Configuration(object): # into the distutils lists. self.cflags = self.adjustCFLAGS(self.cflags, self.defines, self.includes) self.lflags = self.adjustLFLAGS(self.lflags, self.libdirs, self.libs) + + self.cflags.insert(0, '-UNDEBUG') if self.debug and self.WXPORT == 'msw' and self.COMPILER != 'mingw32': self.defines.append( ('_DEBUG', None) ) - + + # WAF wants a simple list of strings, so convert self.defines in case + # we'll be using that instead of distutils + self.wafDefines = [] + for d in self.defines: + if len(d) > 1: + name, val = d + if val: + name = name+'='+val + self.wafDefines.append(name) + # --------------------------------------------------------------- # Helper functions diff --git a/wscript b/wscript index 3a71db54..01bdc106 100644 --- a/wscript +++ b/wscript @@ -1,183 +1,229 @@ #!/usr/bin/python +#----------------------------------------------------------------------------- +# WAF build script for building the wxPython extension modules. +# +# +#----------------------------------------------------------------------------- -import os import sys +import os -import TaskGen -import Utils +import buildtools.config +cfg = buildtools.config.Config(True) -from buildtools.config import Config, msg, opj, loadETG +#----------------------------------------------------------------------------- +# Options and configuration -from distutils.file_util import copy_file -from distutils.dir_util import mkpath -from distutils.dep_util import newer, newer_group -from distutils.spawn import spawn +APPNAME = 'wxPython' +VERSION = cfg.VERSION -source_exts = [".cpp"] +top = '.' out = 'build_waf' -from waflib.TaskGen import feature, after -from waflib.Task import Task -from waflib.Tools import c_preproc - -os.environ["MACOSX_DEPLOYMENT_TARGET"] = "10.4" def options(opt): - opt.load('compiler_cc compiler_cxx') - opt.add_option('--wx-config', dest='wx_config', default='wx-config', action='store') + opt.load('compiler_cc compiler_cxx python') + opt.add_option('--debug', dest='debug', action='store_true', default=False, + help='Turn on debug compile options.') + opt.add_option('--python', dest='python', default='', action='store', + help='Full path to the Python executrable to use.') + opt.add_option('--wx_config', dest='wx_config', default='wx-config', action='store', + help='Full path to the wx-config script to be used for this build.') + opt.add_option('--mac_arch', dest='mac_arch', default='', action='store', + help='One or more comma separated architecture names to be used for ' + 'the Mac builds. Should be at least a subset of the architectures ' + 'used by wxWidgets and Python') + def configure(conf): conf.load('compiler_cc compiler_cxx python') + if conf.options.python: + conf.env.PYTHON = [conf.options.python] conf.check_python_headers() - wx_config = conf.options.wx_config + conf.check_python_version(minver=(2,7,0)) - conf.env.append_value('CFLAGS', '-g') - conf.env.append_value('CXXFLAGS', '-g') - conf.check_cfg(path=wx_config, package='', args='--cxxflags --libs', uselib_store='WX', mandatory=True) + # fetch and save the debug option + conf.env.debug = conf.options.debug + + # Ensure that the headers in siplib and Phoenix's src dir can be found + conf.env.INCLUDES_WXPY = ['sip/siplib', 'src'] + + # Create the other WXPY lib variables we'll be using below + conf.env.CFLAGS_WXPY = [] + conf.env.CXXFLAGS_WXPY = [] + conf.env.ARCH_WXPY = [] + if sys.platform == 'win32': + # Windows/MSVC specific stuff TODO + pass + else: + # Configuration stuff for ports using wx-config + + # Check wx-config exists and fetch some values from it + conf.env.wx_config = conf.options.wx_config + conf.check_cfg(path=conf.options.wx_config, package='', args='--cxxflags --libs', + uselib_store='WX', mandatory=True) + # TODO: Run it again with different libs options to get different + # sets of flags stored to use with different extension modules below. + # WXGL, WXHTML, etc. + + # finish configuring the Config object + cfg.finishSetup(conf.env.wx_config, conf.env.debug) + + # clear out Python's default NDEBUG and make sure it is undef'd too just in case + if 'NDEBUG' in conf.env.DEFINES_PYEXT: + conf.env.DEFINES_PYEXT.remove('NDEBUG') + conf.env.CFLAGS_WXPY.append('-UNDEBUG') + conf.env.CXXFLAGS_WXPY.append('-UNDEBUG') + + # Add basic debug info for all builds + conf.env.CFLAGS_WXPY.append('-g') + conf.env.CXXFLAGS_WXPY.append('-g') + + # And if --debug is set turn on more detailed info and turn off optimization + if conf.env.debug: + conf.env.CFLAGS_WXPY.extend(['-ggdb', '-O0']) + conf.env.CXXFLAGS_WXPY.extend(['-ggdb', '-O0']) + + # Remove some compile flags we don't care about, ones that we may be + # replacing ourselves anyway, or ones which may have duplicates. + flags = ['CFLAGS_PYEXT', 'CXXFLAGS_PYEXT', 'LINKFLAGS_PYEXT', + 'CFLAGS_cshlib', 'CXXFLAGS_cshlib', 'LINKFLAGS_cshlib', + 'CFLAGS_cxxshlib', 'CXXFLAGS_cxxshlib', 'LINKFLAGS_cxxshlib'] + for key in flags: + _cleanFlags(conf, key) + + + # Use the same compilers that wxWidgets used + if cfg.CC: + conf.env.CC = cfg.CC.split() + if cfg.CXX: + conf.env.CXX = cfg.CXX.split() + + + # Some Mac-specific stuff + if sys.platform == 'darwin': + conf.env.MACOSX_DEPLOYMENT_TARGET = "10.4" # should we bump this to 10.5? + + if conf.options.mac_arch: + conf.env.ARCH_WXPY = conf.options.mac_arch.split(',') + + + #import pprint + #pprint.pprint( [(k, conf.env[k]) for k in conf.env.keys()] ) + +#----------------------------------------------------------------------------- +# Build command def build(bld): - #---------------------------------------------------------------------- - - # Create a buildtools.config.Configuration object - cfg = Config() - - # Ensure that the directory containing this script is on the python # path for spawned commands so the builder and phoenix packages can be # found. thisdir = os.path.abspath(".") - os.environ['PYTHONPATH'] = thisdir + os.pathsep + os.environ.get('PYTHONPATH', '') - - - WX_PKGLIST = [ cfg.PKGDIR ] - - SCRIPTS = None - DATA_FILES = [] - HEADERS = None - BUILD_OPTIONS = { 'build_base' : cfg.BUILD_BASE } - if cfg.WXPORT == 'msw': - BUILD_OPTIONS[ 'compiler' ] = cfg.COMPILER - - copy_file('src/__init__.py', cfg.PKGDIR, update=1, verbose=0) - cfg.CLEANUP.append(opj(cfg.PKGDIR, '__init__.py')) + sys.path.insert(0, thisdir) + from distutils.file_util import copy_file + from distutils.dir_util import mkpath + from distutils.dep_util import newer, newer_group + from buildtools.config import opj, loadETG, getEtgSipCppFiles + + cfg.finishSetup(bld.env.wx_config) + # update the license files mkpath('license') for filename in ['preamble.txt', 'licence.txt', 'licendoc.txt', 'lgpl.txt']: - copy_file(opj(cfg.WXDIR, 'docs', filename), opj('license',filename), update=1, verbose=0) - cfg.CLEANUP.append(opj('license',filename)) - cfg.CLEANUP.append('license') - + copy_file(opj(cfg.WXDIR, 'docs', filename), opj('license',filename), update=1, verbose=1) # create the package's __version__ module - open(opj(cfg.PKGDIR, '__version__.py'), 'w').write("""\ -# This file was generated by setup.py... + open(opj(cfg.PKGDIR, '__version__.py'), 'w').write( + "# This file was generated by Phoenix's wscript.\n\n" + "VERSION_STRING = '%(VERSION)s'\n" + "MAJOR_VERSION = %(VER_MAJOR)s\n" + "MINOR_VERSION = %(VER_MINOR)s\n" + "RELEASE_NUMBER = %(VER_RELEASE)s\n" + "SUBRELEASE_NUMBER = %(VER_SUBREL)s\n\n" + "VERSION = (MAJOR_VERSION, MINOR_VERSION, RELEASE_NUMBER, SUBRELEASE_NUMBER, '%(VER_FLAGS)s')\n" + % cfg.__dict__) -VERSION_STRING = '%(VERSION)s' -MAJOR_VERSION = %(VER_MAJOR)s -MINOR_VERSION = %(VER_MINOR)s -RELEASE_NUMBER = %(VER_RELEASE)s -SUBRELEASE_NUMBER = %(VER_SUBREL)s - -VERSION = (MAJOR_VERSION, MINOR_VERSION, RELEASE_NUMBER, - SUBRELEASE_NUMBER, '%(VER_FLAGS)s') - """ % cfg.__dict__) - cfg.CLEANUP.append(opj(cfg.PKGDIR,'__version__.py')) - - + # copy the wx locale message catalogs to the package dir if sys.platform in ['win32', 'darwin']: cfg.build_locale_dir(opj(cfg.PKGDIR, 'locale')) - DATA_FILES += cfg.build_locale_list(opj(cfg.PKGDIR, 'locale')) - - - if os.name == 'nt': - rc_file = ['src/wxc.rc'] - else: - rc_file = [] - source_dirs = [ - "sip/cpp", - ] + + # Create the build tasks for each of our extension modules. + siplib = bld( + features = 'c cxx cxxshlib pyext', + target = 'siplib', + source = ['sip/siplib/apiversions.c', + 'sip/siplib/bool.cpp', + 'sip/siplib/descriptors.c', + 'sip/siplib/objmap.c', + 'sip/siplib/qtlib.c', + 'sip/siplib/siplib.c', + 'sip/siplib/threads.c', + 'sip/siplib/voidptr.c', + ], + uselib = 'WX WXPY', + ) + makeExtCopyRule(bld, 'siplib') + etg = loadETG('etg/_core.py') + rc = ['src/wxc.rc'] if sys.platform == 'win32' else [] + core = bld( + features = 'c cxx cxxshlib pyext', + target = '_core', + source = getEtgSipCppFiles(etg) + rc, + uselib = 'WX WXPY', + ) + makeExtCopyRule(bld, '_core') + + etg = loadETG('etg/_dataview.py') - - def remove_archs(var): - result = [] - skipnext = False - for flag in var: - index = var.index(flag) - nextflag = var[index+1] - if flag == '-arch' or flag == '-isysroot': - skipnext = True - elif not skipnext: - result.append(flag) - else: - skipnext = False - - return result - - bld.env.CFLAGS_PYEXT = remove_archs(bld.env.CFLAGS_PYEXT) - bld.env.CFLAGS_PYEMBED = remove_archs(bld.env.CFLAGS_PYEMBED) - - bld.env.CXXFLAGS_PYEXT = remove_archs(bld.env.CXXFLAGS_PYEXT) - bld.env.CXXFLAGS_PYEMBED = remove_archs(bld.env.CXXFLAGS_PYEMBED) - - bld.env.LINKFLAGS_PYEXT = remove_archs(bld.env.LINKFLAGS_PYEXT) - bld.env.LINKFLAGS_PYEMBED = remove_archs(bld.env.LINKFLAGS_PYEMBED) - - archs = ['-arch', 'i386', '-mmacosx-version-min=10.5'] - bld.env.append_value('CFLAGS_PYEXT', archs) - bld.env.append_value('CFLAGS_PYEMBED', archs) - - bld.env.append_value('CXXFLAGS_PYEXT', archs) - bld.env.append_value('CXXFLAGS_PYEMBED', archs) - - bld.env.append_value('LINKFLAGS_PYEXT', archs) - bld.env.append_value('LINKFLAGS_PYEMBED', archs) - - siplib = bld( - features='c cxx cshlib pyext', - target='siplib', - name='sip', - includes=cfg.includes + ['sip/siplib'], - cflags=cfg.cflags, - defines=cfg.defines, - libpath=cfg.libdirs, - uselib='WX', - install_path="wx" + dataview = bld( + features = 'c cxx cxxshlib pyext', + target = '_dataview', + source = getEtgSipCppFiles(etg) + rc, + uselib = 'WX WXPY', ) + makeExtCopyRule(bld, '_dataview') - siplib.source = siplib.path.ant_glob("sip/siplib/*.c sip/siplib/*.cpp", incl=source_exts) +#----------------------------------------------------------------------------- +# helpers - bld.add_group() +# Remove some unwanted flags from the given key in the context's environment +def _cleanFlags(ctx, key): + cleaned = list() + skipnext = False + for idx, flag in enumerate(ctx.env[key]): + if flag in ['-arch', '-isysroot', '-compatibility_version', '-current_version']: + skipnext = True # implicitly skips this one too + elif not skipnext: + cleaned.append(flag) + else: + skipnext = False + ctx.env[key] = cleaned - corelib = bld( - features='c cxx cxxshlib pyext', - target='_core', - includes=cfg.includes + ['sip/siplib'], - cflags=cfg.cflags, - defines=cfg.defines, - libpath=cfg.libdirs, - linkflags='./siplib.so', - use= ['WX'], - install_path="wx" - ) + + +# Make a rule that will copy a built extension module to the in-place package +# dir so we can test locally without doing an install. +def makeExtCopyRule(bld, name): + src = bld.env.pyext_PATTERN % name + tgt = 'pkg.%s' % name # just a name to be touched to serve as a timestamp of the copy + bld(rule=copyFileToPkg, source=src, target=tgt, after=name) + + +# This is the task function to be called by the above rule. +def copyFileToPkg(task): + from distutils.file_util import copy_file + from buildtools.config import opj + src = task.inputs[0].abspath() + tgt = task.outputs[0].abspath() + task.exec_command('touch %s' % tgt) + tgt = opj(cfg.PKGDIR, os.path.basename(src)) + copy_file(src, tgt, verbose=1) + return 0 - corelib.source = corelib.path.ant_glob("sip/cpp/sip_core*.cpp", incl=source_exts, remove=False, maxdepth=3) - - dataviewlib = bld( - features='c cxx cxxshlib pyext', - target='_dataview', - includes=cfg.includes + ['sip/siplib'], - cflags=cfg.cflags, - defines=cfg.defines, - libpath=cfg.libdirs, - linkflags='./siplib.so ./_core.so', - use= ['WX'], - install_path="wx" - ) - - dataviewlib.source = dataviewlib.path.ant_glob("sip/cpp/sip_dataview*.cpp", incl=source_exts, remove=False, maxdepth=3) +#-----------------------------------------------------------------------------