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