~vcs-imports/kupfer/master-new

« back to all changes in this revision

Viewing changes to waflib/Tools/ccroot.py

  • Committer: Ulrik Sverdrup
  • Date: 2012-02-26 17:32:06 UTC
  • mto: This revision was merged to the branch mainline in revision 2918.
  • Revision ID: git-v1:684a1e79e28fa3d9e346bdf2c1659e7d2c6e7718
Add waf-light and waflib from waf-1.6.11

http://code.google.com/p/waf/
Acquired from: http://waf.googlecode.com/files/waf-1.6.11.tar.bz2

"""
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

1. Redistributions of source code must retain the above copyright
   notice, this list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright
   notice, this list of conditions and the following disclaimer in the
   documentation and/or other materials provided with the distribution.

3. The name of the author may not be used to endorse or promote products
   derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
"""

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/env python
 
2
# encoding: utf-8
 
3
# Thomas Nagy, 2005-2010 (ita)
 
4
 
 
5
"""
 
6
Classes and methods shared by tools providing support for C-like language such
 
7
as C/C++/D/Assembly/Go (this support module is almost never used alone).
 
8
"""
 
9
 
 
10
import os, sys, re
 
11
from waflib import TaskGen, Task, Utils, Logs, Build, Options, Node, Errors
 
12
from waflib.Logs import error, debug, warn
 
13
from waflib.TaskGen import after_method, before_method, feature, taskgen_method, extension
 
14
from waflib.Tools import c_aliases, c_preproc, c_config, c_osx, c_tests
 
15
from waflib.Configure import conf
 
16
 
 
17
USELIB_VARS = Utils.defaultdict(set)
 
18
"""
 
19
Mapping for features to :py:class:`waflib.ConfigSet.ConfigSet` variables. See :py:func:`waflib.Tools.ccroot.propagate_uselib_vars`.
 
20
"""
 
21
 
 
22
USELIB_VARS['c']   = set(['INCLUDES', 'FRAMEWORKPATH', 'DEFINES', 'CPPFLAGS', 'CCDEPS', 'CFLAGS', 'ARCH'])
 
23
USELIB_VARS['cxx'] = set(['INCLUDES', 'FRAMEWORKPATH', 'DEFINES', 'CPPFLAGS', 'CXXDEPS', 'CXXFLAGS', 'ARCH'])
 
24
USELIB_VARS['d']   = set(['INCLUDES', 'DFLAGS'])
 
25
 
 
26
USELIB_VARS['cprogram'] = USELIB_VARS['cxxprogram'] = set(['LIB', 'STLIB', 'LIBPATH', 'STLIBPATH', 'LINKFLAGS', 'RPATH', 'LINKDEPS', 'FRAMEWORK', 'FRAMEWORKPATH', 'ARCH'])
 
27
USELIB_VARS['cshlib']   = USELIB_VARS['cxxshlib']   = set(['LIB', 'STLIB', 'LIBPATH', 'STLIBPATH', 'LINKFLAGS', 'RPATH', 'LINKDEPS', 'FRAMEWORK', 'FRAMEWORKPATH', 'ARCH'])
 
28
USELIB_VARS['cstlib']   = USELIB_VARS['cxxstlib']   = set(['ARFLAGS', 'LINKDEPS'])
 
29
 
 
30
USELIB_VARS['dprogram'] = set(['LIB', 'STLIB', 'LIBPATH', 'STLIBPATH', 'LINKFLAGS', 'RPATH', 'LINKDEPS'])
 
31
USELIB_VARS['dshlib']   = set(['LIB', 'STLIB', 'LIBPATH', 'STLIBPATH', 'LINKFLAGS', 'RPATH', 'LINKDEPS'])
 
32
USELIB_VARS['dstlib']   = set(['ARFLAGS', 'LINKDEPS'])
 
33
 
 
34
USELIB_VARS['go'] = set(['GOCFLAGS'])
 
35
USELIB_VARS['goprogram'] = set(['GOLFLAGS'])
 
36
 
 
37
USELIB_VARS['asm'] = set(['ASFLAGS'])
 
38
 
 
39
# =================================================================================================
 
40
 
 
41
@taskgen_method
 
42
def create_compiled_task(self, name, node):
 
43
        """
 
44
        Create the compilation task: c, cxx, asm, etc. The output node is created automatically (object file with a typical **.o** extension).
 
45
        The task is appended to the list *compiled_tasks* which is then used by :py:func:`waflib.Tools.ccroot.apply_link`
 
46
 
 
47
        :param name: name of the task class
 
48
        :type name: string
 
49
        :param node: the file to compile
 
50
        :type node: :py:class:`waflib.Node.Node`
 
51
        :return: The task created
 
52
        :rtype: :py:class:`waflib.Task.Task`
 
53
        """
 
54
        out = '%s.%d.o' % (node.name, self.idx)
 
55
        task = self.create_task(name, node, node.parent.find_or_declare(out))
 
56
        try:
 
57
                self.compiled_tasks.append(task)
 
58
        except AttributeError:
 
59
                self.compiled_tasks = [task]
 
60
        return task
 
61
 
 
62
@taskgen_method
 
63
def to_incnodes(self, inlst):
 
64
        """
 
65
        Task generator method provided to convert a list of string/nodes into a list of includes folders.
 
66
 
 
67
        The paths are assumed to be relative to the task generator path, except if they begin by **#**
 
68
        in which case they are searched from the top-level directory (``bld.srcnode``).
 
69
        The folders are simply assumed to be existing.
 
70
 
 
71
        The node objects in the list are returned in the output list. The strings are converted
 
72
        into node objects if possible. The node is searched from the source directory, and if a match is found,
 
73
        the equivalent build directory is created and added to the returned list too. When a folder cannot be found, it is ignored.
 
74
 
 
75
        :param inlst: list of folders
 
76
        :type inlst: space-delimited string or a list of string/nodes
 
77
        :rtype: list of :py:class:`waflib.Node.Node`
 
78
        :return: list of include folders as nodes
 
79
        """
 
80
        lst = []
 
81
        seen = set([])
 
82
        for x in self.to_list(inlst):
 
83
                if x in seen or not x:
 
84
                        continue
 
85
                seen.add(x)
 
86
 
 
87
                if isinstance(x, Node.Node):
 
88
                        lst.append(x)
 
89
                else:
 
90
                        if os.path.isabs(x):
 
91
                                lst.append(self.bld.root.make_node(x) or x)
 
92
                        else:
 
93
                                if x[0] == '#':
 
94
                                        p = self.bld.bldnode.make_node(x[1:])
 
95
                                        v = self.bld.srcnode.make_node(x[1:])
 
96
                                else:
 
97
                                        p = self.path.get_bld().make_node(x)
 
98
                                        v = self.path.make_node(x)
 
99
                                if p.is_child_of(self.bld.bldnode):
 
100
                                        p.mkdir()
 
101
                                lst.append(p)
 
102
                                lst.append(v)
 
103
        return lst
 
104
 
 
105
@feature('c', 'cxx', 'd', 'go', 'asm', 'fc', 'includes')
 
106
@after_method('propagate_uselib_vars', 'process_source')
 
107
def apply_incpaths(self):
 
108
        """
 
109
        Task generator method that processes the attribute *includes*::
 
110
 
 
111
                tg = bld(features='includes', includes='.')
 
112
 
 
113
        The folders only need to be relative to the current directory, the equivalent build directory is
 
114
        added automatically (for headers created in the build directory). This enable using a build directory
 
115
        or not (``top == out``).
 
116
 
 
117
        This method will add a list of nodes read by :py:func:`waflib.Tools.ccroot.to_incnodes` in ``tg.env.INCPATHS``,
 
118
        and the list of include paths in ``tg.env.INCLUDES``.
 
119
        """
 
120
 
 
121
        lst = self.to_incnodes(self.to_list(getattr(self, 'includes', [])) + self.env['INCLUDES'])
 
122
        self.includes_nodes = lst
 
123
        self.env['INCPATHS'] = [x.abspath() for x in lst]
 
124
 
 
125
class link_task(Task.Task):
 
126
        """
 
127
        Base class for all link tasks. A task generator is supposed to have at most one link task bound in the attribute *link_task*. See :py:func:`waflib.Tools.ccroot.apply_link`.
 
128
 
 
129
        .. inheritance-diagram:: waflib.Tools.ccroot.stlink_task waflib.Tools.c.cprogram waflib.Tools.c.cshlib waflib.Tools.cxx.cxxstlib  waflib.Tools.cxx.cxxprogram waflib.Tools.cxx.cxxshlib waflib.Tools.d.dprogram waflib.Tools.d.dshlib waflib.Tools.d.dstlib waflib.Tools.ccroot.fake_shlib waflib.Tools.ccroot.fake_stlib waflib.Tools.asm.asmprogram waflib.Tools.asm.asmshlib waflib.Tools.asm.asmstlib
 
130
        """
 
131
        color   = 'YELLOW'
 
132
 
 
133
        inst_to = None
 
134
        """Default installation path for the link task outputs, or None to disable"""
 
135
 
 
136
        chmod   = Utils.O644
 
137
        """Default installation mode for the link task outputs"""
 
138
 
 
139
        def add_target(self, target):
 
140
                """
 
141
                Process the *target* attribute to add the platform-specific prefix/suffix such as *.so* or *.exe*.
 
142
                The settings are retrieved from ``env.clsname_PATTERN``
 
143
                """
 
144
                if isinstance(target, str):
 
145
                        pattern = self.env[self.__class__.__name__ + '_PATTERN']
 
146
                        if not pattern:
 
147
                                pattern = '%s'
 
148
                        folder, name = os.path.split(target)
 
149
 
 
150
                        if self.__class__.__name__.find('shlib') > 0:
 
151
                                if self.env.DEST_BINFMT == 'pe' and getattr(self.generator, 'vnum', None):
 
152
                                        # include the version in the dll file name,
 
153
                                        # the import lib file name stays unversionned.
 
154
                                        name = name + '-' + self.generator.vnum.split('.')[0]
 
155
 
 
156
                        tmp = folder + os.sep + pattern % name
 
157
                        target = self.generator.path.find_or_declare(tmp)
 
158
                self.set_outputs(target)
 
159
 
 
160
class stlink_task(link_task):
 
161
        """
 
162
        Base for static link tasks, which use *ar* most of the time.
 
163
        The target is always removed before being written.
 
164
        """
 
165
        run_str = '${AR} ${ARFLAGS} ${AR_TGT_F}${TGT} ${AR_SRC_F}${SRC}'
 
166
 
 
167
def rm_tgt(cls):
 
168
        old = cls.run
 
169
        def wrap(self):
 
170
                try: os.remove(self.outputs[0].abspath())
 
171
                except OSError: pass
 
172
                return old(self)
 
173
        setattr(cls, 'run', wrap)
 
174
rm_tgt(stlink_task)
 
175
 
 
176
@feature('c', 'cxx', 'd', 'go', 'fc', 'asm')
 
177
@after_method('process_source')
 
178
def apply_link(self):
 
179
        """
 
180
        Collect the tasks stored in ``compiled_tasks`` (created by :py:func:`waflib.Tools.ccroot.create_compiled_task`), and
 
181
        use the outputs for a new instance of :py:class:`waflib.Tools.ccroot.link_task`. The class to use is the first link task
 
182
        matching a name from the attribute *features*, for example::
 
183
 
 
184
                        def build(bld):
 
185
                                tg = bld(features='cxx cxxprogram cprogram', source='main.c', target='app')
 
186
 
 
187
        will create the task ``tg.link_task`` as a new instance of :py:class:`waflib.Tools.cxx.cxxprogram`
 
188
        """
 
189
 
 
190
        for x in self.features:
 
191
                if x == 'cprogram' and 'cxx' in self.features: # limited compat
 
192
                        x = 'cxxprogram'
 
193
                elif x == 'cshlib' and 'cxx' in self.features:
 
194
                        x = 'cxxshlib'
 
195
 
 
196
                if x in Task.classes:
 
197
                        if issubclass(Task.classes[x], link_task):
 
198
                                link = x
 
199
                                break
 
200
        else:
 
201
                return
 
202
 
 
203
        objs = [t.outputs[0] for t in getattr(self, 'compiled_tasks', [])]
 
204
        self.link_task = self.create_task(link, objs)
 
205
        self.link_task.add_target(self.target)
 
206
 
 
207
        # remember that the install paths are given by the task generators
 
208
        # we need to define install_task even during the build phase because others might need the installation path
 
209
        try:
 
210
                inst_to = self.install_path
 
211
        except AttributeError:
 
212
                inst_to = self.link_task.__class__.inst_to
 
213
        if inst_to:
 
214
                # install a copy of the node list we have at this moment (implib not added)
 
215
                self.install_task = self.bld.install_files(inst_to, self.link_task.outputs[:], env=self.env, chmod=self.link_task.chmod)
 
216
 
 
217
@taskgen_method
 
218
def use_rec(self, name, **kw):
 
219
        """
 
220
        Processes the ``use`` keyword recursively. This method is kind of private and only meant to be used from ``process_use``
 
221
        """
 
222
 
 
223
        if name in self.tmp_use_not or name in self.tmp_use_seen:
 
224
                return
 
225
 
 
226
        try:
 
227
                y = self.bld.get_tgen_by_name(name)
 
228
        except Errors.WafError:
 
229
                self.uselib.append(name)
 
230
                self.tmp_use_not.add(name)
 
231
                return
 
232
 
 
233
        self.tmp_use_seen.append(name)
 
234
        y.post()
 
235
 
 
236
        # bind temporary attributes on the task generator
 
237
        y.tmp_use_objects = objects = kw.get('objects', True)
 
238
        y.tmp_use_stlib   = stlib   = kw.get('stlib', True)
 
239
        try:
 
240
                link_task = y.link_task
 
241
        except AttributeError:
 
242
                y.tmp_use_var = ''
 
243
        else:
 
244
                objects = False
 
245
                if not isinstance(y.link_task, stlink_task):
 
246
                        stlib = False
 
247
                        y.tmp_use_var = 'LIB'
 
248
                else:
 
249
                        y.tmp_use_var = 'STLIB'
 
250
 
 
251
        p = self.tmp_use_prec
 
252
        for x in self.to_list(getattr(y, 'use', [])):
 
253
                try:
 
254
                        p[x].append(name)
 
255
                except:
 
256
                        p[x] = [name]
 
257
                self.use_rec(x, objects=objects, stlib=stlib)
 
258
 
 
259
@feature('c', 'cxx', 'd', 'use', 'fc')
 
260
@before_method('apply_incpaths', 'propagate_uselib_vars')
 
261
@after_method('apply_link', 'process_source')
 
262
def process_use(self):
 
263
        """
 
264
        Process the ``use`` attribute which contains a list of task generator names::
 
265
 
 
266
                def build(bld):
 
267
                        bld.shlib(source='a.c', target='lib1')
 
268
                        bld.program(source='main.c', target='app', use='lib1')
 
269
 
 
270
        See :py:func:`waflib.Tools.ccroot.use_rec`.
 
271
        """
 
272
 
 
273
        use_not = self.tmp_use_not = set([])
 
274
        use_seen = self.tmp_use_seen = [] # we would like an ordered set
 
275
        use_prec = self.tmp_use_prec = {}
 
276
        self.uselib = self.to_list(getattr(self, 'uselib', []))
 
277
        self.includes = self.to_list(getattr(self, 'includes', []))
 
278
        names = self.to_list(getattr(self, 'use', []))
 
279
 
 
280
        for x in names:
 
281
                self.use_rec(x)
 
282
 
 
283
        for x in use_not:
 
284
                if x in use_prec:
 
285
                        del use_prec[x]
 
286
 
 
287
        # topological sort
 
288
        out = []
 
289
        tmp = []
 
290
        for x in self.tmp_use_seen:
 
291
                for k in use_prec.values():
 
292
                        if x in k:
 
293
                                break
 
294
                else:
 
295
                        tmp.append(x)
 
296
 
 
297
        while tmp:
 
298
                e = tmp.pop()
 
299
                out.append(e)
 
300
                try:
 
301
                        nlst = use_prec[e]
 
302
                except KeyError:
 
303
                        pass
 
304
                else:
 
305
                        del use_prec[e]
 
306
                        for x in nlst:
 
307
                                for y in use_prec:
 
308
                                        if x in use_prec[y]:
 
309
                                                break
 
310
                                else:
 
311
                                        tmp.append(x)
 
312
        if use_prec:
 
313
                raise Errors.WafError('Cycle detected in the use processing %r' % use_prec)
 
314
        out.reverse()
 
315
 
 
316
        link_task = getattr(self, 'link_task', None)
 
317
        for x in out:
 
318
                y = self.bld.get_tgen_by_name(x)
 
319
                var = y.tmp_use_var
 
320
                if var and link_task:
 
321
                        if var == 'LIB' or y.tmp_use_stlib:
 
322
                                self.env.append_value(var, [y.target[y.target.rfind(os.sep) + 1:]])
 
323
                                self.link_task.dep_nodes.extend(y.link_task.outputs)
 
324
                                tmp_path = y.link_task.outputs[0].parent.path_from(self.bld.bldnode)
 
325
                                self.env.append_value(var + 'PATH', [tmp_path])
 
326
                else:
 
327
                        if y.tmp_use_objects:
 
328
                                self.add_objects_from_tgen(y)
 
329
 
 
330
                if getattr(y, 'export_includes', None):
 
331
                        self.includes.extend(y.to_incnodes(y.export_includes))
 
332
 
 
333
        # and finally, add the uselib variables (no recursion needed)
 
334
        for x in names:
 
335
                try:
 
336
                        y = self.bld.get_tgen_by_name(x)
 
337
                except:
 
338
                        if not self.env['STLIB_' + x] and not x in self.uselib:
 
339
                                self.uselib.append(x)
 
340
                else:
 
341
                        for k in self.to_list(getattr(y, 'uselib', [])):
 
342
                                if not self.env['STLIB_' + k] and not k in self.uselib:
 
343
                                        self.uselib.append(k)
 
344
 
 
345
@taskgen_method
 
346
def add_objects_from_tgen(self, tg):
 
347
        # Not public yet, wait for waf 1.6.7 at least - the purpose of this is to add pdb files to the compiled
 
348
        # tasks but not to the link tasks (to avoid errors)
 
349
        try:
 
350
                link_task = self.link_task
 
351
        except AttributeError:
 
352
                pass
 
353
        else:
 
354
                for tsk in getattr(tg, 'compiled_tasks', []):
 
355
                        for x in tsk.outputs:
 
356
                                if x.name.endswith('.o') or x.name.endswith('.obj'):
 
357
                                        link_task.inputs.append(x)
 
358
 
 
359
@taskgen_method
 
360
def get_uselib_vars(self):
 
361
        """
 
362
        :return: the *uselib* variables associated to the *features* attribute (see :py:attr:`waflib.Tools.ccroot.USELIB_VARS`)
 
363
        :rtype: list of string
 
364
        """
 
365
        _vars = set([])
 
366
        for x in self.features:
 
367
                if x in USELIB_VARS:
 
368
                        _vars |= USELIB_VARS[x]
 
369
        return _vars
 
370
 
 
371
@feature('c', 'cxx', 'd', 'fc', 'javac', 'cs', 'uselib')
 
372
@after_method('process_use')
 
373
def propagate_uselib_vars(self):
 
374
        """
 
375
        Process uselib variables for adding flags. For example, the following target::
 
376
 
 
377
                def build(bld):
 
378
                        bld.env.AFLAGS_aaa = ['bar']
 
379
                        from waflib.Tools.ccroot import USELIB_VARS
 
380
                        USELIB_VARS['aaa'] = set('AFLAGS')
 
381
 
 
382
                        tg = bld(features='aaa', aflags='test')
 
383
 
 
384
        The *aflags* attribute will be processed and this method will set::
 
385
 
 
386
                        tg.env.AFLAGS = ['bar', 'test']
 
387
        """
 
388
        _vars = self.get_uselib_vars()
 
389
        env = self.env
 
390
 
 
391
        for x in _vars:
 
392
                y = x.lower()
 
393
                env.append_unique(x, self.to_list(getattr(self, y, [])))
 
394
 
 
395
        for x in self.features:
 
396
                for var in _vars:
 
397
                        compvar = '%s_%s' % (var, x)
 
398
                        env.append_value(var, env[compvar])
 
399
 
 
400
        for x in self.to_list(getattr(self, 'uselib', [])):
 
401
                for v in _vars:
 
402
                        env.append_value(v, env[v + '_' + x])
 
403
 
 
404
# ============ the code above must not know anything about import libs ==========
 
405
 
 
406
@feature('cshlib', 'cxxshlib', 'fcshlib')
 
407
@after_method('apply_link')
 
408
def apply_implib(self):
 
409
        """
 
410
        Handle dlls and their import libs on Windows-like systems.
 
411
 
 
412
        A ``.dll.a`` file called *import library* is generated.
 
413
        It must be installed as it is required for linking the library.
 
414
        """
 
415
        if not self.env.DEST_BINFMT == 'pe':
 
416
                return
 
417
 
 
418
        dll = self.link_task.outputs[0]
 
419
        if isinstance(self.target, Node.Node):
 
420
                name = self.target.name
 
421
        else:
 
422
                name = os.path.split(self.target)[1]
 
423
        implib = self.env['implib_PATTERN'] % name
 
424
        implib = dll.parent.find_or_declare(implib)
 
425
        self.env.append_value('LINKFLAGS', self.env['IMPLIB_ST'] % implib.bldpath())
 
426
        self.link_task.outputs.append(implib)
 
427
 
 
428
        if getattr(self, 'defs', None) and self.env.DEST_BINFMT == 'pe':
 
429
                node = self.path.find_resource(self.defs)
 
430
                if not node:
 
431
                        raise Errors.WafError('invalid def file %r' % self.defs)
 
432
                if 'msvc' in (self.env.CC_NAME, self.env.CXX_NAME):
 
433
                        self.env.append_value('LINKFLAGS', '/def:%s' % node.path_from(self.bld.bldnode))
 
434
                        self.link_task.dep_nodes.append(node)
 
435
                else:
 
436
                        #gcc for windows takes *.def file a an input without any special flag
 
437
                        self.link_task.inputs.append(node)
 
438
 
 
439
        try:
 
440
                inst_to = self.install_path
 
441
        except AttributeError:
 
442
                inst_to = self.link_task.__class__.inst_to
 
443
        if not inst_to:
 
444
                return
 
445
 
 
446
        self.implib_install_task = self.bld.install_as('${PREFIX}/lib/%s' % implib.name, implib, self.env)
 
447
 
 
448
# ============ the code above must not know anything about vnum processing on unix platforms =========
 
449
 
 
450
@feature('cshlib', 'cxxshlib', 'dshlib', 'fcshlib', 'vnum')
 
451
@after_method('apply_link')
 
452
def apply_vnum(self):
 
453
        """
 
454
        Enforce version numbering on shared libraries. The valid version numbers must have at most two dots::
 
455
 
 
456
                def build(bld):
 
457
                        bld.shlib(source='a.c', target='foo', vnum='14.15.16')
 
458
 
 
459
        In this example, ``libfoo.so`` is installed as ``libfoo.so.1.2.3``, and the following symbolic links are created:
 
460
 
 
461
        * ``libfoo.so   → libfoo.so.1.2.3``
 
462
        * ``libfoo.so.1 → libfoo.so.1.2.3``
 
463
        """
 
464
        if not getattr(self, 'vnum', '') or os.name != 'posix' or self.env.DEST_BINFMT not in ('elf', 'mac-o'):
 
465
                return
 
466
 
 
467
        link = self.link_task
 
468
        nums = self.vnum.split('.')
 
469
        node = link.outputs[0]
 
470
 
 
471
        libname = node.name
 
472
        if libname.endswith('.dylib'):
 
473
                name3 = libname.replace('.dylib', '.%s.dylib' % self.vnum)
 
474
                name2 = libname.replace('.dylib', '.%s.dylib' % nums[0])
 
475
        else:
 
476
                name3 = libname + '.' + self.vnum
 
477
                name2 = libname + '.' + nums[0]
 
478
 
 
479
        # add the so name for the ld linker - to disable, just unset env.SONAME_ST
 
480
        if self.env.SONAME_ST:
 
481
                v = self.env.SONAME_ST % name2
 
482
                self.env.append_value('LINKFLAGS', v.split())
 
483
 
 
484
        # the following task is just to enable execution from the build dir :-/
 
485
        tsk = self.create_task('vnum', node, [node.parent.find_or_declare(name2), node.parent.find_or_declare(name3)])
 
486
 
 
487
        if getattr(self.bld, 'is_install', None):
 
488
                self.install_task.hasrun = Task.SKIP_ME
 
489
                bld = self.bld
 
490
                path = self.install_task.dest
 
491
                t1 = bld.install_as(path + os.sep + name3, node, env=self.env, chmod=self.link_task.chmod)
 
492
                t2 = bld.symlink_as(path + os.sep + name2, name3)
 
493
                t3 = bld.symlink_as(path + os.sep + libname, name3)
 
494
                self.vnum_install_task = (t1, t2, t3)
 
495
 
 
496
        if '-dynamiclib' in self.env['LINKFLAGS'] and getattr(self, 'install_task', None):
 
497
                path = os.path.join(self.install_task.get_install_path(), self.link_task.outputs[0].name)
 
498
                self.env.append_value('LINKFLAGS', ['-install_name', path])
 
499
 
 
500
class vnum(Task.Task):
 
501
        """
 
502
        Create the symbolic links for a versioned shared library. Instances are created by :py:func:`waflib.Tools.ccroot.apply_vnum`
 
503
        """
 
504
        color = 'CYAN'
 
505
        quient = True
 
506
        ext_in = ['.bin']
 
507
        def run(self):
 
508
                for x in self.outputs:
 
509
                        path = x.abspath()
 
510
                        try:
 
511
                                os.remove(path)
 
512
                        except OSError:
 
513
                                pass
 
514
 
 
515
                        try:
 
516
                                os.symlink(self.inputs[0].name, path)
 
517
                        except OSError:
 
518
                                return 1
 
519
 
 
520
class fake_shlib(link_task):
 
521
        """
 
522
        Task used for reading a system library and adding the dependency on it
 
523
        """
 
524
        def runnable_status(self):
 
525
                for t in self.run_after:
 
526
                        if not t.hasrun:
 
527
                                return Task.ASK_LATER
 
528
 
 
529
                for x in self.outputs:
 
530
                        x.sig = Utils.h_file(x.abspath())
 
531
                return Task.SKIP_ME
 
532
 
 
533
class fake_stlib(stlink_task):
 
534
        """
 
535
        Task used for reading a system library and adding the dependency on it
 
536
        """
 
537
        def runnable_status(self):
 
538
                for t in self.run_after:
 
539
                        if not t.hasrun:
 
540
                                return Task.ASK_LATER
 
541
 
 
542
                for x in self.outputs:
 
543
                        x.sig = Utils.h_file(x.abspath())
 
544
                return Task.SKIP_ME
 
545
 
 
546
@conf
 
547
def read_shlib(self, name, paths=[]):
 
548
        """
 
549
        Read a system shared library, enabling its use as a local library. Will trigger a rebuild if the file changes::
 
550
 
 
551
                def build(bld):
 
552
                        bld.read_shlib('m')
 
553
                        bld.program(source='main.c', use='m')
 
554
        """
 
555
        return self(name=name, features='fake_lib', lib_paths=paths, lib_type='shlib')
 
556
 
 
557
@conf
 
558
def read_stlib(self, name, paths=[]):
 
559
        """
 
560
        Read a system static library, enabling a use as a local library. Will trigger a rebuild if the file changes.
 
561
        """
 
562
        return self(name=name, features='fake_lib', lib_paths=paths, lib_type='stlib')
 
563
 
 
564
lib_patterns = {
 
565
        'shlib' : ['lib%s.so', '%s.so', 'lib%s.dll', '%s.dll'],
 
566
        'stlib' : ['lib%s.a', '%s.a', 'lib%s.dll', '%s.dll', 'lib%s.lib', '%s.lib'],
 
567
}
 
568
 
 
569
@feature('fake_lib')
 
570
def process_lib(self):
 
571
        """
 
572
        Find the location of a foreign library. Used by :py:class:`waflib.Tools.ccroot.read_shlib` and :py:class:`waflib.Tools.ccroot.read_stlib`.
 
573
        """
 
574
        node = None
 
575
 
 
576
        names = [x % self.name for x in lib_patterns[self.lib_type]]
 
577
        for x in self.lib_paths + [self.path, '/usr/lib64', '/usr/lib', '/usr/local/lib64', '/usr/local/lib']:
 
578
                if not isinstance(x, Node.Node):
 
579
                        x = self.bld.root.find_node(x) or self.path.find_node(x)
 
580
                        if not x:
 
581
                                continue
 
582
 
 
583
                for y in names:
 
584
                        node = x.find_node(y)
 
585
                        if node:
 
586
                                node.sig = Utils.h_file(node.abspath())
 
587
                                break
 
588
                else:
 
589
                        continue
 
590
                break
 
591
        else:
 
592
                raise Errors.WafError('could not find library %r' % self.name)
 
593
        self.link_task = self.create_task('fake_%s' % self.lib_type, [], [node])
 
594
        self.target = self.name
 
595
 
 
596
 
 
597
class fake_o(Task.Task):
 
598
        def runnable_status(self):
 
599
                return Task.SKIP_ME
 
600
 
 
601
@extension('.o', '.obj')
 
602
def add_those_o_files(self, node):
 
603
        tsk = self.create_task('fake_o', [], node)
 
604
        try:
 
605
                self.compiled_tasks.append(tsk)
 
606
        except AttributeError:
 
607
                self.compiled_tasks = [tsk]
 
608