diff options
Diffstat (limited to 'sip_tqt_distutils.py')
| -rw-r--r-- | sip_tqt_distutils.py | 148 | 
1 files changed, 148 insertions, 0 deletions
| diff --git a/sip_tqt_distutils.py b/sip_tqt_distutils.py new file mode 100644 index 0000000..6c6b9d9 --- /dev/null +++ b/sip_tqt_distutils.py @@ -0,0 +1,148 @@ +# Subclasses disutils.command.build_ext, +# replacing it with a SIP-TQt version that compiles .sip -> .cpp +# before calling the original build_ext command. +# Written by Giovanni Bajo <rasky at develer dot com> +# Based on Pyrex.Distutils, written by Graham Fawcett and Darrel Gallion. + +import distutils.command.build_ext +from distutils.dep_util import newer, newer_group +import os +import sys +from hashlib import sha1 + +build_ext_base = distutils.command.build_ext.build_ext + +def replace_suffix(path, new_suffix): +    return os.path.splitext(path)[0] + new_suffix + +class build_ext (build_ext_base): + +    description = "Compiler SIP-TQt descriptions, then build C/C++ extensions (compile/link to build directory)" + +    user_options = build_ext_base.user_options[:] +    user_options = [opt for opt in user_options if not opt[0].startswith("swig")] +    user_options += [ +        ('sip-opts=', None, +         "list of sip command line options"), +    ] + +    def initialize_options (self): +        build_ext_base.initialize_options(self) +        self.sip_opts = None + +    def finalize_options (self): +        build_ext_base.finalize_options(self) +        if self.sip_opts is None: +            self.sip_opts = [] +        else: +            self.sip_opts = self.sip_opts.split(' ') + +    def _get_sip_output_list(self, sbf): +        """ +        Parse the sbf file specified to extract the name of the generated source +        files. Make them absolute assuming they reside in the temp directory. +        """ +        for L in file(sbf): +            key, value = L.split("=", 1) +            if key.strip() == "sources": +                out = [] +                for o in value.split(): +                    out.append(os.path.join(self.build_temp, o)) +                return out + +        raise RuntimeError("cannot parse SIP-generated '%s'" % sbf) + +    def _find_sip(self): +        import sip_tqt_config +        cfg = sip_tqt_config.Configuration() +        if os.name == "nt": +            if not os.path.splitext(os.path.basename(cfg.sip_bin))[1]: +                return cfg.sip_bin + ".exe" +        return cfg.sip_bin + +    def _sip_inc_dir(self): +        import sip_tqt_config +        cfg = sip_tqt_config.Configuration() +        return cfg.sip_inc_dir + +    def _sip_sipfiles_dir(self): +        import sip_tqt_config +        cfg = sip_tqt_config.Configuration() +        return cfg.default_sip_dir + +    def _sip_calc_signature(self): +        sip_bin = self._find_sip() +        return sha1(open(sip_bin, "rb").read()).hexdigest() + +    def _sip_signature_file(self): +        return os.path.join(self.build_temp, "sip.signature") + +    def build_extension (self, ext): +        oldforce = self.force + +        if not self.force: +            sip_sources = [source for source in ext.sources if source.endswith('.sip')] +            if sip_sources: +                sigfile = self._sip_signature_file() +                if not os.path.isfile(sigfile): +                    self.force = True +                else: +                    old_sig = open(sigfile).read() +                    new_sig = self._sip_calc_signature() +                    if old_sig != new_sig: +                        self.force = True + +        build_ext_base.build_extension(self, ext) + +        self.force = oldforce + +    def swig_sources (self, sources, extension=None): +        if not self.extensions: +            return + +        # Add the SIP-TQt include directory to the include path +        if extension is not None: +            extension.include_dirs.append(self._sip_inc_dir()) +            depends = extension.depends +        else: +            # pre-2.4 compatibility +            self.include_dirs.append(self._sip_inc_dir()) +            depends = []  # ? + +        # Filter dependencies list: we are interested only in .sip files, +        # since the main .sip files can only depend on additional .sip +        # files. For instance, if a .h changes, there is no need to +        # run sip again. +        depends = [f for f in depends if os.path.splitext(f)[1] == ".sip"] + +        # Create the temporary directory if it does not exist already +        if not os.path.isdir(self.build_temp): +            os.makedirs(self.build_temp) + +        # Collect the names of the source (.sip) files +        sip_sources = [] +        sip_sources = [source for source in sources if source.endswith('.sip')] +        other_sources = [source for source in sources if not source.endswith('.sip')] +        generated_sources = [] + +        sip_bin = self._find_sip() + +        for sip in sip_sources: +            # Use the sbf file as dependency check +            sipbasename = os.path.basename(sip) +            sbf = os.path.join(self.build_temp, replace_suffix(sipbasename, ".sbf")) +            if newer_group([sip]+depends, sbf) or self.force: +                self._sip_compile(sip_bin, sip, sbf) +                open(self._sip_signature_file(), "w").write(self._sip_calc_signature()) +            out = self._get_sip_output_list(sbf) +            generated_sources.extend(out) + +        return generated_sources + other_sources + +    def _sip_compile(self, sip_bin, source, sbf): +        self.spawn([sip_bin] + self.sip_opts + +                    ["-c", self.build_temp, +                    "-b", sbf, +                    "-I", self._sip_sipfiles_dir(), +                    source]) + | 
