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