summaryrefslogtreecommitdiffstats
path: root/Lib/distutils/command/build_clib.py
blob: 26b89b3aba0bae75d84df019d0fe672251e02c0d (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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
"""distutils.command.build_lib

Implements the Distutils 'build_lib' command, to build a C/C++ library
that is included in the module distribution and needed by an extension
module."""

# created (an empty husk) 1999/12/18, Greg Ward
# fleshed out 2000/02/03-04

__rcsid__ = "$Id$"


# XXX this module has *lots* of code ripped-off quite transparently from
# build_ext.py -- not surprisingly really, as the work required to build
# a static library from a collection of C source files is not really all
# that different from what's required to build a shared object file from
# a collection of C source files.  Nevertheless, I haven't done the
# necessary refactoring to account for the overlap in code between the
# two modules, mainly because a number of subtle details changed in the
# cut 'n paste.  Sigh.

import os, string
from types import *
from distutils.core import Command
from distutils.errors import *
from distutils.ccompiler import new_compiler


class build_lib (Command):

    user_options = [
        ('debug', 'g',
         "compile with debugging information"),
        ]

    def set_default_options (self):
        # List of libraries to build
        self.libraries = None

        # Compilation options for all libraries
        self.include_dirs = None
        self.define = None
        self.undef = None
        self.debug = None

    # set_default_options()

    def set_final_options (self):
        self.set_undefined_options ('build',
                                    ('debug', 'debug'))
        self.libraries = self.distribution.libraries
        if self.include_dirs is None:
            self.include_dirs = self.distribution.include_dirs or []
        if type (self.include_dirs) is StringType:
            self.include_dirs = string.split (self.include_dirs,
                                              os.pathsep)

        # XXX same as for build_ext -- what about 'self.define' and
        # 'self.undef' ?

    # set_final_options()


    def run (self):

        if not self.libraries:
            return
        self.check_library_list (self.libraries)

        # Yech -- this is cut 'n pasted from build_ext.py!
        self.compiler = new_compiler (plat=os.environ.get ('PLAT'),
                                      verbose=self.verbose,
                                      dry_run=self.dry_run,
                                      force=self.force)
        if self.include_dirs is not None:
            self.compiler.set_include_dirs (self.include_dirs)
        if self.define is not None:
            # 'define' option is a list of (name,value) tuples
            for (name,value) in self.define:
                self.compiler.define_macro (name, value)
        if self.undef is not None:
            for macro in self.undef:
                self.compiler.undefine_macro (macro)

        self.build_libraries (self.libraries)

    # run()


    def check_library_list (self, libraries):
        """Ensure that the list of libraries (presumably provided as a
           command option 'libraries') is valid, i.e. it is a list of
           2-tuples, where the tuples are (library_name, build_info_dict).
           Raise DistutilsValueError if the structure is invalid anywhere;
           just returns otherwise."""

        # Yechh, blecch, ackk: this is ripped straight out of build_ext.py,
        # with only names changed to protect the innocent!

        if type (libraries) is not ListType:
            raise DistutilsValueError, \
                  "'libraries' option must be a list of tuples"

        for lib in libraries:
            if type (lib) is not TupleType and len (lib) != 2:
                raise DistutilsValueError, \
                      "each element of 'libraries' must a 2-tuple"

            if type (lib[0]) is not StringType:
                raise DistutilsValueError, \
                      "first element of each tuple in 'libraries' " + \
                      "must be a string (the library name)"
            if type (lib[1]) is not DictionaryType:
                raise DistutilsValueError, \
                      "second element of each tuple in 'libraries' " + \
                      "must be a dictionary (build info)"
        # for lib

    # check_library_list ()


    def build_libraries (self, libraries):

        compiler = self.compiler

        for (lib_name, build_info) in libraries:
            sources = build_info.get ('sources')
            if sources is None or type (sources) not in (ListType, TupleType):
                raise DistutilsValueError, \
                      ("in 'libraries' option (library '%s'), " +
                       "'sources' must be present and must be " +
                       "a list of source filenames") % lib_name
            sources = list (sources)

            self.announce ("building '%s' library" % lib_name)

            # Extract the directory the library is intended to go in --
            # note translation from "universal" slash-separated form to
            # current platform's pathname convention (so we can use the
            # string for actual filesystem use).
            path = tuple (string.split (lib_name, '/')[:-1])
            if path:
                lib_dir = apply (os.path.join, path)
            else:
                lib_dir = ''

            # First, compile the source code to object files in the library
            # directory.  (This should probably change to putting object
            # files in a temporary build directory.)
            macros = build_info.get ('macros')
            include_dirs = build_info.get ('include_dirs')
            objects = self.compiler.compile (sources,
                                             macros=macros,
                                             include_dirs=include_dirs,
                                             output_dir=lib_dir,
                                             debug=self.debug)

            # Now "link" the object files together into a static library.
            # (On Unix at least, this isn't really linking -- it just
            # builds an archive.  Whatever.)
            self.compiler.link_static_lib (objects, lib_name, debug=self.debug)

        # for libraries

    # build_libraries ()
                

# class BuildLib