diff --git a/siputils.py.orig b/siputils.py.orig deleted file mode 100644 index f4add21..0000000 --- a/siputils.py.orig +++ /dev/null @@ -1,2528 +0,0 @@ -# This module is intended to be used by the build/installation scripts of -# extension modules created with SIP. It provides information about file -# locations, version numbers etc., and provides some classes and functions. -# -# Copyright (c) 2010 Riverbank Computing Limited -# -# This file is part of SIP. -# -# This copy of SIP is licensed for use under the terms of the SIP License -# Agreement. See the file LICENSE for more details. -# -# This copy of SIP may also used under the terms of the GNU General Public -# License v2 or v3 as published by the Free Software Foundation which can be -# found in the files LICENSE-GPL2 and LICENSE-GPL3 included in this package. -# -# SIP is supplied WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - - -import sys -import os -import stat -import string -import re - - -# These are installation specific values created when SIP was configured. -# @SIP_CONFIGURATION@ - -# The stack of configuration dictionaries. -_config_stack = [] - - -class Configuration(object): - """The class that represents SIP configuration values. - """ - def __init__(self, sub_cfg=None): - """Initialise an instance of the class. - - sub_cfg is the list of sub-class configurations. It should be None - when called normally. - """ - # Find the build macros in the closest imported module from where this - # was originally defined. - self._macros = None - - for cls in self.__class__.__mro__: - if cls is object: - continue - - mod = sys.modules[cls.__module__] - - if hasattr(mod, "_default_macros"): - self._macros = mod._default_macros - break - - if sub_cfg: - cfg = sub_cfg - else: - cfg = [] - - cfg.append(_pkg_config) - - global _config_stack - _config_stack = cfg - - def __getattr__(self, name): - """Allow configuration values and user options to be handled as - instance variables. - - name is the name of the configuration value or user option. - """ - for cfg in _config_stack: - try: - return cfg[name] - except KeyError: - pass - - raise AttributeError("\"%s\" is not a valid configuration value or user option" % name) - - def build_macros(self): - """Return the dictionary of platform specific build macros. - """ - return self._macros - - def set_build_macros(self, macros): - """Set the dictionary of build macros to be use when generating - Makefiles. - - macros is the dictionary of platform specific build macros. - """ - self._macros = macros - - -class _UniqueList: - """A limited list that ensures all its elements are unique. - """ - def __init__(self, value=None): - """Initialise the instance. - - value is the initial value of the list. - """ - if value is None: - self._list = [] - else: - self._list = value - - def append(self, value): - """Append a value to the list if it isn't already present. - - value is the value to append. - """ - if value not in self._list: - self._list.append(value) - - def lextend(self, value): - """A normal list extend ignoring the uniqueness. - - value is the list of elements to append. - """ - self._list.extend(value) - - def extend(self, value): - """Append each element of a value to a list if it isn't already - present. - - value is the list of elements to append. - """ - for el in value: - self.append(el) - - def as_list(self): - """Return the list as a raw list. - """ - return self._list - - -class _Macro: - """A macro that can be manipulated as a list. - """ - def __init__(self, name, value): - """Initialise the instance. - - name is the name of the macro. - value is the initial value of the macro. - """ - self._name = name - self.set(value) - - def set(self, value): - """Explicitly set the value of the macro. - - value is the new value. It may be a string, a list of strings or a - _UniqueList instance. - """ - self._macro = [] - - if isinstance(value, _UniqueList): - value = value.as_list() - - if type(value) == list: - self.extend(value) - else: - self.append(value) - - def append(self, value): - """Append a value to the macro. - - value is the value to append. - """ - if value: - self._macro.append(value) - - def extend(self, value): - """Append each element of a value to the macro. - - value is the list of elements to append. - """ - for el in value: - self.append(el) - - def remove(self, value): - """Remove a value from the macro. It doesn't matter if the value - wasn't present. - - value is the value to remove. - """ - try: - self._macro.remove(value) - except: - pass - - def as_list(self): - """Return the macro as a list. - """ - return self._macro - - -class Makefile: - """The base class for the different types of Makefiles. - """ - def __init__(self, configuration, console=0, qt=0, opengl=0, python=0, - threaded=0, warnings=1, debug=0, dir=None, - makefile="Makefile", installs=None, universal=None, - arch=None): - """Initialise an instance of the target. All the macros are left - unchanged allowing scripts to manipulate them at will. - - configuration is the current configuration. - console is set if the target is a console (rather than windows) target. - qt is set if the target uses Qt. For Qt v4 a list of Qt libraries may - be specified and a simple non-zero value implies QtCore and QtGui. - opengl is set if the target uses OpenGL. - python is set if the target #includes Python.h. - debug is set to generated a debugging version of the target. - threaded is set if the target requires thread support. It is - automatically set if the target uses Qt and Qt has thread support - enabled. - warnings is set if compiler warning messages are required. - debug is set if debugging symbols should be generated. - dir is the directory for build files and Makefiles. - makefile is the name of the Makefile. - installs is a list of extra install targets. Each element is a two - part list, the first of which is the source and the second is the - destination. If the source is another list then it is a set of source - files and the destination is a directory. - universal is the name of the SDK if the target is a MacOS/X universal - binary. If it is None then the value is taken from the configuration. - arch is the space separated MacOS/X architectures to build. If it is - None then it is taken from the configuration. - """ - if qt: - if not hasattr(configuration, "qt_version"): - error("The target uses Qt but pyqtconfig has not been imported.") - - # For Qt v4 interpret Qt support as meaning link against the core - # and GUI libraries (which corresponds to the default qmake - # configuration). Also allow a list of Qt v4 modules to be - # specified. - if configuration.qt_version >= 0x040000: - if type(qt) != list: - qt = ["QtCore", "QtGui"] - - self._threaded = configuration.qt_threaded - else: - self._threaded = threaded - - self.config = configuration - self.console = console - self._qt = qt - self._opengl = opengl - self._python = python - self._warnings = warnings - self._debug = debug - self._makefile = makefile - self._installs = installs - - # Make sure the destination directory is an absolute path. - if dir: - self.dir = os.path.abspath(dir) - else: - self.dir = os.path.curdir - - # Assume we are building in the source tree. - self._src_dir = self.dir - - if universal is None: - self._universal = configuration.universal - else: - self._universal = universal - - if arch is None: - self._arch = configuration.arch - else: - self._arch = arch - - self._finalised = 0 - - # Copy the macros and convert them all to instance lists. - macros = configuration.build_macros() - - for m in list(macros.keys()): - # Allow the user to override the default. - try: - val = getattr(configuration, m) - except AttributeError: - val = macros[m] - - # These require special handling as they are (potentially) a set of - # space separated values rather than a single value that might - # contain spaces. - if m in ("DEFINES", "CONFIG") or m[:6] in ("INCDIR", "LIBDIR"): - val = val.split() - - # We also want to treat lists of libraries in the same way so that - # duplicates get eliminated. - if m[:4] == "LIBS": - val = val.split() - - self.__dict__[m] = _Macro(m, val) - - # This is used to alter the configuration more significantly than can - # be done with just configuration files. - self.generator = self.optional_string("MAKEFILE_GENERATOR", "UNIX") - - # These are what configuration scripts normally only need to change. - self.extra_cflags = [] - self.extra_cxxflags = [] - self.extra_defines = [] - self.extra_include_dirs = [] - self.extra_lflags = [] - self.extra_lib_dirs = [] - self.extra_libs = [] - - # Get these once and make them available to sub-classes. - if sys.platform == "win32": - def_copy = "copy" - def_rm = "del" - def_mkdir = "mkdir" - def_chk_dir_exists = "if not exist" - else: - def_copy = "cp -f" - def_rm = "rm -f" - def_mkdir = "mkdir -p" - def_chk_dir_exists = "test -d" - - self.copy = self.optional_string("COPY", def_copy) - self.rm = self.optional_string("DEL_FILE", def_rm) - self.mkdir = self.optional_string("MKDIR", def_mkdir) - self.chkdir = self.optional_string("CHK_DIR_EXISTS", def_chk_dir_exists) - - - def finalise(self): - """Finalise the macros by doing any consolidation that isn't specific - to a Makefile. - """ - # Extract the things we might need from the Windows Qt configuration. - # Note that we used to think that if Qt was built with exceptions, RTTI - # and STL support enabled then anything that linked against it also - # needed the same flags. However, detecting this was broken for some - # time and nobody complained. For the moment we'll leave the code in - # but it will never be used. - if self._qt: - wcfg = self.config.qt_winconfig.split() - win_shared = ("shared" in wcfg) - win_exceptions = ("exceptions" in wcfg) - win_rtti = ("rtti" in wcfg) - win_stl = ("stl" in wcfg) - else: - win_shared = 1 - win_exceptions = 0 - win_rtti = 0 - win_stl = 0 - - # Get what we are going to transform. - cflags = _UniqueList() - cflags.extend(self.extra_cflags) - cflags.extend(self.optional_list("CFLAGS")) - - cxxflags = _UniqueList() - cxxflags.extend(self.extra_cxxflags) - cxxflags.extend(self.optional_list("CXXFLAGS")) - - defines = _UniqueList() - defines.extend(self.extra_defines) - defines.extend(self.optional_list("DEFINES")) - - incdir = _UniqueList(["."]) - incdir.extend(self.extra_include_dirs) - incdir.extend(self.optional_list("INCDIR")) - - lflags = _UniqueList() - lflags.extend(self.extra_lflags) - lflags.extend(self.optional_list("LFLAGS")) - - libdir = _UniqueList() - libdir.extend(self.extra_lib_dirs) - libdir.extend(self.optional_list("LIBDIR")) - - # Handle MacOS/X specific configuration. - if sys.platform == 'darwin': - mac_cflags = [] - mac_lflags = [] - - for a in self._arch.split(): - aflag = '-arch ' + a - mac_cflags.append(aflag) - mac_lflags.append(aflag) - - if self._universal: - mac_cflags.append('-isysroot %s' % self._universal) - mac_lflags.append('-Wl,-syslibroot,%s' % self._universal) - - cflags.lextend(mac_cflags) - cxxflags.lextend(mac_cflags) - lflags.lextend(mac_lflags) - - # Don't use a unique list as libraries may need to be searched more - # than once. Also MacOS/X uses the form "-framework lib" so we don't - # want to lose the multiple "-framework". - libs = [] - - for l in self.extra_libs: - libs.append(self.platform_lib(l)) - - if self._qt: - libs.extend(self._dependent_libs(l)) - - libs.extend(self.optional_list("LIBS")) - - rpaths = _UniqueList() - - for l in self.extra_lib_dirs: - # Ignore relative directories. This is really a hack to handle - # SIP v3 inter-module linking. - if os.path.dirname(l) not in ("", ".", ".."): - rpaths.append(l) - - if self._python: - incdir.append(self.config.py_inc_dir) - incdir.append(self.config.py_conf_inc_dir) - - if sys.platform == "cygwin": - libdir.append(self.config.py_lib_dir) - - py_lib = "python%u.%u" % ((self.config.py_version >> 16), ((self.config.py_version >> 8) & 0xff)) - libs.append(self.platform_lib(py_lib)) - elif sys.platform == "win32": - libdir.append(self.config.py_lib_dir) - - py_lib = "python%u%u" % ((self.config.py_version >> 16), ((self.config.py_version >> 8) & 0xff)) - - # For Borland use the OMF version of the Python library if it - # exists, otherwise assume that Python was built with Borland - # and use the normal library. - if self.generator == "BMAKE": - bpy_lib = py_lib + "_bcpp" - bpy_lib_path = os.path.join(self.config.py_lib_dir, self.platform_lib(bpy_lib)) - - if os.access(bpy_lib_path, os.F_OK): - py_lib = bpy_lib - - if self._debug: - py_lib = py_lib + "_d" - - if self.generator != "MINGW": - cflags.append("/D_DEBUG") - cxxflags.append("/D_DEBUG") - - libs.append(self.platform_lib(py_lib)) - - if self.generator in ("MSVC", "MSVC.NET", "BMAKE"): - if win_exceptions: - cflags_exceptions = "CFLAGS_EXCEPTIONS_ON" - cxxflags_exceptions = "CXXFLAGS_EXCEPTIONS_ON" - else: - cflags_exceptions = "CFLAGS_EXCEPTIONS_OFF" - cxxflags_exceptions = "CXXFLAGS_EXCEPTIONS_OFF" - - cflags.extend(self.optional_list(cflags_exceptions)) - cxxflags.extend(self.optional_list(cxxflags_exceptions)) - - if win_rtti: - cflags_rtti = "CFLAGS_RTTI_ON" - cxxflags_rtti = "CXXFLAGS_RTTI_ON" - else: - cflags_rtti = "CFLAGS_RTTI_OFF" - cxxflags_rtti = "CXXFLAGS_RTTI_OFF" - - cflags.extend(self.optional_list(cflags_rtti)) - cxxflags.extend(self.optional_list(cxxflags_rtti)) - - if win_stl: - cflags_stl = "CFLAGS_STL_ON" - cxxflags_stl = "CXXFLAGS_STL_ON" - else: - cflags_stl = "CFLAGS_STL_OFF" - cxxflags_stl = "CXXFLAGS_STL_OFF" - - cflags.extend(self.optional_list(cflags_stl)) - cxxflags.extend(self.optional_list(cxxflags_stl)) - - if self._debug: - if win_shared: - cflags_mt = "CFLAGS_MT_DLLDBG" - cxxflags_mt = "CXXFLAGS_MT_DLLDBG" - else: - cflags_mt = "CFLAGS_MT_DBG" - cxxflags_mt = "CXXFLAGS_MT_DBG" - - cflags_debug = "CFLAGS_DEBUG" - cxxflags_debug = "CXXFLAGS_DEBUG" - lflags_debug = "LFLAGS_DEBUG" - else: - if win_shared: - cflags_mt = "CFLAGS_MT_DLL" - cxxflags_mt = "CXXFLAGS_MT_DLL" - else: - cflags_mt = "CFLAGS_MT" - cxxflags_mt = "CXXFLAGS_MT" - - cflags_debug = "CFLAGS_RELEASE" - cxxflags_debug = "CXXFLAGS_RELEASE" - lflags_debug = "LFLAGS_RELEASE" - - if self.generator in ("MSVC", "MSVC.NET", "BMAKE"): - if self._threaded: - cflags.extend(self.optional_list(cflags_mt)) - cxxflags.extend(self.optional_list(cxxflags_mt)) - - if self.console: - cflags.extend(self.optional_list("CFLAGS_CONSOLE")) - cxxflags.extend(self.optional_list("CXXFLAGS_CONSOLE")) - - cflags.extend(self.optional_list(cflags_debug)) - cxxflags.extend(self.optional_list(cxxflags_debug)) - lflags.extend(self.optional_list(lflags_debug)) - - if self._warnings: - cflags_warn = "CFLAGS_WARN_ON" - cxxflags_warn = "CXXFLAGS_WARN_ON" - else: - cflags_warn = "CFLAGS_WARN_OFF" - cxxflags_warn = "CXXFLAGS_WARN_OFF" - - cflags.extend(self.optional_list(cflags_warn)) - cxxflags.extend(self.optional_list(cxxflags_warn)) - - if self._threaded: - cflags.extend(self.optional_list("CFLAGS_THREAD")) - cxxflags.extend(self.optional_list("CXXFLAGS_THREAD")) - lflags.extend(self.optional_list("LFLAGS_THREAD")) - - if self._qt: - if self.generator != "UNIX" and win_shared: - defines.append("QT_DLL") - - if not self._debug: - defines.append("QT_NO_DEBUG") - - if self.config.qt_version >= 0x040000: - for mod in self._qt: - # Note that qmake doesn't define anything for QtHelp. - if mod == "QtCore": - defines.append("QT_CORE_LIB") - elif mod == "QtGui": - defines.append("QT_GUI_LIB") - elif mod == "QtMultimedia": - defines.append("QT_MULTIMEDIA_LIB") - elif mod == "QtNetwork": - defines.append("QT_NETWORK_LIB") - elif mod == "QtOpenGL": - defines.append("QT_OPENGL_LIB") - elif mod == "QtScript": - defines.append("QT_SCRIPT_LIB") - elif mod == "QtScriptTools": - defines.append("QT_SCRIPTTOOLS_LIB") - elif mod == "QtSql": - defines.append("QT_SQL_LIB") - elif mod == "QtTest": - defines.append("QT_TEST_LIB") - elif mod == "QtWebKit": - defines.append("QT_WEBKIT_LIB") - elif mod == "QtXml": - defines.append("QT_XML_LIB") - elif mod == "QtXmlPatterns": - defines.append("QT_XMLPATTERNS_LIB") - elif mod == "phonon": - defines.append("QT_PHONON_LIB") - elif self._threaded: - defines.append("QT_THREAD_SUPPORT") - - # Handle library directories. - libdir_qt = self.optional_list("LIBDIR_QT") - libdir.extend(libdir_qt) - rpaths.extend(libdir_qt) - - if self.config.qt_version >= 0x040000: - # For Windows: the macros that define the dependencies on - # Windows libraries. - wdepmap = { - "QtCore": "LIBS_CORE", - "QtGui": "LIBS_GUI", - "QtNetwork": "LIBS_NETWORK", - "QtOpenGL": "LIBS_OPENGL", - "QtWebKit": "LIBS_WEBKIT" - } - - # For Windows: the dependencies between Qt libraries. - qdepmap = { - "QtAssistant": ("QtNetwork", "QtGui", "QtCore"), - "QtGui": ("QtCore", ), - "QtHelp": ("QtSql", "QtGui", "QtCore"), - "QtMultimedia": ("QtGui", "QtCore"), - "QtNetwork": ("QtCore", ), - "QtOpenGL": ("QtGui", "QtCore"), - "QtScript": ("QtCore", ), - "QtScriptTools": ("QtScript", "QtGui", "QtCore"), - "QtSql": ("QtCore", ), - "QtSvg": ("QtXml", "QtGui", "QtCore"), - "QtTest": ("QtGui", "QtCore"), - "QtWebKit": ("QtNetwork", "QtGui", "QtCore"), - "QtXml": ("QtCore", ), - "QtXmlPatterns": ("QtNetwork", "QtCore"), - "phonon": ("QtGui", "QtCore"), - "QtDesigner": ("QtGui", "QtCore"), - "QAxContainer": ("QtGui", "QtCore") - } - - # The QtSql .prl file doesn't include QtGui as a dependency (at - # least on Linux) so we explcitly set the dependency here for - # everything. - if "QtSql" in self._qt: - if "QtGui" not in self._qt: - self._qt.append("QtGui") - - # With Qt v4.2.0, the QtAssistantClient library is now a shared - # library on UNIX. The QtAssistantClient .prl file doesn't - # include QtGui and QtNetwork as a dependency any longer. This - # seems to be a bug in Qt v4.2.0. We explicitly set the - # dependencies here. - if self.config.qt_version >= 0x040200 and "QtAssistant" in self._qt: - if "QtGui" not in self._qt: - self._qt.append("QtGui") - if "QtNetwork" not in self._qt: - self._qt.append("QtNetwork") - - for mod in self._qt: - lib = self._qt4_module_to_lib(mod) - libs.append(self.platform_lib(lib, self._is_framework(mod))) - - if sys.platform == "win32": - # On Windows the dependent libraries seem to be in - # qmake.conf rather than the .prl file and the - # inter-dependencies between Qt libraries don't seem to - # be anywhere. - deps = _UniqueList() - - if mod in list(wdepmap.keys()): - deps.extend(self.optional_list(wdepmap[mod])) - - if mod in list(qdepmap.keys()): - for qdep in qdepmap[mod]: - # Ignore the dependency if it is explicitly - # linked. - if qdep not in self._qt: - libs.append(self.platform_lib(self._qt4_module_to_lib(qdep))) - - if qdep in list(wdepmap.keys()): - deps.extend(self.optional_list(wdepmap[qdep])) - - libs.extend(deps.as_list()) - else: - libs.extend(self._dependent_libs(lib, self._is_framework(mod))) - else: - # Windows needs the version number appended if Qt is a DLL. - qt_lib = self.config.qt_lib - - if self.generator in ("MSVC", "MSVC.NET", "BMAKE") and win_shared: - qt_lib = qt_lib + version_to_string(self.config.qt_version).replace(".", "") - - if self.config.qt_edition == "non-commercial": - qt_lib = qt_lib + "nc" - - libs.append(self.platform_lib(qt_lib, self.config.qt_framework)) - libs.extend(self._dependent_libs(self.config.qt_lib)) - - # Handle header directories. - try: - specd_base = self.config.qt_data_dir - except AttributeError: - specd_base = self.config.qt_dir - - specd = os.path.join(specd_base, "mkspecs", "default") - - if not os.access(specd, os.F_OK): - specd = os.path.join(specd_base, "mkspecs", self.config.platform) - - incdir.append(specd) - - qtincdir = self.optional_list("INCDIR_QT") - - if qtincdir: - if self.config.qt_version >= 0x040000: - for mod in self._qt: - if mod == "QAxContainer": - incdir.append(os.path.join(qtincdir[0], "ActiveQt")) - elif self._is_framework(mod): - if mod == "QtAssistant" and self.config.qt_version < 0x040202: - mod = "QtAssistantClient" - - incdir.append(os.path.join(libdir_qt[0], mod + ".framework", "Headers")) - else: - incdir.append(os.path.join(qtincdir[0], mod)) - - # This must go after the module include directories. - incdir.extend(qtincdir) - - if self._opengl: - incdir.extend(self.optional_list("INCDIR_OPENGL")) - lflags.extend(self.optional_list("LFLAGS_OPENGL")) - libdir.extend(self.optional_list("LIBDIR_OPENGL")) - libs.extend(self.optional_list("LIBS_OPENGL")) - - if self._qt or self._opengl: - if self.config.qt_version < 0x040000 or self._opengl or "QtGui" in self._qt: - incdir.extend(self.optional_list("INCDIR_X11")) - libdir.extend(self.optional_list("LIBDIR_X11")) - libs.extend(self.optional_list("LIBS_X11")) - - if self._threaded: - libs.extend(self.optional_list("LIBS_THREAD")) - libs.extend(self.optional_list("LIBS_RTMT")) - else: - libs.extend(self.optional_list("LIBS_RT")) - - if self.console: - libs.extend(self.optional_list("LIBS_CONSOLE")) - - libs.extend(self.optional_list("LIBS_WINDOWS")) - - lflags.extend(self._platform_rpaths(rpaths.as_list())) - - # Save the transformed values. - self.CFLAGS.set(cflags) - self.CXXFLAGS.set(cxxflags) - self.DEFINES.set(defines) - self.INCDIR.set(incdir) - self.LFLAGS.set(lflags) - self.LIBDIR.set(libdir) - self.LIBS.set(libs) - - # Don't do it again because it has side effects. - self._finalised = 1 - - def _add_manifest(self, target=None): - """Add the link flags for creating a manifest file. - """ - if target is None: - target = "$(TARGET)" - - self.LFLAGS.append("/MANIFEST") - self.LFLAGS.append("/MANIFESTFILE:%s.manifest" % target) - - def _is_framework(self, mod): - """Return true if the given Qt module is a framework. - """ - return (self.config.qt_framework and (self.config.qt_version >= 0x040200 or mod != "QtAssistant")) - - def _qt4_module_to_lib(self, mname): - """Return the name of the Qt4 library corresponding to a module. - - mname is the name of the module. - """ - if mname == "QtAssistant": - if self.config.qt_version >= 0x040202 and sys.platform == "darwin": - lib = mname - else: - lib = "QtAssistantClient" - else: - lib = mname - - if self._debug: - if sys.platform == "win32": - lib = lib + "d" - elif self.config.qt_version < 0x040200 or sys.platform == "darwin": - lib = lib + "_debug" - - if sys.platform == "win32" and "shared" in self.config.qt_winconfig.split(): - if (mname in ("QtCore", "QtDesigner", "QtGui", "QtHelp", - "QtMultimedia", "QtNetwork", "QtOpenGL", "QtScript", - "QtScriptTools", "QtSql", "QtSvg", "QtTest", - "QtWebKit", "QtXml", "QtXmlPatterns", "phonon") or - (self.config.qt_version >= 0x040200 and mname == "QtAssistant")): - lib = lib + "4" - - return lib - - def optional_list(self, name): - """Return an optional Makefile macro as a list. - - name is the name of the macro. - """ - return self.__dict__[name].as_list() - - def optional_string(self, name, default=""): - """Return an optional Makefile macro as a string. - - name is the name of the macro. - default is the default value - """ - s = ' '.join(self.optional_list(name)) - - if not s: - s = default - - return s - - def required_string(self, name): - """Return a required Makefile macro as a string. - - name is the name of the macro. - """ - s = self.optional_string(name) - - if not s: - raise ValueError("\"%s\" must have a non-empty value" % name) - - return s - - def _platform_rpaths(self, rpaths): - """Return a list of platform specific rpath flags. - - rpaths is the cannonical list of rpaths. - """ - flags = [] - prefix = self.optional_string("RPATH") - - if prefix: - for r in rpaths: - flags.append(_quote(prefix + r)) - - return flags - - def platform_lib(self, clib, framework=0): - """Return a library name in platform specific form. - - clib is the library name in cannonical form. - framework is set of the library is implemented as a MacOS framework. - """ - if self.generator in ("MSVC", "MSVC.NET", "BMAKE"): - plib = clib + ".lib" - elif sys.platform == "darwin" and framework: - plib = "-framework " + clib - else: - plib = "-l" + clib - - return plib - - def _dependent_libs(self, clib, framework=0): - """Return a list of additional libraries (in platform specific form) - that must be linked with a library. - - clib is the library name in cannonical form. - framework is set of the library is implemented as a MacOS framework. - """ - prl_libs = [] - - if self.generator in ("MSVC", "MSVC.NET", "BMAKE"): - prl_name = os.path.join(self.config.qt_lib_dir, clib + ".prl") - elif sys.platform == "darwin" and framework: - prl_name = os.path.join(self.config.qt_lib_dir, clib + ".framework", clib + ".prl") - else: - prl_name = os.path.join(self.config.qt_lib_dir, "lib" + clib + ".prl") - - if os.access(prl_name, os.F_OK): - try: - f = open(prl_name, "r") - except IOError: - error("Unable to open \"%s\"" % prl_name) - - line = f.readline() - while line: - line = line.strip() - if line and line[0] != "#": - eq = line.find("=") - if eq > 0 and line[:eq].strip() == "QMAKE_PRL_LIBS": - prl_libs = line[eq + 1:].split() - break - - line = f.readline() - - f.close() - - return prl_libs - - - def parse_build_file(self, filename): - """ - Parse a build file and return the corresponding dictionary. - - filename is the name of the build file. If it is a dictionary instead - then its contents are validated. - """ - if type(filename) == dict: - bfname = "dictionary" - bdict = filename - else: - if os.path.isabs(filename): - # We appear to be building out of the source tree. - self._src_dir = os.path.dirname(filename) - bfname = filename - else: - bfname = os.path.join(self.dir, filename) - - bdict = {} - - try: - f = open(bfname, "r") - except IOError: - error("Unable to open \"%s\"" % bfname) - - line_nr = 1 - line = f.readline() - - while line: - line = line.strip() - - if line and line[0] != "#": - eq = line.find("=") - - if eq <= 0: - error("\"%s\" line %d: Line must be in the form 'name = value value...'." % (bfname, line_nr)) - - bdict[line[:eq].strip()] = line[eq + 1:].strip() - - line_nr = line_nr + 1 - line = f.readline() - - f.close() - - # Check the compulsory values. - for i in ("target", "sources"): - try: - bdict[i] - except KeyError: - error("\"%s\" is missing from \"%s\"." % (i, bfname)) - - # Get the optional values. - for i in ("headers", "tqmoc_headers"): - try: - bdict[i] - except KeyError: - bdict[i] = "" - - # Generate the list of objects. - if self.generator in ("MSVC", "MSVC.NET", "BMAKE"): - ext = ".obj" - else: - ext = ".o" - - olist = [] - - for f in bdict["sources"].split(): - root, discard = os.path.splitext(f) - olist.append(root + ext) - - for f in bdict["tqmoc_headers"].split(): - if not self._qt: - error("\"%s\" defines \"tqmoc_headers\" for a non-Qt module." % bfname) - - root, discard = os.path.splitext(f) - olist.append("tqmoc_" + root + ext) - - bdict["objects"] = ' '.join(olist) - - return bdict - - def clean_build_file_objects(self, mfile, build): - """Generate the clean target. - - mfile is the file object. - build is the dictionary created from the build file. - """ - mfile.write("\t-%s $(TARGET)\n" % self.rm) - - for f in build["objects"].split(): - mfile.write("\t-%s %s\n" % (self.rm, f)) - - for f in build["tqmoc_headers"].split(): - root, discard = os.path.splitext(f) - mfile.write("\t-%s tqmoc_%s.cpp\n" % (self.rm, root)) - - def ready(self): - """The Makefile is now ready to be used. - """ - if not self._finalised: - self.finalise() - - def generate(self): - """Generate the Makefile. - """ - self.ready() - - # Make sure the destination directory exists. - try: - os.makedirs(self.dir) - except: - pass - - mfname = os.path.join(self.dir, self._makefile) - - try: - mfile = open(mfname, "w") - except IOError: - error("Unable to create \"%s\"" % mfname) - - self.generate_macros_and_rules(mfile) - self.generate_target_default(mfile) - self.generate_target_install(mfile) - - if self._installs: - if type(self._installs) != list: - self._installs = [self._installs] - - for src, dst in self._installs: - self.install_file(mfile, src, dst) - - self.generate_target_clean(mfile) - - mfile.close() - - def generate_macros_and_rules(self, mfile): - """The default implementation of the macros and rules generation. - - mfile is the file object. - """ - mfile.write("CC = %s\n" % self.required_string("CC")) - mfile.write("CXX = %s\n" % self.required_string("CXX")) - mfile.write("LINK = %s\n" % self.required_string("LINK")) - - cppflags = [] - - if not self._debug: - cppflags.append("-DNDEBUG") - - for f in self.optional_list("DEFINES"): - cppflags.append("-D" + f) - - for f in self.optional_list("INCDIR"): - cppflags.append("-I" + _quote(f)) - - libs = [] - - if self.generator in ("MSVC", "MSVC.NET"): - libdir_prefix = "/LIBPATH:" - else: - libdir_prefix = "-L" - - for ld in self.optional_list("LIBDIR"): - if sys.platform == "darwin" and self.config.qt_framework: - fflag = "-F" + _quote(ld) - libs.append(fflag) - cppflags.append(fflag) - - libs.append(libdir_prefix + _quote(ld)) - - libs.extend(self.optional_list("LIBS")) - - mfile.write("CPPFLAGS = %s\n" % ' '.join(cppflags)) - - mfile.write("CFLAGS = %s\n" % self.optional_string("CFLAGS")) - mfile.write("CXXFLAGS = %s\n" % self.optional_string("CXXFLAGS")) - mfile.write("LFLAGS = %s\n" % self.optional_string("LFLAGS")) - - mfile.write("LIBS = %s\n" % ' '.join(libs)) - - if self._qt: - mfile.write("MOC = %s\n" % _quote(self.required_string("MOC"))) - - if self._src_dir != self.dir: - mfile.write("VPATH = %s\n\n" % self._src_dir) - - # These probably don't matter. - if self.generator == "MINGW": - mfile.write(".SUFFIXES: .cpp .cxx .cc .C .c\n\n") - elif self.generator == "UNIX": - mfile.write(".SUFFIXES: .c .o .cpp .cc .cxx .C\n\n") - else: - mfile.write(".SUFFIXES: .c .cpp .cc .cxx .C\n\n") - - if self.generator in ("MSVC", "MSVC.NET"): - mfile.write(""" -{.}.cpp{}.obj:: -\t$(CXX) -c $(CXXFLAGS) $(CPPFLAGS) -Fo @<< -\t$< -<< - -{.}.cc{}.obj:: -\t$(CXX) -c $(CXXFLAGS) $(CPPFLAGS) -Fo @<< -\t$< -<< - -{.}.cxx{}.obj:: -\t$(CXX) -c $(CXXFLAGS) $(CPPFLAGS) -Fo @<< -\t$< -<< - -{.}.C{}.obj:: -\t$(CXX) -c $(CXXFLAGS) $(CPPFLAGS) -Fo @<< -\t$< -<< - -{.}.c{}.obj:: -\t$(CC) -c $(CFLAGS) $(CPPFLAGS) -Fo @<< -\t$< -<< -""") - elif self.generator == "BMAKE": - mfile.write(""" -.cpp.obj: -\t$(CXX) -c $(CXXFLAGS) $(CPPFLAGS) -o$@ $< - -.cc.obj: -\t$(CXX) -c $(CXXFLAGS) $(CPPFLAGS) -o$@ $< - -.cxx.obj: -\t$(CXX) -c $(CXXFLAGS) $(CPPFLAGS) -o$@ $< - -.C.obj: -\t$(CXX) -c $(CXXFLAGS) $(CPPFLAGS) -o$@ $< - -.c.obj: -\t$(CC) -c $(CFLAGS) $(CPPFLAGS) -o$@ $< -""") - else: - mfile.write(""" -.cpp.o: -\t$(CXX) -c $(CXXFLAGS) $(CPPFLAGS) -o $@ $< - -.cc.o: -\t$(CXX) -c $(CXXFLAGS) $(CPPFLAGS) -o $@ $< - -.cxx.o: -\t$(CXX) -c $(CXXFLAGS) $(CPPFLAGS) -o $@ $< - -.C.o: -\t$(CXX) -c $(CXXFLAGS) $(CPPFLAGS) -o $@ $< - -.c.o: -\t$(CC) -c $(CFLAGS) $(CPPFLAGS) -o $@ $< -""") - - def generate_target_default(self, mfile): - """The default implementation of the default target. - - mfile is the file object. - """ - mfile.write("\nall:\n") - - def generate_target_install(self, mfile): - """The default implementation of the install target. - - mfile is the file object. - """ - mfile.write("\ninstall:\n") - - def generate_target_clean(self, mfile): - """The default implementation of the clean target. - - mfile is the file object. - """ - mfile.write("\nclean:\n") - - def install_file(self, mfile, src, dst, strip=0): - """Install one or more files in a directory. - - mfile is the file object. - src is the name of a single file to install, or the list of a number of - files to install. - dst is the name of the destination directory. - strip is set if the files should be stripped after been installed. - """ - # Help package builders. - if self.generator == "UNIX": - dst = "$(DESTDIR)" + dst - - mfile.write("\t@%s %s " % (self.chkdir, _quote(dst))) - - if self.generator == "UNIX": - mfile.write("|| ") - - mfile.write("%s %s\n" % (self.mkdir, _quote(dst))) - - if type(src) != list: - src = [src] - - # Get the strip command if needed. - if strip: - strip_cmd = self.optional_string("STRIP") - - if not strip_cmd: - strip = 0 - - for sf in src: - target = _quote(os.path.join(dst, os.path.basename(sf))) - - mfile.write("\t%s %s %s\n" % (self.copy, _quote(sf), target)) - - if strip: - mfile.write("\t%s %s\n" % (strip_cmd, target)) - - -class ParentMakefile(Makefile): - """The class that represents a parent Makefile. - """ - def __init__(self, configuration, subdirs, dir=None, makefile="Makefile", - installs=None): - """Initialise an instance of a parent Makefile. - - subdirs is the sequence of subdirectories. - """ - Makefile.__init__(self, configuration, dir=dir, makefile=makefile, installs=installs) - - self._subdirs = subdirs - - def generate_macros_and_rules(self, mfile): - """Generate the macros and rules. - - mfile is the file object. - """ - # We don't want them. - pass - - def generate_target_default(self, mfile): - """Generate the default target. - - mfile is the file object. - """ - self._subdir_target(mfile) - - def generate_target_install(self, mfile): - """Generate the install target. - - mfile is the file object. - """ - self._subdir_target(mfile, "install") - - def generate_target_clean(self, mfile): - """Generate the clean target. - - mfile is the file object. - """ - self._subdir_target(mfile, "clean") - - def _subdir_target(self, mfile, target="all"): - """Create a target for a list of sub-directories. - - mfile is the file object. - target is the name of the target. - """ - if target == "all": - tname = "" - else: - tname = " " + target - - mfile.write("\n" + target + ":\n") - - for d in self._subdirs: - if self.generator == "MINGW": - mfile.write("\t@$(MAKE) -C %s%s\n" % (d, tname)) - elif self.generator == "UNIX": - mfile.write("\t@(cd %s; $(MAKE)%s)\n" % (d, tname)) - else: - mfile.write("\tcd %s\n" % d) - mfile.write("\t$(MAKE)%s\n" % tname) - mfile.write("\t@cd ..\n") - - -class PythonModuleMakefile(Makefile): - """The class that represents a Python module Makefile. - """ - def __init__(self, configuration, dstdir, srcdir=None, dir=None, - makefile="Makefile", installs=None): - """Initialise an instance of a parent Makefile. - - dstdir is the name of the directory where the module's Python code will - be installed. - srcdir is the name of the directory (relative to the directory in which - the Makefile will be created) containing the module's Python code. It - defaults to the same directory. - """ - Makefile.__init__(self, configuration, dir=dir, makefile=makefile, installs=installs) - - if not srcdir: - srcdir = "." - - if dir: - self._moddir = os.path.join(dir, srcdir) - else: - self._moddir = srcdir - - self._srcdir = srcdir - self._dstdir = dstdir - - def generate_macros_and_rules(self, mfile): - """Generate the macros and rules. - - mfile is the file object. - """ - # We don't want them. - pass - - def generate_target_install(self, mfile): - """Generate the install target. - - mfile is the file object. - """ - Makefile.generate_target_install(self, mfile) - - for root, dirs, files in os.walk(self._moddir): - # Do not recurse into certain directories. - for skip in (".svn", "CVS"): - if skip in dirs: - dirs.remove(skip) - - tail = root[len(self._moddir):] - flist = [] - - for f in files: - if f == "Makefile": - continue - - if os.path.isfile(os.path.join(root, f)): - flist.append(os.path.join(self._srcdir + tail, f)) - - self.install_file(mfile, flist, self._dstdir + tail) - - -class ModuleMakefile(Makefile): - """The class that represents a Python extension module Makefile - """ - def __init__(self, configuration, build_file, install_dir=None, static=0, - console=0, qt=0, opengl=0, threaded=0, warnings=1, debug=0, - dir=None, makefile="Makefile", installs=None, strip=1, - export_all=0, universal=None, arch=None): - """Initialise an instance of a module Makefile. - - build_file is the file containing the target specific information. If - it is a dictionary instead then its contents are validated. - install_dir is the directory the target will be installed in. - static is set if the module should be built as a static library. - strip is set if the module should be stripped of unneeded symbols when - installed. The default is 1. - export_all is set if all the module's symbols should be exported rather - than just the module's initialisation function. Exporting all symbols - increases the size of the module and slows down module load times but - may avoid problems with modules that use exceptions. The default is 0. - """ - Makefile.__init__(self, configuration, console, qt, opengl, 1, threaded, warnings, debug, dir, makefile, installs, universal, arch) - - self._build = self.parse_build_file(build_file) - self._install_dir = install_dir - self.static = static - - self._manifest = ("embed_manifest_dll" in self.optional_list("CONFIG")) - - # Don't strip or restrict the exports if this is a debug or static - # build. - if debug or static: - self._strip = 0 - self._limit_exports = 0 - else: - self._strip = strip - self._limit_exports = not export_all - - # Save the target name for later. - self._target = self._build["target"] - - # The name of the module entry point is Python version specific. - if self.config.py_version >= 0x030000: - self._entry_point = "PyInit_%s" % self._target - else: - self._entry_point = "init%s" % self._target - - if sys.platform != "win32" and static: - self._target = "lib" + self._target - - if sys.platform == "win32" and debug: - self._target = self._target + "_d" - - def finalise(self): - """Finalise the macros common to all module Makefiles. - """ - if self.console: - lflags_console = "LFLAGS_CONSOLE" - else: - lflags_console = "LFLAGS_WINDOWS" - - if self.static: - self.DEFINES.append("SIP_STATIC_MODULE") - else: - self.CFLAGS.extend(self.optional_list("CFLAGS_SHLIB")) - self.CXXFLAGS.extend(self.optional_list("CXXFLAGS_SHLIB")) - - lflags_dll = self.optional_list("LFLAGS_DLL") - - if lflags_dll: - self.LFLAGS.extend(lflags_dll) - elif self.console: - lflags_console = "LFLAGS_CONSOLE_DLL" - else: - lflags_console = "LFLAGS_WINDOWS_DLL" - - if self._manifest: - self._add_manifest() - - # We use this to explictly create bundles on MacOS. Apple's Python - # can handle extension modules that are bundles or dynamic - # libraries, but python.org versions need bundles (unless built - # with DYNLOADFILE=dynload_shlib.o). - if sys.platform == "darwin": - lflags_plugin = ["-bundle"] - else: - lflags_plugin = self.optional_list("LFLAGS_PLUGIN") - - if not lflags_plugin: - lflags_plugin = self.optional_list("LFLAGS_SHLIB") - - self.LFLAGS.extend(lflags_plugin) - - self.LFLAGS.extend(self.optional_list(lflags_console)) - - if sys.platform == "darwin": - # 'real_prefix' exists if virtualenv is being used. - dl = getattr(sys, 'real_prefix', sys.exec_prefix).split(os.sep) - - if "Python.framework" not in dl: - error("SIP requires Python to be built as a framework") - - self.LFLAGS.append("-undefined dynamic_lookup") - - Makefile.finalise(self) - - if not self.static: - if self.optional_string("AIX_SHLIB"): - # AIX needs a lot of special handling. - if self.required_string('LINK') == 'g++': - # g++ is used for linking. - # For SIP v4 and g++: - # 1.) Import the python symbols - aix_lflags = ['-Wl,-bI:%s/python.exp' % self.config.py_lib_dir] - - if self._limit_exports: - aix_lflags.append('-Wl,-bnoexpall') - aix_lflags.append('-Wl,-bnoentry') - aix_lflags.append('-Wl,-bE:%s.exp' % self._target) - else: - # IBM VisualAge C++ is used for linking. - # For SIP v4 and xlC: - # 1.) Create a shared object - # 2.) Import the python symbols - aix_lflags = ['-qmkshrobj', - '-bI:%s/python.exp' % self.config.py_lib_dir] - - if self._limit_exports: - aix_lflags.append('-bnoexpall') - aix_lflags.append('-bnoentry') - aix_lflags.append('-bE:%s.exp' % self._target) - - self.LFLAGS.extend(aix_lflags) - else: - if self._limit_exports: - if sys.platform[:5] == 'linux': - self.LFLAGS.extend(['-Wl,--version-script=%s.exp' % self._target]) - elif sys.platform[:5] == 'sunos': - if self.required_string('LINK') == 'g++': - self.LFLAGS.extend(['-Wl,-z,noversion', '-Wl,-M,%s.exp' % self._target]) - else: - self.LFLAGS.extend(['-z' 'noversion', '-M', '%s.exp' % self._target]) - elif sys.platform[:5] == 'hp-ux': - self.LFLAGS.extend(['-Wl,+e,%s' % self._entry_point]) - elif sys.platform[:5] == 'irix' and self.required_string('LINK') != 'g++': - # Doesn't work when g++ is used for linking on IRIX. - self.LFLAGS.extend(['-Wl,-exported_symbol,%s' % self._entry_point]) - - # Force the shared linker if there is one. - link_shlib = self.optional_list("LINK_SHLIB") - - if link_shlib: - self.LINK.set(link_shlib) - - # This made an appearence in Qt v4.4rc1 and breaks extension modules so - # remove it. It was removed at my request but some stupid distros may - # have kept it. - self.LFLAGS.remove('-Wl,--no-undefined') - - def module_as_lib(self, mname): - """Return the name of a SIP v3.x module when it is used as a library. - This will raise an exception when used with SIP v4.x modules. - - mname is the name of the module. - """ - raise ValueError("module_as_lib() can only be used with SIP v3.x") - - def generate_macros_and_rules(self, mfile): - """Generate the macros and rules generation. - - mfile is the file object. - """ - if self.static: - if sys.platform == "win32": - ext = "lib" - else: - ext = "a" - else: - if sys.platform == "win32": - ext = "pyd" - elif sys.platform == "darwin": - ext = "so" - elif sys.platform == "cygwin": - ext = "dll" - else: - ext = self.optional_string("EXTENSION_PLUGIN") - if not ext: - ext = self.optional_string("EXTENSION_SHLIB", "so") - - mfile.write("TARGET = %s\n" % (self._target + "." + ext)) - mfile.write("OFILES = %s\n" % self._build["objects"]) - mfile.write("HFILES = %s %s\n" % (self._build["headers"], self._build["tqmoc_headers"])) - mfile.write("\n") - - if self.static: - if self.generator in ("MSVC", "MSVC.NET", "BMAKE"): - mfile.write("LIB = %s\n" % self.required_string("LIB")) - elif self.generator == "MINGW": - mfile.write("AR = %s\n" % self.required_string("LIB")) - self._ranlib = None - else: - mfile.write("AR = %s\n" % self.required_string("AR")) - - self._ranlib = self.optional_string("RANLIB") - - if self._ranlib: - mfile.write("RANLIB = %s\n" % self._ranlib) - - Makefile.generate_macros_and_rules(self, mfile) - - def generate_target_default(self, mfile): - """Generate the default target. - - mfile is the file object. - """ - # Do these first so that it's safe for a sub-class to append additional - # commands to the real target, but make sure the default is correct. - mfile.write("\nall: $(TARGET)\n") - mfile.write("\n$(OFILES): $(HFILES)\n") - - for mf in self._build["tqmoc_headers"].split(): - root, _ = os.path.splitext(mf) - cpp = "tqmoc_" + root + ".cpp" - - if self._src_dir != self.dir: - mf = os.path.join(self._src_dir, mf) - - mfile.write("\n%s: %s\n" % (cpp, mf)) - mfile.write("\t$(MOC) -o %s %s\n" % (cpp, mf)) - - mfile.write("\n$(TARGET): $(OFILES)\n") - - if self.generator in ("MSVC", "MSVC.NET"): - if self.static: - mfile.write("\t$(LIB) /OUT:$(TARGET) @<<\n") - mfile.write("\t $(OFILES)\n") - mfile.write("<<\n") - else: - mfile.write("\t$(LINK) $(LFLAGS) /OUT:$(TARGET) @<<\n") - mfile.write("\t $(OFILES) $(LIBS)\n") - mfile.write("<<\n") - - if self._manifest: - mfile.write("\tmt -nologo -manifest $(TARGET).manifest -outputresource:$(TARGET);2\n") - elif self.generator == "BMAKE": - if self.static: - mfile.write("\t-%s $(TARGET)\n" % (self.rm)) - mfile.write("\t$(LIB) $(TARGET) @&&|\n") - - for of in self._build["objects"].split(): - mfile.write("+%s \\\n" % (of)) - - mfile.write("|\n") - else: - mfile.write("\t$(LINK) @&&|\n") - mfile.write("\t$(LFLAGS) $(OFILES) ,$(TARGET),,$(LIBS),%s\n" % (self._target)) - mfile.write("|\n") - - # Create the .def file that renames the entry point. - defname = os.path.join(self.dir, self._target + ".def") - - try: - dfile = open(defname, "w") - except IOError: - error("Unable to create \"%s\"" % defname) - - dfile.write("EXPORTS\n") - dfile.write("%s=_%s\n" % (self._entry_point, self._entry_point)) - - dfile.close() - - else: - if self.static: - mfile.write("\t-%s $(TARGET)\n" % self.rm) - mfile.write("\t$(AR) $(TARGET) $(OFILES)\n") - - if self._ranlib: - mfile.write("\t$(RANLIB) $(TARGET)\n") - else: - if self._limit_exports: - # Create an export file for AIX, Linux and Solaris. - if sys.platform[:5] == 'linux': - mfile.write("\t@echo '{ global: %s; local: *; };' > %s.exp\n" % (self._entry_point, self._target)) - elif sys.platform[:5] == 'sunos': - mfile.write("\t@echo '{ global: %s; local: *; };' > %s.exp\n" % (self._entry_point, self._target)) - elif sys.platform[:3] == 'aix': - mfile.write("\t@echo '#!' >%s.exp" % self._target) - mfile.write("; \\\n\t echo '%s' >>%s.exp\n" % (self._entry_point, self._target)) - - mfile.write("\t$(LINK) $(LFLAGS) -o $(TARGET) $(OFILES) $(LIBS)\n") - - def generate_target_install(self, mfile): - """Generate the install target. - - mfile is the file object. - """ - if self._install_dir is None: - self._install_dir = self.config.default_mod_dir - - mfile.write("\ninstall: $(TARGET)\n") - self.install_file(mfile, "$(TARGET)", self._install_dir, self._strip) - - def generate_target_clean(self, mfile): - """Generate the clean target. - - mfile is the file object. - """ - mfile.write("\nclean:\n") - self.clean_build_file_objects(mfile, self._build) - - if self._manifest and not self.static: - mfile.write("\t-%s $(TARGET).manifest\n" % self.rm) - - # Remove any export file on AIX, Linux and Solaris. - if self._limit_exports and (sys.platform[:5] == 'linux' or - sys.platform[:5] == 'sunos' or - sys.platform[:3] == 'aix'): - mfile.write("\t-%s %s.exp\n" % (self.rm, self._target)) - - -class SIPModuleMakefile(ModuleMakefile): - """The class that represents a SIP generated module Makefile. - """ - def __init__(self, configuration, build_file, install_dir=None, static=0, - console=0, qt=0, opengl=0, threaded=0, warnings=1, debug=0, - dir=None, makefile="Makefile", installs=None, strip=1, - export_all=0, universal=None, arch=None, prot_is_public=0): - """Initialise an instance of a SIP generated module Makefile. - - prot_is_public is set if "protected" is to be redefined as "public". - If the platform's C++ ABI allows it this can significantly reduce the - size of the generated code. - - For all other arguments see ModuleMakefile. - """ - ModuleMakefile.__init__(self, configuration, build_file, install_dir, - static, console, qt, opengl, threaded, warnings, debug, dir, - makefile, installs, strip, export_all, universal, arch) - - self._prot_is_public = prot_is_public - - def finalise(self): - """Finalise the macros for a SIP generated module Makefile. - """ - if self._prot_is_public: - self.DEFINES.append('SIP_PROTECTED_IS_PUBLIC') - self.DEFINES.append('protected=public') - - self.INCDIR.append(self.config.sip_inc_dir) - - ModuleMakefile.finalise(self) - - -class ProgramMakefile(Makefile): - """The class that represents a program Makefile. - """ - def __init__(self, configuration, build_file=None, install_dir=None, - console=0, qt=0, opengl=0, python=0, threaded=0, warnings=1, - debug=0, dir=None, makefile="Makefile", installs=None, - universal=None, arch=None): - """Initialise an instance of a program Makefile. - - build_file is the file containing the target specific information. If - it is a dictionary instead then its contents are validated. - install_dir is the directory the target will be installed in. - """ - Makefile.__init__(self, configuration, console, qt, opengl, python, threaded, warnings, debug, dir, makefile, installs, universal, arch) - - self._install_dir = install_dir - - self._manifest = ("embed_manifest_exe" in self.optional_list("CONFIG")) - self._target = None - - if build_file: - self._build = self.parse_build_file(build_file) - else: - self._build = None - - def build_command(self, source): - """Create a command line that will build an executable. Returns a - tuple of the name of the executable and the command line. - - source is the name of the source file. - """ - # The name of the executable. - self._target, _ = os.path.splitext(source) - - if sys.platform in ("win32", "cygwin"): - exe = self._target + ".exe" - else: - exe = self._target - - self.ready() - - # The command line. - build = [] - - build.append(self.required_string("CXX")) - - for a in self._arch.split(): - build.append('-arch ' + a) - - for f in self.optional_list("DEFINES"): - build.append("-D" + f) - - for f in self.optional_list("INCDIR"): - build.append("-I" + _quote(f)) - - build.extend(self.optional_list("CXXFLAGS")) - - # Borland requires all flags to precede all file names. - if self.generator != "BMAKE": - build.append(source) - - if self.generator in ("MSVC", "MSVC.NET"): - build.append("-Fe") - build.append("/link") - libdir_prefix = "/LIBPATH:" - elif self.generator == "BMAKE": - build.append("-e" + exe) - libdir_prefix = "-L" - else: - build.append("-o") - build.append(exe) - libdir_prefix = "-L" - - for ld in self.optional_list("LIBDIR"): - if sys.platform == "darwin" and self.config.qt_framework: - build.append("-F" + _quote(ld)) - - build.append(libdir_prefix + _quote(ld)) - - lflags = self.optional_list("LFLAGS") - - # This is a huge hack demonstrating my lack of understanding of how the - # Borland compiler works. - if self.generator == "BMAKE": - blflags = [] - - for lf in lflags: - for f in lf.split(): - # Tell the compiler to pass the flags to the linker. - if f[-1] == "-": - f = "-l-" + f[1:-1] - elif f[0] == "-": - f = "-l" + f[1:] - - # Remove any explicit object files otherwise the compiler - # will complain that they can't be found, but they don't - # seem to be needed. - if f[-4:].lower() != ".obj": - blflags.append(f) - - lflags = blflags - - build.extend(lflags) - - build.extend(self.optional_list("LIBS")) - - if self.generator == "BMAKE": - build.append(source) - - return (exe, ' '.join(build)) - - def finalise(self): - """Finalise the macros for a program Makefile. - """ - if self.generator in ("MSVC", "MSVC.NET"): - self.LFLAGS.append("/INCREMENTAL:NO") - - if self._manifest: - self._add_manifest(self._target) - - if self.console: - lflags_console = "LFLAGS_CONSOLE" - else: - lflags_console = "LFLAGS_WINDOWS" - - self.LFLAGS.extend(self.optional_list(lflags_console)) - - Makefile.finalise(self) - - def generate_macros_and_rules(self, mfile): - """Generate the macros and rules generation. - - mfile is the file object. - """ - if not self._build: - raise ValueError("pass a filename as build_file when generating a Makefile") - - target = self._build["target"] - - if sys.platform in ("win32", "cygwin"): - target = target + ".exe" - - mfile.write("TARGET = %s\n" % target) - mfile.write("OFILES = %s\n" % self._build["objects"]) - mfile.write("HFILES = %s\n" % self._build["headers"]) - mfile.write("\n") - - Makefile.generate_macros_and_rules(self, mfile) - - def generate_target_default(self, mfile): - """Generate the default target. - - mfile is the file object. - """ - # Do these first so that it's safe for a sub-class to append additional - # commands to the real target, but make sure the default is correct. - mfile.write("\nall: $(TARGET)\n") - mfile.write("\n$(OFILES): $(HFILES)\n") - - for mf in self._build["tqmoc_headers"].split(): - root, _ = os.path.splitext(mf) - cpp = "tqmoc_" + root + ".cpp" - - if self._src_dir != self.dir: - mf = os.path.join(self._src_dir, mf) - - mfile.write("\n%s: %s\n" % (cpp, mf)) - mfile.write("\t$(MOC) -o %s %s\n" % (cpp, mf)) - - mfile.write("\n$(TARGET): $(OFILES)\n") - - if self.generator in ("MSVC", "MSVC.NET"): - mfile.write("\t$(LINK) $(LFLAGS) /OUT:$(TARGET) @<<\n") - mfile.write("\t $(OFILES) $(LIBS)\n") - mfile.write("<<\n") - elif self.generator == "BMAKE": - mfile.write("\t$(LINK) @&&|\n") - mfile.write("\t$(LFLAGS) $(OFILES) ,$(TARGET),,$(LIBS),,\n") - mfile.write("|\n") - else: - mfile.write("\t$(LINK) $(LFLAGS) -o $(TARGET) $(OFILES) $(LIBS)\n") - - if self._manifest: - mfile.write("\tmt -nologo -manifest $(TARGET).manifest -outputresource:$(TARGET);1\n") - - def generate_target_install(self, mfile): - """Generate the install target. - - mfile is the file object. - """ - if self._install_dir is None: - self._install_dir = self.config.default_bin_dir - - mfile.write("\ninstall: $(TARGET)\n") - self.install_file(mfile, "$(TARGET)", self._install_dir) - - def generate_target_clean(self, mfile): - """Generate the clean target. - - mfile is the file object. - """ - mfile.write("\nclean:\n") - self.clean_build_file_objects(mfile, self._build) - - if self._manifest: - mfile.write("\t-%s $(TARGET).manifest\n" % self.rm) - - -def _quote(s): - """Return a string surrounded by double quotes it if contains a space. - - s is the string. - """ - if s.find(" ") >= 0: - s = '"' + s + '"' - - return s - - -def version_to_string(v): - """Convert a 3 part version number encoded as a hexadecimal value to a - string. - """ - return "%u.%u.%u" % (((v >> 16) & 0xff), ((v >> 8) & 0xff), (v & 0xff)) - - -def read_version(filename, description, numdefine=None, strdefine=None): - """Read the version information for a package from a file. The information - is specified as #defines of a numeric (hexadecimal or decimal) value and/or - a string value. - - filename is the name of the file. - description is the descriptive name of the package. - numdefine is the name of the #define of the numeric version. It is ignored - if it is None. - strdefine is the name of the #define of the string version. It is ignored - if it is None. - - Returns a tuple of the version as a number and as a string. - """ - need_num = numdefine is not None - need_str = strdefine is not None - - vers = None - versstr = None - - f = open(filename) - l = f.readline() - - while l and (need_num or need_str): - wl = l.split() - if len(wl) >= 3 and wl[0] == "#define": - if need_num and wl[1] == numdefine: - v = wl[2] - - if v[0:2] == "0x": - vers = int(v, 16) - else: - dec = int(v) - maj = dec / 100 - min = (dec % 100) / 10 - bug = (dec % 10) - vers = (maj << 16) + (min << 8) + bug - - need_num = 0 - - if need_str and wl[1] == strdefine: - # Take account of embedded spaces. - versstr = ' '.join(wl[2:])[1:-1] - need_str = 0 - - l = f.readline() - - f.close() - - if need_num or need_str: - error("The %s version number could not be determined by parsing %s." % (description, filename)) - - return (vers, versstr) - - -def create_content(cdict, macros=None): - """Convert a dictionary to a string (typically to use as the content to a - call to create_config_module()). Dictionary values that are strings are - quoted. Dictionary values that are lists are converted to quoted strings. - - dict is the dictionary. - macros is the optional dictionary of platform specific build macros. - """ - content = "_pkg_config = {\n" - - keys = list(cdict.keys()) - keys.sort() - - # Format it nicely. - width = 0 - - for k in keys: - klen = len(k) - - if width < klen: - width = klen - - for k in keys: - val = cdict[k] - vtype = type(val) - delim = None - - if val is None: - val = "None" - elif vtype == list: - val = ' '.join(val) - delim = "'" - elif vtype == int: - if k.find("version") >= 0: - # Assume it's a hexadecimal version number. It doesn't matter - # if it isn't, we are just trying to make it look pretty. - val = "0x%06x" % val - else: - val = str(val) - else: - val = str(val) - delim = "'" - - if delim: - if "'" in val: - delim = "'''" - - val = delim + val + delim - - content = content + " '" + k + "':" + (" " * (width - len(k) + 2)) + val.replace("\\", "\\\\") - - if k != keys[-1]: - content = content + "," - - content = content + "\n" - - content = content + "}\n\n" - - # Format the optional macros. - content = content + "_default_macros = " - - if macros: - content = content + "{\n" - - names = list(macros.keys()) - names.sort() - - width = 0 - for c in names: - clen = len(c) - if width < clen: - width = clen - - for c in names: - if c == names[-1]: - sep = "" - else: - sep = "," - - val = macros[c] - if "'" in val: - delim = "'''" - else: - delim = "'" - - k = "'" + c + "':" - content = content + " %-*s %s%s%s%s\n" % (1 + width + 2, k, delim, val.replace("\\", "\\\\"), delim, sep) - - content = content + "}\n" - else: - content = content + "None\n" - - return content - - -def create_config_module(module, template, content, macros=None): - """Create a configuration module by replacing "@" followed by - "SIP_CONFIGURATION" followed by "@" in a template file with a content - string. - - module is the name of the module file. - template is the name of the template file. - content is the content string. If it is a dictionary it is first converted - to a string using create_content(). - macros is an optional dictionary of platform specific build macros. It is - only used if create_content() is called to convert the content to a string. - """ - if type(content) == dict: - content = create_content(content, macros) - - # Allow this file to used as a template. - key = "@" + "SIP_CONFIGURATION" + "@" - - df = open(module, "w") - sf = open(template, "r") - - line = sf.readline() - while line: - if line.find(key) >= 0: - line = content - - df.write(line) - - line = sf.readline() - - -def version_to_sip_tag(version, tags, description): - """Convert a version number to a SIP tag. - - version is the version number. If it is negative then the latest version - is assumed. (This is typically useful if a snapshot is indicated by a - negative version number.) - tags is the dictionary of tags keyed by version number. The tag used is - the one with the smallest key (ie. earliest version) that is greater than - the given version number. - description is the descriptive name of the package used for error messages. - - Returns the corresponding tag. - """ - vl = list(tags.keys()) - vl.sort() - - # For a snapshot use the latest tag. - if version < 0: - tag = tags[vl[-1]] - else: - for v in vl: - if version < v: - tag = tags[v] - break - else: - error("Unsupported %s version: 0x%06x." % (description, version)) - - return tag - - -def error(msg): - """Display an error message and terminate. - - msg is the text of the error message. - """ - sys.stderr.write(format("Error: " + msg) + "\n") - sys.exit(1) - - -def inform(msg): - """Display an information message. - - msg is the text of the error message. - """ - sys.stdout.write(format(msg) + "\n") - - -def format(msg, leftmargin=0, rightmargin=78): - """Format a message by inserting line breaks at appropriate places. - - msg is the text of the message. - leftmargin is the position of the left margin. - rightmargin is the position of the right margin. - - Return the formatted message. - """ - curs = leftmargin - fmsg = " " * leftmargin - - for w in msg.split(): - l = len(w) - if curs != leftmargin and curs + l > rightmargin: - fmsg = fmsg + "\n" + (" " * leftmargin) - curs = leftmargin - - if curs > leftmargin: - fmsg = fmsg + " " - curs = curs + 1 - - fmsg = fmsg + w - curs = curs + l - - return fmsg - - -def parse_build_macros(filename, names, overrides=None, properties=None): - """Parse a qmake compatible file of build system macros and convert it to a - dictionary. A macro is a name/value pair. The dictionary is returned or - None if any of the overrides was invalid. - - filename is the name of the file to parse. - names is a list of the macro names to extract from the file. - overrides is an optional list of macro names and values that modify those - found in the file. They are of the form "name=value" (in which case the - value replaces the value found in the file) or "name+=value" (in which case - the value is appended to the value found in the file). - properties is an optional dictionary of property name and values that are - used to resolve any expressions of the form "$[name]" in the file. - """ - # Validate and convert the overrides to a dictionary. - orides = {} - - if overrides is not None: - for oride in overrides: - prefix = "" - name_end = oride.find("+=") - - if name_end >= 0: - prefix = "+" - val_start = name_end + 2 - else: - name_end = oride.find("=") - - if name_end >= 0: - val_start = name_end + 1 - else: - return None - - name = oride[:name_end] - - if name not in names: - return None - - orides[name] = prefix + oride[val_start:] - - # This class defines a file like object that handles the nested include() - # directives in qmake files. - class qmake_build_file_reader: - def __init__(self, filename): - self.filename = filename - self.currentfile = None - self.filestack = [] - self.pathstack = [] - self.cond_fname = None - self._openfile(filename) - - def _openfile(self, filename): - try: - f = open(filename, 'r') - except IOError: - # If this file is conditional then don't raise an error. - if self.cond_fname == filename: - return - - error("Unable to open %s" % filename) - - if self.currentfile: - self.filestack.append(self.currentfile) - self.pathstack.append(self.path) - - self.currentfile = f - self.path = os.path.dirname(filename) - - def readline(self): - line = self.currentfile.readline() - sline = line.strip() - - if self.cond_fname and sline == '}': - # The current condition is closed. - self.cond_fname = None - line = self.currentfile.readline() - elif sline.startswith('exists(') and sline.endswith('{'): - # A new condition is opened so extract the filename. - self.cond_fname = self._normalise(sline[:-1].strip()[7:-1].strip()) - line = self.currentfile.readline() - elif sline.startswith('include('): - nextfile = self._normalise(sline[8:-1].strip()) - self._openfile(nextfile) - return self.readline() - - if not line and self.filestack: - self.currentfile = self.filestack.pop() - self.path = self.pathstack.pop() - return self.readline() - - return line - - # Normalise a filename by expanding any environment variables and - # making sure it is absolute. - def _normalise(self, fname): - if "$(" in fname: - fname = os.path.normpath(self._expandvars(fname)) - - if not os.path.isabs(fname): - fname = os.path.join(self.path, fname) - - return fname - - # Expand the environment variables in a filename. - def _expandvars(self, fname): - i = 0 - while True: - m = re.search(r'\$\((\w+)\)', fname[i:]) - if not m: - break - - i, j = m.span(0) - name = m.group(1) - if name in os.environ: - tail = fname[j:] - fname = fname[:i] + os.environ[name] - i = len(fname) - fname += tail - else: - i = j - - return fname - - f = qmake_build_file_reader(filename) - - # Get everything into a dictionary. - raw = { - "DIR_SEPARATOR": os.sep, - "LITERAL_WHITESPACE": " ", - "LITERAL_DOLLAR": "$", - "LITERAL_HASH": "#" - } - - line = f.readline() - while line: - # Handle line continuations. - while len(line) > 1 and line[-2] == "\\": - line = line[:-2] - - next = f.readline() - - if next: - line = line + next - else: - break - - line = line.strip() - - # Ignore comments. - if line and line[0] != "#": - assstart = line.find("+") - if assstart > 0 and line[assstart + 1] == '=': - adding = True - assend = assstart + 1 - else: - adding = False - assstart = line.find("=") - assend = assstart - - if assstart > 0: - lhs = line[:assstart].strip() - rhs = line[assend + 1:].strip() - - # Remove the escapes for any quotes. - rhs = rhs.replace(r'\"', '"').replace(r"\'", "'") - - if adding and rhs != "": - orig_rhs = raw.get(lhs) - if orig_rhs is not None: - rhs = orig_rhs + " " + rhs - - raw[lhs] = rhs - - line = f.readline() - - # Go through the raw dictionary extracting the macros we need and - # resolving any macro expansions. First of all, make sure every macro has - # a value. - refined = {} - - for m in names: - refined[m] = "" - - macro_prefix = "QMAKE_" - - for lhs in list(raw.keys()): - # Strip any prefix. - if lhs.find(macro_prefix) == 0: - reflhs = lhs[len(macro_prefix):] - else: - reflhs = lhs - - # See if we are interested in this one. - if reflhs not in names: - continue - - rhs = raw[lhs] - - # Resolve any references. - estart = rhs.find("$$(") - mstart = rhs.find("$$") - - while mstart >= 0 and mstart != estart: - rstart = mstart + 2 - if rstart < len(rhs) and rhs[rstart] == "{": - rstart = rstart + 1 - term = "}" - elif rstart < len(rhs) and rhs[rstart] == "[": - rstart = rstart + 1 - term = "]" - else: - term = string.whitespace - - mend = rstart - while mend < len(rhs) and rhs[mend] not in term: - mend = mend + 1 - - lhs = rhs[rstart:mend] - - if term in "}]": - mend = mend + 1 - - if term == "]": - if properties is None or lhs not in list(properties.keys()): - error("%s: property '%s' is not defined." % (filename, lhs)) - - value = properties[lhs] - else: - try: - value = raw[lhs] - except KeyError: - # We used to treat this as an error, but Qt v4.3.0 has at - # least one case that refers to an undefined macro. If - # qmake handles it then this must be the correct behaviour. - value = "" - - rhs = rhs[:mstart] + value + rhs[mend:] - estart = rhs.find("$$(") - mstart = rhs.find("$$") - - # Expand any POSIX style environment variables. - pleadin = ["$$(", "$("] - - for pl in pleadin: - estart = rhs.find(pl) - - if estart >= 0: - nstart = estart + len(pl) - break - else: - estart = -1 - - while estart >= 0: - eend = rhs[nstart:].find(")") - - if eend < 0: - break - - eend = nstart + eend - - name = rhs[nstart:eend] - - try: - env = os.environ[name] - except KeyError: - env = "" - - rhs = rhs[:estart] + env + rhs[eend + 1:] - - for pl in pleadin: - estart = rhs.find(pl) - - if estart >= 0: - nstart = estart + len(pl) - break - else: - estart = -1 - - # Expand any Windows style environment variables. - estart = rhs.find("%") - - while estart >= 0: - eend = rhs[estart + 1:].find("%") - - if eend < 0: - break - - eend = estart + 1 + eend - - name = rhs[estart + 1:eend] - - try: - env = os.environ[name] - except KeyError: - env = "" - - rhs = rhs[:estart] + env + rhs[eend + 1:] - - estart = rhs.find("%") - - refined[reflhs] = rhs - - # Handle the user overrides. - for lhs in list(orides.keys()): - rhs = refined[lhs] - oride = orides[lhs] - - if oride.find("+") == 0: - if rhs: - rhs = rhs + " " + oride[1:] - else: - rhs = oride[1:] - else: - rhs = oride - - refined[lhs] = rhs - - return refined - - -def create_wrapper(script, wrapper, gui=0, use_arch=''): - """Create a platform dependent executable wrapper around a Python script. - - script is the full pathname of the script. - wrapper is the name of the wrapper file to create. - gui is non-zero if a GUI enabled version of the interpreter should be used. - use_arch is the MacOS/X architecture to invoke python with. - - Returns the platform specific name of the wrapper. - """ - if sys.platform == "win32": - wrapper = wrapper + ".bat" - - wf = open(wrapper, "w") - - if sys.platform == "win32": - exe = sys.executable - - if gui: - exe = exe[:-4] + "w.exe" - - wf.write("@\"%s\" \"%s\" %%1 %%2 %%3 %%4 %%5 %%6 %%7 %%8 %%9\n" % (exe, script)) - elif sys.platform == "darwin": - # The installation of MacOS's python is a mess that changes from - # version to version and where sys.executable is useless. - - if gui: - exe = "pythonw" - else: - exe = "python" - - version = sys.version_info - exe = "%s%d.%d" % (exe, version[0], version[1]) - - if use_arch: - # Note that this may not work with the "standard" interpreter but - # should with the "pythonX.Y" version. - exe = "arch -%s %s" % (use_arch, exe) - - wf.write("#!/bin/sh\n") - wf.write("exec %s %s ${1+\"$@\"}\n" % (exe, script)) - else: - wf.write("#!/bin/sh\n") - wf.write("exec %s %s ${1+\"$@\"}\n" % (sys.executable, script)) - - wf.close() - - if sys.platform != "win32": - sbuf = os.stat(wrapper) - mode = sbuf.st_mode - mode |= (stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH) - - os.chmod(wrapper, mode) - - return wrapper