From pykde Wed Jun 27 16:47:55 2001 From: Thomas Malik Date: Wed, 27 Jun 2001 16:47:55 +0000 To: pykde Subject: [PyKDE] !@#$% ... distutils setup script for PyQt/PyKDE, again X-MARC-Message: https://marc.info/?l=pykde&m=102191945721131 ---------- Forwarded Message ---------- Subject: distutils setup script for Date: Wed, 27 Jun 2001 14:21:18 +0200 From: Thomas Malik Dumb mail server administrators to hell. Ok, here are verbatim copies of the scripts. Watch out for wrong line breaks. Next time i'll use uuencode to send files (oh, those old days ...) I've splitted the setup scripts in two parts, mainly because most of the stuff is the same for PyQt and PyKDE. The configurable options are in the first file, sip_setup.py, which also contains two class defs, extensions to the distutils build_ext Extension classes. Just drop these files into the PyQt/PyKDE source directories, modify the paths in sip_setup.py and run python setup.py build python setup.py install (or python setup.py --help or python setup.py --help-commands, for that matter) Later, i'll modify these so you can set the directories in setup.cfg (not needing to edit a python source file). Sorry that i have to send these as an attached info-zip file, but our email policy doesn't allow me anything else - hopefully these will make it through. BTW, Phil, I've found it useful to have the PyQt version number stored in the PyQt module. For this reason, i've appended char *version; %C++Code char *version="2.4"; %End to qglobal.sip. Would you agree to this ? ### PyQt/sip_setup.py start # common include for PyQt and PyKDE setup scripts # this file is meant to be 'execfile'd (the cheesy way) from distutils.core import setup, Extension from distutils.cmd import Command from distutils.command.build_ext import build_ext from distutils.command.install import install from distutils.ccompiler import new_compiler from distutils.sysconfig import customize_compiler from distutils.util import get_platform from glob import glob import sys, os, commands, string, re, types plat_specifier = ".%s-%s" % (get_platform(), sys.version[0:3]) # configurable stuff starts here x11_incdir='/apps/prod/X11R6.4/include' # could have been taken from $KDEDIR (if there were only one of it ...) # kdedir=os.environ['KDEDIR'] kdedir='/apps/prod/X11R6.4/kde/1.1.2' kde_incdir=os.path.join(kdedir, 'include') kde_libdir=os.path.join(kdedir, 'lib') # could have been taken from $QTDIR (if there were only one of it ...) # qtdir=os.environ['QTDIR'] qtdir='/apps/prod/X11R6.4/qt-1.44' qt_incdir=os.path.join(qtdir, 'include') qt_libdir=os.path.join(qtdir, 'lib') #qt_libdir='/apps/prod/X11R6.4/lib' sip_incdir='/opt/tools/include/sip' sip_libdir='/opt/tools/lib' # link statically (because of multiple versions in different directories) extra_objects=[os.path.join(sip_libdir, 'libsip.a')] # where libstdc++.so lives (without this, gcc link will bomb out) stdcpp_libdir='/apps/prod/lib' # build dir for PyQt (only needed for linking the PyKDE shared module with the PyQt shared module) # !!! please check !!! pyqt_builddir = os.path.join(pyqt_srcdir, 'build', 'lib' + plat_specifier) # used as argument to sip processor sip_include_dirs=['sip', os.path.join(pyqt_srcdir, 'sip')] def find_program_in_path(program): if os.name == 'posix': for dir in string.split(os.environ['PATH'], os.pathsep): if os.access(os.path.join(dir, program), os.X_OK): return os.path.join(dir, program) elif os.name == 'nt': (base, ext) = os.path.splitext(string.lower(program)) if ext != '.exe': program = program + '.exe' for dir in string.split(os.environ['PATH'], os.pathsep): # no idea if existence is sufficient on NT, but should be in most cases. if os.path.exists(os.path.join(dir, program)): return os.path.join(dir, program) class sip_build_ext(build_ext): description = "build C/C++ extensions with sources created from sip files (compile/link to build directory)" user_options = build_ext.user_options + \ [('install-platlib=', None, "installation directory for non-pure module distributions" " (needed to link against other shared python modules)"), ('sip-only', None, "only rebuild sources from sip specifications"), ## currently not used. All other configuration options should be included as well, so you can put them into setup.cfg. ## ('sip-program=', None, "full path of sip program (default: 'sip' as found in $PATH)"), ## ('sip-incdir', None, "where the sip include files have been installed (default: dirname(sip)/../include/sip"), ## ('sip-libdir', None, "where the sip library has been installed (default: dirname(sip)/../lib"), ('compile', 'c', "compile .py to .pyc"), ('no-compile', None, "don't compile .py files [default]"), ('optimize=', 'O', "also compile with optimization: -O1 for \"python -O\", " "-O2 for \"python -OO\", and -O0 to disable [default: -O0]"), ('force', 'f', "forcibly build everything (ignore file timestamps)"), ] boolean_options=build_ext.boolean_options + ['sip-only', 'compile', 'force'] negative_opt = {'no-compile' : 'compile'} command_name = 'build_ext' def initialize_options(self): self.install_platlib=None self.sip_only=0 ## self.sip_program=None ## self.sip_incdir=None ## self.sip_libdir=None self.compile = 1 self.optimize = 0 build_ext.initialize_options(self) def finalize_options(self): build_ext.finalize_options(self) self.set_undefined_options('install', ('install_platlib', 'install_platlib')) if not self.install_platlib: raise RuntimeError('install_platlib not defined') ## if not self.sip_program: ## self.sip_program = find_program_in_path('sip') ## self.announce( 'sip_program = %s' % self.sip_program) ## if not self.sip_incdir: ## self.sip_incdir = os.path.abspath(os.path.join(os.path.abspath(self.sip_program), '..', 'include', 'sip')) ## self.announce( 'sip_incdir = %s' % self.sip_incdir) ## if not self.sip_libdir: ## self.sip_libdir = os.path.abspath(os.path.join(os.path.abspath(self.sip_program), '..', 'lib', 'sip')) ## self.announce( 'sip_libdir = %s' % self.sip_libdir) if not isinstance(self.optimize, types.IntType): try: self.optimize = int(self.optimize) assert 0 <= self.optimize <= 2 except (ValueError, AssertionError): raise DistutilsOptionError, "optimize must be 0, 1, or 2" def rebuild_src(self, extension): build = self.get_finalized_command('build') name = extension.pkgname # call sip with appropriate arguments includes = [] for dir in extension.sip_include_dirs: includes.append('-I') includes.append(dir) cmd = ['sip'] + includes + ['-c', name, extension.sipfile] self.spawn(cmd) # build & run sip_helper. compiler = new_compiler(compiler=self.compiler, verbose=self.verbose, dry_run=self.dry_run, force=self.force) customize_compiler(compiler) compiler.set_include_dirs(extension.include_dirs) compiler.set_library_dirs(extension.library_dirs) compiler.set_runtime_library_dirs(extension.runtime_library_dirs) objects = compiler.compile(extension.sip_helper_srcs) compiler.link_executable(objects, extension.sip_helper, libraries =['stdc++']) sipVersion = commands.getoutput(extension.sip_helper) # write sip_helper output if it really changes the version file contents (can make builds quicker) old_sipVersion = '' try: old_sipVersion = open(extension.sipVersion_h).read() except: pass if sipVersion != old_sipVersion: open(extension.sipVersion_h,'w').write(sipVersion) self.announce('sip_helper output %s written' % extension.sipVersion_h) else: self.announce('sip_helper output %s did not change, not written' % extension.sipVersion_h) # not really needed. No idea what it was originally meant for in distutils. ## def get_outputs(self): ## print 'sip_build_ext.get_outputs' ## outputs = build_ext.get_outputs() ## for ext in self.extensions: ## if isinstance(ext, SipExtension): ## fullname = self.get_ext_fullname(ext.name) ## outputs.append(os.path.join(self.build_lib, ext.sip_modfile)) ## print 'outputs =', outputs ## return outputs def build_py_module (self, file): from distutils.util import byte_compile prefix = self.build_lib if prefix[-1] != os.sep: prefix = prefix + os.sep self.copy_file(file, self.build_lib) pyfile = os.path.join(self.build_lib, os.path.basename(file)) if self.compile: byte_compile([pyfile], optimize=0, force=self.force, prefix=prefix, verbose=self.verbose, dry_run=self.dry_run) if self.optimize > 0: byte_compile([pyfile], optimize=self.optimize, force=self.force, prefix=prefix, verbose=self.verbose, dry_run=self.dry_run) def run(self): for ext in self.extensions: if isinstance(ext, SipExtension): ## self.make_file([ext.sipfile] + ext.sipdepend, ext.init_file, self.rebuild_src, (ext,)) # build python module from sip sources self.make_file([ext.sipfile] + ext.sipdepend, ext.sip_modfile, self.rebuild_src, (ext,)) # extend the library_dirs and runtime_library_dirs to include the directories of %Imported modules also. for module in ext.sipdepend_modules: print 'library_dirs(1) =', ext.library_dirs ext.libraries = [module + 'c'] + ext.libraries # this is for the alternative package structure (qt package as subdir with __init__.py) print 'self.build_lib =', self.build_lib libdir = os.path.join(self.build_lib, module) # this is for the 'normal' way building PyQt libdir = self.build_lib if os.path.exists(libdir) and not libdir in ext.library_dirs: # use this mad way of appending because the original lists may be the same python objects ext.library_dirs = ext.library_dirs + [libdir] # append rt_libdir = os.path.join(self.install_platlib, module) if not rt_libdir in ext.runtime_library_dirs: ext.runtime_library_dirs = ext.runtime_library_dirs + [rt_libdir] print 'library_dirs =', ext.library_dirs print 'runtime_library_dirs =', ext.runtime_library_dirs ## print ext.sources if self.sip_only: return 1 build_ext.run(self) for ext in self.extensions: if isinstance(ext, SipExtension): self.build_py_module(ext.sip_modfile) class SipExtension(Extension): # list of sections to ignore in sip input files skipSections=['Copying', 'Doc', 'ExportedDoc', 'Makefile'] # 'C++Code', 'CanConvertToClassCode', 'ConvertFromClassCode', # 'ConvertToClassCode', 'ConvertToSubClassCode', # return the list of directly %Included and the list of directly or # indirectly %Imported sip modules as a 2-tuple def get_depend(self, sipfile): print 'get_depend:', sipfile sipdepend = [] sipdepend_modules = [] skiplines = 0 for line in open(sipfile, 'r').readlines(): if skiplines: if re.match(r'^%End', line): skiplines = 0 else: for s in self.skipSections: if re.match(r'^%' + s, line): skiplines = 1 else: m = re.match(r'^%Include (.*\.sip)', line) if m: include_file = m.group(1) for incldir in ['.'] + self.sip_include_dirs: if os.path.exists(os.path.join(incldir, include_file)): sipdepend.append(os.path.join(incldir, include_file)) break else: raise Exception(include_file + ' not found') m = re.match(r'^%Import (.*\.sip)', line) if m: include_file = m.group(1) for incldir in ['.'] + self.sip_include_dirs: if os.path.exists(os.path.join(incldir, include_file)): sipdepend.append(os.path.join(incldir, include_file)) break else: raise Exception(include_file + ' not found') (depmod, ext) = os.path.splitext(include_file) sipdepend_modules.append(depmod) (more_includes, add_depend) = self.get_depend(os.path.join(incldir, include_file)) ## print 'add_depend:', add_depend sipdepend_modules.extend(add_depend) return (sipdepend, sipdepend_modules) # scan each sipfile for class declarations through a simple regular # expression. The skipSections are ignored in the sip files. def get_classes(self, sipfiles): classes = {} # such that each class is inserted once only for sipfile in sipfiles: skiplines=0 for line in open(sipfile, 'r').readlines(): if skiplines: if re.match(r'^%End', line): skiplines = 0 else: for s in self.skipSections: if re.match(r'^%' + s, line): skiplines = 1 else: m = re.match(r'^class *(\w+)', line) if m: ## print sipfile, m.group(0), m.group(1) classes[m.group(1)]=sipfile classes = classes.keys() classes.sort() return classes def __init__(self, name, sip_include_dirs=['sip'], **kwargs): self.pkgname = name # different from extension name (which is the name of the # shared library) extname = 'lib%sc' % name self.sipfile = os.path.join('sip', name + '.sip') self.sipdepend = [] self.sipdepend_modules = [] classes = {} self.sip_include_dirs=sip_include_dirs self.sip_modfile = os.path.join(name, name + '.py') ## self.init_file = os.path.join(name, '__init__.py') self.sip_helper = os.path.join(name, 'sip_helper') self.sip_helper_srcs = [os.path.join(name, 'sip_helper.cpp')] self.sipVersion_h = os.path.join(name, 'sip%sVersion.h' % name) (self.sipdepend, self.sipdepend_modules) = self.get_depend(self.sipfile) self.classes = self.get_classes(self.sipdepend) ## print self.classes sources = map(lambda c, pkgname=self.pkgname: os.path.join(pkgname, 'sip%s%s.cpp' % (pkgname, c)), self.classes) sources.sort() sources.append(os.path.join(name, name + 'cmodule.cpp')) # now call the base class constructor with the sources we've found apply(Extension.__init__, (self, extname, sources), kwargs) self.include_dirs.append(os.path.join(os.getcwd(), name)) print 'library_dirs(0) =', self.library_dirs ### PyQt/sip_setup.py end ### PyQt/setup.py start #!/usr/bin/env python """ Setup script for the PyKDE module distribution. Check sip_setup.py in the PyQt source directory for qt/kde/sip installation directories and other configurable stuff. """ __revision__ = "$Id: setup.py,v 1.1.1.1 2001/03/08 16:25:33 cvsuser Exp $" import os # where the PyQt sources are installed (../PyQt-2.4 assumed) pyqt_srcdir = os.path.abspath(os.path.join(os.getcwd(), '..', 'PyQt-2.4')) execfile(os.path.join(pyqt_srcdir, 'sip_setup.py'), globals(), locals()) # common include directories for all modules include_dirs = [qt_incdir, x11_incdir, sip_incdir] # common link library search directories for all modules library_dirs = [stdcpp_libdir, qt_libdir] # common runtime library search directories for all modules runtime_library_dirs = [stdcpp_libdir, qt_libdir] setup (# Distribution meta-data name = "PyQt", version = "2.4", description = "python qt binding", author = "phil thompson", author_email = "", url = "", cmdclass = { 'build_ext': sip_build_ext, 'sip_build_ext': sip_build_ext}, ext_modules = [ SipExtension('qt', sip_include_dirs=sip_include_dirs, include_dirs=include_dirs, library_dirs=library_dirs, libraries=['qt', 'stdc++'], extra_objects=extra_objects, runtime_library_dirs=runtime_library_dirs ), ] ) ### PyQt/setup.py end ### PyKDEsetup.py start #!/usr/bin/env python """ Setup script for the PyKDE module distribution. Check sip_setup.py in the PyQt source directory for qt/kde/sip installation directories and other configurable stuff. """ __revision__ = "$Id: template_setup.py,v 1.1.1.1 2001/03/08 16:25:33 cvsuser Exp $" import os # where the PyQt sources are installed (../PyQt-2.4 assumed) pyqt_srcdir = os.path.abspath(os.path.join(os.getcwd(), '..', 'PyQt-2.4')) execfile(os.path.join(pyqt_srcdir, 'sip_setup.py'), globals(), locals()) # common include directories for all modules include_dirs = [qt_incdir, kde_incdir, x11_incdir, sip_incdir] # common link library search directories for all modules library_dirs = [stdcpp_libdir, qt_libdir, kde_libdir, pyqt_builddir] # common runtime library search directories for all modules (libqtc's directory will be added automatically) runtime_library_dirs = [stdcpp_libdir, qt_libdir, kde_libdir] setup (# Distribution meta-data name = "PyKDE", version = "2.4", description = "python kde binding", author = "phil thompson", author_email = "", url = "", cmdclass = { 'build_ext': sip_build_ext, 'sip_build_ext': sip_build_ext}, ext_modules = [ SipExtension('kdecore', sip_include_dirs=sip_include_dirs, include_dirs=include_dirs, library_dirs=library_dirs, libraries=['kdecore', 'qt', 'stdc++'], extra_objects=extra_objects, runtime_library_dirs=runtime_library_dirs ), SipExtension('kdeui', sip_include_dirs=sip_include_dirs, include_dirs=include_dirs, library_dirs=library_dirs, libraries=['kdeui', 'kdecore', 'qt', 'stdc++'], extra_objects=extra_objects, runtime_library_dirs=runtime_library_dirs ), SipExtension('kfm', sip_include_dirs=sip_include_dirs, include_dirs=include_dirs, library_dirs=library_dirs, libraries=['kdecore', 'kfm', 'qt', 'stdc++'], extra_objects=extra_objects, runtime_library_dirs=runtime_library_dirs ), SipExtension('kfile', sip_include_dirs=sip_include_dirs, include_dirs=include_dirs, library_dirs=library_dirs, libraries=['kdeui', 'kdecore', 'kfile', 'qt', 'stdc++'], extra_objects=extra_objects, runtime_library_dirs=runtime_library_dirs ), SipExtension('khtmlw', sip_include_dirs=sip_include_dirs, include_dirs=include_dirs, library_dirs=library_dirs, libraries=['khtmlw', 'kdeui', 'kimgio', 'kdecore', 'jscript', 'qt', 'stdc++'], extra_objects=extra_objects, runtime_library_dirs=runtime_library_dirs ), SipExtension('kspell', sip_include_dirs=sip_include_dirs, include_dirs=include_dirs, library_dirs=library_dirs, libraries=['kdecore', 'kspell', 'qt', 'stdc++'], extra_objects=extra_objects, runtime_library_dirs=runtime_library_dirs ), ] ) ### PyKDE/setup.py end -- Thomas Malik Landesbank Baden-Wuerttemberg (Stuttgart, Germany) Abt. 2340 Tel. (+49 711) 124-7049 Thomas_Malik%lgbank@lbbw.de ------------------------------------------------------- -- Thomas Malik Landesbank Baden-Wuerttemberg (Stuttgart, Germany) Abt. 2340 Tel. (+49 711) 124-7049 Thomas_Malik%lgbank@lbbw.de ______________________________________________________________________ -------------------------------------------------------------------------------------------- Bitte beachten Sie, dass der Inhalt dieser E-Mail einschließlich eventuell angehängter Dokumente vertraulich ist. Falls Sie nicht der angegebene Empfänger sind oder falls diese E-Mail irrtümlich an Sie adressiert wurde, dürfen Sie die E-Mail und eventuell angehängte Dokumente weder öffnen, lesen, kopieren, verbreiten noch ihren Inhalt in irgendeiner Weise nutzen. Bitte verständigen Sie den Absender sofort und löschen Sie Die E-Mail sodann. Die Sicherheit von Übermittlungen per E-Mail kann nicht garantiert werden. Per E-Mail übermittelte Informationen können abgefangen oder geändert werden, verloren gehen oder zerstört werden, verspätet oder unvollständig ankommen, oder Viren enthalten. Der Absender übernimmt daher keine Gewähr für Irrtümer oder Auslassungen jeder Art im Inhalt sowie sonstige Risiken, die auf die Übermittlung per E-Mail zurückzuführen sind. Falls Sie eine Bestätigung wünschen, fordern Sie bitte den Inhalt der E-Mail als Hardcopy an. This e-mail and any attached files are confidential. If you are not the named addressee or if this transmission has been addressed to you in error, any disclosure, reproduction, copying, distrubtion, or other dissemination or use of this communication is prohibited. If you have received this transmission in error please notify the sender immediately and then delete this e-mail. E-mail transmission cannot be guaranteed to be secure or free from error as information could be intercepted, corrupted, lost, destroyed, arrive late or incomplete, or contain viruses. The sender therefore does not accept liability for any errors or omissions in the contents of this message or any other of such risks which arise as a result of e-mail transmission. If verification is required, please request a hard copy version. ---------------------------------------------------------------------------------------------