From 3b2c81c759c2653c32a870c0fb027d51045b47e6 Mon Sep 17 00:00:00 2001 From: Robin Dunn Date: Fri, 25 Jun 2010 20:53:39 +0000 Subject: [PATCH] Move build tools into the main part of the repository tree git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@64739 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- build/tools/build-wxwidgets.py | 509 +++++++++++++++++++++++++++++++++ build/tools/builder.py | 235 +++++++++++++++ build/tools/create-archive.py | 239 ++++++++++++++++ 3 files changed, 983 insertions(+) create mode 100755 build/tools/build-wxwidgets.py create mode 100755 build/tools/builder.py create mode 100755 build/tools/create-archive.py diff --git a/build/tools/build-wxwidgets.py b/build/tools/build-wxwidgets.py new file mode 100755 index 0000000000..b1e1081494 --- /dev/null +++ b/build/tools/build-wxwidgets.py @@ -0,0 +1,509 @@ +#!/usr/bin/env python + +################################### +# Author: Kevin Ollivier +# License: wxWidgets License +################################### + +import os +import re +import sys +import builder +import commands +import glob +import optparse +import platform +import shutil +import types + +# builder object +wxBuilder = None + +# other globals +scriptDir = None +wxRootDir = None +contribDir = None +options = None +configure_opts = None +exitWithException = True + + +def exitIfError(code, msg): + if code != 0: + print msg + if exitWithException: + raise builder.BuildError, msg + else: + sys.exit(1) + + +def getWxRelease(): + global wxRootDir + configureText = open(os.path.join(wxRootDir, "configure.in"), "r").read() + + majorVersion = re.search("wx_major_version_number=(\d+)", configureText).group(1) + minorVersion = re.search("wx_minor_version_number=(\d+)", configureText).group(1) + + return "%s.%s" % (majorVersion, minorVersion) + + + +def doMacLipoBuild(arch, buildDir, installDir, + cxxcompiler="g++-4.0", cccompiler="gcc-4.0", target="10.4", flags=""): + archInstallDir = installDir + "/" + arch + old_env = dict(CXX = os.environ.get('CXX'), + CC = os.environ.get('CC'), + MACOSX_DEPLOYMENT_TARGET = os.environ.get('MACOSX_DEPLOYMENT_TARGET'), + ) + + os.environ["CXX"] = "%s -arch %s %s" % (cxxcompiler, arch, flags) + os.environ["CC"] = "%s -arch %s %s" % (cccompiler, arch, flags) + os.environ["MACOSX_DEPLOYMENT_TARGET"] = target + archArgs = ["DESTDIR=" + archInstallDir] + buildRoot = "bld-" + arch + if buildDir: + buildRoot = buildDir + "/" + buildRoot + + if not os.path.exists(buildRoot): + os.makedirs(buildRoot) + + olddir = os.getcwd() + os.chdir(buildRoot) + + if not options.no_config: + exitIfError(wxBuilder.configure(dir=wxRootDir, options=configure_opts), "Error running configure for "+arch) + exitIfError(wxBuilder.build(options=archArgs), "Error building for "+arch) + exitIfError(wxBuilder.install(options=["DESTDIR=" + archInstallDir]), "Error Installing for "+arch) + + if options.wxpython and os.path.exists(os.path.join(wxRootDir, contribDir)): + exitIfError(wxBuilder.build(dir=os.path.join(contribDir, "gizmos"), options=archArgs), + "Error building gizmos for "+arch) + exitIfError(wxBuilder.install(os.path.join(contribDir, "gizmos"), options=["DESTDIR=" + archInstallDir]), + "Error Installing gizmos for "+arch) + + exitIfError(wxBuilder.build(dir=os.path.join(contribDir, "stc"),options=archArgs), + "Error building stc for "+arch) + exitIfError(wxBuilder.install(os.path.join(contribDir, "stc"),options=["DESTDIR=" + archInstallDir]), + "Error installing stc for "+arch) + + os.chdir(olddir) + for key, val in old_env.items(): + if val: + os.environ[key] = val + else: + del os.environ[key] + + +def macFixupInstallNames(destdir, prefix): + # When an installdir is used then the install_names embedded in + # the dylibs are not correct. Reset the IDs and the dependencies + # to use just the prefix. + pwd = os.getcwd() + os.chdir(destdir+prefix+'/lib') + dylibs = glob.glob('*.dylib') # ('*[0-9].[0-9].[0-9].[0-9]*.dylib') + for lib in dylibs: + cmd = 'install_name_tool -id %s/lib/%s %s/lib/%s' % \ + (prefix,lib, destdir+prefix,lib) + print cmd + os.system(cmd) + for dep in dylibs: + cmd = 'install_name_tool -change %s/lib/%s %s/lib/%s %s/lib/%s' % \ + (destdir+prefix,dep, prefix,dep, destdir+prefix,lib) + print cmd + os.system(cmd) + os.chdir(pwd) + + + +def main(scriptName, args): + global scriptDir + global wxRootDir + global contribDir + global options + global configure_opts + global wxBuilder + + scriptDir = os.path.dirname(os.path.abspath(scriptName)) + wxRootDir = os.path.abspath(os.path.join(scriptDir, "..", "..")) + + contribDir = os.path.join("contrib", "src") + installDir = None + + VERSION = tuple([int(i) for i in getWxRelease().split('.')]) + + if sys.platform.startswith("win"): + contribDir = os.path.join(wxRootDir, "contrib", "build") + + if sys.platform.startswith("win"): + toolkit = "msvc" + else: + toolkit = "autoconf" + + option_dict = { + "clean" : (False, "Clean all files from the build directory"), + "debug" : (False, "Build the library in debug symbols"), + "builddir" : ("", "Directory where the build will be performed for autoconf builds."), + "prefix" : ("", "Configured prefix to use for autoconf builds. Defaults to installdir if set."), + "install" : (False, "Install the toolkit to the installdir directory, or the default dir."), + "installdir" : ("", "Directory where built wxWidgets will be installed"), + "mac_universal_binary" : (False, "Build Mac version as a universal binary"), + "mac_lipo" : (False, "EXPERIMENTAL: Create a universal binary by merging a PPC and Intel build together."), + "mac_framework" : (False, "Install the Mac build as a framework"), + "no_config" : (False, "Turn off configure step on autoconf builds"), + "rebake" : (False, "Regenerate Bakefile and autoconf files"), + "unicode" : (False, "Build the library with unicode support"), + "wxpython" : (False, "Build the wxWidgets library with all options needed by wxPython"), + "cocoa" : (False, "Build the Cooca port (Mac only currently)."), + "osx_cocoa" : (False, "Build the new Cocoa port"), + "shared" : (False, "Build wx as a dynamic library"), + "cairo" : (False, "Build support for wxCairoContext (always true on GTK+)"), + "extra_make" : ("", "Extra args to pass on [n]make's command line."), + "features" : ("", "A comma-separated list of wxUSE_XYZ defines on Win, or a list of configure flags on unix."), + } + + parser = optparse.OptionParser(usage="usage: %prog [options]", version="%prog 1.0") + + for opt in option_dict: + default = option_dict[opt][0] + + action = "store" + if type(default) == types.BooleanType: + action = "store_true" + parser.add_option("--" + opt, default=default, action=action, dest=opt, help=option_dict[opt][1]) + + options, arguments = parser.parse_args(args=args) + + # compiler / build system specific args + buildDir = options.builddir + args = None + installDir = options.installdir + prefixDir = options.prefix + + if toolkit == "autoconf": + configure_opts = [] + if options.features != "": + configure_opts.extend(options.features.split(" ")) + + if options.unicode: + configure_opts.append("--enable-unicode") + + if options.debug: + configure_opts.append("--enable-debug") + + if options.mac_universal_binary: + configure_opts.append("--enable-universal_binary") + + if options.cocoa: + configure_opts.append("--with-cocoa") + + if options.osx_cocoa: + configure_opts.append("--with-osx_cocoa") + + wxpy_configure_opts = [ + "--with-opengl", + "--enable-sound", + "--enable-graphics_ctx", + "--enable-mediactrl", + "--enable-display", + "--enable-geometry", + "--enable-debug_flag", + "--enable-optimise", + "--disable-debugreport", + "--enable-uiactionsim", + ] + + if sys.platform.startswith("darwin"): + wxpy_configure_opts.append("--enable-monolithic") + else: + wxpy_configure_opts.append("--with-sdl") + wxpy_configure_opts.append("--with-gnomeprint") + + if not options.mac_framework: + if installDir and not prefixDir: + prefixDir = installDir + if prefixDir: + configure_opts.append("--prefix=" + prefixDir) + + if options.wxpython: + configure_opts.extend(wxpy_configure_opts) + if options.debug: + # wxPython likes adding these debug options too + configure_opts.append("--enable-debug_gdb") + configure_opts.append("--disable-optimise") + + if options.rebake: + retval = os.system("make -f autogen.mk") + exitIfError(retval, "Error running autogen.mk") + + if options.mac_framework: + # Framework build is always a universal binary + options.mac_lipo = True + name = "wx" + if options.osx_cocoa: + name += "OSXCocoa" + installDir = "/Library/Frameworks/%s.framework/Versions/%s" % (name, getWxRelease()) + configure_opts.append("--prefix=" + installDir) + # framework builds always need to be monolithic + if not "--enable-monolithic" in configure_opts: + configure_opts.append("--enable-monolithic") + + print "Configure options: " + `configure_opts` + wxBuilder = builder.AutoconfBuilder() + if not options.no_config and not options.clean and not options.mac_lipo: + olddir = os.getcwd() + if buildDir: + os.chdir(buildDir) + exitIfError(wxBuilder.configure(dir=wxRootDir, options=configure_opts), + "Error running configure") + os.chdir(olddir) + + elif toolkit in ["msvc", "msvcProject"]: + flags = {} + buildDir = os.path.abspath(os.path.join(scriptDir, "..", "msw")) + + if options.unicode: + flags["wxUSE_UNICODE"] = "1" + if VERSION < (2,9): + flags["wxUSE_UNICODE_MSLU"] = "1" + + if options.cairo: + flags["wxUSE_CAIRO"] = "1" + + if options.wxpython: + flags["wxDIALOG_UNIT_COMPATIBILITY "] = "0" + flags["wxUSE_DEBUG_CONTEXT"] = "1" + flags["wxUSE_MEMORY_TRACING"] = "1" + flags["wxUSE_DIALUP_MANAGER"] = "0" + flags["wxUSE_GLCANVAS"] = "1" + flags["wxUSE_POSTSCRIPT"] = "1" + flags["wxUSE_AFM_FOR_POSTSCRIPT"] = "0" + flags["wxUSE_DISPLAY"] = "1" + flags["wxUSE_DEBUGREPORT"] = "0" + flags["wxUSE_GRAPHICS_CONTEXT"] = "1" + flags["wxUSE_DATEPICKCTRL_GENERIC"] = "1" + if VERSION < (2,9): + flags["wxUSE_DIB_FOR_BITMAP"] = "1" + + if VERSION >= (2,9): + flags["wxUSE_UIACTIONSIMULATOR"] = "1" + + # setup the wxPython 'hybrid' build + if not options.debug: + flags["wxUSE_MEMORY_TRACING"] = "0" + flags["wxUSE_DEBUG_CONTEXT"] = "0" + + mswIncludeDir = os.path.join(wxRootDir, "include", "wx", "msw") + setup0File = os.path.join(mswIncludeDir, "setup0.h") + setupText = open(setup0File, "rb").read() + + for flag in flags: + setupText, subsMade = re.subn(flag + "\s+?\d", "%s %s" % (flag, flags[flag]), setupText) + if subsMade == 0: + print "Flag %s wasn't found in setup0.h!" % flag + sys.exit(1) + + setupFile = open(os.path.join(mswIncludeDir, "setup.h"), "wb") + setupFile.write(setupText) + setupFile.close() + args = [] + if toolkit == "msvc": + print "setting build options..." + args.append("-f makefile.vc") + if options.unicode: + args.append("UNICODE=1") + if VERSION < (2,9): + args.append("MSLU=1") + + if options.wxpython: + args.append("OFFICIAL_BUILD=1") + args.append("SHARED=1") + args.append("MONOLITHIC=0") + args.append("USE_OPENGL=1") + args.append("USE_GDIPLUS=1") + args.append("CXXFLAGS=/D__NO_VC_CRTDBG__") + + if not options.debug: + # "Hybrid" build, not really release or debug + args.append("DEBUG_FLAG=1") + args.append("WXDEBUGFLAG=h") + args.append("BUILD=release") + else: + args.append("BUILD=debug") + + wxBuilder = builder.MSVCBuilder() + + if toolkit == "msvcProject": + args = [] + if options.shared or options.wxpython: + args.append("wx_dll.dsw") + else: + args.append("wx.dsw") + + # TODO: + wxBuilder = builder.MSVCProjectBuilder() + + if not wxBuilder: + print "Builder not available for your specified platform/compiler." + sys.exit(1) + + if options.clean: + print "Performing cleanup." + wxBuilder.clean() + + if options.wxpython: + exitIfError(wxBuilder.clean(os.path.join(contribDir, "gizmos")), "Error building gizmos") + exitIfError(wxBuilder.clean(os.path.join(contribDir, "stc")), "Error building stc") + + sys.exit(0) + + isLipo = False + if options.mac_lipo: + if options.mac_universal_binary: + print "WARNING: Cannot specify both mac_lipo and mac_universal_binary, as they conflict." + print " Using mac_universal_binary..." + else: + isLipo = True + # TODO: Add 64-bit when we're building OS X Cocoa + + # 2.8, use gcc 3.3 on PPC for 10.3 support, but only when building ... + macVersion = platform.mac_ver()[0] + isLeopard = macVersion.find("10.5") != -1 + + if not isLeopard and os.path.exists(os.path.join(wxRootDir, contribDir)): + # Building wx 2.8 so make the ppc build compatible with Panther + doMacLipoBuild("ppc", buildDir, installDir, cxxcompiler="g++-3.3", cccompiler="gcc-3.3", + target="10.3", flags="-DMAC_OS_X_VERSION_MAX_ALLOWED=1040") + else: + doMacLipoBuild("ppc", buildDir, installDir) + + doMacLipoBuild("i386", buildDir, installDir) + + # Use lipo to merge together all binaries in the install dirs, and it + # also copies all other files and links it finds to the new destination. + result = os.system("python %s/distrib/scripts/mac/lipo-dir.py %s %s %s" % + (wxRootDir, installDir+"/ppc", installDir+"/i386", installDir)) + + # tweak the wx-config script + fname = os.path.abspath(installDir + '/bin/wx-config') + data = open(fname).read() + data = data.replace('ppc/', '') + data = data.replace('i386/', '') + open(fname, 'w').write(data) + + shutil.rmtree(installDir + "/ppc") + shutil.rmtree(installDir + "/i386") + + + + if not isLipo: + if options.extra_make: + args.append(options.extra_make) + exitIfError(wxBuilder.build(dir=buildDir, options=args), "Error building") + + if options.wxpython and os.path.exists(contribDir): + exitIfError(wxBuilder.build(os.path.join(contribDir, "gizmos"), options=args), "Error building gizmos") + exitIfError(wxBuilder.build(os.path.join(contribDir, "stc"),options=args), "Error building stc") + + if options.install: + extra=None + if installDir: + extra = ['DESTDIR='+installDir] + wxBuilder.install(options=extra) + + if options.wxpython and os.path.exists(contribDir): + exitIfError(wxBuilder.install(os.path.join(contribDir, "gizmos"), options=extra), "Error building gizmos") + exitIfError(wxBuilder.install(os.path.join(contribDir, "stc"), options=extra), "Error building stc") + + if options.mac_framework: + + def renameLibrary(libname, frameworkname): + reallib = libname + links = [] + while os.path.islink(reallib): + links.append(reallib) + reallib = "lib/" + os.readlink(reallib) + + print "reallib is %s" % reallib + os.system("mv -f %s lib/%s.dylib" % (reallib, frameworkname)) + + for link in links: + os.system("ln -s -f %s.dylib %s" % (frameworkname, link)) + + os.chdir(installDir) + build_string = "" + if options.debug: + build_string = "d" + version = commands.getoutput("bin/wx-config --release") + basename = commands.getoutput("bin/wx-config --basename") + configname = commands.getoutput("bin/wx-config --selected-config") + + os.system("ln -s -f bin Resources") + + # we make wx the "actual" library file and link to it from libwhatever.dylib + # so that things can link to wx and survive minor version changes + renameLibrary("lib/lib%s-%s.dylib" % (basename, version), "wx") + os.system("ln -s -f lib/wx.dylib wx") + + os.system("ln -s -f include/wx Headers") + + for lib in ["GL", "STC", "Gizmos", "Gizmos_xrc"]: + libfile = "lib/lib%s_%s-%s.dylib" % (basename, lib.lower(), version) + if os.path.exists(libfile): + frameworkDir = "framework/wx%s/%s" % (lib, version) + if not os.path.exists(frameworkDir): + os.makedirs(frameworkDir) + renameLibrary(libfile, "wx" + lib) + os.system("ln -s -f ../../../%s %s/wx%s" % (libfile, frameworkDir, lib)) + + for lib in glob.glob("lib/*.dylib"): + if not os.path.islink(lib): + corelibname = "lib/lib%s-%s.0.dylib" % (basename, version) + os.system("install_name_tool -id %s %s" % (os.path.join(installDir, lib), lib)) + os.system("install_name_tool -change %s %s %s" % (os.path.join(installDir, "i386", corelibname), os.path.join(installDir, corelibname), lib)) + + os.chdir("include") + + header_template = """ + +#ifndef __WX_FRAMEWORK_HEADER__ +#define __WX_FRAMEWORK_HEADER__ + +%s + +#endif // __WX_FRAMEWORK_HEADER__ +""" + headers = "" + header_dir = "wx-%s/wx" % version + for include in glob.glob(header_dir + "/*.h"): + headers += "wx/" + os.path.basename(include) + "\n" + + framework_header = open("wx.h", "w") + framework_header.write(header_template % headers) + framework_header.close() + + os.system("ln -s -f %s wx" % header_dir) + os.system("ln -s -f ../../../lib/wx/include/%s/wx/setup.h wx/setup.h" % configname) + + os.chdir(os.path.join(installDir, "..", "..")) + os.system("ln -s -f %s Versions/Current" % os.path.basename(installDir)) + os.system("ln -s -f Versions/Current/Headers Headers") + os.system("ln -s -f Versions/Current/Resources Resources") + os.system("ln -s -f Versions/Current/wx wx") + + + # adjust the install_name if needed TODO: skip this for framework builds? + if sys.platform.startswith("darwin") and \ + options.install and \ + options.installdir and \ + not options.wxpython: # wxPython's build will do this later if needed + prefix = options.prefix + if not prefix: + prefix = '/usr/local' + macFixupInstallNames(options.installdir, prefix) + + + +if __name__ == '__main__': + exitWithException = False # use sys.exit instead + main(sys.argv[0], sys.argv[1:]) + diff --git a/build/tools/builder.py b/build/tools/builder.py new file mode 100755 index 0000000000..7c067ae8a8 --- /dev/null +++ b/build/tools/builder.py @@ -0,0 +1,235 @@ +import os +import string +import subprocess +import sys +import time + +class BuildError(Exception): + def __init__(self, value): + self.value = value + + def __repr__(self): + return repr(self.value) + +def runInDir(command, dir=None, verbose=True): + if dir: + olddir = os.getcwd() + os.chdir(dir) + + commandStr = " ".join(command) + if verbose: + print commandStr + result = os.system(commandStr) + + if dir: + os.chdir(olddir) + + return result + +class Builder: + """ + Base class exposing the Builder interface. + """ + + def __init__(self, formatName="", commandName="", programDir=None): + """ + formatName = human readable name for project format (should correspond with Bakefile names) + commandName = name of command line program used to invoke builder + programDir = directory program is located in, if not on the path + """ + + self.dir = dir + self.name = commandName + self.formatName = formatName + self.programDir = programDir + self.doSetup() + + def doSetup(self): + """ + Do anything special needed to configure the environment to build with this builder. + """ + + pass + + def isAvailable(self): + """ + Run sanity checks before attempting to build with this format + """ + # Make sure the builder program exists + programPath = self.getProgramPath() + if os.path.exists(programPath): + return True + else: + # check the PATH for the program + # TODO: How do we check if we're in Cygwin? + if sys.platform.startswith("win"): + result = os.system(self.name) + if result == 0: + return True + dirs = os.environ["PATH"].split(":") + + for dir in dirs: + if os.path.isfile(os.path.join(dir, self.name)): + return True + + else: + result = os.system("which %s" % self.name) + + if result == 0: + return True + + return False + + def getProgramPath(self): + if self.programDir: + path = os.path.join(self.programDir, self.name) + if sys.platform.startswith("win"): + path = '"%s"' % path + return path + + return self.name + + def clean(self, dir=None, projectFile=None): + """ + dir = the directory containing the project file + projectFile = Some formats need to explicitly specify the project file's name + """ + + args = [self.getProgramPath(), "clean"] + if dir: + args.append(dir) + if self.isAvailable(): + result = runInDir(args) + return result + + return False + + def configure(self, options=None): + # if we don't have configure, just report success + return True + + def build(self, dir=None, projectFile=None, targets=None, options=None): + if self.isAvailable(): + if options: + optionList = list(options) + else: + optionList = [] + + optionList.insert(0, self.getProgramPath()) + + result = runInDir(optionList, dir) + + return result + + return 1 + + def install(self, dir=None, options=None): + if self.isAvailable(): + + args = ["make", "install"] + if options: + args.extend(options) + result = runInDir(args, dir) + return result + + return 1 + +# Concrete subclasses of abstract Builder interface + +class GNUMakeBuilder(Builder): + def __init__(self, commandName="make", formatName="GNUMake"): + Builder.__init__(self, commandName=commandName, formatName=formatName) + + +class XCodeBuilder(Builder): + def __init__(self, commandName="xcodebuild", formatName="XCode"): + Builder.__init__(self, commandName=commandName, formatName=formatName) + + +class AutoconfBuilder(GNUMakeBuilder): + def __init__(self, formatName="autoconf"): + GNUMakeBuilder.__init__(self, formatName=formatName) + + def configure(self, dir=None, options=None): + #olddir = os.getcwd() + #os.chdir(dir) + + configdir = dir + if not dir: + configdir = os.getcwd() + + configure_cmd = "" + while os.path.exists(configdir): + config_cmd = os.path.join(configdir, "configure") + if not os.path.exists(config_cmd): + parentdir = os.path.abspath(os.path.join(configdir, "..")) + if configdir == parentdir: + break + + configdir = parentdir + else: + configure_cmd = config_cmd + break + + if not configure_cmd: + sys.stderr.write("Could not find configure script at %r. Have you run autoconf?\n" % dir) + return 1 + + optionsStr = string.join(options, " ") if options else "" + command = "%s %s" % (configure_cmd, optionsStr) + print command + result = os.system(command) + #os.chdir(olddir) + return result + + +class MSVCBuilder(Builder): + def __init__(self): + Builder.__init__(self, commandName="nmake.exe", formatName="msvc") + + def isAvailable(self): + PATH = os.environ['PATH'].split(os.path.pathsep) + for p in PATH: + if os.path.exists(os.path.join(p, self.name)): + return True + return False + + +class MSVCProjectBuilder(Builder): + def __init__(self): + Builder.__init__(self, commandName="VCExpress.exe", formatName="msvcProject") + for key in ["VS90COMNTOOLS", "VC80COMNTOOLS", "VC71COMNTOOLS"]: + if os.environ.has_key(key): + self.prgoramDir = os.path.join(os.environ[key], "..", "IDE") + + if self.programDir == None: + for version in ["9.0", "8", ".NET 2003"]: + msvcDir = "C:\\Program Files\\Microsoft Visual Studio %s\\Common7\\IDE" % version + if os.path.exists(msvcDir): + self.programDir = msvcDir + + def isAvailable(self): + if self.programDir: + path = os.path.join(self.programDir, self.name) + if os.path.exists(path): + return True + else: + # I don't have commercial versions of MSVC so I can't test this + name = "devenv.com" + path = os.path.join(self.programDir, name) + if os.path.exists(path): + self.name = "devenv.com" + return True + + return False + +builders = [GNUMakeBuilder, XCodeBuilder, AutoconfBuilder, MSVCBuilder, MSVCProjectBuilder] + +def getAvailableBuilders(): + availableBuilders = {} + for symbol in builders: + thisBuilder = symbol() + if thisBuilder.isAvailable(): + availableBuilders[thisBuilder.formatName] = symbol + + return availableBuilders diff --git a/build/tools/create-archive.py b/build/tools/create-archive.py new file mode 100755 index 0000000000..750018e2e8 --- /dev/null +++ b/build/tools/create-archive.py @@ -0,0 +1,239 @@ +#!/usr/bin/env python + +import glob +import optparse +import os +import platform +import re +import shutil +import string +import sys +import tempfile +import types +import pdb + +## CONSTANTS + +scriptDir = os.path.join(sys.path[0]) +rootDir = os.path.abspath(os.path.join(scriptDir, "..", "..")) +contribDir = os.path.join("contrib", "src") + +dirsToCopy = ["art", "build", "debian", "demos", "distrib/mac", "docs", "include", "interface", "lib", + "locale", "samples", "src", "tests", "utils"] + +dirsToIgnore = [".svn", "CVS"] +excludeExtensions = [".rej", ".orig", ".mine", ".tmp"] + +option_dict = { + "compression" : ("gzip", "Compression to use. Values are: gzip, bzip, zip, all (default: gzip)"), + "docs" : ("html", "Doc formats to build. Comma separated. Values are: none, html (default: html)"), + "name" : ("wxWidgets", "Name given to the tarball created (default: wxWidgets)"), + "postfix" : ("", "String appended to the version to indicate a special release (default: none)"), + "wxpython" : (False, "Produce wxPython source tarball (name defaults to wxPython-src)") + } + +mswProjectFiles = [ ".vcproj", ".sln", ".dsp", ".dsw", ".vc", ".bat"] +nativeLineEndingFiles = [".cpp", ".h", ".c", ".txt"] + + + +## PARSE OPTIONS + +usage="""usage: %prog [options] \n +Create a wxWidgets archive and store it in . +The output directory must be an absolute, existing path. +Type %prog --help for options. +""" + +parser = optparse.OptionParser(usage, version="%prog 1.0") + +for opt in option_dict: + default = option_dict[opt][0] + + action = "store" + if type(default) == types.BooleanType: + action = "store_true" + parser.add_option("--" + opt, default=default, action=action, dest=opt, help=option_dict[opt][1]) + +options, arguments = parser.parse_args() + +if len(arguments) < 1 or not os.path.exists(arguments[0]) or not os.path.isabs(arguments[0]): + parser.print_usage() + sys.exit(1) + +destDir = arguments[0] +if not os.path.exists(destDir): + os.makedirs(destDir) + +wxVersion = None +VERSION_FILE = os.path.join(rootDir, 'include/wx/version.h') + + +## HELPER FUNCTIONS + +def makeDOSLineEndings(dir, extensions): + fileList = [] + for root, subFolders, files in os.walk(dir): + for file in files: + if os.path.splitext(file)[1] in extensions: + os.system("unix2dos %s" % os.path.join(root, file)) + +def getVersion(includeSubrelease=False): + """Returns wxWidgets version as a tuple: (major,minor,release).""" + + wxVersion = None + major = None + minor = None + release = None + subrelease = None + if wxVersion == None: + f = open(VERSION_FILE, 'rt') + lines = f.readlines() + f.close() + major = minor = release = None + for l in lines: + if not l.startswith('#define'): continue + splitline = l.strip().split() + if splitline[0] != '#define': continue + if len(splitline) < 3: continue + name = splitline[1] + value = splitline[2] + if value == None: continue + if name == 'wxMAJOR_VERSION': major = int(value) + if name == 'wxMINOR_VERSION': minor = int(value) + if name == 'wxRELEASE_NUMBER': release = int(value) + if name == 'wxSUBRELEASE_NUMBER': subrelease = int(value) + if major != None and minor != None and release != None: + if not includeSubrelease or subrelease != None: + break + + if includeSubrelease: + wxVersion = (major, minor, release, subrelease) + else: + wxVersion = (major, minor, release) + return wxVersion + +def allFilesRecursive(dir): + fileList = [] + for root, subFolders, files in os.walk(dir): + shouldCopy = True + for ignoreDir in dirsToIgnore: + if ignoreDir in root: + shouldCopy = False + + if shouldCopy: + for file in files: + path = os.path.join(root,file) + for exclude in excludeExtensions: + if not os.path.splitext(file)[1] in excludeExtensions: + fileList.append(os.path.join(root,file)) + return fileList + + +## MAKE THE RELEASE! + +str_version = "" ##"%d.%d.%d" % getVersion() +archive_name = options.name + +if options.wxpython: + dirsToCopy.append("wxPython") + archive_name = "wxPython-src" +## str_version = "%d.%d.%d.%d" % getVersion(includeSubrelease=True) + options.docs = "none" + +if options.postfix != "": + str_version += "-" + options.postfix + +full_name = archive_name ## + "-" + str_version + +copyDir = tempfile.mkdtemp() +wxCopyDir = os.path.join(copyDir, full_name) + +os.makedirs(wxCopyDir) + +os.chdir(rootDir) +fileList = [] +rootFiles = glob.glob("*") +for afile in rootFiles: + if os.path.isfile(os.path.abspath(afile)): + fileList.append(afile) + +for dir in dirsToCopy: + print "Determining files to copy from %s..." % dir + fileList.extend(allFilesRecursive(dir)) + +print "Copying files to the temporary folder %s..." % copyDir +for afile in fileList: + destFile = os.path.join(wxCopyDir, afile) + dirName = os.path.dirname(destFile) + if not os.path.exists(dirName): + os.makedirs(dirName) + shutil.copy(os.path.join(rootDir, afile), destFile) + +# copy include/wx/msw/setup0.h -> include/wx/msw/setup.h +mswSetup0 = os.path.join(wxCopyDir, "include","wx","msw","setup0.h") +shutil.copy(mswSetup0, mswSetup0.replace("setup0.h", "setup.h")), + +all = options.compression == "all" + +# make sure they have the DOS line endings everywhere +##print "Setting MSW Project files to use DOS line endings..." +##makeDOSLineEndings(wxCopyDir, mswProjectFiles) + +if all or options.compression == "gzip": + print "Creating gzip archive..." + os.chdir(copyDir) + os.system("tar -czvf %s/%s.tar.gz %s" % (destDir, full_name, "*")) + os.chdir(rootDir) + +if all or options.compression == "bzip": + print "Creating bzip archive..." + os.chdir(copyDir) + os.system("tar -cjvf %s/%s.tar.bz2 %s" % (destDir, full_name, "*")) + os.chdir(rootDir) + +if all or options.compression == "zip": + os.chdir(copyDir) + print "Setting DOS line endings on source and text files..." + ## makeDOSLineEndings(copyDir, nativeLineEndingFiles) + print "Creating zip archive..." + os.system("zip -9 -r %s/%s.zip %s" % (destDir, full_name, "*")) + os.chdir(rootDir) + +shutil.rmtree(copyDir) + + +# build any docs packages: +doc_formats = string.split(options.docs, ",") +doxy_dir = "docs/doxygen" +output_dir = "out" +if not os.path.exists(output_dir): + os.makedirs(output_dir) + +for format in doc_formats: + if not format == "none": + os.chdir(doxy_dir) + if platform.system() == "Windows": + print "Windows platform" + os.system("regen.bat %s" % format) + else: + os.system("regen.sh %s" % format) + + os.chdir(output_dir) + + if format == "html": + src = format + docs_full_name = "%s-%s" % (full_name, format.upper()) + files_to_zip = "*" + else: + src = "wx.%s" % format + docs_full_name = "%s.%s" % (full_name, format.upper()) + files_to_zip = docs_full_name + + os.rename(src, docs_full_name) + os.system("zip -9 -r %s/%s.zip %s" % (destDir, docs_full_name, files_to_zip)) + os.chdir(rootDir) + +os.chdir(rootDir) +if os.path.exists(output_dir): + shutil.rmtree(output_dir) -- 2.45.2