~ubuntu-branches/ubuntu/saucy/xmms2/saucy-proposed

« back to all changes in this revision

Viewing changes to wafadmin/Tools/ccroot.py

  • Committer: Bazaar Package Importer
  • Author(s): Benjamin Drung
  • Date: 2011-10-22 23:53:00 UTC
  • mto: (38.1.2 sid)
  • mto: This revision was merged to the branch mainline in revision 43.
  • Revision ID: james.westby@ubuntu.com-20111022235300-u50pdo3g341jvk7q
ImportĀ upstreamĀ versionĀ 0.8+dfsg

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-2008 (ita)
4
 
 
5
 
"base for all c/c++ programs and libraries"
6
 
 
7
 
import os, sys, re
8
 
import TaskGen, Task, Utils, preproc, Logs, Build, Options
9
 
from Logs import error, debug, warn
10
 
from Utils import md5
11
 
from TaskGen import taskgen, after, before, feature
12
 
from Constants import *
13
 
from Configure import conftest
14
 
try:
15
 
        from cStringIO import StringIO
16
 
except ImportError:
17
 
        from io import StringIO
18
 
 
19
 
import config_c # <- necessary for the configuration, do not touch
20
 
 
21
 
USE_TOP_LEVEL = False
22
 
 
23
 
def get_cc_version(conf, cc, gcc=False, icc=False):
24
 
 
25
 
        cmd = cc + ['-dM', '-E', '-']
26
 
        try:
27
 
                p = Utils.pproc.Popen(cmd, stdin=Utils.pproc.PIPE, stdout=Utils.pproc.PIPE, stderr=Utils.pproc.PIPE)
28
 
                p.stdin.write('\n')
29
 
                out = p.communicate()[0]
30
 
        except:
31
 
                conf.fatal('could not determine the compiler version %r' % cmd)
32
 
 
33
 
        # PY3K: do not touch
34
 
        out = str(out)
35
 
 
36
 
        if gcc:
37
 
                if out.find('__INTEL_COMPILER') >= 0:
38
 
                        conf.fatal('The intel compiler pretends to be gcc')
39
 
                if out.find('__GNUC__') < 0:
40
 
                        conf.fatal('Could not determine the compiler type')
41
 
 
42
 
        if icc and out.find('__INTEL_COMPILER') < 0:
43
 
                conf.fatal('Not icc/icpc')
44
 
 
45
 
        k = {}
46
 
        if icc or gcc:
47
 
                out = out.split('\n')
48
 
                import shlex
49
 
 
50
 
                for line in out:
51
 
                        lst = shlex.split(line)
52
 
                        if len(lst)>2:
53
 
                                key = lst[1]
54
 
                                val = lst[2]
55
 
                                k[key] = val
56
 
 
57
 
                def isD(var):
58
 
                        return var in k
59
 
 
60
 
                def isT(var):
61
 
                        return var in k and k[var] != '0'
62
 
 
63
 
                # Some documentation is available at http://predef.sourceforge.net
64
 
                # The names given to DEST_OS must match what Utils.unversioned_sys_platform() returns.
65
 
                mp1 = {
66
 
                        '__linux__'   : 'linux',
67
 
                        '__GNU__'     : 'hurd',
68
 
                        '__FreeBSD__' : 'freebsd',
69
 
                        '__NetBSD__'  : 'netbsd',
70
 
                        '__OpenBSD__' : 'openbsd',
71
 
                        '__sun'       : 'sunos',
72
 
                        '__hpux'      : 'hpux',
73
 
                        '__sgi'       : 'irix',
74
 
                        '_AIX'        : 'aix',
75
 
                        '__CYGWIN__'  : 'cygwin',
76
 
                        '__MSYS__'    : 'msys',
77
 
                        '_UWIN'       : 'uwin',
78
 
                        '_WIN64'      : 'win32',
79
 
                        '_WIN32'      : 'win32',
80
 
                        }
81
 
 
82
 
                for i in mp1:
83
 
                        if isD(i):
84
 
                                conf.env.DEST_OS = mp1[i]
85
 
                                break
86
 
                else:
87
 
                        if isD('__APPLE__') and isD('__MACH__'):
88
 
                                conf.env.DEST_OS = 'darwin'
89
 
                        elif isD('__unix__'): # unix must be tested last as it's a generic fallback
90
 
                                conf.env.DEST_OS = 'generic'
91
 
 
92
 
                if isD('__ELF__'):
93
 
                        conf.env.DEST_BINFMT = 'elf'
94
 
 
95
 
                mp2 = {
96
 
                                '__x86_64__'  : 'x86_64',
97
 
                                '__i386__'    : 'x86',
98
 
                                '__ia64__'    : 'ia',
99
 
                                '__mips__'    : 'mips',
100
 
                                '__sparc__'   : 'sparc',
101
 
                                '__alpha__'   : 'alpha',
102
 
                                '__arm__'     : 'arm',
103
 
                                '__hppa__'    : 'hppa',
104
 
                                '__powerpc__' : 'powerpc',
105
 
                                }
106
 
                for i in mp2:
107
 
                        if isD(i):
108
 
                                conf.env.DEST_CPU = mp2[i]
109
 
                                break
110
 
 
111
 
                debug('ccroot: dest platform: ' + ' '.join([conf.env[x] or '?' for x in ('DEST_OS', 'DEST_BINFMT', 'DEST_CPU')]))
112
 
                conf.env['CC_VERSION'] = (k['__GNUC__'], k['__GNUC_MINOR__'], k['__GNUC_PATCHLEVEL__'])
113
 
        return k
114
 
 
115
 
class DEBUG_LEVELS:
116
 
        """Will disappear in waf 1.6"""
117
 
        ULTRADEBUG = "ultradebug"
118
 
        DEBUG = "debug"
119
 
        RELEASE = "release"
120
 
        OPTIMIZED = "optimized"
121
 
        CUSTOM = "custom"
122
 
 
123
 
        ALL = [ULTRADEBUG, DEBUG, RELEASE, OPTIMIZED, CUSTOM]
124
 
 
125
 
def scan(self):
126
 
        "look for .h the .cpp need"
127
 
        debug('ccroot: _scan_preprocessor(self, node, env, path_lst)')
128
 
 
129
 
        # TODO waf 1.6 - assume the default input has exactly one file
130
 
 
131
 
        if len(self.inputs) == 1:
132
 
                node = self.inputs[0]
133
 
                (nodes, names) = preproc.get_deps(node, self.env, nodepaths = self.env['INC_PATHS'])
134
 
                if Logs.verbose:
135
 
                        debug('deps: deps for %s: %r; unresolved %r' % (str(node), nodes, names))
136
 
                return (nodes, names)
137
 
 
138
 
        all_nodes = []
139
 
        all_names = []
140
 
        seen = set()
141
 
        for node in self.inputs:
142
 
                (nodes, names) = preproc.get_deps(node, self.env, nodepaths = self.env['INC_PATHS'])
143
 
                if Logs.verbose:
144
 
                        debug('deps: deps for %s: %r; unresolved %r' % (str(node), nodes, names))
145
 
                for x in nodes:
146
 
                        if id(x) in seen: continue
147
 
                        seen.add(id(x))
148
 
                        all_nodes.append(x)
149
 
                for x in names:
150
 
                        if not x in all_names:
151
 
                                all_names.append(x)
152
 
        return (all_nodes, all_names)
153
 
 
154
 
class ccroot_abstract(TaskGen.task_gen):
155
 
        "Parent class for programs and libraries in languages c, c++ and moc (Qt)"
156
 
        def __init__(self, *k, **kw):
157
 
                # COMPAT remove in waf 1.6 TODO
158
 
                if len(k) > 1:
159
 
                        k = list(k)
160
 
                        if k[1][0] != 'c':
161
 
                                k[1] = 'c' + k[1]
162
 
                TaskGen.task_gen.__init__(self, *k, **kw)
163
 
 
164
 
def get_target_name(self):
165
 
        tp = 'program'
166
 
        for x in self.features:
167
 
                if x in ['cshlib', 'cstaticlib']:
168
 
                        tp = x.lstrip('c')
169
 
 
170
 
        pattern = self.env[tp + '_PATTERN']
171
 
        if not pattern: pattern = '%s'
172
 
 
173
 
        dir, name = os.path.split(self.target)
174
 
 
175
 
        if self.env.DEST_BINFMT == 'pe' and getattr(self, 'vnum', None) and 'cshlib' in self.features:
176
 
                # include the version in the dll file name,
177
 
                # the import lib file name stays unversionned.
178
 
                name = name + '-' + self.vnum.split('.')[0]
179
 
 
180
 
        return os.path.join(dir, pattern % name)
181
 
 
182
 
@feature('cc', 'cxx')
183
 
@before('apply_core')
184
 
def default_cc(self):
185
 
        """compiled_tasks attribute must be set before the '.c->.o' tasks can be created"""
186
 
        Utils.def_attrs(self,
187
 
                includes = '',
188
 
                defines= '',
189
 
                rpaths = '',
190
 
                uselib = '',
191
 
                uselib_local = '',
192
 
                add_objects = '',
193
 
                p_flag_vars = [],
194
 
                p_type_vars = [],
195
 
                compiled_tasks = [],
196
 
                link_task = None)
197
 
 
198
 
        # The only thing we need for cross-compilation is DEST_BINFMT.
199
 
        # At some point, we may reach a case where DEST_BINFMT is not enough, but for now it's sufficient.
200
 
        # Currently, cross-compilation is auto-detected only for the gnu and intel compilers.
201
 
        if not self.env.DEST_BINFMT:
202
 
                # Infer the binary format from the os name.
203
 
                self.env.DEST_BINFMT = Utils.unversioned_sys_platform_to_binary_format(
204
 
                        self.env.DEST_OS or Utils.unversioned_sys_platform())
205
 
 
206
 
        if not self.env.BINDIR: self.env.BINDIR = Utils.subst_vars('${PREFIX}/bin', self.env)
207
 
        if not self.env.LIBDIR: self.env.LIBDIR = Utils.subst_vars('${PREFIX}/lib${LIB_EXT}', self.env)
208
 
 
209
 
@feature('cprogram', 'dprogram', 'cstaticlib', 'dstaticlib', 'cshlib', 'dshlib')
210
 
def apply_verif(self):
211
 
        """no particular order, used for diagnostic"""
212
 
        if not (self.source or getattr(self, 'add_objects', None)):
213
 
                raise Utils.WafError('no source files specified for %s' % self)
214
 
        if not self.target:
215
 
                raise Utils.WafError('no target for %s' % self)
216
 
 
217
 
# TODO reference the d programs, shlibs in d.py, not here
218
 
 
219
 
@feature('cprogram', 'dprogram')
220
 
@after('default_cc')
221
 
@before('apply_core')
222
 
def vars_target_cprogram(self):
223
 
        self.default_install_path = self.env.BINDIR
224
 
        self.default_chmod = O755
225
 
 
226
 
@after('default_cc')
227
 
@feature('cshlib', 'dshlib')
228
 
@before('apply_core')
229
 
def vars_target_cshlib(self):
230
 
        if self.env.DEST_BINFMT == 'pe':
231
 
                #   set execute bit on libs to avoid 'permission denied' (issue 283)
232
 
                self.default_chmod = O755
233
 
                self.default_install_path = self.env.BINDIR
234
 
        else:
235
 
                self.default_install_path = self.env.LIBDIR
236
 
 
237
 
@feature('cprogram', 'dprogram', 'cstaticlib', 'dstaticlib', 'cshlib', 'dshlib')
238
 
@after('apply_link', 'vars_target_cprogram', 'vars_target_cshlib')
239
 
def default_link_install(self):
240
 
        """you may kill this method to inject your own installation for the first element
241
 
        any other install should only process its own nodes and not those from the others"""
242
 
        if self.install_path:
243
 
                self.bld.install_files(self.install_path, self.link_task.outputs[0], env=self.env, chmod=self.chmod)
244
 
 
245
 
@feature('cc', 'cxx')
246
 
@after('apply_type_vars', 'apply_lib_vars', 'apply_core')
247
 
def apply_incpaths(self):
248
 
        """used by the scanner
249
 
        after processing the uselib for CPPPATH
250
 
        after apply_core because some processing may add include paths
251
 
        """
252
 
        lst = []
253
 
        # TODO move the uselib processing out of here
254
 
        for lib in self.to_list(self.uselib):
255
 
                for path in self.env['CPPPATH_' + lib]:
256
 
                        if not path in lst:
257
 
                                lst.append(path)
258
 
        if preproc.go_absolute:
259
 
                for path in preproc.standard_includes:
260
 
                        if not path in lst:
261
 
                                lst.append(path)
262
 
 
263
 
        for path in self.to_list(self.includes):
264
 
                if not path in lst:
265
 
                        if preproc.go_absolute or not os.path.isabs(path):
266
 
                                lst.append(path)
267
 
                        else:
268
 
                                self.env.prepend_value('CPPPATH', path)
269
 
 
270
 
        for path in lst:
271
 
                node = None
272
 
                if os.path.isabs(path):
273
 
                        if preproc.go_absolute:
274
 
                                node = self.bld.root.find_dir(path)
275
 
                elif path[0] == '#':
276
 
                        node = self.bld.srcnode
277
 
                        if len(path) > 1:
278
 
                                node = node.find_dir(path[1:])
279
 
                else:
280
 
                        node = self.path.find_dir(path)
281
 
 
282
 
                if node:
283
 
                        self.env.append_value('INC_PATHS', node)
284
 
 
285
 
        # TODO WAF 1.6
286
 
        if USE_TOP_LEVEL:
287
 
                self.env.append_value('INC_PATHS', self.bld.srcnode)
288
 
 
289
 
@feature('cc', 'cxx')
290
 
@after('init_cc', 'init_cxx')
291
 
@before('apply_lib_vars')
292
 
def apply_type_vars(self):
293
 
        """before apply_lib_vars because we modify uselib
294
 
        after init_cc and init_cxx because web need p_type_vars
295
 
        """
296
 
        for x in self.features:
297
 
                if not x in ['cprogram', 'cstaticlib', 'cshlib']:
298
 
                        continue
299
 
                x = x.lstrip('c')
300
 
 
301
 
                # if the type defines uselib to add, add them
302
 
                st = self.env[x + '_USELIB']
303
 
                if st: self.uselib = self.uselib + ' ' + st
304
 
 
305
 
                # each compiler defines variables like 'shlib_CXXFLAGS', 'shlib_LINKFLAGS', etc
306
 
                # so when we make a task generator of the type shlib, CXXFLAGS are modified accordingly
307
 
                for var in self.p_type_vars:
308
 
                        compvar = '%s_%s' % (x, var)
309
 
                        #print compvar
310
 
                        value = self.env[compvar]
311
 
                        if value: self.env.append_value(var, value)
312
 
 
313
 
@feature('cprogram', 'cshlib', 'cstaticlib')
314
 
@after('apply_core')
315
 
def apply_link(self):
316
 
        """executes after apply_core for collecting 'compiled_tasks'
317
 
        use a custom linker if specified (self.link='name-of-custom-link-task')"""
318
 
        link = getattr(self, 'link', None)
319
 
        if not link:
320
 
                if 'cstaticlib' in self.features: link = 'static_link'
321
 
                elif 'cxx' in self.features: link = 'cxx_link'
322
 
                else: link = 'cc_link'
323
 
 
324
 
        tsk = self.create_task(link)
325
 
        outputs = [t.outputs[0] for t in self.compiled_tasks]
326
 
        tsk.set_inputs(outputs)
327
 
        tsk.set_outputs(self.path.find_or_declare(get_target_name(self)))
328
 
 
329
 
        self.link_task = tsk
330
 
 
331
 
@feature('cc', 'cxx')
332
 
@after('apply_link', 'init_cc', 'init_cxx')
333
 
def apply_lib_vars(self):
334
 
        """after apply_link because of 'link_task'
335
 
        after default_cc because of the attribute 'uselib'"""
336
 
        env = self.env
337
 
 
338
 
        # 1. the case of the libs defined in the project (visit ancestors first)
339
 
        # the ancestors external libraries (uselib) will be prepended
340
 
        self.uselib = self.to_list(self.uselib)
341
 
        names = self.to_list(self.uselib_local)
342
 
 
343
 
        seen = set([])
344
 
        tmp = Utils.deque(names) # consume a copy of the list of names
345
 
        while tmp:
346
 
                lib_name = tmp.popleft()
347
 
                # visit dependencies only once
348
 
                if lib_name in seen:
349
 
                        continue
350
 
 
351
 
                y = self.name_to_obj(lib_name)
352
 
                if not y:
353
 
                        raise Utils.WafError('object %r was not found in uselib_local (required by %r)' % (lib_name, self.name))
354
 
                y.post()
355
 
                seen.add(lib_name)
356
 
 
357
 
                # object has ancestors to process (shared libraries): add them to the end of the list
358
 
                if getattr(y, 'uselib_local', None):
359
 
                        lst = y.to_list(y.uselib_local)
360
 
                        if 'cshlib' in y.features or 'cprogram' in y.features:
361
 
                                lst = [x for x in lst if not 'cstaticlib' in self.name_to_obj(x).features]
362
 
                        tmp.extend(lst)
363
 
 
364
 
                # link task and flags
365
 
                if getattr(y, 'link_task', None):
366
 
 
367
 
                        link_name = y.target[y.target.rfind(os.sep) + 1:]
368
 
                        if 'cstaticlib' in y.features:
369
 
                                env.append_value('STATICLIB', link_name)
370
 
                        elif 'cshlib' in y.features or 'cprogram' in y.features:
371
 
                                # WARNING some linkers can link against programs
372
 
                                env.append_value('LIB', link_name)
373
 
 
374
 
                        # the order
375
 
                        self.link_task.set_run_after(y.link_task)
376
 
 
377
 
                        # for the recompilation
378
 
                        dep_nodes = getattr(self.link_task, 'dep_nodes', [])
379
 
                        self.link_task.dep_nodes = dep_nodes + y.link_task.outputs
380
 
 
381
 
                        # add the link path too
382
 
                        tmp_path = y.link_task.outputs[0].parent.bldpath(self.env)
383
 
                        if not tmp_path in env['LIBPATH']: env.prepend_value('LIBPATH', tmp_path)
384
 
 
385
 
                # add ancestors uselib too - but only propagate those that have no staticlib
386
 
                for v in self.to_list(y.uselib):
387
 
                        if not env['STATICLIB_' + v]:
388
 
                                if not v in self.uselib:
389
 
                                        self.uselib.insert(0, v)
390
 
 
391
 
                # if the library task generator provides 'export_incdirs', add to the include path
392
 
                # the export_incdirs must be a list of paths relative to the other library
393
 
                if getattr(y, 'export_incdirs', None):
394
 
                        for x in self.to_list(y.export_incdirs):
395
 
                                node = y.path.find_dir(x)
396
 
                                if not node:
397
 
                                        raise Utils.WafError('object %r: invalid folder %r in export_incdirs' % (y.target, x))
398
 
                                self.env.append_unique('INC_PATHS', node)
399
 
 
400
 
        # 2. the case of the libs defined outside
401
 
        for x in self.uselib:
402
 
                for v in self.p_flag_vars:
403
 
                        val = self.env[v + '_' + x]
404
 
                        if val: self.env.append_value(v, val)
405
 
 
406
 
@feature('cprogram', 'cstaticlib', 'cshlib')
407
 
@after('init_cc', 'init_cxx', 'apply_link')
408
 
def apply_objdeps(self):
409
 
        "add the .o files produced by some other object files in the same manner as uselib_local"
410
 
        if not getattr(self, 'add_objects', None): return
411
 
 
412
 
        seen = []
413
 
        names = self.to_list(self.add_objects)
414
 
        while names:
415
 
                x = names[0]
416
 
 
417
 
                # visit dependencies only once
418
 
                if x in seen:
419
 
                        names = names[1:]
420
 
                        continue
421
 
 
422
 
                # object does not exist ?
423
 
                y = self.name_to_obj(x)
424
 
                if not y:
425
 
                        raise Utils.WafError('object %r was not found in uselib_local (required by add_objects %r)' % (x, self.name))
426
 
 
427
 
                # object has ancestors to process first ? update the list of names
428
 
                if getattr(y, 'add_objects', None):
429
 
                        added = 0
430
 
                        lst = y.to_list(y.add_objects)
431
 
                        lst.reverse()
432
 
                        for u in lst:
433
 
                                if u in seen: continue
434
 
                                added = 1
435
 
                                names = [u]+names
436
 
                        if added: continue # list of names modified, loop
437
 
 
438
 
                # safe to process the current object
439
 
                y.post()
440
 
                seen.append(x)
441
 
 
442
 
                for t in y.compiled_tasks:
443
 
                        self.link_task.inputs.extend(t.outputs)
444
 
 
445
 
@feature('cprogram', 'cshlib', 'cstaticlib')
446
 
@after('apply_lib_vars')
447
 
def apply_obj_vars(self):
448
 
        """after apply_lib_vars for uselib"""
449
 
        v = self.env
450
 
        lib_st           = v['LIB_ST']
451
 
        staticlib_st     = v['STATICLIB_ST']
452
 
        libpath_st       = v['LIBPATH_ST']
453
 
        staticlibpath_st = v['STATICLIBPATH_ST']
454
 
        rpath_st         = v['RPATH_ST']
455
 
 
456
 
        app = v.append_unique
457
 
 
458
 
        if v['FULLSTATIC']:
459
 
                v.append_value('LINKFLAGS', v['FULLSTATIC_MARKER'])
460
 
 
461
 
        for i in v['RPATH']:
462
 
                if i and rpath_st:
463
 
                        app('LINKFLAGS', rpath_st % i)
464
 
 
465
 
        for i in v['LIBPATH']:
466
 
                app('LINKFLAGS', libpath_st % i)
467
 
                app('LINKFLAGS', staticlibpath_st % i)
468
 
 
469
 
        if v['STATICLIB']:
470
 
                v.append_value('LINKFLAGS', v['STATICLIB_MARKER'])
471
 
                k = [(staticlib_st % i) for i in v['STATICLIB']]
472
 
                app('LINKFLAGS', k)
473
 
 
474
 
        # fully static binaries ?
475
 
        if not v['FULLSTATIC']:
476
 
                if v['STATICLIB'] or v['LIB']:
477
 
                        v.append_value('LINKFLAGS', v['SHLIB_MARKER'])
478
 
 
479
 
        app('LINKFLAGS', [lib_st % i for i in v['LIB']])
480
 
 
481
 
@after('apply_link')
482
 
def process_obj_files(self):
483
 
        if not hasattr(self, 'obj_files'): return
484
 
        for x in self.obj_files:
485
 
                node = self.path.find_resource(x)
486
 
                self.link_task.inputs.append(node)
487
 
 
488
 
@taskgen
489
 
def add_obj_file(self, file):
490
 
        """Small example on how to link object files as if they were source
491
 
        obj = bld.create_obj('cc')
492
 
        obj.add_obj_file('foo.o')"""
493
 
        if not hasattr(self, 'obj_files'): self.obj_files = []
494
 
        if not 'process_obj_files' in self.meths: self.meths.append('process_obj_files')
495
 
        self.obj_files.append(file)
496
 
 
497
 
c_attrs = {
498
 
'cxxflag' : 'CXXFLAGS',
499
 
'cflag' : 'CCFLAGS',
500
 
'ccflag' : 'CCFLAGS',
501
 
'linkflag' : 'LINKFLAGS',
502
 
'ldflag' : 'LINKFLAGS',
503
 
'lib' : 'LIB',
504
 
'libpath' : 'LIBPATH',
505
 
'staticlib': 'STATICLIB',
506
 
'staticlibpath': 'STATICLIBPATH',
507
 
'rpath' : 'RPATH',
508
 
'framework' : 'FRAMEWORK',
509
 
'frameworkpath' : 'FRAMEWORKPATH'
510
 
}
511
 
 
512
 
@feature('cc', 'cxx')
513
 
@before('init_cxx', 'init_cc')
514
 
@before('apply_lib_vars', 'apply_obj_vars', 'apply_incpaths', 'init_cc')
515
 
def add_extra_flags(self):
516
 
        """case and plural insensitive
517
 
        before apply_obj_vars for processing the library attributes
518
 
        """
519
 
        for x in self.__dict__.keys():
520
 
                y = x.lower()
521
 
                if y[-1] == 's':
522
 
                        y = y[:-1]
523
 
                if c_attrs.get(y, None):
524
 
                        self.env.append_unique(c_attrs[y], getattr(self, x))
525
 
 
526
 
# ============ the code above must not know anything about import libs ==========
527
 
 
528
 
@feature('cshlib')
529
 
@after('apply_link', 'default_cc')
530
 
@before('apply_lib_vars', 'apply_objdeps', 'default_link_install')
531
 
def apply_implib(self):
532
 
        """On mswindows, handle dlls and their import libs
533
 
        the .dll.a is the import lib and it is required for linking so it is installed too
534
 
        """
535
 
        if not self.env.DEST_BINFMT == 'pe':
536
 
                return
537
 
 
538
 
        self.meths.remove('default_link_install')
539
 
 
540
 
        bindir = self.install_path
541
 
        if not bindir: return
542
 
 
543
 
        # install the dll in the bin dir
544
 
        dll = self.link_task.outputs[0]
545
 
        self.bld.install_files(bindir, dll, self.env, self.chmod)
546
 
 
547
 
        # add linker flags to generate the import lib
548
 
        implib = self.env['implib_PATTERN'] % os.path.split(self.target)[1]
549
 
 
550
 
        implib = dll.parent.find_or_declare(implib)
551
 
        self.link_task.outputs.append(implib)
552
 
        self.bld.install_as('${LIBDIR}/%s' % implib.name, implib, self.env)
553
 
 
554
 
        self.env.append_value('LINKFLAGS', (self.env['IMPLIB_ST'] % implib.bldpath(self.env)).split())
555
 
 
556
 
# ============ the code above must not know anything about vnum processing on unix platforms =========
557
 
 
558
 
@feature('cshlib')
559
 
@after('apply_link')
560
 
@before('apply_lib_vars', 'default_link_install')
561
 
def apply_vnum(self):
562
 
        """
563
 
        libfoo.so is installed as libfoo.so.1.2.3
564
 
        """
565
 
        if not getattr(self, 'vnum', '') or not 'cshlib' in self.features or os.name != 'posix' or self.env.DEST_BINFMT not in ('elf', 'mac-o'):
566
 
                return
567
 
 
568
 
        self.meths.remove('default_link_install')
569
 
 
570
 
        link = self.link_task
571
 
        nums = self.vnum.split('.')
572
 
        node = link.outputs[0]
573
 
 
574
 
        libname = node.name
575
 
        if libname.endswith('.dylib'):
576
 
                name3 = libname.replace('.dylib', '.%s.dylib' % self.vnum)
577
 
                name2 = libname.replace('.dylib', '.%s.dylib' % nums[0])
578
 
        else:
579
 
                name3 = libname + '.' + self.vnum
580
 
                name2 = libname + '.' + nums[0]
581
 
 
582
 
        if self.env.SONAME_ST:
583
 
                v = self.env.SONAME_ST % name2
584
 
                self.env.append_value('LINKFLAGS', v.split())
585
 
 
586
 
        bld = self.bld
587
 
        nums = self.vnum.split('.')
588
 
 
589
 
        path = self.install_path
590
 
        if not path: return
591
 
 
592
 
        bld.install_as(path + os.sep + name3, node, env=self.env)
593
 
        bld.symlink_as(path + os.sep + name2, name3)
594
 
        bld.symlink_as(path + os.sep + libname, name3)
595
 
 
596
 
        # the following task is just to enable execution from the build dir :-/
597
 
        tsk = self.create_task('vnum')
598
 
        tsk.set_inputs([node])
599
 
        tsk.set_outputs(node.parent.find_or_declare(name2))
600
 
 
601
 
def exec_vnum_link(self):
602
 
        path = self.outputs[0].abspath(self.env)
603
 
        try:
604
 
                os.remove(path)
605
 
        except OSError:
606
 
                pass
607
 
 
608
 
        try:
609
 
                os.symlink(self.inputs[0].name, path)
610
 
        except OSError:
611
 
                return 1
612
 
 
613
 
cls = Task.task_type_from_func('vnum', func=exec_vnum_link, ext_in='.bin', color='CYAN')
614
 
cls.quiet = 1
615
 
 
616
 
# ============ the --as-needed flag should added during the configuration, not at runtime =========
617
 
 
618
 
@conftest
619
 
def add_as_needed(conf):
620
 
        if conf.env.DEST_BINFMT == 'elf' and 'gcc' in (conf.env.CXX_NAME, conf.env.CC_NAME):
621
 
                conf.env.append_unique('LINKFLAGS', '--as-needed')
622