backported the openbsd fixes from waf 1.7
[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 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.%s' % (pattern, nums[0], nums[1])
188
189         return os.path.join(dir, pattern % name)
190
191 @feature('cc', 'cxx')
192 @before('apply_core')
193 def default_cc(self):
194         """compiled_tasks attribute must be set before the '.c->.o' tasks can be created"""
195         Utils.def_attrs(self,
196                 includes = '',
197                 defines= '',
198                 rpaths = '',
199                 uselib = '',
200                 uselib_local = '',
201                 add_objects = '',
202                 p_flag_vars = [],
203                 p_type_vars = [],
204                 compiled_tasks = [],
205                 link_task = None)
206
207         # The only thing we need for cross-compilation is DEST_BINFMT.
208         # At some point, we may reach a case where DEST_BINFMT is not enough, but for now it's sufficient.
209         # Currently, cross-compilation is auto-detected only for the gnu and intel compilers.
210         if not self.env.DEST_BINFMT:
211                 # Infer the binary format from the os name.
212                 self.env.DEST_BINFMT = Utils.unversioned_sys_platform_to_binary_format(
213                         self.env.DEST_OS or Utils.unversioned_sys_platform())
214
215         if not self.env.BINDIR: self.env.BINDIR = Utils.subst_vars('${PREFIX}/bin', self.env)
216         if not self.env.LIBDIR: self.env.LIBDIR = Utils.subst_vars('${PREFIX}/lib${LIB_EXT}', self.env)
217
218 @feature('cprogram', 'dprogram', 'cstaticlib', 'dstaticlib', 'cshlib', 'dshlib')
219 def apply_verif(self):
220         """no particular order, used for diagnostic"""
221         if not (self.source or getattr(self, 'add_objects', None) or getattr(self, 'uselib_local', None) or getattr(self, 'obj_files', None)):
222                 raise Utils.WafError('no source files specified for %s' % self)
223         if not self.target:
224                 raise Utils.WafError('no target for %s' % self)
225
226 # TODO reference the d programs, shlibs in d.py, not here
227
228 @feature('cprogram', 'dprogram')
229 @after('default_cc')
230 @before('apply_core')
231 def vars_target_cprogram(self):
232         self.default_install_path = self.env.BINDIR
233         self.default_chmod = O755
234
235 @after('default_cc')
236 @feature('cshlib', 'dshlib')
237 @before('apply_core')
238 def vars_target_cshlib(self):
239         if self.env.DEST_BINFMT == 'pe':
240                 #   set execute bit on libs to avoid 'permission denied' (issue 283)
241                 self.default_chmod = O755
242                 self.default_install_path = self.env.BINDIR
243         else:
244                 self.default_install_path = self.env.LIBDIR
245
246 @feature('cprogram', 'dprogram', 'cstaticlib', 'dstaticlib', 'cshlib', 'dshlib')
247 @after('apply_link', 'vars_target_cprogram', 'vars_target_cshlib')
248 def default_link_install(self):
249         """you may kill this method to inject your own installation for the first element
250         any other install should only process its own nodes and not those from the others"""
251         if self.install_path:
252                 self.bld.install_files(self.install_path, self.link_task.outputs[0], env=self.env, chmod=self.chmod)
253
254 @feature('cc', 'cxx')
255 @after('apply_type_vars', 'apply_lib_vars', 'apply_core')
256 def apply_incpaths(self):
257         """used by the scanner
258         after processing the uselib for CPPPATH
259         after apply_core because some processing may add include paths
260         """
261         lst = []
262         # TODO move the uselib processing out of here
263         for lib in self.to_list(self.uselib):
264                 for path in self.env['CPPPATH_' + lib]:
265                         if not path in lst:
266                                 lst.append(path)
267         if preproc.go_absolute:
268                 for path in preproc.standard_includes:
269                         if not path in lst:
270                                 lst.append(path)
271
272         for path in self.to_list(self.includes):
273                 if not path in lst:
274                         if preproc.go_absolute or not os.path.isabs(path):
275                                 lst.append(path)
276                         else:
277                                 self.env.prepend_value('CPPPATH', path)
278
279         for path in lst:
280                 node = None
281                 if os.path.isabs(path):
282                         if preproc.go_absolute:
283                                 node = self.bld.root.find_dir(path)
284                 elif path[0] == '#':
285                         node = self.bld.srcnode
286                         if len(path) > 1:
287                                 node = node.find_dir(path[1:])
288                 else:
289                         node = self.path.find_dir(path)
290
291                 if node:
292                         self.env.append_value('INC_PATHS', node)
293
294         # TODO WAF 1.6
295         if USE_TOP_LEVEL:
296                 self.env.append_value('INC_PATHS', self.bld.srcnode)
297
298 @feature('cc', 'cxx')
299 @after('init_cc', 'init_cxx')
300 @before('apply_lib_vars')
301 def apply_type_vars(self):
302         """before apply_lib_vars because we modify uselib
303         after init_cc and init_cxx because web need p_type_vars
304         """
305         for x in self.features:
306                 if not x in ['cprogram', 'cstaticlib', 'cshlib']:
307                         continue
308                 x = x.lstrip('c')
309
310                 # if the type defines uselib to add, add them
311                 st = self.env[x + '_USELIB']
312                 if st: self.uselib = self.uselib + ' ' + st
313
314                 # each compiler defines variables like 'shlib_CXXFLAGS', 'shlib_LINKFLAGS', etc
315                 # so when we make a task generator of the type shlib, CXXFLAGS are modified accordingly
316                 for var in self.p_type_vars:
317                         compvar = '%s_%s' % (x, var)
318                         #print compvar
319                         value = self.env[compvar]
320                         if value: self.env.append_value(var, value)
321
322 @feature('cprogram', 'cshlib', 'cstaticlib')
323 @after('apply_core')
324 def apply_link(self):
325         """executes after apply_core for collecting 'compiled_tasks'
326         use a custom linker if specified (self.link='name-of-custom-link-task')"""
327         link = getattr(self, 'link', None)
328         if not link:
329                 if 'cstaticlib' in self.features: link = 'static_link'
330                 elif 'cxx' in self.features: link = 'cxx_link'
331                 else: link = 'cc_link'
332
333         tsk = self.create_task(link)
334         outputs = [t.outputs[0] for t in self.compiled_tasks]
335         tsk.set_inputs(outputs)
336         tsk.set_outputs(self.path.find_or_declare(get_target_name(self)))
337
338         self.link_task = tsk
339
340 @feature('cc', 'cxx')
341 @after('apply_link', 'init_cc', 'init_cxx', 'apply_core')
342 def apply_lib_vars(self):
343         """after apply_link because of 'link_task'
344         after default_cc because of the attribute 'uselib'"""
345
346         # after 'apply_core' in case if 'cc' if there is no link
347
348         env = self.env
349
350         # 1. the case of the libs defined in the project (visit ancestors first)
351         # the ancestors external libraries (uselib) will be prepended
352         self.uselib = self.to_list(self.uselib)
353         names = self.to_list(self.uselib_local)
354
355         seen = set([])
356         tmp = Utils.deque(names) # consume a copy of the list of names
357         while tmp:
358                 lib_name = tmp.popleft()
359                 # visit dependencies only once
360                 if lib_name in seen:
361                         continue
362
363                 y = self.name_to_obj(lib_name)
364                 if not y:
365                         raise Utils.WafError('object %r was not found in uselib_local (required by %r)' % (lib_name, self.name))
366                 y.post()
367                 seen.add(lib_name)
368
369                 # object has ancestors to process (shared libraries): add them to the end of the list
370                 if getattr(y, 'uselib_local', None):
371                         lst = y.to_list(y.uselib_local)
372                         if 'cshlib' in y.features or 'cprogram' in y.features:
373                                 lst = [x for x in lst if not 'cstaticlib' in self.name_to_obj(x).features]
374                         tmp.extend(lst)
375
376                 # link task and flags
377                 if getattr(y, 'link_task', None):
378
379                         link_name = y.target[y.target.rfind(os.sep) + 1:]
380                         if 'cstaticlib' in y.features:
381                                 env.append_value('STATICLIB', link_name)
382                         elif 'cshlib' in y.features or 'cprogram' in y.features:
383                                 # WARNING some linkers can link against programs
384                                 env.append_value('LIB', link_name)
385
386                         # the order
387                         self.link_task.set_run_after(y.link_task)
388
389                         # for the recompilation
390                         dep_nodes = getattr(self.link_task, 'dep_nodes', [])
391                         self.link_task.dep_nodes = dep_nodes + y.link_task.outputs
392
393                         # add the link path too
394                         tmp_path = y.link_task.outputs[0].parent.bldpath(self.env)
395                         if not tmp_path in env['LIBPATH']: env.prepend_value('LIBPATH', tmp_path)
396
397                 # add ancestors uselib too - but only propagate those that have no staticlib
398                 for v in self.to_list(y.uselib):
399                         if not env['STATICLIB_' + v]:
400                                 if not v in self.uselib:
401                                         self.uselib.insert(0, v)
402
403                 # if the library task generator provides 'export_incdirs', add to the include path
404                 # the export_incdirs must be a list of paths relative to the other library
405                 if getattr(y, 'export_incdirs', None):
406                         for x in self.to_list(y.export_incdirs):
407                                 node = y.path.find_dir(x)
408                                 if not node:
409                                         raise Utils.WafError('object %r: invalid folder %r in export_incdirs' % (y.target, x))
410                                 self.env.append_unique('INC_PATHS', node)
411
412         # 2. the case of the libs defined outside
413         for x in self.uselib:
414                 for v in self.p_flag_vars:
415                         val = self.env[v + '_' + x]
416                         if val: self.env.append_value(v, val)
417
418 @feature('cprogram', 'cstaticlib', 'cshlib')
419 @after('init_cc', 'init_cxx', 'apply_link')
420 def apply_objdeps(self):
421         "add the .o files produced by some other object files in the same manner as uselib_local"
422         if not getattr(self, 'add_objects', None): return
423
424         seen = []
425         names = self.to_list(self.add_objects)
426         while names:
427                 x = names[0]
428
429                 # visit dependencies only once
430                 if x in seen:
431                         names = names[1:]
432                         continue
433
434                 # object does not exist ?
435                 y = self.name_to_obj(x)
436                 if not y:
437                         raise Utils.WafError('object %r was not found in uselib_local (required by add_objects %r)' % (x, self.name))
438
439                 # object has ancestors to process first ? update the list of names
440                 if getattr(y, 'add_objects', None):
441                         added = 0
442                         lst = y.to_list(y.add_objects)
443                         lst.reverse()
444                         for u in lst:
445                                 if u in seen: continue
446                                 added = 1
447                                 names = [u]+names
448                         if added: continue # list of names modified, loop
449
450                 # safe to process the current object
451                 y.post()
452                 seen.append(x)
453
454                 for t in y.compiled_tasks:
455                         self.link_task.inputs.extend(t.outputs)
456
457 @feature('cprogram', 'cshlib', 'cstaticlib')
458 @after('apply_lib_vars')
459 def apply_obj_vars(self):
460         """after apply_lib_vars for uselib"""
461         v = self.env
462         lib_st           = v['LIB_ST']
463         staticlib_st     = v['STATICLIB_ST']
464         libpath_st       = v['LIBPATH_ST']
465         staticlibpath_st = v['STATICLIBPATH_ST']
466         rpath_st         = v['RPATH_ST']
467
468         app = v.append_unique
469
470         if v['FULLSTATIC']:
471                 v.append_value('LINKFLAGS', v['FULLSTATIC_MARKER'])
472
473         for i in v['RPATH']:
474                 if i and rpath_st:
475                         app('LINKFLAGS', rpath_st % i)
476
477         for i in v['LIBPATH']:
478                 app('LINKFLAGS', libpath_st % i)
479                 app('LINKFLAGS', staticlibpath_st % i)
480
481         if v['STATICLIB']:
482                 v.append_value('LINKFLAGS', v['STATICLIB_MARKER'])
483                 k = [(staticlib_st % i) for i in v['STATICLIB']]
484                 app('LINKFLAGS', k)
485
486         # fully static binaries ?
487         if not v['FULLSTATIC']:
488                 if v['STATICLIB'] or v['LIB']:
489                         v.append_value('LINKFLAGS', v['SHLIB_MARKER'])
490
491         app('LINKFLAGS', [lib_st % i for i in v['LIB']])
492
493 @after('apply_link')
494 def process_obj_files(self):
495         if not hasattr(self, 'obj_files'): return
496         for x in self.obj_files:
497                 node = self.path.find_resource(x)
498                 self.link_task.inputs.append(node)
499
500 @taskgen
501 def add_obj_file(self, file):
502         """Small example on how to link object files as if they were source
503         obj = bld.create_obj('cc')
504         obj.add_obj_file('foo.o')"""
505         if not hasattr(self, 'obj_files'): self.obj_files = []
506         if not 'process_obj_files' in self.meths: self.meths.append('process_obj_files')
507         self.obj_files.append(file)
508
509 c_attrs = {
510 'cxxflag' : 'CXXFLAGS',
511 'cflag' : 'CCFLAGS',
512 'ccflag' : 'CCFLAGS',
513 'linkflag' : 'LINKFLAGS',
514 'ldflag' : 'LINKFLAGS',
515 'lib' : 'LIB',
516 'libpath' : 'LIBPATH',
517 'staticlib': 'STATICLIB',
518 'staticlibpath': 'STATICLIBPATH',
519 'rpath' : 'RPATH',
520 'framework' : 'FRAMEWORK',
521 'frameworkpath' : 'FRAMEWORKPATH'
522 }
523
524 @feature('cc', 'cxx')
525 @before('init_cxx', 'init_cc')
526 @before('apply_lib_vars', 'apply_obj_vars', 'apply_incpaths', 'init_cc')
527 def add_extra_flags(self):
528         """case and plural insensitive
529         before apply_obj_vars for processing the library attributes
530         """
531         for x in self.__dict__.keys():
532                 y = x.lower()
533                 if y[-1] == 's':
534                         y = y[:-1]
535                 if c_attrs.get(y, None):
536                         self.env.append_unique(c_attrs[y], getattr(self, x))
537
538 # ============ the code above must not know anything about import libs ==========
539
540 @feature('cshlib')
541 @after('apply_link', 'default_cc')
542 @before('apply_lib_vars', 'apply_objdeps', 'default_link_install')
543 def apply_implib(self):
544         """On mswindows, handle dlls and their import libs
545         the .dll.a is the import lib and it is required for linking so it is installed too
546         """
547         if not self.env.DEST_BINFMT == 'pe':
548                 return
549
550         self.meths.remove('default_link_install')
551
552         bindir = self.install_path
553         if not bindir: return
554
555         # install the dll in the bin dir
556         dll = self.link_task.outputs[0]
557         self.bld.install_files(bindir, dll, self.env, self.chmod)
558
559         # add linker flags to generate the import lib
560         implib = self.env['implib_PATTERN'] % os.path.split(self.target)[1]
561
562         implib = dll.parent.find_or_declare(implib)
563         self.link_task.outputs.append(implib)
564         self.bld.install_as('${LIBDIR}/%s' % implib.name, implib, self.env)
565
566         self.env.append_value('LINKFLAGS', (self.env['IMPLIB_ST'] % implib.bldpath(self.env)).split())
567
568 # ============ the code above must not know anything about vnum processing on unix platforms =========
569
570 @feature('cshlib')
571 @after('apply_link')
572 @before('apply_lib_vars', 'default_link_install')
573 def apply_vnum(self):
574         """
575         libfoo.so is installed as libfoo.so.1.2.3
576         """
577         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'):
578                 return
579
580         self.meths.remove('default_link_install')
581
582         link = self.link_task
583         nums = self.vnum.split('.')
584         node = link.outputs[0]
585
586         libname = node.name
587         if libname.endswith('.dylib'):
588                 name3 = libname.replace('.dylib', '.%s.dylib' % self.vnum)
589                 name2 = libname.replace('.dylib', '.%s.dylib' % nums[0])
590         else:
591                 name3 = libname + '.' + self.vnum
592                 name2 = libname + '.' + nums[0]
593
594         if self.env.SONAME_ST:
595                 v = self.env.SONAME_ST % name2
596                 self.env.append_value('LINKFLAGS', v.split())
597
598         bld = self.bld
599         nums = self.vnum.split('.')
600
601         path = self.install_path
602         if not path: return
603
604         if self.env.DEST_OS == 'openbsd':
605                 libname = self.link_task.outputs[0].name
606                 bld.install_as('%s%s%s' % (path, os.sep, libname), node, env=self.env)
607         else:
608                 bld.install_as(path + os.sep + name3, node, env=self.env)
609                 bld.symlink_as(path + os.sep + name2, name3)
610                 bld.symlink_as(path + os.sep + libname, name3)
611
612         # the following task is just to enable execution from the build dir :-/
613         if self.env.DEST_OS != 'openbsd':
614                 self.create_task('vnum', node, [node.parent.find_or_declare(name2), node.parent.find_or_declare(name3)])
615
616 def exec_vnum_link(self):
617         for x in self.outputs:
618                 path = x.abspath(self.env)
619                 try:
620                         os.remove(path)
621                 except OSError:
622                         pass
623
624                 try:
625                         os.symlink(self.inputs[0].name, path)
626                 except OSError:
627                         return 1
628
629 cls = Task.task_type_from_func('vnum', func=exec_vnum_link, ext_in='.bin', color='CYAN')
630 cls.quiet = 1
631
632 # ============ the --as-needed flag should added during the configuration, not at runtime =========
633
634 @conftest
635 def add_as_needed(conf):
636         if conf.env.DEST_BINFMT == 'elf' and 'gcc' in (conf.env.CXX_NAME, conf.env.CC_NAME):
637                 conf.env.append_unique('LINKFLAGS', '--as-needed')
638