#!/usr/bin/python ########################################################################### # kdedistutils - description # # ------------------------------ # # begin : Thu Apr 21 2005 # # copyright : (C) 2005 by Simon Edwards # # email : simon@simonzone.com # # # ########################################################################### # # # This program is free software; you can redistribute it and/or modify # # it under the terms of the GNU Library General Public License as # # published by the Free Software Foundation; either version 2 of the # # License, or (at your option) any later version. # # # ########################################################################### import distutils.core from distutils.core import Extension from distutils.cmd import Command from distutils.dist import Distribution from distutils.command.build import build from distutils.command.install import install from distutils.command.install_scripts import install_scripts from distutils.command.install_data import install_data from distutils.command.install_lib import install_lib from distutils.util import change_root, convert_path from distutils.spawn import find_executable,spawn from distutils import sysconfig from distutils import log from distutils import file_util from distutils import dir_util from distutils.util import byte_compile import qtuicompiler import stat import os,os.path,imp,glob import sys from types import StringType INSTALL_LIST = 'install_log.txt' ########################################################################### def setup(**arg_dict): if 'cmdclass' not in arg_dict: arg_dict['cmdclass'] = {} cmdclass = arg_dict['cmdclass'] arg_dict.setdefault('data_files',[]) kdecmdclass = {'install' : InstallKDE, 'install_executable_links' : InstallExecutableLinks, 'install_application_data' : InstallApplicationDataAndLinks, 'build_messages' : BuildI18NMessages, 'install_messages' : InstallI18NMessages, 'update_messages' : UpdateI18NMessages, 'checkpyqt' : CheckPyQt, 'checkpykde' : CheckPyKDE, 'uninstall' : Uninstall, 'build' : BuildKDE, 'build_kcm' : BuildKControlModule, 'install_kcm' : InstallKControlModule, 'build_html' : BuildDocbookHTML, 'install_html' : InstallDocbookHTML, 'install_lib' : InstallLibWithRoot, 'build_kioslave' : BuildKioslave, 'install_kioslave' : InstallKioslave} for key in kdecmdclass.iterkeys(): cmdclass.setdefault(key,kdecmdclass[key]) arg_dict.setdefault('distclass',KDEDistribution) apply(distutils.core.setup,[],arg_dict) ########################################################################### class KDEDistribution(Distribution): def __init__(self,attrs=None): self.min_kde_version = None self.min_qt_version = None self.kcontrol_modules = None self.kioslaves = None self.executable_links = None self.docbooks = None self.application_data = None self.i18n = None Distribution.__init__(self,attrs) ########################################################################### def has_kcms(self): if self.distribution.kcontrol_modules is None: return 0 return len(self.distribution.kcontrol_modules)!=0 def has_docbook_html(self): if self.distribution.docbooks is None: return 0 return len(self.distribution.docbooks)!=0 def has_messages(self): if self.distribution.i18n is None: return 0 return len(self.distribution.i18n)!=0 def has_application_data(self): if self.distribution.application_data is None: return 0 return len(self.distribution.application_data)!=0 def has_kioslaves(self): if self.distribution.kioslaves is None: return 0 return len(self.distribution.kioslaves)!=0 ########################################################################### # Our slightly extended build command. This also does kcontrol modules. class BuildKDE(build): user_options = build.user_options[:] user_options.append( ('msgfmt-exe=',None,'Path to the msgfmt executable') ) user_options.append( ('meinproc-exe=',None,'Path to the meinproc executable') ) sub_commands = build.sub_commands[:] sub_commands.append( ('build_kcm',has_kcms) ) sub_commands.append( ('build_kioslave',has_kioslaves) ) sub_commands.append( ('build_html',has_docbook_html) ) sub_commands.append( ('build_messages',has_messages) ) def __init__(self,dist): build.__init__(self,dist) self.has_kcms = has_kcms self.has_kioslaves = has_kioslaves self.has_docbook_html = has_docbook_html self.has_messages = has_messages def initialize_options(self): self.msgfmt_exe = None self.meinproc_exe = None build.initialize_options(self) def finalize_options(self): build.finalize_options(self) if self.msgfmt_exe is None: # Find msgfmt canidatepaths = [] canidatepaths.append( ask_kde_config('--install exe --expandvars').strip() ) self.msgfmt_exe = FindExeOnPath('msgfmt',canidatepaths) if self.msgfmt_exe is None: raise SystemExit, "Unable to find 'msgfmt', needed to build i18n messages." if self.meinproc_exe is None: # Find meinproc canidatepaths = [] canidatepaths.append( ask_kde_config('--install exe --expandvars').strip() ) self.meinproc_exe = FindExeOnPath('meinproc',canidatepaths) if self.meinproc_exe is None: raise SystemExit, "Unable to find 'meinproc', needed to generate Docbook HTML documentation." ########################################################################### def has_executable_links(self): if self.distribution.executable_links is None: return 0 return len(self.distribution.executable_links)!=0 ########################################################################### class InstallKDE(install): user_options = install.user_options[:] user_options.append( ('kde-prefix=',None,"KDE installation prefix") ) user_options.append( ('install-messages=',None,"installation directory for i18n message files") ) user_options.append( ('install-html=',None,"installation directory for Docbook HTML files") ) user_options.append( ('install-cmd=',None,"Command to use to install the files") ) user_options.append( ('install-xdg-apps=',None,"directory for XDG app files") ) user_options.append( ('install-kcm=',None,"directory for kcm library files") ) user_options.append( ('install-kioslave',None,"directory for kioslave library files") ) user_options.append( ('install-protocol',None,"directory for kioslave protocol files") ) sub_commands = install.sub_commands[:] sub_commands.insert(0, ('checkpykde',None) ) sub_commands.insert(0, ('checkpyqt',None) ) sub_commands.append( ('install_executable_links',has_executable_links) ) sub_commands.append( ('install_messages',has_messages) ) sub_commands.append( ('install_html',has_docbook_html) ) sub_commands.append( ('install_kcm',has_kcms) ) sub_commands.append( ('install_kioslave',has_kioslaves) ) sub_commands.append( ('install_application_data',has_application_data) ) def initialize_options(self): self.kde_prefix = None self.install_messages = None self.install_html = None self.install_cmd = None self.install_xdg_apps = None self.install_kcm = None self.install_kioslave = None self.install_protocol = None self.install_application_data = None install.initialize_options(self) def finalize_options(self): # If no install prefix was provided, then we try to detect the KDE install prefix. self.user_supplied_kde_prefix = True if self.install_scripts is None: if self.kde_prefix is not None: self.install_scripts = os.path.join(self.kde_prefix,'bin') else: self.announce("Detecting KDE 'bin' directory...") self.install_scripts = ask_kde_config('--install exe --expandvars').strip() self.announce(" ...KDE 'bin' directory is %s" % self.install_scripts) if self.install_application_data is None: if self.kde_prefix is not None: self.install_application_data = os.path.join(self.kde_prefix,'share/apps',self.distribution.metadata.name) else: self.announce("Detecting KDE application directory...") kdeappdir = ask_kde_config('--install data --expandvars').strip() self.announce(" ...KDE application directory is %s" % self.install_application_data) self.install_application_data = os.path.join(kdeappdir,self.distribution.metadata.name) if self.install_messages is None: if self.kde_prefix is not None: self.install_messages = os.path.join(self.kde_prefix,'share/locale') else: self.announce("Detecting KDE messages directory...") self.install_messages = ask_kde_config('--install locale --expandvars').strip() self.announce(" ...KDE messages directory is %s" % self.install_messages) if self.install_html is None: if self.kde_prefix is not None: self.install_html = os.path.join(self.kde_prefix,'share/doc/HTML') else: self.announce("Detecting KDE HTML directory...") self.install_html = ask_kde_config('--install html --expandvars').strip() self.announce(" ...KDE HTML directory is %s" % self.install_html) if self.kde_prefix is None: self.announce("Detecting KDE install prefix...") self.kde_prefix = ask_kde_config('--prefix').strip() self.announce(" ...KDE install prefix is %s" % self.kde_prefix) self.user_supplied_kde_prefix = False if self.install_cmd is None: self.announce("Detecting 'install' command...") # Ok, time to find the install command. self.install_cmd = find_executable('install') if self.install_cmd is None: raise SystemExit, "Unable to find the 'install' command, needed to install libraries." self.announce(" ...'install' command is %s" % self.install_cmd) if self.install_xdg_apps is None: self.announce("Detecting XDG apps directory...") self.install_xdg_apps = ask_kde_config('--install xdgdata-apps --expandvars').strip() self.announce(" ...XDG apps directory is %s" % self.install_xdg_apps) if self.install_kcm is None: self.announce("Detecting kcm library directory...") self.install_kcm = os.path.join(ask_kde_config('--install lib --expandvars').strip(),'kde3') self.announce(" ...kcm library directory is %s" % self.install_kcm) if self.install_kioslave is None: self.announce("Detecting kioslave library directory...") self.install_kioslave = os.path.join(ask_kde_config('--install lib --expandvars').strip(),'kde3') self.announce(" ...kioslave library directory is %s" % self.install_kioslave) if self.install_protocol is None: self.announce("Detecting kioslave protocol directory...") self.install_protocol = ask_kde_config('--install services --expandvars').strip() self.announce(" ...kioslave protocol directory is %s" % self.install_protocol) install.finalize_options(self) if self.root is not None: self.change_roots('application_data','html','messages','xdg_apps','kcm') def get_command_name(self): return 'install' def run(self): global INSTALL_LIST install.run(self) # Write out the uninstall list. fhandle = open(INSTALL_LIST,'w') for item in self.get_outputs(): fhandle.write(item) fhandle.write('\n') fhandle.close() ########################################################################### class InstallApplicationDataAndLinks(install_data): def get_command_name(self): return 'install_application_data' def initialize_options(self): install_data.initialize_options(self) self.data_files = self.distribution.application_data def finalize_options(self): self.set_undefined_options('install', ('install_application_data', 'install_dir'), ('root', 'root'), ('force', 'force'), ) def run(self): self.outfiles.extend(self.mkpath(self.install_dir)) for f in self.data_files: if type(f) is StringType: # it's a simple file, so copy it f = convert_path(f) if self.warn_dir: self.warn("setup script did not provide a directory for " "'%s' -- installing right in '%s'" % (f, self.install_dir)) if os.path.isfile(f): (out, _) = self.copy_file(f, self.install_dir) self.outfiles.append(out) elif os.path.isdir(f): out = self.copy_tree(f,os.path.join(self.install_dir,f)) self.outfiles.extend(out) else: self.warn("Setup script can't find file or directory %s needed for installation." % f) else: # it's a tuple with path to install to and a list of files dir = convert_path(f[0]) if not os.path.isabs(dir): dir = change_root(self.install_dir, dir) elif self.root: dir = change_root(self.root, dir) self.outfiles.extend(self.mkpath(dir)) if f[1] == []: # If there are no files listed, the user must be # trying to create an empty directory, so add the # directory to the list of output files. self.outfiles.append(dir) else: # Copy files, adding them to the list of output files. for data in f[1]: data = convert_path(data) if os.path.islink(data): # Transplant the link to the new location without changing # where it points to. (ie it is _not_ relocated). dest = os.path.join(dir, os.path.basename(data)) if os.path.exists(dest): os.remove(dest) os.symlink(os.readlink(data),dest) log.info("moving link %s -> %s" % (data,dest) ) #os.chmod(dest, os.stat(data)[stat.ST_MODE]) elif os.path.isdir(data): out = self.copy_tree(data,dir) self.outfiles.extend(out) else: (out, _) = self.copy_file(data, dir) self.outfiles.append(out) # Compile the .ui files install_cmd = self.get_finalized_command('install') prefix = self.install_dir if prefix[-1] != os.sep: prefix = prefix + os.sep self.outfiles.extend(compile_qtdesigner(self.outfiles, force=1, prefix=prefix, base_dir=install_cmd.prefix, dry_run=self.dry_run)) # Byte compile the .py files from distutils.util import byte_compile byte_compile(self.outfiles, optimize=0, force=1, prefix=prefix, base_dir=install_cmd.prefix, dry_run=self.dry_run) # Add the .pyc files to the list of outfiles. self.outfiles.extend( [item+'c' for item in self.outfiles if item.endswith('.py')] ) def mkpath(self, name, mode=0777): return dir_util.mkpath(name, mode, dry_run=self.dry_run) ########################################################################### class InstallExecutableLinks(Command): description = "Install symlinks" user_options = [] def initialize_options(self): self.outfiles = [] def finalize_options(self): pass def get_command_name(self): return 'install_executable_links' def run(self): # FIXME add cmd options? install_script_cmd = self.get_finalized_command('install_scripts') install_data_cmd = self.get_finalized_command('install_application_data') destination_dir = install_data_cmd.install_dir if not os.path.exists(install_script_cmd.install_dir): self.outfiles.extend(self.mkpath(install_script_cmd.install_dir)) if self.distribution.executable_links is not None: for link in self.distribution.executable_links: symname = os.path.join(install_script_cmd.install_dir,link[0]) target = os.path.join(destination_dir,link[1]) log.info("symlinking %s -> %s", symname, target) if not self.dry_run: if os.path.islink(symname): os.remove(symname) os.symlink(target,symname) self.outfiles.append(symname) def get_outputs(self): return self.outfiles or [] def mkpath(self, name, mode=0777): return dir_util.mkpath(name, mode, dry_run=self.dry_run) ########################################################################### # Fix the --root option for the install_lib command. class InstallLibWithRoot(install_lib): user_options = install_lib.user_options[:] user_options.append( ('root=',None,"install everything relative to this alternate root directory") ) def initialize_options(self): install_lib.initialize_options(self) self.root = None def finalize_options(self): own_install_dir = self.install_dir is not None install_lib.finalize_options(self) self.set_undefined_options('install', ('root', 'root')) if self.root is not None and own_install_dir: self.install_dir = change_root(self.root, self.install_dir) ########################################################################### class Uninstall(Command): description = "Remove all installed files" user_options = [] def initialize_options(self): pass def finalize_options(self): pass def get_command_name(self): return 'uninstall' def run(self): global INSTALL_LIST if not os.path.isfile(INSTALL_LIST): self.announce("Unable to uninstall, can't find the file list %s." % INSTALL_LIST) return # Suck in the file list. fhandle = open(INSTALL_LIST,'r') file_list = fhandle.readlines() fhandle.close() # Remove the files first. for item in file_list: item = item.strip() if os.path.isfile(item) or os.path.islink(item): self.announce("removing '%s'" % item) if not self.dry_run: try: os.remove(item) except OSError, details: self.warn("Could not remove file: %s" % details) elif not os.path.isdir(item): self.announce("skipping removal of '%s' (does not exist)" % item) # Remove the directories. file_list.sort() file_list.reverse() # Starting with the longest paths first. for item in file_list: item = item.strip() if os.path.isdir(item): self.announce("removing '%s'" % item) if not self.dry_run: try: os.rmdir(item) except OSError, details: self.warn("Could not remove directory: %s" % details) ########################################################################### class BuildKControlModule(Command): description = "Build KControl extensions" user_options = [('no-kcontrol',None,"Don't build kcontrol extensions"), ('build-dir=','b', "build directory (where to install from)"), ('python-dir=',None,'Directory containing the Python installation'), ('python-inc-dir=',None,'Directory containing C Header files for Python'), ('kde-inc-dir=',None,'Directory containing C++ header files for KDE'), ('kde-lib-dir=',None,'Directory containing library files for KDE'), ('kde-kcm-lib-dir=',None,'Directory for KDE kcm library files'), ('qt-inc-dir=',None,'Directory containing C++ header files for Qt'), ('qt-lib-dir=',None,'Directory containing library files for Qt'), ('sip-dir=','/usr/lib/pyshared/python2.6','Directory containing the sip library files'), ('clib=',None,'gcc library and path'), ('pyqt-dir=','/usr/lib/pyshared/python2.6','PyQt module directory'), ('pykde-dir=',None,'PyKDE module directory'), ('data-dir=',None,'installation directory for data (script) files')] def initialize_options(self): self.no_kcontrol = 0 self.build_dir = None self.python_inc_dir = None self.python_dir = None self.kde_inc_dir = None self.kde_lib_dir = None self.kde_kcm_lib_dir = None self.qt_inc_dir = None self.qt_lib_dir = None self.sip_dir = "/usr/lib/pyshared/python2.6" self.clib = None self.pyqt_dir = "/usr/lib/pyshared/python2.6" self.pykde_dir = None self.data_dir = None def finalize_options(self): if self.no_kcontrol==0: self.set_undefined_options('install', ('build_base', 'build_dir'),('install_application_data','data_dir')) install = self.get_finalized_command('install') self.install_prefix = "/opt/kde3/" # KDE inc dir: find it! if self.kde_inc_dir is None: canidatepaths = [] kdedir = os.getenv("KDEDIR") if kdedir!=None: canidatepaths.append(os.path.join(kdedir,"include")) canidatepaths.append(os.path.join(install.prefix,"include")) canidatepaths.append('/opt/kde3/include') canidatepaths.append('/opt/kde/include') self.kde_inc_dir = FindFileInPaths('kapplication.h',canidatepaths) if self.kde_inc_dir is None: raise SystemExit, "Failed to find the KDE header file directory." if FindFileInPaths('kapplication.h',[self.kde_inc_dir]) is None: raise SystemExit, "Failed to find KDE header files in: %s" % self.kde_inc_dir self.announce("Using %s for KDE header files" % self.kde_inc_dir) # KDE lib dir #if self.kde_lib_dir is None: # self.kde_lib_dir = os.path.join(install.prefix,"lib") self.kde_lib_dir = "/opt/kde3/lib/" self.announce("Using %s for KDE library files" % self.kde_lib_dir) # KDE KCM lib dir #if self.kde_kcm_lib_dir is None: # self.kde_kcm_lib_dir = os.path.join(self.kde_lib_dir,"kde3") self.kde_kcm_lib_dir = "/opt/kde3/lib/kde3/" if FindFileInPaths('*kcm*.so',[self.kde_kcm_lib_dir]) is None: raise SystemExit, "Failed to find KDE KCM files in: %s" % self.kde_kcm_lib_dir self.announce("Using %s for KDE KCM library files" % self.kde_kcm_lib_dir) # Qt inc dir if self.qt_inc_dir is None: canidatepaths = [] qtdir = os.getenv("QTDIR") if qtdir != None: canidatepaths.append(os.path.join(qtdir,"include")) canidatepaths.append(os.path.join(install.prefix,"lib/qt3/include")) canidatepaths.append(os.path.join(install.prefix,"lib/qt3/include")) canidatepaths.append(os.path.join(install.prefix,"include")) canidatepaths.append("/opt/qt3/include") canidatepaths.append("/opt/qt/include") canidatepaths.append("/opt/qt/lib/include") canidatepaths.append("/opt/qt3/lib/include") canidatepaths.append("/usr/include/qt3") self.qt_inc_dir = FindFileInPaths('qstring.h',canidatepaths) if self.qt_inc_dir is None: raise SystemExit,"Failed to find the Qt header file directory" if FindFileInPaths('qstring.h',[self.qt_inc_dir]) is None: raise SystemExit, "Failed to find Qt header files in: %s" % self.qt_inc_dir self.announce("Using %s for Qt header files" % self.qt_inc_dir) # Qt lib dir if self.qt_lib_dir is None: canidatepaths = [] qtdir = os.getenv("QTDIR") if qtdir != None: canidatepaths.append(os.path.join(qtdir,get_libdir_name())) canidatepaths.append(os.path.join(install.prefix,"lib/qt3/"+get_libdir_name())) canidatepaths.append(os.path.join(install.prefix,"lib/qt3/"+get_libdir_name())) canidatepaths.append(os.path.join(install.prefix,get_libdir_name())) canidatepaths.append("/opt/qt3/"+get_libdir_name()) canidatepaths.append("/opt/qt/"+get_libdir_name()) canidatepaths.append("/opt/qt/lib/"+get_libdir_name()) canidatepaths.append("/opt/qt3/lib/"+get_libdir_name()) self.qt_lib_dir = FindFileInPaths('libqt*',canidatepaths) if self.qt_lib_dir is None: raise SystemExit, "Failed to find Qt library files" self.announce("Using %s for Qt library files" % self.qt_lib_dir) # Python dir if self.python_dir is None: self.python_dir = os.path.split(sysconfig.get_config_var("LIBP"))[0] self.announce("Using %s for the python directory" % self.python_dir) # Python include dir. if self.python_inc_dir is None: # Find the Python include directory. self.python_inc_dir = sysconfig.get_config_var("INCLUDEPY") self.announce("Using %s for Python header files" % self.python_inc_dir) # PyQt dir if self.pyqt_dir is None: self.pyqt_dir = sysconfig.get_python_lib() if (FindFileInPaths("libqtcmodule*",[self.pyqt_dir]) is None) and (FindFileInPaths("qt*",[self.pyqt_dir]) is None): raise SystemExit, "Failed to find the PyQt directory: %s" % self.pyqt_dir self.announce("Using %s for PyQt modules" % self.pyqt_dir) # PyKDE dir if self.pykde_dir is None: self.pykde_dir = sysconfig.get_python_lib() if (FindFileInPaths("libkdecorecmodule*",[self.pykde_dir]) is None) and (FindFileInPaths("kdecore*",[self.pykde_dir]) is None): raise SystemExit, "Failed to find the PyKDE directory: %s" % self.pykde_dir self.announce("Using %s for PyKDE modules" % self.pykde_dir) # Sip dir if self.sip_dir is None: self.sip_dir = sysconfig.get_python_lib() if (FindFileInPaths("libsip*", [self.sip_dir]) is None) and (FindFileInPaths("sip*", [self.sip_dir]) is None): raise SystemExit, "Failed to find libsip files in directory: %s" % self.sip_dir self.announce("Using %s for libsip files" % self.sip_dir) # Find the C library (libgcc, libgcc_s or some other variation). if self.clib is None: canidatepaths = ["/usr/"+get_libdir_name(), "/usr/local/"+get_libdir_name() ] self.clib = FindFileInPaths("libgcc*.so",canidatepaths) if self.clib!=None: self.clib = glob.glob(os.path.join(self.clib,'libgcc*.so'))[0] else: self.clib = FindFileInPaths("libgcc*.a",canidatepaths) if self.clib!=None: self.clib = glob.glob(os.path.join(self.clib,'libgcc*.a'))[0] if self.clib is None: raise SystemExit, "Failed to find a suitable libgcc library" self.announce("Using %s for clib" % self.clib) # Make a list of places to look for python .so modules self.python_sub_dirs = sysconfig.get_config_var("LIBSUBDIRS").split() base = sysconfig.get_config_var("LIBP") self.python_sub_dirs = [ os.path.join(base,item) for item in self.python_sub_dirs ] self.python_sub_dirs.append(base) def get_command_name(self): return 'build_kcm' def run(self): if self.no_kcontrol: self.announce("Skipping KControl modules") return if not os.path.isdir(self.build_dir): os.mkdir(self.build_dir) for moduletuple in self.distribution.kcontrol_modules: self.announce("Building KControl module from desktop file %s." % moduletuple[0]) # Read the desktop file factoryfunction = None libraryname = None cmodulecategory = None try: fhandle = open(moduletuple[0],'r') for line in fhandle.readlines(): parts = line.strip().split('=') try: if parts[0]=="X-KDE-Library": libraryname = parts[1] elif parts[0]=="Exec": shellcmd = parts[1].split() modulepath = shellcmd[-1] if '/' in modulepath: cmodulecategory = os.path.dirname(modulepath) else: cmodulecategory = "" elif parts[0]=="X-KDE-FactoryName": factoryfunction = 'create_'+parts[1] except IndexError: pass fhandle.close() except IOError: raise SystemExit, "Failed to find kcontrol desktop file: %s" % moduletuple[0] # Sanity check. if factoryfunction is None: raise SystemExit, "Failed to find factory name (Was there a X-KDE-FactoryName entry in the desktop file?)" if libraryname is None: raise SystemExit, "Failed to find library name (Was there a X-KDE-Library entry in the desktop file?)" if cmodulecategory is None: raise SystemExit, "Failed to find the kcontrol category name (Was there a Exec entry in the desktop file?)" modulename = os.path.basename(moduletuple[1]) if modulename.endswith('.py'): modulename = modulename[:-3] desktopfilename = moduletuple[0] stub_cpp_name = 'kcm_'+libraryname+'.cpp' stub_so_name = 'kcm_'+libraryname+'.so' stub_la_name = 'kcm_'+libraryname+'.la' python_version = '%i.%i' % (sys.version_info[0],sys.version_info[1]) # Build the 'stub' code. cppcode = self.cpptemplate % {"moduledir": self.data_dir, "modulename": modulename, "factoryfunction": factoryfunction, "python_version": python_version} # Put it on disk. cppfile = os.path.join(os.path.dirname(moduletuple[0]),stub_cpp_name) try: fhandle = open(cppfile,'w') fhandle.write(cppcode) fhandle.close() except IOError: raise SystemExit, "Could not write the C++ stub: %s" % cppfile # Compile the stub library. cmdlist = ['libtool'] # Couldn't get it to pass without this ... cmdlist.append("--mode=compile") cmdlist.append("--tag=CXX") # Find the compiler flags and options # CXX is empty on some Systems, let's do it 'the hard way'. # FIXME :: get CXX from make.conf for Gentoo. if len(sysconfig.get_config_var("CXX").split()) >= 2: cmdlist.extend(sysconfig.get_config_var("CXX").split()) else: cmdlist.extend(['g++', '-pthread']) #cmdlist.extend(sysconfig.get_config_var("CXX").split()) # cc_flags cmdlist.append("-c") cmdlist.append("-g") # The 4 is randomly chosen! # FIXME :: get CFLAGS from make.conf for Gentoo. if len(sysconfig.get_config_var("CFLAGS").split()) >=4: cmdlist.extend(sysconfig.get_config_var("CFLAGS").split()) else: # On Gentoo systems, CFLAGS are not in the environment. raw = os.popen('emerge info 2> /dev/null|grep CFLAGS') lines = raw.readlines() if len(lines): cflags = lines[0].split('"')[1].split() print "Got CFLAGS from emerge info." cmdlist.extend(cflags) else: # Still no CFLAGS found, use these ... cmdlist.extend(['-fno-strict-aliasing', '-DNDEBUG', '-g', '-O3', '-Wall', '-Wstrict-prototypes']) #sysconfig.get_config_var("CFLAGS").split() # includes cmdlist.append("-I" + sysconfig.get_config_var("INCLUDEDIR")) cmdlist.append("-I" + sysconfig.get_config_var("INCLUDEDIR")) cmdlist.append("-I" + sysconfig.get_config_var("INCLUDEPY")) cmdlist.append("-I" + self.python_inc_dir) cmdlist.append("-I" + self.kde_inc_dir) cmdlist.append("-I" + self.qt_inc_dir) cmdlist.append("-I.") # input cmdlist.append(cppfile) # output outputfile = os.path.join(self.build_dir,libraryname+'.lo') cmdlist.append("-o") cmdlist.append(outputfile) spawn(cmdlist) # Execute!!! print # Link the resulting object file to create a shared library. cmdlist = ['libtool'] cmdlist.append("--mode=link") # Grab the linker command name cmdlist.append(sysconfig.get_config_var("LDSHARED").split()[0]) # link_flags cmdlist.append("-module") cmdlist.append("-export-dynamic") # object cmdlist.append(outputfile) cmdlist.append("-rpath"); cmdlist.append(self.kde_kcm_lib_dir) cmdlist.append("-o"); cmdlist.append(os.path.join(self.build_dir,stub_la_name)) # Link libs linklist = [] linklist.append("-lpython%s" % python_version) linklist.extend(sysconfig.get_config_var("LIBS").split()) # FIXME I doubt half of these libraries need to be here. linklist.append(self.sip_dir+"/sip.so") # PyQt libs linklist.append(self.pyqt_dir+"/qt.so") # PyKDE libs linklist.append(self.pykde_dir+"/kdecore.so") linklist.append(self.pykde_dir+"/kdeui.so") # linklist.append("-L"+self.sip_dir); linklist.append("-lsip") # # PyQt libs # linklist.append("-L"+self.pyqt_dir); linklist.append("-lqtcmodule") # # PyKDE libs # linklist.append("-L"+self.pykde_dir); linklist.append("-lkdecorecmodule"); linklist.append("-lkdeuicmodule") linklist.append("-L"+self.kde_lib_dir); linklist.append("-L/opt/kde3/lib"); linklist.append("-lkdecore"); linklist.append("-lpythonize") linklist.append("-L"+self.qt_lib_dir); linklist.append("-lqt-mt") linklist.append("-lm") linklist.append("-lstdc++") linklist.append("-lc") linklist.append(self.clib) linklist.append("-R"); linklist.append(self.python_dir) linklist.append("-R"); linklist.append(self.qt_lib_dir) linklist.append("-R"); linklist.append(self.sip_dir) linklist.append("-R"); linklist.append(self.pyqt_dir) linklist.append("-R"); linklist.append(self.pykde_dir) linklist.append("-R"); linklist.append(self.kde_lib_dir) cmdlist.extend(linklist) spawn(cmdlist) # Execute!! print cpptemplate = r""" /* * pykcm_launcher.cpp * * Launch Control Centre modules written in Python using an embedded Python * interpreter. * Based on David Boddie's PyKDE-components. */ // pythonize.h must be included first. #include #include #include #include #include #include #include #include #include #define MODULE_DIR "%(moduledir)s" #define EXTRA_MODULE_DIR "/opt/kde3/share/python-support/kde-guidance-kde3" #define EXTRA_MODULE_DIR_TWO "/opt/kde3/share/python-support/guidance-backends-kde3" #define EXTRA_MODULE_DIR_THREE "/opt/kde3/share/python-support/kde-guidance-powermanager-kde3" #define MODULE_NAME "%(modulename)s" #define FACTORY "%(factoryfunction)s" #define CPP_FACTORY %(factoryfunction)s #define LIB_PYTHON "libpython%(python_version)s.so" #define debug 1 static KCModule *report_error(char *msg) { if (debug) printf ("error: %%s\n", msg); return NULL; } static KCModule* return_instance( QWidget *parent, const char *name ) { KCModule* kcmodule; PyObject *pyKCModuleTuple; PyObject *pyKCModule; Pythonize *pyize; // Pythonize object to manage the Python interpreter. int isErr; // Try to determine what py script we're loading. Note that "name" // typically appears to be NULL. QString script(MODULE_NAME); // Reload libpython, but this time tell the runtime linker to make the // symbols global and available for later loaded libraries/module. KLibLoader::self()->globalLibrary(LIB_PYTHON); // Start the interpreter. pyize = initialize(); if (!pyize) { return report_error ("***Failed to start interpreter\n"); } // Add the path to the python script to the interpreter search path. QString path = QString(MODULE_DIR); if(path == QString::null) { return report_error ("***Failed to locate script path"); } if(!pyize->appendToSysPath (path.latin1 ())) { return report_error ("***Failed to set sys.path\n"); } QString extrapath = QString(EXTRA_MODULE_DIR); if(!pyize->appendToSysPath (extrapath.latin1 ())) { return report_error ("***Failed to set extra sys.path\n"); } QString extrapath_two = QString(EXTRA_MODULE_DIR_TWO); if(!pyize->appendToSysPath (extrapath_two.latin1 ())) { return report_error ("***Failed to set extra 2 sys.path\n"); } QString extrapath_three = QString(EXTRA_MODULE_DIR_THREE); if(!pyize->appendToSysPath (extrapath_three.latin1 ())) { return report_error ("***Failed to set extra 3 sys.path\n"); } // Load the Python script. PyObject *pyModule = pyize->importModule ((char *)script.latin1 ()); if(!pyModule) { PyErr_Print(); return report_error ("***failed to import module\n"); } // Inject a helper function QString bridge = QString("import sip\n" "import qt\n" "def kcontrol_bridge_" FACTORY "(parent,name):\n" " if parent!=0:\n" #if SIP_VERSION >= 0x040200 " wparent = sip.wrapinstance(parent,qt.QWidget)\n" #else " wparent = sip.wrapinstance(parent,'QWidget')\n" #endif " else:\n" " wparent = None\n" " inst = " FACTORY "(wparent, name)\n" " return (inst,sip.unwrapinstance(inst))\n"); PyRun_String(bridge.latin1(),Py_file_input,PyModule_GetDict(pyModule),PyModule_GetDict(pyModule)); // Get the Python module's factory function. PyObject *kcmFactory = pyize->getNewObjectRef(pyModule, "kcontrol_bridge_" FACTORY); if(!kcmFactory) { return report_error ("***failed to find module factory\n"); } // Call the factory function. Set up the args. PyObject *pyParent = PyLong_FromVoidPtr(parent); PyObject *pyName = PyString_FromString(MODULE_NAME); // Using NN here is effect gives our references to the arguement away. PyObject *args = Py_BuildValue ("NN", pyParent, pyName); if(pyName && pyParent && args) { // run the factory function pyKCModuleTuple = pyize->runFunction(kcmFactory, args); if(!pyKCModuleTuple) { PyErr_Print(); return report_error ("*** runFunction failure\n;"); } } else { return report_error ("***failed to create args\n"); } // cleanup a bit pyize->decref(args); pyize->decref(kcmFactory); // Stop this from getting garbage collected. Py_INCREF(PyTuple_GET_ITEM(pyKCModuleTuple,0)); // convert the KCModule PyObject to a real C++ KCModule *. isErr = 0; pyKCModule = PyTuple_GET_ITEM(pyKCModuleTuple,1); kcmodule = (KCModule *)PyLong_AsVoidPtr(pyKCModule); if(!kcmodule) { return report_error ("***failed sip conversion to C++ pointer\n"); } pyize->decref(pyKCModuleTuple); // PyKDE can't run the module without this - Pythonize // grabs the lock at initialization and we have to give // it back before exiting. At this point, we no longer need // it. //pyize->releaseLock (); // take care of any translation info KGlobal::locale()->insertCatalogue(script); // Return the pointer to our new KCModule return kcmodule; } extern "C" { // Factory function that kcontrol will call. KCModule* CPP_FACTORY(QWidget *parent, const char *name) { return return_instance(parent, name); } } """ ########################################################################### class InstallKControlModule(Command): description = "Install Kcontrol module files" user_options = [ ('install-dir=', 'd', "base directory for installing kcontrol module files"), ('install-cmd=', None, "Command to use to install the files"), ('xdg-apps-dir=',None,"directory for XDG app files"), ('build-dir=','b', "build directory (where to install from)"), ('root=', None, "install everything relative to this alternate root directory"), ('force', 'f', "force installation (overwrite existing files)"), ('skip-build', None, "skip the build steps"), ] boolean_options = ['force', 'skip-build'] def initialize_options(self): self.build_dir = None self.install_dir = None self.install_cmd = None self.xdg_apps_dir = None self.outfiles = [] self.root = None self.force = 0 self.warn_dir = 1 self.skip_build = None def finalize_options(self): own_install_dir = self.install_dir is not None own_xdg_apps_dir = self.xdg_apps_dir is not None self.set_undefined_options('install', ('build_base', 'build_dir'), ('install_kcm', 'install_dir'), ('install_xdg_apps','xdg_apps_dir'), ('root', 'root'), ('force', 'force'), ('skip_build', 'skip_build'), ('install_cmd', 'install_cmd') ) if own_install_dir and self.root is not None: self.install_dir = change_root(self.root,self.installdir) if own_xdg_apps_dir and self.root is not None: self.xdg_apps_dir = change_root(self.root,self.xdg_apps_dir) def get_command_name(self): return 'install_kcm' def run(self): if not self.skip_build: self.run_command('build_kcm') self.announce("Installing Kcontrol module files...") for moduletuple in self.distribution.kcontrol_modules: self.announce("Building KControl module from desktop file %s." % moduletuple[0]) # Read the desktop file libraryname = None cmodulecategory = None try: fhandle = open(moduletuple[0],'r') for line in fhandle.readlines(): parts = line.strip().split('=') try: if parts[0]=="X-KDE-Library": libraryname = parts[1] elif parts[0]=="Exec": shellcmd = parts[1].split() modulepath = shellcmd[-1] if '/' in modulepath: cmodulecategory = os.path.dirname(modulepath) else: cmodulecategory = "" except IndexError: pass fhandle.close() except IOError: raise SystemExit, "Failed to find kcontrol desktop file: %s" % moduletuple[0] if libraryname is None: raise SystemExit, "Failed to find library name (Was there a X-KDE-Library entry in the desktop file?)" if cmodulecategory is None: raise SystemExit, "Failed to find the kcontrol category name (Was there a Exec entry in the desktop file?)" desktopfilename = moduletuple[0] self.outfiles.extend(self.mkpath(self.xdg_apps_dir)) desktopfile_dest = os.path.join(self.xdg_apps_dir,os.path.basename(desktopfilename)) self.copy_file(desktopfilename, desktopfile_dest) stub_la_name = 'kcm_'+libraryname+'.la' self.outfiles.extend(self.mkpath(self.install_dir)) # Install the library. cmdlist = ['libtool'] cmdlist.append("--mode=install") cmdlist.append(self.install_cmd) cmdlist.append("-c") cmdlist.append(os.path.join(self.build_dir,stub_la_name)) cmdlist.append(os.path.join(self.install_dir,stub_la_name)) spawn(cmdlist) # Execute!! print self.outfiles = [os.path.join(self.install_dir,os.path.basename(file)) for file in glob.glob(os.path.join(self.build_dir,'.libs','kcm_'+libraryname+'*'))] self.outfiles.append(desktopfile_dest) self.announce("Done installing Kcontrol module files.") def get_outputs(self): return self.outfiles or [] def mkpath(self, name, mode=0777): return dir_util.mkpath(name, mode, dry_run=self.dry_run) ########################################################################### class BuildDocbookHTML(Command): description = "Build Docbook HTML documentation" user_options = [('meinproc-exe=',None,"Path to the meinproc executable")] def initialize_options(self): self.html_prefix = None self.meinproc_exe = None def finalize_options(self): self.set_undefined_options('build', ('meinproc_exe', 'meinproc_exe') ) def get_command_name(self): return 'build_docbook' def run(self): for docbook_tuple in self.distribution.docbooks: input_dir = docbook_tuple[0] language_code = docbook_tuple[1] self.announce("Building Docbook documentation from directory %s." % input_dir) indexdoc_file_name = os.path.join(input_dir,'index.docbook') if not os.path.exists(indexdoc_file_name): raise SystemExit, "File %s is missing." % indexdoc_file_name cwd = os.getcwd() os.chdir(input_dir) try: spawn([self.meinproc_exe,"--check","--cache",'index.cache.bz2', 'index.docbook']) spawn([self.meinproc_exe, 'index.docbook']) finally: os.chdir(cwd) ########################################################################### class InstallDocbookHTML(Command): description = "Install Docbook HTML files" user_options = [ ('install-dir=', 'd',"base directory for installing docbook HTML files"), ('root=', None, "install everything relative to this alternate root directory"), ('force', 'f', "force installation (overwrite existing files)"), ('skip-build', None, "skip the build steps"), ] boolean_options = ['force', 'skip-build'] def initialize_options(self): self.install_dir = None self.outfiles = [] self.root = None self.force = 0 self.warn_dir = 1 self.skip_build = None def finalize_options(self): own_install_dir = self.install_dir is not None self.set_undefined_options('install', ('install_html', 'install_dir'), ('root', 'root'), ('force', 'force'), ('skip_build', 'skip_build'), ) if own_install_dir and self.root is not None: self.install_dir = change_root(self.root,self.installdir) def get_command_name(self): return 'install_html' def run(self): if not self.skip_build: self.run_command('build_html') self.announce("Installing HTML files...") counter = 0 for docbook_tuple in self.distribution.docbooks: input_dir = docbook_tuple[0] language_code = docbook_tuple[1] self.announce("Install Docbook documentation from directory %s." % input_dir) source_file = os.path.join(input_dir,'index.cache.bz2') if not os.path.exists(source_file): raise SystemExit, "File %s is missing." % source_file dest_path = os.path.join(self.install_dir, language_code, self.distribution.metadata.name) self.outfiles.extend(self.mkpath(dest_path)) dest_file = os.path.join(dest_path,'index.cache.bz2') self.copy_file(source_file, dest_file) self.outfiles.append(dest_file) counter += 1 # Also install any lose HTML files. for source_file in glob.glob(os.path.join(input_dir,'*.html')): htmlfile = os.path.basename(source_file) dest_file = os.path.join(dest_path,htmlfile) self.copy_file(source_file, dest_file) self.outfiles.append(dest_file) counter += 1 if len(docbook_tuple)==3: extra_files = docbook_tuple[2] for file in extra_files: source_file = os.path.join(input_dir,file) dest_file = os.path.join(self.install_dir, language_code, self.distribution.metadata.name,file) self.copy_file(source_file, dest_file) self.outfiles.append(dest_file) counter += 1 self.announce("Done installing %i HTML files." % counter) def get_outputs(self): return self.outfiles or [] def mkpath(self, name, mode=0777): return dir_util.mkpath(name, mode, dry_run=self.dry_run) ########################################################################### class UpdateI18NMessages(Command): description = "Extract and update messages for translation" user_options = [('xgettext-exe=',None,'Full path to the xgetext executable'),\ ('kde-pot=',None,'Location of the the KDE pot file'),\ ('msgmerge-exe=',None,'Full path to the msgmerge executable')] def initialize_options(self): self.xgettext_exe = None self.msgmerge_exe = None self.kde_pot = None def finalize_options(self): if self.xgettext_exe is None: install = self.get_finalized_command('install') canidate_paths = [] if install.user_supplied_kde_prefix: canidate_paths.append(os.path.join(install.kde_prefix,'bin')) self.announce("Detecting xgettext...") canidate_paths.append(ask_kde_config('--install exe --expandvars').strip()) self.xgettext_exe = FindExeOnPath('xgettext',canidate_paths) if self.xgettext_exe is None: raise SystemExit, "Unable to find 'xgettext'." self.announce(" ...xgettext found at %s" % self.xgettext_exe) if self.msgmerge_exe is None: install = self.get_finalized_command('install') canidate_paths = [] if install.user_supplied_kde_prefix: canidate_paths.append(os.path.join(install.kde_prefix,'bin')) self.announce("Detecting msgmerge...") canidate_paths.append(ask_kde_config('--install exe --expandvars').strip()) self.msgmerge_exe = FindExeOnPath('msgmerge',canidate_paths) if self.msgmerge_exe is None: raise SystemExit, "Unable to find 'xgettext'." self.announce(" ...msgmerge found at %s" % self.msgmerge_exe) if self.kde_pot is None: self.announce("Detecting kde.pot...") canidatepaths = [] kdedir = os.getenv("KDEDIR") if kdedir!=None: canidatepaths.append(os.path.join(kdedir,"include")) install = self.get_finalized_command('install') canidatepaths.append(os.path.join(install.kde_prefix,"include")) canidatepaths.append('/opt/kde3/include') canidatepaths.append('/opt/kde/include') kde_pot_dir = FindFileInPaths('kde.pot',canidatepaths) if kde_pot_dir is None: raise SystemExit, "Failed to find the kde.pot file." self.kde_pot = os.path.join(kde_pot_dir,'kde.pot') self.announce(" ...kde.pot found at %s" % self.kde_pot) def get_command_name(self): return 'update_messages' def run(self): if self.distribution.i18n is None: return self.announce("Extracting and merging i18n messages...") po_dir = self.distribution.i18n[0] # FIXME : .rc and .ui files input_files = [] # Compile any UI files for dir in self.distribution.i18n[1]: for file in glob.glob(os.path.join(dir,'*.ui')): qtuicompiler.UpdateUI(file,kde=True) # Fetch all of the python files. for dir in self.distribution.i18n[1]: input_files.extend(glob.glob(os.path.join(dir,'*.py'))) target_pot = os.path.join(po_dir,self.distribution.metadata.name+".pot") cmd = [self.xgettext_exe, '-o', target_pot, '-ki18n', '-ktr2i18n', \ '-kI18N_NOOP', '-ktranslate', '-kaliasLocale','-x',self.kde_pot] cmd.extend(input_files) spawn(cmd) for po_file in glob.glob(os.path.join(po_dir,'*.po')): temp_po = po_file + '.temp' cmd = [self.msgmerge_exe,'-q','-o',temp_po,po_file,target_pot] spawn(cmd) os.rename(temp_po,po_file) self.announce("Finished with i18n messages.") ########################################################################### class BuildI18NMessages(Command): description = "Build i18n messages" user_options = [('msgfmt-exe=',None,'Path to the msgfmt executable')] def initialize_options(self): self.msgfmt_exe = None def finalize_options(self): self.set_undefined_options('build', ('msgfmt_exe', 'msgfmt_exe')) def get_command_name(self): return 'build_messages' def run(self): if self.distribution.i18n is None: return self.announce("Building i18n messages...") po_dir = self.distribution.i18n[0] i = 0 for po_file in [file for file in os.listdir(po_dir) if file.endswith('.po')]: source = os.path.join(po_dir,po_file) target = source[:-3]+'.gmo' cmd = [self.msgfmt_exe,'-o',target, source] spawn(cmd) i += 1 self.announce("Done building %i i18n messages." % i) ########################################################################### class InstallI18NMessages(Command): description = "Install messages" user_options = [ ('install-dir=', 'd',"base directory for installing message files (default: installation base dir)"), ('root=', None, "install everything relative to this alternate root directory"), ('force', 'f', "force installation (overwrite existing files)"), ('skip-build', None, "skip the build steps"), ] boolean_options = ['force', 'skip-build'] def initialize_options(self): self.install_dir = None self.outfiles = [] self.root = None self.force = 0 self.warn_dir = 1 self.skip_build = None def finalize_options(self): own_install_dir = self.install_dir is not None self.set_undefined_options('install', ('install_messages', 'install_dir'), ('root', 'root'), ('force', 'force'), ('skip_build', 'skip_build'), ) if own_install_dir and self.root is not None: self.install_dir = change_root(self.root,self.installdir) def get_command_name(self): return 'install_messages' def run(self): if not self.skip_build: self.run_command('build_messages') self.announce("Installing i18n messages...") po_dir = self.distribution.i18n[0] counter = 0 for po_file in os.listdir(po_dir): if po_file.endswith('.po'): source_file = os.path.join(po_dir,po_file[:-3]) + '.gmo' # Setup installation of the translation file. dest_path = os.path.join(self.install_dir, po_file[:-3],'LC_MESSAGES') self.outfiles.extend(self.mkpath(dest_path)) dest_file = os.path.join(dest_path, self.distribution.metadata.name+'.mo') self.copy_file(source_file, dest_file) self.outfiles.append(dest_file) counter += 1 self.announce("Done installing %i i18n messages." % counter) def get_outputs(self): return self.outfiles def mkpath(self, name, mode=0777): return dir_util.mkpath(name, mode, dry_run=self.dry_run) ########################################################################### class BuildKioslave(Command): description = "Build Kioslaves" user_options = [('no-kioslave',None,"Don't build kioslaves"), ('build-dir=','b', "build directory (where to install from)"), ('python-dir=',None,'Directory containing the Python installation'), ('python-inc-dir=',None,'Directory containing C Header files for Python'), ('kde-inc-dir=',None,'Directory containing C++ header files for KDE'), ('kde-lib-dir=',None,'Directory containing library files for KDE'), ('kde-kioslave-lib-dir=',None,'Directory for KDE kioslave library files'), ('kde-protocol-dir=',None,'Directory for KDE kioslave protocol files'), ('qt-inc-dir=',None,'Directory containing C++ header files for Qt'), ('qt-lib-dir=',None,'Directory containing library files for Qt'), ('sip-dir=','/usr/lib/pyshared/python2.6','Directory containing the sip library files'), ('clib=',None,'gcc library and path'), ('pyqt-dir=','/usr/lib/pyshared/python2.6','PyQt module directory'), ('pykde-dir=',None,'PyKDE module directory'), ('data-dir=',None,'installation directory for data (script) files')] def initialize_options(self): self.no_kioslave = 0 self.build_dir = None self.python_inc_dir = None self.python_dir = None self.kde_inc_dir = None self.kde_lib_dir = None self.kde_kioslave_lib_dir = None self.kde_protocol_dir = None self.qt_inc_dir = None self.qt_lib_dir = None self.sip_dir = "/usr/lib/pyshared/python2.6" self.clib = None self.pyqt_dir = "/usr/lib/pyshared/python2.6" self.pykde_dir = None self.data_dir = None def finalize_options(self): if self.no_kioslave==0: self.set_undefined_options('install', ('build_base', 'build_dir'),('install_application_data','data_dir')) install = self.get_finalized_command('install') self.install_prefix = "/opt/kde3/" # KDE inc dir: find it! if self.kde_inc_dir is None: canidatepaths = [] kdedir = os.getenv("KDEDIR") if kdedir!=None: canidatepaths.append(os.path.join(kdedir,"include")) canidatepaths.append(os.path.join(install.prefix,"include")) canidatepaths.append('/opt/kde3/include') canidatepaths.append('/opt/kde/include') self.kde_inc_dir = FindFileInPaths('kapplication.h',canidatepaths) if self.kde_inc_dir is None: raise SystemExit, "Failed to find the KDE header file directory." if FindFileInPaths('kapplication.h',[self.kde_inc_dir]) is None: raise SystemExit, "Failed to find KDE header files in: %s" % self.kde_inc_dir self.announce("Using %s for KDE header files" % self.kde_inc_dir) # KDE lib dir #if self.kde_lib_dir is None: # self.kde_lib_dir = os.path.join(install.prefix,"lib") self.kde_lib_dir = "/opt/kde3/lib/" self.announce("Using %s for KDE library files" % self.kde_lib_dir) # KDE kioslave lib dir #if self.kde_kioslave_lib_dir is None: # self.kde_kioslave_lib_dir = os.path.join(self.kde_lib_dir,"kde3") self.kde_kioslave_lib_dir = "/opt/kde3/lib/kde3/" if FindFileInPaths('kio_*.so',[self.kde_kioslave_lib_dir]) is None: raise SystemExit, "Failed to find KDE Kioslave library files in: %s" % self.kde_kioslave_lib_dir self.announce("Using %s for KDE Kioslave library files" % self.kde_kioslave_lib_dir) # Qt inc dir if self.qt_inc_dir is None: canidatepaths = [] qtdir = os.getenv("QTDIR") if qtdir != None: canidatepaths.append(os.path.join(qtdir,"include")) canidatepaths.append(os.path.join(install.prefix,"lib/qt3/include")) canidatepaths.append(os.path.join(install.prefix,"lib/qt3/include")) canidatepaths.append(os.path.join(install.prefix,"include")) canidatepaths.append("/opt/qt3/include") canidatepaths.append("/opt/qt/include") canidatepaths.append("/opt/qt/lib/include") canidatepaths.append("/opt/qt3/lib/include") self.qt_inc_dir = FindFileInPaths('qstring.h',canidatepaths) if self.qt_inc_dir is None: raise SystemExit,"Failed to find the Qt header file directory" if FindFileInPaths('qstring.h',[self.qt_inc_dir]) is None: raise SystemExit, "Failed to find Qt header files in: %s" % self.qt_inc_dir self.announce("Using %s for Qt header files" % self.qt_inc_dir) # Qt lib dir if self.qt_lib_dir is None: canidatepaths = [] qtdir = os.getenv("QTDIR") if qtdir != None: canidatepaths.append(os.path.join(qtdir,get_libdir_name())) canidatepaths.append(os.path.join(install.prefix,"lib/qt3/"+get_libdir_name())) canidatepaths.append(os.path.join(install.prefix,"lib/qt3/"+get_libdir_name())) canidatepaths.append(os.path.join(install.prefix,get_libdir_name())) canidatepaths.append("/opt/qt3/"+get_libdir_name()) canidatepaths.append("/opt/qt/"+get_libdir_name()) canidatepaths.append("/opt/qt/lib/"+get_libdir_name()) canidatepaths.append("/opt/qt3/lib/"+get_libdir_name()) self.qt_lib_dir = FindFileInPaths('libqt*',canidatepaths) if self.qt_lib_dir is None: raise SystemExit, "Failed to find Qt library files" self.announce("Using %s for Qt library files" % self.qt_lib_dir) # Python dir if self.python_dir is None: self.python_dir = os.path.split(sysconfig.get_config_var("LIBP"))[0] self.announce("Using %s for the python directory" % self.python_dir) # Python include dir. if self.python_inc_dir is None: # Find the Python include directory. self.python_inc_dir = sysconfig.get_config_var("INCLUDEPY") self.announce("Using %s for Python header files" % self.python_inc_dir) # PyQt dir if self.pyqt_dir is None: self.pyqt_dir = sysconfig.get_python_lib() if (FindFileInPaths("libqtcmodule*",[self.pyqt_dir]) is None) and (FindFileInPaths("qt*",[self.pyqt_dir]) is None): raise SystemExit, "Failed to find the PyQt directory: %s" % self.pyqt_dir self.announce("Using %s for PyQt modules" % self.pyqt_dir) # PyKDE dir if self.pykde_dir is None: self.pykde_dir = sysconfig.get_python_lib() if (FindFileInPaths("libkdecorecmodule*",[self.pykde_dir]) is None) and (FindFileInPaths("kdecore*",[self.pykde_dir]) is None): raise SystemExit, "Failed to find the PyKDE directory: %s" % self.pykde_dir self.announce("Using %s for PyKDE modules" % self.pykde_dir) # Sip dir if self.sip_dir is None: self.sip_dir = sysconfig.get_python_lib() if (FindFileInPaths("libsip*", [self.sip_dir]) is None) and (FindFileInPaths("sip*", [self.sip_dir]) is None): raise SystemExit, "Failed to find libsip files in directory: %s" % self.sip_dir self.announce("Using %s for libsip files" % self.sip_dir) # Find the C library (libgcc, libgcc_s or some other variation). if self.clib is None: canidatepaths = ["/usr/"+get_libdir_name(), "/usr/local/"+get_libdir_name() ] self.clib = FindFileInPaths("libgcc*.so",canidatepaths) if self.clib!=None: self.clib = glob.glob(os.path.join(self.clib,'libgcc*.so'))[0] else: self.clib = FindFileInPaths("libgcc*.a",canidatepaths) if self.clib!=None: self.clib = glob.glob(os.path.join(self.clib,'libgcc*.a'))[0] if self.clib is None: raise SystemExit, "Failed to find a suitable libgcc library" self.announce("Using %s for clib" % self.clib) # Make a list of places to look for python .so modules self.python_sub_dirs = sysconfig.get_config_var("LIBSUBDIRS").split() base = sysconfig.get_config_var("LIBP") self.python_sub_dirs = [ os.path.join(base,item) for item in self.python_sub_dirs ] self.python_sub_dirs.append(base) def get_command_name(self): return 'build_kioslave' def run(self): if self.no_kioslave: self.announce("Skipping KIO Slaves") return if not os.path.isdir(self.build_dir): os.mkdir(self.build_dir) for moduletuple in self.distribution.kioslaves: self.announce("Building KIO Slave from protocol file %s." % moduletuple[0]) protocolfilename = moduletuple[0] # Read the protocol file libraryname = None try: fhandle = open(protocolfilename,'r') for line in fhandle.readlines(): parts = line.strip().split('=') try: if parts[0]=="exec": libraryname = parts[1] except IndexError: pass fhandle.close() except IOError: raise SystemExit, "Failed to find kioslave protocol file: %s" % moduletuple[0] # Sanity check. if libraryname is None: raise SystemExit, "Failed to find library name (Was there a exec entry in the protocol file?)" modulename = os.path.basename(moduletuple[1]) if modulename.endswith('.py'): modulename = modulename[:-3] stub_cpp_name = libraryname+'.cpp' stub_so_name = libraryname+'.so' stub_la_name = libraryname+'.la' python_version = '%i.%i' % (sys.version_info[0],sys.version_info[1]) # Build the 'stub' code. cppcode = self.cpptemplate % {"moduledir": self.data_dir, "modulename": modulename, "python_version": python_version} # Put it on disk. cppfile = os.path.join(os.path.dirname(moduletuple[0]),stub_cpp_name) try: fhandle = open(cppfile,'w') fhandle.write(cppcode) fhandle.close() except IOError: raise SystemExit, "Could not write the C++ stub: %s" % cppfile # Compile the stub library. cmdlist = ['libtool'] # Couldn't get it to pass without this ... cmdlist.append("--mode=compile") cmdlist.append("--tag=CXX") # Find the compiler flags and options # CXX is empty on some Systems, let's do it 'the hard way'. # FIXME :: get CXX from make.conf for Gentoo. if len(sysconfig.get_config_var("CXX").split()) >= 2: cmdlist.extend(sysconfig.get_config_var("CXX").split()) else: cmdlist.extend(['g++', '-pthread']) #cmdlist.extend(sysconfig.get_config_var("CXX").split()) # cc_flags cmdlist.append("-c") cmdlist.append("-g") # The 4 is randomly chosen! # FIXME :: get CFLAGS from make.conf for Gentoo. if len(sysconfig.get_config_var("CFLAGS").split()) >=4: cmdlist.extend(sysconfig.get_config_var("CFLAGS").split()) else: # On Gentoo systems, CFLAGS are not in the environment. raw = os.popen('emerge info 2> /dev/null|grep CFLAGS') lines = raw.readlines() if len(lines): cflags = lines[0].split('"')[1].split() print "Got CFLAGS from emerge info." cmdlist.extend(cflags) else: # Still no CFLAGS found, use these ... cmdlist.extend(['-fno-strict-aliasing', '-DNDEBUG', '-g', '-O3', '-Wall', '-Wstrict-prototypes']) #sysconfig.get_config_var("CFLAGS").split() # includes cmdlist.append("-I" + sysconfig.get_config_var("INCLUDEDIR")) cmdlist.append("-I" + sysconfig.get_config_var("INCLUDEDIR")) cmdlist.append("-I" + sysconfig.get_config_var("INCLUDEPY")) cmdlist.append("-I" + self.python_inc_dir) cmdlist.append("-I" + self.kde_inc_dir) cmdlist.append("-I" + self.qt_inc_dir) cmdlist.append("-I.") # input cmdlist.append(cppfile) # output outputfile = os.path.join(self.build_dir,libraryname+'.lo') cmdlist.append("-o") cmdlist.append(outputfile) spawn(cmdlist) # Execute!!! print # Link the resulting object file to create a shared library. cmdlist = ['libtool'] cmdlist.append("--mode=link") # Grab the linker command name cmdlist.append(sysconfig.get_config_var("LDSHARED").split()[0]) # link_flags cmdlist.append("-module") cmdlist.append("-export-dynamic") # object cmdlist.append(outputfile) cmdlist.append("-rpath"); cmdlist.append(self.kde_kioslave_lib_dir) cmdlist.append("-o"); cmdlist.append(os.path.join(self.build_dir,stub_la_name)) # Link libs linklist = [] linklist.append("-lpython%s" % python_version) linklist.extend(sysconfig.get_config_var("LIBS").split()) # FIXME I doubt half of these libraries need to be here. linklist.append(self.sip_dir+"/sip.so") # PyQt libs linklist.append(self.pyqt_dir+"/qt.so") # PyKDE libs linklist.append(self.pykde_dir+"/kdecore.so") # linklist.append("-L"+self.sip_dir); linklist.append("-lsip") # # PyQt libs # linklist.append("-L"+self.pyqt_dir); linklist.append("-lqtcmodule") # # PyKDE libs # linklist.append("-L"+self.pykde_dir); linklist.append("-lkdecorecmodule"); linklist.append("-lkdeuicmodule") linklist.append("-L"+self.kde_lib_dir); linklist.append("-L/opt/kde3/lib"); linklist.append("-lkdecore"); linklist.append("-lpythonize") linklist.append("-L"+self.qt_lib_dir); linklist.append("-lqt-mt") linklist.append("-lm") linklist.append("-lstdc++") linklist.append("-lc") linklist.append(self.clib) linklist.append("-R"); linklist.append(self.python_dir) linklist.append("-R"); linklist.append(self.qt_lib_dir) linklist.append("-R"); linklist.append(self.sip_dir) linklist.append("-R"); linklist.append(self.pyqt_dir) linklist.append("-R"); linklist.append(self.pykde_dir) linklist.append("-R"); linklist.append(self.kde_lib_dir) cmdlist.extend(linklist) spawn(cmdlist) # Execute!! print cpptemplate = r""" /* * Launch Control Centre modules written in Python using an embedded Python * interpreter. * Based on David Boddie's PyKDE-components. */ #include #include #include #define MODULE_DIR "%(moduledir)s" #define MODULE_NAME "%(modulename)s" #define FACTORY "SlaveFactory" const char modname[] = MODULE_NAME; #define MAIN_METHOD "dispatchLoop" FILE *d = NULL; PyObject* call_function(PyObject *callable, PyObject *args) { PyObject *result, *pArgs; if (callable == NULL) { printf(MODULE_NAME " kioslave error: callable == NULL in call_function\n"); return NULL; } if (PyCallable_Check(callable)) { if(args == NULL) { pArgs = PyTuple_New(0); } else { pArgs = args; } result = PyObject_CallObject(callable, pArgs); /* If the arguments were created is this function then decrease their reference count. */ if(args == NULL) { Py_XDECREF(pArgs); /* pDict and pFunc are borrowed and must not be Py_DECREF-ed */ } if(result == NULL) { PyErr_Print(); PyErr_Clear(); } } return result; } extern "C" { int kdemain( int argc, char **argv) { PyObject *pModule, *pName, *pDict; KInstance slave(MODULE_NAME); Py_SetProgramName(argv[0]); Py_Initialize(); //PyEval_InitThreads(); PySys_SetArgv(1, argv); PyRun_SimpleString("import sys\n"); PyRun_SimpleString("sys.path.append('"MODULE_DIR"')\n"); pName = PyString_FromString(modname); pModule = PyImport_Import(pName); Py_XDECREF(pName); if(pModule == NULL) { printf(MODULE_NAME " kioslave error: pModule == NULL\n"); return 1; } else { PyObject *pClass, *pMethod, *pArgs, *pArg1, *pArg2, *pInstance; int i; pDict = PyModule_GetDict(pModule); /* pDict is a borrowed reference */ pClass = PyDict_GetItemString(pDict, FACTORY); if(pClass == NULL) { printf(MODULE_NAME " kioslave error: pClass == NULL\n"); return 1; } else { pArgs = PyTuple_New(2); pArg1 = PyString_FromString(argv[2]); pArg2 = PyString_FromString(argv[3]); PyTuple_SetItem(pArgs, 0, pArg1); PyTuple_SetItem(pArgs, 1, pArg2); call_function(pClass, pArgs); /* Some time later... */ Py_XDECREF(pClass); Py_XDECREF(pArgs); } Py_XDECREF(pModule); } Py_Finalize(); return 0; } } """ ########################################################################### class InstallKioslave(Command): description = "Install Kioslave files" user_options = [ ('install-dir=', 'd', "base directory for installing kioslave module files"), ('install-cmd=', None, "Command to use to install the files"), ('install-protocol-dir=',None,"directory for kioslave protocol files"), ('build-dir=','b', "build directory (where to install from)"), ('root=', None, "install everything relative to this alternate root directory"), ('force', 'f', "force installation (overwrite existing files)"), ('skip-build', None, "skip the build steps"), ] boolean_options = ['force', 'skip-build'] def initialize_options(self): self.build_dir = None self.install_dir = None self.install_cmd = None self.install_protocol_dir = None self.outfiles = [] self.root = None self.force = 0 self.warn_dir = 1 self.skip_build = None def finalize_options(self): own_install_dir = self.install_dir is not None own_install_protocol_dir = self.install_protocol_dir is not None self.set_undefined_options('install', ('build_base', 'build_dir'), ('install_kioslave', 'install_dir'), ('root', 'root'), ('force', 'force'), ('skip_build', 'skip_build'), ('install_cmd', 'install_cmd'), ('install_protocol','install_protocol_dir') ) if own_install_dir and self.root is not None: self.install_dir = change_root(self.root,self.installdir) if own_install_protocol_dir and self.root is not None: self.install_protocol_dir = change_root(self.root,self.install_protocol_dir) def get_command_name(self): return 'install_kioslave' def run(self): if not self.skip_build: self.run_command('build_kioslave') self.announce("Installing Kioslave files...") for moduletuple in self.distribution.kioslaves: self.announce("Building Kioslave module from protocol file %s." % moduletuple[0]) protocolfilename = moduletuple[0] # Read the protocol file libraryname = None try: fhandle = open(protocolfilename,'r') for line in fhandle.readlines(): parts = line.strip().split('=') try: if parts[0]=="exec": libraryname = parts[1] except IndexError: pass fhandle.close() except IOError: raise SystemExit, "Failed to find kioslave protocol file: %s" % moduletuple[0] if libraryname is None: raise SystemExit, "Failed to find library name (Was there a exec entry in the protocol file?)" self.outfiles.extend(self.mkpath(self.install_protocol_dir)) protocolfile_dest = os.path.join(self.install_protocol_dir,os.path.basename(protocolfilename)) self.copy_file(protocolfilename, protocolfile_dest) stub_la_name = libraryname+'.la' self.outfiles.extend(self.mkpath(self.install_dir)) # Install the library. cmdlist = ['libtool'] cmdlist.append("--mode=install") cmdlist.append(self.install_cmd) cmdlist.append("-c") cmdlist.append(os.path.join(self.build_dir,stub_la_name)) cmdlist.append(os.path.join(self.install_dir,stub_la_name)) spawn(cmdlist) # Execute!! print self.outfiles = [os.path.join(self.install_dir,os.path.basename(file)) for file in glob.glob(os.path.join(self.build_dir,'.libs',libraryname+'*'))] self.outfiles.append(protocolfile_dest) self.announce("Done installing Kioslave files.") def get_outputs(self): return self.outfiles or [] def mkpath(self, name, mode=0777): return dir_util.mkpath(name, mode, dry_run=self.dry_run) ########################################################################### class CheckPyQt(Command): description = "Checks for the presence of a working PyQt installation" user_options = [] def initialize_options(self): pass def finalize_options(self): self.min_qt_version = self.distribution.min_qt_version def run(self): if self.min_qt_version!=None: qtver,kdever = get_qt_kde_versions() if compare_versions(self.min_qt_version,qtver)==1: raise SystemExit, "Your Qt version is too old. Version %s or higher is required, found %s." % (self.min_qt_version,qtver) self.announce("Found Qt version %s." % qtver) try: self.announce("Checking for a working PyQt...") import qt self.announce(" ...PyQt is working") except: raise SystemExit, "Couldn't import Qt! Please make sure that PyQt is installed and working." def get_outputs(self): return [] ########################################################################### class CheckPyKDE(Command): description = "Checks for the presence of a working PyKDE installation" user_options = [] def initialize_options(self): pass def finalize_options(self): self.min_kde_version = self.distribution.min_kde_version def run(self): if self.min_kde_version!=None: qtver,kdever = get_qt_kde_versions() if compare_versions(self.min_kde_version,kdever)==1: raise SystemExit, "Your KDE version is too old. Version %s or higher is required, found %s." % (self.min_kde_version,kdever) self.announce("Found KDE version %s." % kdever) self.announce("Checking for a working PyKDE...") # Try to import modules one by one. for k_module in ('dcop', 'kdecore', 'kdeui', 'kio', 'kfile', 'kparts', 'khtml', 'kspell'): self.announce(k_module) try: exec('import ' + k_module) except: raise SystemExit, "Error: Couldn't find module '" + k_module + "'. \n" + \ "Couldn't import KDE! Please make sure that PyKDE is installed and working.\n" + \ "PyKDE is available here: http://www.riverbankcomputing.co.uk/pykde/index.php" self.announce(" ...PyKDE is working") def get_outputs(self): return [] ########################################################################### def FindFileInPaths2(globpattern,canidatepaths): if canidatepaths is None or len(canidatepaths)==0: return (None,None) # Look for the globpattern on the path. for path in canidatepaths: if path!=None: files = glob.glob(os.path.join(path, globpattern)) if len(files)!=0: return (path,os.path.basename(files[0])) # Continue searching with a breadth first search. dirs = [] for path in canidatepaths: # Examine any directories on this path. dirlist = glob.glob(os.path.join(path, "*")) for item in dirlist: if os.path.isdir(item): # Examine each subdirectory. dirs.append(item) # Examine all subdirectories. return FindFileInPaths2(globpattern, dirs) ########################################################################### def FindFileInPaths(globpattern,canidatepaths): x,y = FindFileInPaths2(globpattern,canidatepaths) return x ########################################################################### # FIXME replace this with spawn.find_executable(). def FindExeOnPath(exe_name,high_prio_dirs=None,low_prio_dirs=None): candiate_paths = [] if high_prio_dirs is not None: candiate_paths.extend(high_prio_dirs) path_var = os.getenv("PATH") candiate_paths.extend(path_var.split(':')) if low_prio_dirs is not None: candiate_paths.extend(low_prio_dirs) for dir in candiate_paths: if dir is not None: candiate = os.path.join(dir,exe_name) if os.path.isfile(candiate): if os.access(candiate,os.X_OK): return candiate return None ########################################################################### def ask_kde_config(question): # Look for the kde-config program kdeconfig = find_executable("kde-config", os.environ['PATH'] + os.pathsep + \ os.pathsep.join(['/bin','/usr/bin','/opt/kde3/bin','/opt/kde/bin','/usr/local/bin'])) if kdeconfig!=None: # Ask the kde-config program for the fhandle = os.popen(kdeconfig+' ' + question,'r') result = fhandle.read() fhandle.close() return result else: return None ########################################################################### # Convert for example, "3.1.1a" => [3,1,1,'a'] # def split_version_name(name): result = [] accu = '' type = 0 for c in name: if type==0: if c.isdigit(): type = 1 else: type = 2 accu += c elif c=='.': if type==1: result.append(int(accu)) else: result.append(accu) accu = '' type = 0 elif type==1: # Digits if c.isdigit(): accu += c else: result.append(int(accu)) type = 2 accu = c else: if c.isdigit(): result.append(accu) type = 1 accu = c else: accu += c if accu!='': result.append(accu) return result ########################################################################### # # Returns: # -1 if a < b # 0 if a and b are equal # 1 if a > b def compare_versions(a,b): aparts = split_version_name(a) bparts = split_version_name(b) if len(aparts)>len(bparts): compmax = len(aparts) else: compmax = len(bparts) i = 0 for i in range(compmax): abit = 0 if ibbit: return 1 elif abit