Move waf into third_party/.
[samba.git] / third_party / waf / 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 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__'     : 'gnu',
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                         '__POWERPC__' : 'powerpc',
81                         }
82
83                 for i in mp1:
84                         if isD(i):
85                                 conf.env.DEST_OS = mp1[i]
86                                 break
87                 else:
88                         if isD('__APPLE__') and isD('__MACH__'):
89                                 conf.env.DEST_OS = 'darwin'
90                         elif isD('__unix__'): # unix must be tested last as it's a generic fallback
91                                 conf.env.DEST_OS = 'generic'
92
93                 if isD('__ELF__'):
94                         conf.env.DEST_BINFMT = 'elf'
95                 elif isD('__WINNT__') or isD('__CYGWIN__'):
96                         conf.env.DEST_BINFMT = 'pe'
97                 elif isD('__APPLE__'):
98                         conf.env.DEST_BINFMT = 'mac-o'
99
100                 mp2 = {
101                                 '__x86_64__'  : 'x86_64',
102                                 '__i386__'    : 'x86',
103                                 '__ia64__'    : 'ia',
104                                 '__mips__'    : 'mips',
105                                 '__sparc__'   : 'sparc',
106                                 '__alpha__'   : 'alpha',
107                                 '__arm__'     : 'arm',
108                                 '__hppa__'    : 'hppa',
109                                 '__powerpc__' : 'powerpc',
110                                 }
111                 for i in mp2:
112                         if isD(i):
113                                 conf.env.DEST_CPU = mp2[i]
114                                 break
115
116                 debug('ccroot: dest platform: ' + ' '.join([conf.env[x] or '?' for x in ('DEST_OS', 'DEST_BINFMT', 'DEST_CPU')]))
117                 conf.env['CC_VERSION'] = (k['__GNUC__'], k['__GNUC_MINOR__'], k['__GNUC_PATCHLEVEL__'])
118         return k
119
120 class DEBUG_LEVELS:
121         """Will disappear in waf 1.6"""
122         ULTRADEBUG = "ultradebug"
123         DEBUG = "debug"
124         RELEASE = "release"
125         OPTIMIZED = "optimized"
126         CUSTOM = "custom"
127
128         ALL = [ULTRADEBUG, DEBUG, RELEASE, OPTIMIZED, CUSTOM]
129
130 def scan(self):
131         "look for .h the .cpp need"
132         debug('ccroot: _scan_preprocessor(self, node, env, path_lst)')
133
134         # TODO waf 1.6 - assume the default input has exactly one file
135
136         if len(self.inputs) == 1:
137                 node = self.inputs[0]
138                 (nodes, names) = preproc.get_deps(node, self.env, nodepaths = self.env['INC_PATHS'])
139                 if Logs.verbose:
140                         debug('deps: deps for %s: %r; unresolved %r', str(node), nodes, names)
141                 return (nodes, names)
142
143         all_nodes = []
144         all_names = []
145         seen = set()
146         for node in self.inputs:
147                 (nodes, names) = preproc.get_deps(node, self.env, nodepaths = self.env['INC_PATHS'])
148                 if Logs.verbose:
149                         debug('deps: deps for %s: %r; unresolved %r', str(node), nodes, names)
150                 for x in nodes:
151                         if id(x) in seen: continue
152                         seen.add(id(x))
153                         all_nodes.append(x)
154                 for x in names:
155                         if not x in all_names:
156                                 all_names.append(x)
157         return (all_nodes, all_names)
158
159 class ccroot_abstract(TaskGen.task_gen):
160         "Parent class for programs and libraries in languages c, c++ and moc (Qt)"
161         def __init__(self, *k, **kw):
162                 # COMPAT remove in waf 1.6 TODO
163                 if len(k) > 1:
164                         k = list(k)
165                         if k[1][0] != 'c':
166                                 k[1] = 'c' + k[1]
167                 TaskGen.task_gen.__init__(self, *k, **kw)
168
169 def get_target_name(self):
170         tp = 'program'
171         for x in self.features:
172                 if x in ['cshlib', 'cstaticlib']:
173                         tp = x.lstrip('c')
174
175         pattern = self.env[tp + '_PATTERN']
176         if not pattern: pattern = '%s'
177
178         dir, name = os.path.split(self.target)
179
180         if 'cshlib' in self.features and getattr(self, 'vnum', None):
181                 nums = self.vnum.split('.')
182                 if self.env.DEST_BINFMT == 'pe':
183                         # include the version in the dll file name,
184                         # the import lib file name stays unversionned.
185                         name = name + '-' + nums[0]
186                 elif self.env.DEST_OS == 'openbsd':
187                         pattern = '%s.%s' % (pattern, nums[0])
188                         if len(nums) >= 2:
189                                 pattern += '.%s' % nums[1]
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 i and rpath_st:
477                         app('LINKFLAGS', rpath_st % i)
478
479         for i in v['LIBPATH']:
480                 app('LINKFLAGS', libpath_st % i)
481                 app('LINKFLAGS', staticlibpath_st % i)
482
483         if v['STATICLIB']:
484                 v.append_value('LINKFLAGS', v['STATICLIB_MARKER'])
485                 k = [(staticlib_st % i) for i in v['STATICLIB']]
486                 app('LINKFLAGS', k)
487
488         # fully static binaries ?
489         if not v['FULLSTATIC']:
490                 if v['STATICLIB'] or v['LIB']:
491                         v.append_value('LINKFLAGS', v['SHLIB_MARKER'])
492
493         app('LINKFLAGS', [lib_st % i for i in v['LIB']])
494
495 @after('apply_link')
496 def process_obj_files(self):
497         if not hasattr(self, 'obj_files'): return
498         for x in self.obj_files:
499                 node = self.path.find_resource(x)
500                 self.link_task.inputs.append(node)
501
502 @taskgen
503 def add_obj_file(self, file):
504         """Small example on how to link object files as if they were source
505         obj = bld.create_obj('cc')
506         obj.add_obj_file('foo.o')"""
507         if not hasattr(self, 'obj_files'): self.obj_files = []
508         if not 'process_obj_files' in self.meths: self.meths.append('process_obj_files')
509         self.obj_files.append(file)
510
511 c_attrs = {
512 'cxxflag' : 'CXXFLAGS',
513 'cflag' : 'CCFLAGS',
514 'ccflag' : 'CCFLAGS',
515 'linkflag' : 'LINKFLAGS',
516 'ldflag' : 'LINKFLAGS',
517 'lib' : 'LIB',
518 'libpath' : 'LIBPATH',
519 'staticlib': 'STATICLIB',
520 'staticlibpath': 'STATICLIBPATH',
521 'rpath' : 'RPATH',
522 'framework' : 'FRAMEWORK',
523 'frameworkpath' : 'FRAMEWORKPATH'
524 }
525
526 @feature('cc', 'cxx')
527 @before('init_cxx', 'init_cc')
528 @before('apply_lib_vars', 'apply_obj_vars', 'apply_incpaths', 'init_cc')
529 def add_extra_flags(self):
530         """case and plural insensitive
531         before apply_obj_vars for processing the library attributes
532         """
533         for x in self.__dict__.keys():
534                 y = x.lower()
535                 if y[-1] == 's':
536                         y = y[:-1]
537                 if c_attrs.get(y, None):
538                         self.env.append_unique(c_attrs[y], getattr(self, x))
539
540 # ============ the code above must not know anything about import libs ==========
541
542 @feature('cshlib')
543 @after('apply_link', 'default_cc')
544 @before('apply_lib_vars', 'apply_objdeps', 'default_link_install')
545 def apply_implib(self):
546         """On mswindows, handle dlls and their import libs
547         the .dll.a is the import lib and it is required for linking so it is installed too
548         """
549         if not self.env.DEST_BINFMT == 'pe':
550                 return
551
552         self.meths.remove('default_link_install')
553
554         bindir = self.install_path
555         if not bindir: return
556
557         # install the dll in the bin dir
558         dll = self.link_task.outputs[0]
559         self.bld.install_files(bindir, dll, self.env, self.chmod)
560
561         # add linker flags to generate the import lib
562         implib = self.env['implib_PATTERN'] % os.path.split(self.target)[1]
563
564         implib = dll.parent.find_or_declare(implib)
565         self.link_task.outputs.append(implib)
566         self.bld.install_as('${LIBDIR}/%s' % implib.name, implib, self.env)
567
568         self.env.append_value('LINKFLAGS', (self.env['IMPLIB_ST'] % implib.bldpath(self.env)).split())
569
570 # ============ the code above must not know anything about vnum processing on unix platforms =========
571
572 @feature('cshlib')
573 @after('apply_link')
574 @before('apply_lib_vars', 'default_link_install')
575 def apply_vnum(self):
576         """
577         libfoo.so is installed as libfoo.so.1.2.3
578         """
579         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'):
580                 return
581
582         self.meths.remove('default_link_install')
583
584         link = self.link_task
585         nums = self.vnum.split('.')
586         node = link.outputs[0]
587
588         libname = node.name
589         if libname.endswith('.dylib'):
590                 name3 = libname.replace('.dylib', '.%s.dylib' % self.vnum)
591                 name2 = libname.replace('.dylib', '.%s.dylib' % nums[0])
592         else:
593                 name3 = libname + '.' + self.vnum
594                 name2 = libname + '.' + nums[0]
595
596         if self.env.SONAME_ST:
597                 v = self.env.SONAME_ST % name2
598                 self.env.append_value('LINKFLAGS', v.split())
599
600         bld = self.bld
601         nums = self.vnum.split('.')
602
603         path = self.install_path
604         if not path: return
605
606         if self.env.DEST_OS == 'openbsd':
607                 libname = self.link_task.outputs[0].name
608                 bld.install_as('%s%s%s' % (path, os.sep, libname), node, env=self.env)
609         else:
610                 bld.install_as(path + os.sep + name3, node, env=self.env)
611                 bld.symlink_as(path + os.sep + name2, name3)
612                 bld.symlink_as(path + os.sep + libname, name3)
613
614         # the following task is just to enable execution from the build dir :-/
615         if self.env.DEST_OS != 'openbsd':
616                 self.create_task('vnum', node, [node.parent.find_or_declare(name2), node.parent.find_or_declare(name3)])
617
618 def exec_vnum_link(self):
619         for x in self.outputs:
620                 path = x.abspath(self.env)
621                 try:
622                         os.remove(path)
623                 except OSError:
624                         pass
625
626                 try:
627                         os.symlink(self.inputs[0].name, path)
628                 except OSError:
629                         return 1
630
631 cls = Task.task_type_from_func('vnum', func=exec_vnum_link, ext_in='.bin', color='CYAN')
632 cls.quiet = 1
633
634 # ============ the --as-needed flag should added during the configuration, not at runtime =========
635
636 @conftest
637 def add_as_needed(conf):
638         if conf.env.DEST_BINFMT == 'elf' and 'gcc' in (conf.env.CXX_NAME, conf.env.CC_NAME):
639                 conf.env.append_unique('LINKFLAGS', '--as-needed')