]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/tools/build/src/tools/builtin.py
import new upstream nautilus stable release 14.2.8
[ceph.git] / ceph / src / boost / tools / build / src / tools / builtin.py
1 # Status: minor updates by Steven Watanabe to make gcc work
2 #
3 # Copyright (C) Vladimir Prus 2002. Permission to copy, use, modify, sell and
4 # distribute this software is granted provided this copyright notice appears in
5 # all copies. This software is provided "as is" without express or implied
6 # warranty, and with no claim as to its suitability for any purpose.
7
8 """ Defines standard features and rules.
9 """
10
11 import b2.build.targets as targets
12
13 import sys
14 from b2.build import feature, property, virtual_target, generators, type, property_set, scanner
15 from b2.util.utility import *
16 from b2.util import path, regex, bjam_signature, is_iterable_typed
17 import b2.tools.types
18 from b2.manager import get_manager
19
20
21 # Records explicit properties for a variant.
22 # The key is the variant name.
23 __variant_explicit_properties = {}
24
25 def reset ():
26 """ Clear the module state. This is mainly for testing purposes.
27 """
28 global __variant_explicit_properties
29
30 __variant_explicit_properties = {}
31
32 @bjam_signature((["name"], ["parents_or_properties", "*"], ["explicit_properties", "*"]))
33 def variant (name, parents_or_properties, explicit_properties = []):
34 """ Declares a new variant.
35 First determines explicit properties for this variant, by
36 refining parents' explicit properties with the passed explicit
37 properties. The result is remembered and will be used if
38 this variant is used as parent.
39
40 Second, determines the full property set for this variant by
41 adding to the explicit properties default values for all properties
42 which neither present nor are symmetric.
43
44 Lastly, makes appropriate value of 'variant' property expand
45 to the full property set.
46 name: Name of the variant
47 parents_or_properties: Specifies parent variants, if
48 'explicit_properties' are given,
49 and explicit_properties otherwise.
50 explicit_properties: Explicit properties.
51 """
52 parents = []
53 if not explicit_properties:
54 explicit_properties = parents_or_properties
55 else:
56 parents = parents_or_properties
57
58 inherited = property_set.empty()
59 if parents:
60
61 # If we allow multiple parents, we'd have to to check for conflicts
62 # between base variants, and there was no demand for so to bother.
63 if len (parents) > 1:
64 raise BaseException ("Multiple base variants are not yet supported")
65
66 p = parents[0]
67 # TODO: the check may be stricter
68 if not feature.is_implicit_value (p):
69 raise BaseException ("Invalid base variant '%s'" % p)
70
71 inherited = __variant_explicit_properties[p]
72
73 explicit_properties = property_set.create_with_validation(explicit_properties)
74 explicit_properties = inherited.refine(explicit_properties)
75
76 # Record explicitly specified properties for this variant
77 # We do this after inheriting parents' properties, so that
78 # they affect other variants, derived from this one.
79 __variant_explicit_properties[name] = explicit_properties
80
81 feature.extend('variant', [name])
82 feature.compose ("<variant>" + name, explicit_properties.all())
83
84 __os_names = """
85 amiga aix appletv bsd cygwin darwin dos emx freebsd hpux iphone linux netbsd
86 openbsd osf qnx qnxnto sgi solaris sun sunos svr4 sysv ultrix unix unixware
87 vms windows
88 """.split()
89
90 # Translates from bjam current OS to the os tags used in host-os and target-os,
91 # i.e. returns the running host-os.
92 #
93 def default_host_os():
94 host_os = os_name()
95 if host_os not in (x.upper() for x in __os_names):
96 if host_os == 'NT': host_os = 'windows'
97 elif host_os == 'AS400': host_os = 'unix'
98 elif host_os == 'MINGW': host_os = 'windows'
99 elif host_os == 'BSDI': host_os = 'bsd'
100 elif host_os == 'COHERENT': host_os = 'unix'
101 elif host_os == 'DRAGONFLYBSD': host_os = 'bsd'
102 elif host_os == 'IRIX': host_os = 'sgi'
103 elif host_os == 'MACOSX': host_os = 'darwin'
104 elif host_os == 'KFREEBSD': host_os = 'freebsd'
105 elif host_os == 'LINUX': host_os = 'linux'
106 elif host_os == 'HAIKU': host_os = 'haiku'
107 else: host_os = 'unix'
108 return host_os.lower()
109
110 def register_globals ():
111 """ Registers all features and variants declared by this module.
112 """
113
114 # This feature is used to determine which OS we're on.
115 # In future, this may become <target-os> and <host-os>
116 # TODO: check this. Compatibility with bjam names? Subfeature for version?
117 os = sys.platform
118 feature.feature ('os', [os], ['propagated', 'link-incompatible'])
119
120
121 # The two OS features define a known set of abstract OS names. The host-os is
122 # the OS under which bjam is running. Even though this should really be a fixed
123 # property we need to list all the values to prevent unknown value errors. Both
124 # set the default value to the current OS to account for the default use case of
125 # building on the target OS.
126 feature.feature('host-os', __os_names)
127 feature.set_default('host-os', default_host_os())
128
129 feature.feature('target-os', __os_names, ['propagated', 'link-incompatible'])
130 feature.set_default('target-os', default_host_os())
131
132 feature.feature ('toolset', [], ['implicit', 'propagated' ,'symmetric'])
133
134 feature.feature ('stdlib', ['native'], ['propagated', 'composite'])
135
136 feature.feature ('link', ['shared', 'static'], ['propagated'])
137 feature.feature ('runtime-link', ['shared', 'static'], ['propagated'])
138 feature.feature ('runtime-debugging', ['on', 'off'], ['propagated'])
139
140
141 feature.feature ('optimization', ['off', 'speed', 'space'], ['propagated'])
142 feature.feature ('profiling', ['off', 'on'], ['propagated'])
143 feature.feature ('inlining', ['off', 'on', 'full'], ['propagated'])
144
145 feature.feature ('threading', ['single', 'multi'], ['propagated'])
146 feature.feature ('rtti', ['on', 'off'], ['propagated'])
147 feature.feature ('exception-handling', ['on', 'off'], ['propagated'])
148
149 # Whether there is support for asynchronous EH (e.g. catching SEGVs).
150 feature.feature ('asynch-exceptions', ['off', 'on'], ['propagated'])
151
152 # Whether all extern "C" functions are considered nothrow by default.
153 feature.feature ('extern-c-nothrow', ['off', 'on'], ['propagated'])
154
155 feature.feature ('debug-symbols', ['on', 'off'], ['propagated'])
156 feature.feature ('define', [], ['free'])
157 feature.feature ('undef', [], ['free'])
158 feature.feature ('include', [], ['free', 'path']) #order-sensitive
159 feature.feature ('cflags', [], ['free'])
160 feature.feature ('cxxflags', [], ['free'])
161 feature.feature ('asmflags', [], ['free'])
162 feature.feature ('linkflags', [], ['free'])
163 feature.feature ('archiveflags', [], ['free'])
164 feature.feature ('version', [], ['free'])
165
166 feature.feature ('location-prefix', [], ['free'])
167
168 feature.feature ('action', [], ['free'])
169
170
171 # The following features are incidental, since
172 # in themself they have no effect on build products.
173 # Not making them incidental will result in problems in corner
174 # cases, for example:
175 #
176 # unit-test a : a.cpp : <use>b ;
177 # lib b : a.cpp b ;
178 #
179 # Here, if <use> is not incidental, we'll decide we have two
180 # targets for a.obj with different properties, and will complain.
181 #
182 # Note that making feature incidental does not mean it's ignored. It may
183 # be ignored when creating the virtual target, but the rest of build process
184 # will use them.
185 feature.feature ('use', [], ['free', 'dependency', 'incidental'])
186 feature.feature ('dependency', [], ['free', 'dependency', 'incidental'])
187 feature.feature ('implicit-dependency', [], ['free', 'dependency', 'incidental'])
188
189 feature.feature('warnings', [
190 'on', # Enable default/"reasonable" warning level for the tool.
191 'all', # Enable all possible warnings issued by the tool.
192 'off'], # Disable all warnings issued by the tool.
193 ['incidental', 'propagated'])
194
195 feature.feature('warnings-as-errors', [
196 'off', # Do not fail the compilation if there are warnings.
197 'on'], # Fail the compilation if there are warnings.
198 ['incidental', 'propagated'])
199
200 feature.feature('coverage', [
201 'off', # Disable coverage generation for the tool.
202 'on'], # Enable coverage generation for the tool.
203 ['incidental', 'propagated'])
204
205 feature.feature('c++-template-depth',
206 [str(i) for i in range(64,1024+1,64)] +
207 [str(i) for i in range(20,1000+1,10)] +
208 # Maximum template instantiation depth guaranteed for ANSI/ISO C++
209 # conforming programs.
210 ['17'],
211 ['incidental', 'optional', 'propagated'])
212
213 feature.feature ('source', [], ['free', 'dependency', 'incidental'])
214 feature.feature ('library', [], ['free', 'dependency', 'incidental'])
215 feature.feature ('file', [], ['free', 'dependency', 'incidental'])
216 feature.feature ('find-shared-library', [], ['free']) #order-sensitive ;
217 feature.feature ('find-static-library', [], ['free']) #order-sensitive ;
218 feature.feature ('library-path', [], ['free', 'path']) #order-sensitive ;
219 # Internal feature.
220 feature.feature ('library-file', [], ['free', 'dependency'])
221
222 feature.feature ('name', [], ['free'])
223 feature.feature ('tag', [], ['free'])
224 feature.feature ('search', [], ['free', 'path']) #order-sensitive ;
225 feature.feature ('location', [], ['free', 'path'])
226
227 feature.feature ('dll-path', [], ['free', 'path'])
228 feature.feature ('hardcode-dll-paths', ['true', 'false'], ['incidental'])
229
230
231 # This is internal feature which holds the paths of all dependency
232 # dynamic libraries. On Windows, it's needed so that we can all
233 # those paths to PATH, when running applications.
234 # On Linux, it's needed to add proper -rpath-link command line options.
235 feature.feature ('xdll-path', [], ['free', 'path'])
236
237 #provides means to specify def-file for windows dlls.
238 feature.feature ('def-file', [], ['free', 'dependency'])
239
240 # This feature is used to allow specific generators to run.
241 # For example, QT tools can only be invoked when QT library
242 # is used. In that case, <allow>qt will be in usage requirement
243 # of the library.
244 feature.feature ('allow', [], ['free'])
245
246 # The addressing model to generate code for. Currently a limited set only
247 # specifying the bit size of pointers.
248 feature.feature('address-model', ['16', '32', '64'], ['propagated', 'optional'])
249
250 # Type of CPU architecture to compile for.
251 feature.feature('architecture', [
252 # x86 and x86-64
253 'x86',
254
255 # ia64
256 'ia64',
257
258 # Sparc
259 'sparc',
260
261 # RS/6000 & PowerPC
262 'power',
263
264 # MIPS/SGI
265 'mips1', 'mips2', 'mips3', 'mips4', 'mips32', 'mips32r2', 'mips64',
266
267 # HP/PA-RISC
268 'parisc',
269
270 # Advanced RISC Machines
271 'arm',
272
273 # z Systems (aka s390x)
274 's390x',
275
276 # Combined architectures for platforms/toolsets that support building for
277 # multiple architectures at once. "combined" would be the default multi-arch
278 # for the toolset.
279 'combined',
280 'combined-x86-power'],
281
282 ['propagated', 'optional'])
283
284 # The specific instruction set in an architecture to compile.
285 feature.feature('instruction-set', [
286 # x86 and x86-64
287 'native', 'i486', 'i586', 'i686', 'pentium', 'pentium-mmx', 'pentiumpro', 'pentium2', 'pentium3',
288 'pentium3m', 'pentium-m', 'pentium4', 'pentium4m', 'prescott', 'nocona', 'core2', 'corei7', 'corei7-avx', 'core-avx-i',
289 'conroe', 'conroe-xe', 'conroe-l', 'allendale', 'merom', 'merom-xe', 'kentsfield', 'kentsfield-xe', 'penryn', 'wolfdale',
290 'yorksfield', 'nehalem', 'sandy-bridge', 'ivy-bridge', 'haswell', 'k6', 'k6-2', 'k6-3', 'athlon', 'athlon-tbird', 'athlon-4', 'athlon-xp',
291 'athlon-mp', 'k8', 'opteron', 'athlon64', 'athlon-fx', 'k8-sse3', 'opteron-sse3', 'athlon64-sse3', 'amdfam10', 'barcelona',
292 'bdver1', 'bdver2', 'bdver3', 'btver1', 'btver2', 'winchip-c6', 'winchip2', 'c3', 'c3-2', 'atom',
293
294 # ia64
295 'itanium', 'itanium1', 'merced', 'itanium2', 'mckinley',
296
297 # Sparc
298 'v7', 'cypress', 'v8', 'supersparc', 'sparclite', 'hypersparc', 'sparclite86x', 'f930', 'f934',
299 'sparclet', 'tsc701', 'v9', 'ultrasparc', 'ultrasparc3',
300
301 # RS/6000 & PowerPC
302 '401', '403', '405', '405fp', '440', '440fp', '505', '601', '602',
303 '603', '603e', '604', '604e', '620', '630', '740', '7400',
304 '7450', '750', '801', '821', '823', '860', '970', '8540',
305 'power-common', 'ec603e', 'g3', 'g4', 'g5', 'power', 'power2',
306 'power3', 'power4', 'power5', 'powerpc', 'powerpc64', 'rios',
307 'rios1', 'rsc', 'rios2', 'rs64a',
308
309 # MIPS
310 '4kc', '4kp', '5kc', '20kc', 'm4k', 'r2000', 'r3000', 'r3900', 'r4000',
311 'r4100', 'r4300', 'r4400', 'r4600', 'r4650',
312 'r6000', 'r8000', 'rm7000', 'rm9000', 'orion', 'sb1', 'vr4100',
313 'vr4111', 'vr4120', 'vr4130', 'vr4300',
314 'vr5000', 'vr5400', 'vr5500',
315
316 # HP/PA-RISC
317 '700', '7100', '7100lc', '7200', '7300', '8000',
318
319 # Advanced RISC Machines
320 'armv2', 'armv2a', 'armv3', 'armv3m', 'armv4', 'armv4t', 'armv5',
321 'armv5t', 'armv5te', 'armv6', 'armv6j', 'iwmmxt', 'ep9312',
322
323 # z Systems (aka s390x)
324 'z196', 'zEC12', 'z13', 'z13', 'z14'],
325
326 ['propagated', 'optional'])
327
328 feature.feature('conditional', [], ['incidental', 'free'])
329
330 # The value of 'no' prevents building of a target.
331 feature.feature('build', ['yes', 'no'], ['optional'])
332
333 # Windows-specific features
334 feature.feature ('user-interface', ['console', 'gui', 'wince', 'native', 'auto'], [])
335 feature.feature ('variant', [], ['implicit', 'composite', 'propagated', 'symmetric'])
336
337
338 variant ('debug', ['<optimization>off', '<debug-symbols>on', '<inlining>off', '<runtime-debugging>on'])
339 variant ('release', ['<optimization>speed', '<debug-symbols>off', '<inlining>full',
340 '<runtime-debugging>off', '<define>NDEBUG'])
341 variant ('profile', ['release'], ['<profiling>on', '<debug-symbols>on'])
342
343
344 reset ()
345 register_globals ()
346
347 class SearchedLibTarget (virtual_target.AbstractFileTarget):
348 def __init__ (self, name, project, shared, search, action):
349 virtual_target.AbstractFileTarget.__init__ (self, name, 'SEARCHED_LIB', project, action)
350
351 self.shared_ = shared
352 self.search_ = search
353
354 def shared (self):
355 return self.shared_
356
357 def search (self):
358 return self.search_
359
360 def actualize_location (self, target):
361 bjam.call("NOTFILE", target)
362
363 def path (self):
364 #FIXME: several functions rely on this not being None
365 return ""
366
367
368 class CScanner (scanner.Scanner):
369 def __init__ (self, includes):
370 scanner.Scanner.__init__ (self)
371
372 self.includes_ = []
373
374 for i in includes:
375 self.includes_.extend(i.split("&&"))
376
377 def pattern (self):
378 return r'#[ \t]*include[ ]*(<(.*)>|"(.*)")'
379
380 def process (self, target, matches, binding):
381 # since it's possible for this function to be called
382 # thousands to millions of times (depending on how many
383 # header files there are), as such, there are some
384 # optimizations that have been used here. Anything that
385 # is slightly out of the ordinary for Python code
386 # has been commented.
387 angle = []
388 quoted = []
389 for match in matches:
390 if '<' in match:
391 angle.append(match.strip('<>'))
392 elif '"' in match:
393 quoted.append(match.strip('"'))
394
395 g = id(self)
396 b = os.path.normpath(os.path.dirname(binding[0]))
397
398 # Attach binding of including file to included targets.
399 # When target is directly created from virtual target
400 # this extra information is unnecessary. But in other
401 # cases, it allows to distinguish between two headers of the
402 # same name included from different places.
403 # We don't need this extra information for angle includes,
404 # since they should not depend on including file (we can't
405 # get literal "." in include path).
406 # Note: string interpolation is slightly faster
407 # than .format()
408 g2 = '<%s#%s>' % (g, b)
409 g = "<%s>" % g
410
411 angle = [g + x for x in angle]
412 quoted = [g2 + x for x in quoted]
413
414 all = angle + quoted
415 bjam.call("mark-included", target, all)
416
417 # each include in self.includes_ looks something like this:
418 # <include>path/to/somewhere
419 # calling get_value(include) is super slow,
420 # calling .replace('<include>', '') is much faster
421 # however, i[9:] is the fastest way of stripping off the "<include>"
422 # substring.
423 include_paths = [i[9:] for i in self.includes_]
424
425 engine = get_manager().engine()
426 engine.set_target_variable(angle, "SEARCH", include_paths)
427 engine.set_target_variable(quoted, "SEARCH", [b] + include_paths)
428
429 # Just propagate current scanner to includes, in a hope
430 # that includes do not change scanners.
431 get_manager().scanners().propagate(self, all)
432
433 scanner.register (CScanner, 'include')
434 type.set_scanner ('CPP', CScanner)
435 type.set_scanner ('C', CScanner)
436 type.set_scanner('H', CScanner)
437 type.set_scanner('HPP', CScanner)
438
439 # Ported to trunk@47077
440 class LibGenerator (generators.Generator):
441 """ The generator class for libraries (target type LIB). Depending on properties it will
442 request building of the approapriate specific type -- SHARED_LIB, STATIC_LIB or
443 SHARED_LIB.
444 """
445
446 def __init__(self, id, composing = True, source_types = [], target_types_and_names = ['LIB'], requirements = []):
447 generators.Generator.__init__(self, id, composing, source_types, target_types_and_names, requirements)
448
449 def run(self, project, name, prop_set, sources):
450 assert isinstance(project, targets.ProjectTarget)
451 assert isinstance(name, basestring) or name is None
452 assert isinstance(prop_set, property_set.PropertySet)
453 assert is_iterable_typed(sources, virtual_target.VirtualTarget)
454 # The lib generator is composing, and can be only invoked with
455 # explicit name. This check is present in generator.run (and so in
456 # builtin.LinkingGenerator), but duplicate it here to avoid doing
457 # extra work.
458 if name:
459 properties = prop_set.raw()
460 # Determine the needed target type
461 actual_type = None
462 properties_grist = get_grist(properties)
463 if '<source>' not in properties_grist and \
464 ('<search>' in properties_grist or '<name>' in properties_grist):
465 actual_type = 'SEARCHED_LIB'
466 elif '<file>' in properties_grist:
467 # The generator for
468 actual_type = 'LIB'
469 elif '<link>shared' in properties:
470 actual_type = 'SHARED_LIB'
471 else:
472 actual_type = 'STATIC_LIB'
473
474 prop_set = prop_set.add_raw(['<main-target-type>LIB'])
475
476 # Construct the target.
477 return generators.construct(project, name, actual_type, prop_set, sources)
478
479 def viable_source_types(self):
480 return ['*']
481
482 generators.register(LibGenerator("builtin.lib-generator"))
483
484 generators.override("builtin.prebuilt", "builtin.lib-generator")
485
486 def lib(names, sources=[], requirements=[], default_build=[], usage_requirements=[]):
487 """The implementation of the 'lib' rule. Beyond standard syntax that rule allows
488 simplified: 'lib a b c ;'."""
489 assert is_iterable_typed(names, basestring)
490 assert is_iterable_typed(sources, basestring)
491 assert is_iterable_typed(requirements, basestring)
492 assert is_iterable_typed(default_build, basestring)
493 assert is_iterable_typed(usage_requirements, basestring)
494 if len(names) > 1:
495 if any(r.startswith('<name>') for r in requirements):
496 get_manager().errors()("When several names are given to the 'lib' rule\n" +
497 "it is not allowed to specify the <name> feature.")
498
499 if sources:
500 get_manager().errors()("When several names are given to the 'lib' rule\n" +
501 "it is not allowed to specify sources.")
502
503 project = get_manager().projects().current()
504 result = []
505
506 for name in names:
507 r = requirements[:]
508
509 # Support " lib a ; " and " lib a b c ; " syntax.
510 if not sources and not any(r.startswith("<name>") for r in requirements) \
511 and not any(r.startswith("<file") for r in requirements):
512 r.append("<name>" + name)
513
514 result.append(targets.create_typed_metatarget(name, "LIB", sources,
515 r,
516 default_build,
517 usage_requirements))
518 return result
519
520 get_manager().projects().add_rule("lib", lib)
521
522
523 # Updated to trunk@47077
524 class SearchedLibGenerator (generators.Generator):
525 def __init__ (self, id = 'SearchedLibGenerator', composing = False, source_types = [], target_types_and_names = ['SEARCHED_LIB'], requirements = []):
526 # TODO: the comment below looks strange. There are no requirements!
527 # The requirements cause the generators to be tried *only* when we're building
528 # lib target and there's 'search' feature. This seems ugly --- all we want
529 # is make sure SearchedLibGenerator is not invoked deep in transformation
530 # search.
531 generators.Generator.__init__ (self, id, composing, source_types, target_types_and_names, requirements)
532
533 def run(self, project, name, prop_set, sources):
534 assert isinstance(project, targets.ProjectTarget)
535 assert isinstance(name, basestring) or name is None
536 assert isinstance(prop_set, property_set.PropertySet)
537 assert is_iterable_typed(sources, virtual_target.VirtualTarget)
538
539 if not name:
540 return None
541
542 # If name is empty, it means we're called not from top-level.
543 # In this case, we just fail immediately, because SearchedLibGenerator
544 # cannot be used to produce intermediate targets.
545
546 properties = prop_set.raw ()
547 shared = '<link>shared' in properties
548
549 a = virtual_target.NullAction (project.manager(), prop_set)
550
551 real_name = feature.get_values ('<name>', properties)
552 if real_name:
553 real_name = real_name[0]
554 else:
555 real_name = name
556 search = feature.get_values('<search>', properties)
557 usage_requirements = property_set.create(['<xdll-path>' + p for p in search])
558 t = SearchedLibTarget(real_name, project, shared, search, a)
559
560 # We return sources for a simple reason. If there's
561 # lib png : z : <name>png ;
562 # the 'z' target should be returned, so that apps linking to
563 # 'png' will link to 'z', too.
564 return(usage_requirements, [b2.manager.get_manager().virtual_targets().register(t)] + sources)
565
566 generators.register (SearchedLibGenerator ())
567
568 class PrebuiltLibGenerator(generators.Generator):
569
570 def __init__(self, id, composing, source_types, target_types_and_names, requirements):
571 generators.Generator.__init__ (self, id, composing, source_types, target_types_and_names, requirements)
572
573 def run(self, project, name, properties, sources):
574 assert isinstance(project, targets.ProjectTarget)
575 assert isinstance(name, basestring)
576 assert isinstance(properties, property_set.PropertySet)
577 assert is_iterable_typed(sources, virtual_target.VirtualTarget)
578
579 f = properties.get("file")
580 return f + sources
581
582 generators.register(PrebuiltLibGenerator("builtin.prebuilt", False, [],
583 ["LIB"], ["<file>"]))
584
585 generators.override("builtin.prebuilt", "builtin.lib-generator")
586
587
588 class CompileAction (virtual_target.Action):
589 def __init__ (self, manager, sources, action_name, prop_set):
590 virtual_target.Action.__init__ (self, manager, sources, action_name, prop_set)
591
592 def adjust_properties (self, prop_set):
593 """ For all virtual targets for the same dependency graph as self,
594 i.e. which belong to the same main target, add their directories
595 to include path.
596 """
597 assert isinstance(prop_set, property_set.PropertySet)
598 s = self.targets () [0].creating_subvariant ()
599
600 return prop_set.add_raw (s.implicit_includes ('include', 'H'))
601
602 class CCompilingGenerator (generators.Generator):
603 """ Declare a special compiler generator.
604 The only thing it does is changing the type used to represent
605 'action' in the constructed dependency graph to 'CompileAction'.
606 That class in turn adds additional include paths to handle a case
607 when a source file includes headers which are generated themselves.
608 """
609 def __init__ (self, id, composing, source_types, target_types_and_names, requirements):
610 # TODO: (PF) What to do with optional_properties? It seemed that, in the bjam version, the arguments are wrong.
611 generators.Generator.__init__ (self, id, composing, source_types, target_types_and_names, requirements)
612
613 def action_class (self):
614 return CompileAction
615
616 def register_c_compiler (id, source_types, target_types, requirements, optional_properties = []):
617 g = CCompilingGenerator (id, False, source_types, target_types, requirements + optional_properties)
618 return generators.register (g)
619
620
621 class LinkingGenerator (generators.Generator):
622 """ The generator class for handling EXE and SHARED_LIB creation.
623 """
624 def __init__ (self, id, composing, source_types, target_types_and_names, requirements):
625 generators.Generator.__init__ (self, id, composing, source_types, target_types_and_names, requirements)
626
627 def run (self, project, name, prop_set, sources):
628 assert isinstance(project, targets.ProjectTarget)
629 assert isinstance(name, basestring) or name is None
630 assert isinstance(prop_set, property_set.PropertySet)
631 assert is_iterable_typed(sources, virtual_target.VirtualTarget)
632
633 # create a copy since sources is being modified
634 sources = list(sources)
635 sources.extend(prop_set.get('<library>'))
636
637 # Add <library-path> properties for all searched libraries
638 extra = []
639 for s in sources:
640 if s.type () == 'SEARCHED_LIB':
641 search = s.search()
642 extra.extend(property.Property('<library-path>', sp) for sp in search)
643
644 # It's possible that we have libraries in sources which did not came
645 # from 'lib' target. For example, libraries which are specified
646 # just as filenames as sources. We don't have xdll-path properties
647 # for such target, but still need to add proper dll-path properties.
648 extra_xdll_path = []
649 for s in sources:
650 if type.is_derived (s.type (), 'SHARED_LIB') and not s.action ():
651 # Unfortunately, we don't have a good way to find the path
652 # to a file, so use this nasty approach.
653 p = s.project()
654 location = path.root(s.name(), p.get('source-location')[0])
655 extra_xdll_path.append(os.path.dirname(location))
656
657 # Hardcode DLL paths only when linking executables.
658 # Pros: do not need to relink libraries when installing.
659 # Cons: "standalone" libraries (plugins, python extensions) can not
660 # hardcode paths to dependent libraries.
661 if prop_set.get('<hardcode-dll-paths>') == ['true'] \
662 and type.is_derived(self.target_types_ [0], 'EXE'):
663 xdll_path = prop_set.get('<xdll-path>')
664 extra.extend(property.Property('<dll-path>', sp) \
665 for sp in extra_xdll_path)
666 extra.extend(property.Property('<dll-path>', sp) \
667 for sp in xdll_path)
668
669 if extra:
670 prop_set = prop_set.add_raw (extra)
671 result = generators.Generator.run(self, project, name, prop_set, sources)
672
673 if result:
674 ur = self.extra_usage_requirements(result, prop_set)
675 ur = ur.add(property_set.create(['<xdll-path>' + p for p in extra_xdll_path]))
676 else:
677 return None
678 return (ur, result)
679
680 def extra_usage_requirements (self, created_targets, prop_set):
681 assert is_iterable_typed(created_targets, virtual_target.VirtualTarget)
682 assert isinstance(prop_set, property_set.PropertySet)
683
684 result = property_set.empty ()
685 extra = []
686
687 # Add appropriate <xdll-path> usage requirements.
688 raw = prop_set.raw ()
689 if '<link>shared' in raw:
690 paths = []
691
692 # TODO: is it safe to use the current directory? I think we should use
693 # another mechanism to allow this to be run from anywhere.
694 pwd = os.getcwd()
695
696 for t in created_targets:
697 if type.is_derived(t.type(), 'SHARED_LIB'):
698 paths.append(path.root(path.make(t.path()), pwd))
699
700 extra += replace_grist(paths, '<xdll-path>')
701
702 # We need to pass <xdll-path> features that we've got from sources,
703 # because if shared library is built, exe which uses it must know paths
704 # to other shared libraries this one depends on, to be able to find them
705 # all at runtime.
706
707 # Just pass all features in property_set, it's theorically possible
708 # that we'll propagate <xdll-path> features explicitly specified by
709 # the user, but then the user's to blame for using internal feature.
710 values = prop_set.get('<xdll-path>')
711 extra += replace_grist(values, '<xdll-path>')
712
713 if extra:
714 result = property_set.create(extra)
715
716 return result
717
718 def generated_targets (self, sources, prop_set, project, name):
719 assert is_iterable_typed(sources, virtual_target.VirtualTarget)
720 assert isinstance(prop_set, property_set.PropertySet)
721 assert isinstance(project, targets.ProjectTarget)
722 assert isinstance(name, basestring)
723 # sources to pass to inherited rule
724 sources2 = []
725 # sources which are libraries
726 libraries = []
727
728 # Searched libraries are not passed as argument to linker
729 # but via some option. So, we pass them to the action
730 # via property.
731 fsa = []
732 fst = []
733 for s in sources:
734 if type.is_derived(s.type(), 'SEARCHED_LIB'):
735 n = s.name()
736 if s.shared():
737 fsa.append(n)
738
739 else:
740 fst.append(n)
741
742 else:
743 sources2.append(s)
744
745 add = []
746 if fsa:
747 add.append("<find-shared-library>" + '&&'.join(fsa))
748 if fst:
749 add.append("<find-static-library>" + '&&'.join(fst))
750
751 spawn = generators.Generator.generated_targets(self, sources2, prop_set.add_raw(add), project, name)
752 return spawn
753
754
755 def register_linker(id, source_types, target_types, requirements):
756 g = LinkingGenerator(id, True, source_types, target_types, requirements)
757 generators.register(g)
758
759 class ArchiveGenerator (generators.Generator):
760 """ The generator class for handling STATIC_LIB creation.
761 """
762 def __init__ (self, id, composing, source_types, target_types_and_names, requirements):
763 generators.Generator.__init__ (self, id, composing, source_types, target_types_and_names, requirements)
764
765 def run (self, project, name, prop_set, sources):
766 assert isinstance(project, targets.ProjectTarget)
767 assert isinstance(name, basestring) or name is None
768 assert isinstance(prop_set, property_set.PropertySet)
769 assert is_iterable_typed(sources, virtual_target.VirtualTarget)
770
771 # create a copy since this modifies the sources list
772 sources = list(sources)
773 sources.extend(prop_set.get('<library>'))
774
775 result = generators.Generator.run (self, project, name, prop_set, sources)
776
777 usage_requirements = []
778 link = prop_set.get('<link>')
779 if 'static' in link:
780 for t in sources:
781 if type.is_derived(t.type(), 'LIB'):
782 usage_requirements.append(property.Property('<library>', t))
783
784 usage_requirements = property_set.create(usage_requirements)
785
786 return usage_requirements, result
787
788
789 def register_archiver(id, source_types, target_types, requirements):
790 g = ArchiveGenerator(id, True, source_types, target_types, requirements)
791 generators.register(g)
792
793 class DummyGenerator(generators.Generator):
794 """Generator that accepts everything and produces nothing. Useful as a general
795 fallback for toolset-specific actions like PCH generation.
796 """
797 def run (self, project, name, prop_set, sources):
798 return (property_set.empty(), [])
799
800
801 get_manager().projects().add_rule("variant", variant)
802
803 import stage
804 import symlink
805 import message