[PyKDE] Building SIP with distutils
Giovanni Bajo
rasky at develer.com
Fri Dec 16 17:36:52 GMT 2005
Hello,
I'm working so that people wanting to use SIP as a binding generator do not
have to play with the custom build engine (which is required only by PyQt).
I already contributed sipdistutils.py which lets compile SIP-generated
bindings with distutils.
The next step is to compile SIP itself with distutils, and this is what the
attached setup.py does. It's almost complete:
- It builds and installs SIP correctly. Compared to the custom build system,
the main differences is that the sip executable is put into the python
scripts directory (by default: /usr/bin under Linux, c:\python\scripts
under Windows), and the sip header file is put within the per-package python
include directory (by default: /usr/include/python2.4/sip/sip.h under Linux,
c:\python\include\sip\sip.h under Windows).
- Of course, we now have all the fancy distutils options, so "setup.py
bdist_wininst" will generate "sip-snapshot-20051130.win32-py2.4.exe" as
expected, and "setup.py bdist_rpm" will generate
"sip-snapshot_20051130-1.i386.rpm" and "sip-snapshot_20051130-1.src.rpm",
and they all work correctly:
$ rpm -qpl sip-snapshot_20051130-1.i386.rpm
/usr/bin/sip
/usr/include/python2.4/sip/sip.h
/usr/lib/python2.4/site-packages/sip.so
/usr/lib/python2.4/site-packages/sipdistutils.py
/usr/lib/python2.4/site-packages/sipdistutils.pyc
- I had to work around a couple of issues in distutils, and to add support
for building native scripts (that is, executables). Not too bad though, as
the compiler abstraction class in distutils already had a "link_executable"
method, it's just that it was not hooked up everywhere as needed.
- It's incomplete, as in it still does not generate sipconfig.py, but that's
easy to add. It's the last step though, I wanted to make sure that
everything else is OK.
Phil, I'd appreciate if you (or others) could give this a go and confirm
that it mostly works. I'll add support for generation of sipconfig.py in the
next few days.
--
Giovanni Bajo
-------------- next part --------------
#!/usr/bin/env python
from distutils.core import setup, Extension
from distutils.command.build_ext import build_ext
from distutils.command.build import build
from distutils.command.sdist import sdist
from distutils.command.bdist_rpm import bdist_rpm
from distutils.command.install import install
from distutils.command.install_scripts import install_scripts
from distutils.dist import Distribution
import sys, os
import glob
sip_version = 0x040300
sip_version_str = "snapshot-20051130"
desc = "SIP - Python C/C++ Bindings Generator"
long_desc = """\
SIP is a tool for automatically generating Python bindings for C and C++
libraries. Bindings are fast to load, have minimum memory consumption. SIP
features automatic conversion between standard Python and C/C++ data types,
supports function and methods overloading, allows to derive Python classes
from C++ classes, (re)implementation virtual methods, C++ exceptions (and
their conversion into Python exceptions), explicit ownership semantic of
objects, and full support for the Python cyclic garbage collector."""
class _Distribution(Distribution):
def __init__(self, *args, **kwargs):
self.native_scripts = []
Distribution.__init__(self, *args, **kwargs)
def has_native_scripts(self):
return len(self.native_scripts) > 0
def is_pure(self):
return Distribution.is_pure(self) and not self.has_native_scripts()
# Redefine the build class so that "setup.py build" will also run "build_native_scripts"
class _build(build):
def has_native_scripts(self):
return self.distribution.has_native_scripts()
sub_commands = build.sub_commands + [
('build_native_scripts', has_native_scripts)
]
# Redefine install so that install_scripts will be run even if there are
# native scripts.
class _install(install):
def has_scripts(self):
return install.has_scripts(self) or self.distribution.has_native_scripts()
sub_commands = install.sub_commands[:]
for i, (name, cond) in enumerate(sub_commands):
if name == "install_scripts":
sub_commands[i] = (name, has_scripts)
# Redefine the install_scripts class so that "setup.py build_native_scripts" will
# be automatically run.
class _install_scripts(install_scripts):
def run(self, *args, **kwargs):
if not self.skip_build:
self.run_command('build_native_scripts')
install_scripts.run(self, *args, **kwargs)
# Redefine sdist so that it includes native script source files by default.
# Also add dependencies for both native scripts and extensions (this is
# a distutil missing feature already added to setuptools).
class _sdist(sdist):
def __get_depends(self, b):
deps = []
for e in b.extensions:
if e.depends:
deps.extend(e.depends)
return deps
def add_defaults(self, *args, **kwargs):
sdist.add_defaults(self, *args, **kwargs)
if self.distribution.has_native_scripts():
build_native_scripts = self.get_finalized_command('build_native_scripts')
self.filelist.extend(build_native_scripts.get_source_files())
self.filelist.extend(self.__get_depends(build_native_scripts))
if self.distribution.has_ext_modules():
build_ext = self.get_finalized_command('build_ext')
self.filelist.extend(self.__get_depends(build_ext))
# Redefine bdist_rpm to fix a bug when the version number contains hypens ("-").
# This is a bug in disutils shipped with Python 2.4.2, which I reported to
# the distutils-sig mailing list.
class _bdist_rpm(bdist_rpm):
def run_command(self, cmd, *args, **kwargs):
if cmd == "sdist":
old_version = self.distribution.metadata.version
if self.distribution.metadata.version is not None:
self.distribution.metadata.version = old_version.replace("-", "_")
print self.distribution.get_version()
bdist_rpm.run_command(self, cmd, *args, **kwargs)
self.distribution.metadata.version = old_version
return
bdist_rpm.run_command(self, cmd, *args, **kwargs)
class build_native_scripts(build_ext):
description = "Compile scripts in the form of native executables"
user_options = build_ext.user_options[:]
for i,opt in enumerate(user_options):
if opt[0] == "build-lib=":
del user_options[i]
break
else:
assert 0, "build-lib not found?"
user_options = [
('build-lib=', 'b',
"directory for compiled scripts"),
] + user_options
def finalize_options(self, *args, **kwargs):
self.set_undefined_options('build',
('build_scripts', 'build_lib'))
build_ext.finalize_options(self, *args, **kwargs)
# We must build things marked as native scripts
self.extensions = self.distribution.native_scripts
def build_extension(self, *args, **kwargs):
# piggy-back the executable linking function
def fake_link_shared_object(*args, **kwargs):
del kwargs["export_symbols"]
del kwargs["build_temp"]
return self.compiler.link_executable(*args, **kwargs)
self.compiler.link_shared_object = fake_link_shared_object
build_ext.build_extension(self, *args, **kwargs)
def get_ext_filename(self, *args, **kwargs):
from distutils.sysconfig import get_config_var
fn = build_ext.get_ext_filename(self, *args, **kwargs)
# Remove .pyd, and no need to put an extension, as link_executable
# will automatically take care of it.
return os.path.splitext(fn)[0]
setup(
name = 'sip',
version = sip_version_str,
description = desc,
long_description = long_desc,
author = "Riverbank Computing Ltd.",
author_email = "info at riverbankcomputing.co.uk",
url = "http://www.riverbankcomputing.co.uk/sip/",
download_url = "http://www.riverbankcomputing.co.uk/sip/download.php",
license = "Python (MIT style)",
platforms = "Python 2.3 and later.",
classifiers = [
"Development Status :: 5 - Production/Stable",
"Intended Audience :: Developers",
"License :: OSI Approved :: Python Software Foundation License",
"Operating System :: MacOS :: MacOS X",
"Operating System :: Microsoft :: Windows",
"Operating System :: POSIX",
"Programming Language :: Python",
"Programming Language :: C"
"Programming Language :: C++",
"Topic :: Software Development :: Code Generators",
"Topic :: Software Development :: Libraries :: Python Modules",
],
py_modules=[
"sipdistutils",
],
ext_modules=[
Extension("sip",
glob.glob(os.path.join("siplib", "*.c")) +
glob.glob(os.path.join("siplib", "*.cpp")),
include_dirs=["."],
depends=glob.glob(os.path.join("siplib", "*.h"))),
],
native_scripts=[
Extension("sip",
glob.glob(os.path.join("sipgen", "*.c")) +
glob.glob(os.path.join("sipgen", "*.cpp")),
include_dirs=["."],
depends=glob.glob(os.path.join("sipgen", "*.h"))),
],
headers = [ "sipgen/sip.h" ],
distclass = _Distribution,
cmdclass = {
'build': _build,
'build_native_scripts': build_native_scripts,
'install': _install,
'install_scripts': _install_scripts,
'sdist': _sdist,
'bdist_rpm': _bdist_rpm,
},
)
-------------- next part --------------
A non-text attachment was scrubbed...
Name: MANIFEST.in
Type: application/octet-stream
Size: 194 bytes
Desc: not available
Url : http://www.riverbankcomputing.com/pipermail/pyqt/attachments/20051216/d6be01ff/MANIFEST.obj
More information about the PyQt
mailing list