summaryrefslogtreecommitdiffstats
path: root/python/sip/sipdistutils.py
blob: 1c2ab7ed5ec341c345520690aa855048c12f8179 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# Subclasses disutils.command.build_ext,
# replacing it with a SIP 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

def replace_suffix(path, new_suffix):
    return os.path.splitext(path)[0] + new_suffix

class build_ext (distutils.command.build_ext.build_ext):

    description = "Compiler SIP descriptions, then build C/C++ extensions (compile/link to build directory)"

    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 sipconfig
        cfg = sipconfig.Configuration()
        return cfg.sip_bin

    def _sip_inc_dir(self):
        import sipconfig
        cfg = sipconfig.Configuration()
        return cfg.sip_inc_dir

    def swig_sources (self, sources, extension=None):
        if not self.extensions:
            return

        # Add the SIP 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)
            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,
                    "-c", self.build_temp,
                    "-b", sbf,
                    source])