You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
sip4-tqt/siputils.py.orig

2529 lines
82 KiB

# 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 <info@riverbankcomputing.com>
#
# 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)