~ubuntu-branches/ubuntu/maverick/python3.1/maverick

« back to all changes in this revision

Viewing changes to Lib/distutils/command/build_clib.py

  • Committer: Bazaar Package Importer
  • Author(s): Matthias Klose
  • Date: 2009-03-23 00:01:27 UTC
  • Revision ID: james.westby@ubuntu.com-20090323000127-5fstfxju4ufrhthq
Tags: upstream-3.1~a1+20090322
ImportĀ upstreamĀ versionĀ 3.1~a1+20090322

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
"""distutils.command.build_clib
 
2
 
 
3
Implements the Distutils 'build_clib' command, to build a C/C++ library
 
4
that is included in the module distribution and needed by an extension
 
5
module."""
 
6
 
 
7
__revision__ = "$Id: build_clib.py 58495 2007-10-16 18:12:55Z guido.van.rossum $"
 
8
 
 
9
 
 
10
# XXX this module has *lots* of code ripped-off quite transparently from
 
11
# build_ext.py -- not surprisingly really, as the work required to build
 
12
# a static library from a collection of C source files is not really all
 
13
# that different from what's required to build a shared object file from
 
14
# a collection of C source files.  Nevertheless, I haven't done the
 
15
# necessary refactoring to account for the overlap in code between the
 
16
# two modules, mainly because a number of subtle details changed in the
 
17
# cut 'n paste.  Sigh.
 
18
 
 
19
import os
 
20
from distutils.core import Command
 
21
from distutils.errors import *
 
22
from distutils.sysconfig import customize_compiler
 
23
from distutils import log
 
24
 
 
25
def show_compilers():
 
26
    from distutils.ccompiler import show_compilers
 
27
    show_compilers()
 
28
 
 
29
 
 
30
class build_clib(Command):
 
31
 
 
32
    description = "build C/C++ libraries used by Python extensions"
 
33
 
 
34
    user_options = [
 
35
        ('build-clib', 'b',
 
36
         "directory to build C/C++ libraries to"),
 
37
        ('build-temp', 't',
 
38
         "directory to put temporary build by-products"),
 
39
        ('debug', 'g',
 
40
         "compile with debugging information"),
 
41
        ('force', 'f',
 
42
         "forcibly build everything (ignore file timestamps)"),
 
43
        ('compiler=', 'c',
 
44
         "specify the compiler type"),
 
45
        ]
 
46
 
 
47
    boolean_options = ['debug', 'force']
 
48
 
 
49
    help_options = [
 
50
        ('help-compiler', None,
 
51
         "list available compilers", show_compilers),
 
52
        ]
 
53
 
 
54
    def initialize_options(self):
 
55
        self.build_clib = None
 
56
        self.build_temp = None
 
57
 
 
58
        # List of libraries to build
 
59
        self.libraries = None
 
60
 
 
61
        # Compilation options for all libraries
 
62
        self.include_dirs = None
 
63
        self.define = None
 
64
        self.undef = None
 
65
        self.debug = None
 
66
        self.force = 0
 
67
        self.compiler = None
 
68
 
 
69
 
 
70
    def finalize_options(self):
 
71
        # This might be confusing: both build-clib and build-temp default
 
72
        # to build-temp as defined by the "build" command.  This is because
 
73
        # I think that C libraries are really just temporary build
 
74
        # by-products, at least from the point of view of building Python
 
75
        # extensions -- but I want to keep my options open.
 
76
        self.set_undefined_options('build',
 
77
                                   ('build_temp', 'build_clib'),
 
78
                                   ('build_temp', 'build_temp'),
 
79
                                   ('compiler', 'compiler'),
 
80
                                   ('debug', 'debug'),
 
81
                                   ('force', 'force'))
 
82
 
 
83
        self.libraries = self.distribution.libraries
 
84
        if self.libraries:
 
85
            self.check_library_list(self.libraries)
 
86
 
 
87
        if self.include_dirs is None:
 
88
            self.include_dirs = self.distribution.include_dirs or []
 
89
        if isinstance(self.include_dirs, str):
 
90
            self.include_dirs = self.include_dirs.split(os.pathsep)
 
91
 
 
92
        # XXX same as for build_ext -- what about 'self.define' and
 
93
        # 'self.undef' ?
 
94
 
 
95
 
 
96
    def run(self):
 
97
        if not self.libraries:
 
98
            return
 
99
 
 
100
        # Yech -- this is cut 'n pasted from build_ext.py!
 
101
        from distutils.ccompiler import new_compiler
 
102
        self.compiler = new_compiler(compiler=self.compiler,
 
103
                                     dry_run=self.dry_run,
 
104
                                     force=self.force)
 
105
        customize_compiler(self.compiler)
 
106
 
 
107
        if self.include_dirs is not None:
 
108
            self.compiler.set_include_dirs(self.include_dirs)
 
109
        if self.define is not None:
 
110
            # 'define' option is a list of (name,value) tuples
 
111
            for (name,value) in self.define:
 
112
                self.compiler.define_macro(name, value)
 
113
        if self.undef is not None:
 
114
            for macro in self.undef:
 
115
                self.compiler.undefine_macro(macro)
 
116
 
 
117
        self.build_libraries(self.libraries)
 
118
 
 
119
 
 
120
    def check_library_list(self, libraries):
 
121
        """Ensure that the list of libraries (presumably provided as a
 
122
           command option 'libraries') is valid, i.e. it is a list of
 
123
           2-tuples, where the tuples are (library_name, build_info_dict).
 
124
           Raise DistutilsSetupError if the structure is invalid anywhere;
 
125
           just returns otherwise."""
 
126
        # Yechh, blecch, ackk: this is ripped straight out of build_ext.py,
 
127
        # with only names changed to protect the innocent!
 
128
        if not isinstance(libraries, list):
 
129
            raise DistutilsSetupError(
 
130
                  "'libraries' option must be a list of tuples")
 
131
 
 
132
        for lib in libraries:
 
133
            if not isinstance(lib, tuple) and len(lib) != 2:
 
134
                raise DistutilsSetupError(
 
135
                      "each element of 'libraries' must a 2-tuple")
 
136
 
 
137
            if isinstance(lib[0], str):
 
138
                raise DistutilsSetupError(
 
139
                      "first element of each tuple in 'libraries' "
 
140
                      "must be a string (the library name)")
 
141
            if '/' in lib[0] or (os.sep != '/' and os.sep in lib[0]):
 
142
                raise DistutilsSetupError("bad library name '%s': "
 
143
                       "may not contain directory separators" % lib[0])
 
144
 
 
145
            if not isinstance(lib[1], dict):
 
146
                raise DistutilsSetupError(
 
147
                      "second element of each tuple in 'libraries' "
 
148
                      "must be a dictionary (build info)")
 
149
 
 
150
 
 
151
    def get_library_names(self):
 
152
        # Assume the library list is valid -- 'check_library_list()' is
 
153
        # called from 'finalize_options()', so it should be!
 
154
        if not self.libraries:
 
155
            return None
 
156
 
 
157
        lib_names = []
 
158
        for (lib_name, build_info) in self.libraries:
 
159
            lib_names.append(lib_name)
 
160
        return lib_names
 
161
 
 
162
 
 
163
    def get_source_files(self):
 
164
        self.check_library_list(self.libraries)
 
165
        filenames = []
 
166
        for (lib_name, build_info) in self.libraries:
 
167
            sources = build_info.get('sources')
 
168
            if sources is None or not isinstance(sources, (list, tuple)):
 
169
                raise DistutilsSetupError(
 
170
                       "in 'libraries' option (library '%s'), "
 
171
                       "'sources' must be present and must be "
 
172
                       "a list of source filenames" % lib_name)
 
173
 
 
174
            filenames.extend(sources)
 
175
        return filenames
 
176
 
 
177
 
 
178
    def build_libraries(self, libraries):
 
179
        for (lib_name, build_info) in libraries:
 
180
            sources = build_info.get('sources')
 
181
            if sources is None or not isinstance(sources, (list, tuple)):
 
182
                raise DistutilsSetupError(
 
183
                       "in 'libraries' option (library '%s'), "
 
184
                       "'sources' must be present and must be "
 
185
                       "a list of source filenames" % lib_name)
 
186
            sources = list(sources)
 
187
 
 
188
            log.info("building '%s' library", lib_name)
 
189
 
 
190
            # First, compile the source code to object files in the library
 
191
            # directory.  (This should probably change to putting object
 
192
            # files in a temporary build directory.)
 
193
            macros = build_info.get('macros')
 
194
            include_dirs = build_info.get('include_dirs')
 
195
            objects = self.compiler.compile(sources,
 
196
                                            output_dir=self.build_temp,
 
197
                                            macros=macros,
 
198
                                            include_dirs=include_dirs,
 
199
                                            debug=self.debug)
 
200
 
 
201
            # Now "link" the object files together into a static library.
 
202
            # (On Unix at least, this isn't really linking -- it just
 
203
            # builds an archive.  Whatever.)
 
204
            self.compiler.create_static_lib(objects, lib_name,
 
205
                                            output_dir=self.build_clib,
 
206
                                            debug=self.debug)