]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/tools/build/src/tools/builtin.py
add subtree-ish sources for 12.0.3
[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('c++-template-depth',
201 [str(i) for i in range(64,1024+1,64)] +
202 [str(i) for i in range(20,1000+1,10)] +
203 # Maximum template instantiation depth guaranteed for ANSI/ISO C++
204 # conforming programs.
205 ['17'],
206 ['incidental', 'optional', 'propagated'])
207
208 feature.feature ('source', [], ['free', 'dependency', 'incidental'])
209 feature.feature ('library', [], ['free', 'dependency', 'incidental'])
210 feature.feature ('file', [], ['free', 'dependency', 'incidental'])
211 feature.feature ('find-shared-library', [], ['free']) #order-sensitive ;
212 feature.feature ('find-static-library', [], ['free']) #order-sensitive ;
213 feature.feature ('library-path', [], ['free', 'path']) #order-sensitive ;
214 # Internal feature.
215 feature.feature ('library-file', [], ['free', 'dependency'])
216
217 feature.feature ('name', [], ['free'])
218 feature.feature ('tag', [], ['free'])
219 feature.feature ('search', [], ['free', 'path']) #order-sensitive ;
220 feature.feature ('location', [], ['free', 'path'])
221
222 feature.feature ('dll-path', [], ['free', 'path'])
223 feature.feature ('hardcode-dll-paths', ['true', 'false'], ['incidental'])
224
225
226 # This is internal feature which holds the paths of all dependency
227 # dynamic libraries. On Windows, it's needed so that we can all
228 # those paths to PATH, when running applications.
229 # On Linux, it's needed to add proper -rpath-link command line options.
230 feature.feature ('xdll-path', [], ['free', 'path'])
231
232 #provides means to specify def-file for windows dlls.
233 feature.feature ('def-file', [], ['free', 'dependency'])
234
235 # This feature is used to allow specific generators to run.
236 # For example, QT tools can only be invoked when QT library
237 # is used. In that case, <allow>qt will be in usage requirement
238 # of the library.
239 feature.feature ('allow', [], ['free'])
240
241 # The addressing model to generate code for. Currently a limited set only
242 # specifying the bit size of pointers.
243 feature.feature('address-model', ['16', '32', '64'], ['propagated', 'optional'])
244
245 # Type of CPU architecture to compile for.
246 feature.feature('architecture', [
247 # x86 and x86-64
248 'x86',
249
250 # ia64
251 'ia64',
252
253 # Sparc
254 'sparc',
255
256 # RS/6000 & PowerPC
257 'power',
258
259 # MIPS/SGI
260 'mips1', 'mips2', 'mips3', 'mips4', 'mips32', 'mips32r2', 'mips64',
261
262 # HP/PA-RISC
263 'parisc',
264
265 # Advanced RISC Machines
266 'arm',
267
268 # Combined architectures for platforms/toolsets that support building for
269 # multiple architectures at once. "combined" would be the default multi-arch
270 # for the toolset.
271 'combined',
272 'combined-x86-power'],
273
274 ['propagated', 'optional'])
275
276 # The specific instruction set in an architecture to compile.
277 feature.feature('instruction-set', [
278 # x86 and x86-64
279 'native', 'i486', 'i586', 'i686', 'pentium', 'pentium-mmx', 'pentiumpro', 'pentium2', 'pentium3',
280 'pentium3m', 'pentium-m', 'pentium4', 'pentium4m', 'prescott', 'nocona', 'core2', 'corei7', 'corei7-avx', 'core-avx-i',
281 'conroe', 'conroe-xe', 'conroe-l', 'allendale', 'merom', 'merom-xe', 'kentsfield', 'kentsfield-xe', 'penryn', 'wolfdale',
282 'yorksfield', 'nehalem', 'sandy-bridge', 'ivy-bridge', 'haswell', 'k6', 'k6-2', 'k6-3', 'athlon', 'athlon-tbird', 'athlon-4', 'athlon-xp',
283 'athlon-mp', 'k8', 'opteron', 'athlon64', 'athlon-fx', 'k8-sse3', 'opteron-sse3', 'athlon64-sse3', 'amdfam10', 'barcelona',
284 'bdver1', 'bdver2', 'bdver3', 'btver1', 'btver2', 'winchip-c6', 'winchip2', 'c3', 'c3-2', 'atom',
285
286 # ia64
287 'itanium', 'itanium1', 'merced', 'itanium2', 'mckinley',
288
289 # Sparc
290 'v7', 'cypress', 'v8', 'supersparc', 'sparclite', 'hypersparc', 'sparclite86x', 'f930', 'f934',
291 'sparclet', 'tsc701', 'v9', 'ultrasparc', 'ultrasparc3',
292
293 # RS/6000 & PowerPC
294 '401', '403', '405', '405fp', '440', '440fp', '505', '601', '602',
295 '603', '603e', '604', '604e', '620', '630', '740', '7400',
296 '7450', '750', '801', '821', '823', '860', '970', '8540',
297 'power-common', 'ec603e', 'g3', 'g4', 'g5', 'power', 'power2',
298 'power3', 'power4', 'power5', 'powerpc', 'powerpc64', 'rios',
299 'rios1', 'rsc', 'rios2', 'rs64a',
300
301 # MIPS
302 '4kc', '4kp', '5kc', '20kc', 'm4k', 'r2000', 'r3000', 'r3900', 'r4000',
303 'r4100', 'r4300', 'r4400', 'r4600', 'r4650',
304 'r6000', 'r8000', 'rm7000', 'rm9000', 'orion', 'sb1', 'vr4100',
305 'vr4111', 'vr4120', 'vr4130', 'vr4300',
306 'vr5000', 'vr5400', 'vr5500',
307
308 # HP/PA-RISC
309 '700', '7100', '7100lc', '7200', '7300', '8000',
310
311 # Advanced RISC Machines
312 'armv2', 'armv2a', 'armv3', 'armv3m', 'armv4', 'armv4t', 'armv5',
313 'armv5t', 'armv5te', 'armv6', 'armv6j', 'iwmmxt', 'ep9312'],
314
315 ['propagated', 'optional'])
316
317 feature.feature('conditional', [], ['incidental', 'free'])
318
319 # The value of 'no' prevents building of a target.
320 feature.feature('build', ['yes', 'no'], ['optional'])
321
322 # Windows-specific features
323 feature.feature ('user-interface', ['console', 'gui', 'wince', 'native', 'auto'], [])
324 feature.feature ('variant', [], ['implicit', 'composite', 'propagated', 'symmetric'])
325
326
327 variant ('debug', ['<optimization>off', '<debug-symbols>on', '<inlining>off', '<runtime-debugging>on'])
328 variant ('release', ['<optimization>speed', '<debug-symbols>off', '<inlining>full',
329 '<runtime-debugging>off', '<define>NDEBUG'])
330 variant ('profile', ['release'], ['<profiling>on', '<debug-symbols>on'])
331
332
333 reset ()
334 register_globals ()
335
336 class SearchedLibTarget (virtual_target.AbstractFileTarget):
337 def __init__ (self, name, project, shared, search, action):
338 virtual_target.AbstractFileTarget.__init__ (self, name, 'SEARCHED_LIB', project, action)
339
340 self.shared_ = shared
341 self.search_ = search
342
343 def shared (self):
344 return self.shared_
345
346 def search (self):
347 return self.search_
348
349 def actualize_location (self, target):
350 bjam.call("NOTFILE", target)
351
352 def path (self):
353 #FIXME: several functions rely on this not being None
354 return ""
355
356
357 class CScanner (scanner.Scanner):
358 def __init__ (self, includes):
359 scanner.Scanner.__init__ (self)
360
361 self.includes_ = []
362
363 for i in includes:
364 self.includes_.extend(i.split("&&"))
365
366 def pattern (self):
367 return r'#[ \t]*include[ ]*(<(.*)>|"(.*)")'
368
369 def process (self, target, matches, binding):
370 # since it's possible for this function to be called
371 # thousands to millions of times (depending on how many
372 # header files there are), as such, there are some
373 # optimizations that have been used here. Anything that
374 # is slightly out of the ordinary for Python code
375 # has been commented.
376 angle = []
377 quoted = []
378 for match in matches:
379 if '<' in match:
380 angle.append(match.strip('<>'))
381 elif '"' in match:
382 quoted.append(match.strip('"'))
383
384 g = id(self)
385 b = os.path.normpath(os.path.dirname(binding[0]))
386
387 # Attach binding of including file to included targets.
388 # When target is directly created from virtual target
389 # this extra information is unnecessary. But in other
390 # cases, it allows to distinguish between two headers of the
391 # same name included from different places.
392 # We don't need this extra information for angle includes,
393 # since they should not depend on including file (we can't
394 # get literal "." in include path).
395 # Note: string interpolation is slightly faster
396 # than .format()
397 g2 = '<%s#%s>' % (g, b)
398 g = "<%s>" % g
399
400 angle = [g + x for x in angle]
401 quoted = [g2 + x for x in quoted]
402
403 all = angle + quoted
404 bjam.call("mark-included", target, all)
405
406 # each include in self.includes_ looks something like this:
407 # <include>path/to/somewhere
408 # calling get_value(include) is super slow,
409 # calling .replace('<include>', '') is much faster
410 # however, i[9:] is the fastest way of stripping off the "<include>"
411 # substring.
412 include_paths = [i[9:] for i in self.includes_]
413
414 engine = get_manager().engine()
415 engine.set_target_variable(angle, "SEARCH", include_paths)
416 engine.set_target_variable(quoted, "SEARCH", [b] + include_paths)
417
418 # Just propagate current scanner to includes, in a hope
419 # that includes do not change scanners.
420 get_manager().scanners().propagate(self, all)
421
422 scanner.register (CScanner, 'include')
423 type.set_scanner ('CPP', CScanner)
424 type.set_scanner ('C', CScanner)
425 type.set_scanner('H', CScanner)
426 type.set_scanner('HPP', CScanner)
427
428 # Ported to trunk@47077
429 class LibGenerator (generators.Generator):
430 """ The generator class for libraries (target type LIB). Depending on properties it will
431 request building of the approapriate specific type -- SHARED_LIB, STATIC_LIB or
432 SHARED_LIB.
433 """
434
435 def __init__(self, id, composing = True, source_types = [], target_types_and_names = ['LIB'], requirements = []):
436 generators.Generator.__init__(self, id, composing, source_types, target_types_and_names, requirements)
437
438 def run(self, project, name, prop_set, sources):
439 assert isinstance(project, targets.ProjectTarget)
440 assert isinstance(name, basestring) or name is None
441 assert isinstance(prop_set, property_set.PropertySet)
442 assert is_iterable_typed(sources, virtual_target.VirtualTarget)
443 # The lib generator is composing, and can be only invoked with
444 # explicit name. This check is present in generator.run (and so in
445 # builtin.LinkingGenerator), but duplicate it here to avoid doing
446 # extra work.
447 if name:
448 properties = prop_set.raw()
449 # Determine the needed target type
450 actual_type = None
451 properties_grist = get_grist(properties)
452 if '<source>' not in properties_grist and \
453 ('<search>' in properties_grist or '<name>' in properties_grist):
454 actual_type = 'SEARCHED_LIB'
455 elif '<file>' in properties_grist:
456 # The generator for
457 actual_type = 'LIB'
458 elif '<link>shared' in properties:
459 actual_type = 'SHARED_LIB'
460 else:
461 actual_type = 'STATIC_LIB'
462
463 prop_set = prop_set.add_raw(['<main-target-type>LIB'])
464
465 # Construct the target.
466 return generators.construct(project, name, actual_type, prop_set, sources)
467
468 def viable_source_types(self):
469 return ['*']
470
471 generators.register(LibGenerator("builtin.lib-generator"))
472
473 generators.override("builtin.prebuilt", "builtin.lib-generator")
474
475 def lib(names, sources=[], requirements=[], default_build=[], usage_requirements=[]):
476 """The implementation of the 'lib' rule. Beyond standard syntax that rule allows
477 simplified: 'lib a b c ;'."""
478 assert is_iterable_typed(names, basestring)
479 assert is_iterable_typed(sources, basestring)
480 assert is_iterable_typed(requirements, basestring)
481 assert is_iterable_typed(default_build, basestring)
482 assert is_iterable_typed(usage_requirements, basestring)
483 if len(names) > 1:
484 if any(r.startswith('<name>') for r in requirements):
485 get_manager().errors()("When several names are given to the 'lib' rule\n" +
486 "it is not allowed to specify the <name> feature.")
487
488 if sources:
489 get_manager().errors()("When several names are given to the 'lib' rule\n" +
490 "it is not allowed to specify sources.")
491
492 project = get_manager().projects().current()
493 result = []
494
495 for name in names:
496 r = requirements[:]
497
498 # Support " lib a ; " and " lib a b c ; " syntax.
499 if not sources and not any(r.startswith("<name>") for r in requirements) \
500 and not any(r.startswith("<file") for r in requirements):
501 r.append("<name>" + name)
502
503 result.append(targets.create_typed_metatarget(name, "LIB", sources,
504 r,
505 default_build,
506 usage_requirements))
507 return result
508
509 get_manager().projects().add_rule("lib", lib)
510
511
512 # Updated to trunk@47077
513 class SearchedLibGenerator (generators.Generator):
514 def __init__ (self, id = 'SearchedLibGenerator', composing = False, source_types = [], target_types_and_names = ['SEARCHED_LIB'], requirements = []):
515 # TODO: the comment below looks strange. There are no requirements!
516 # The requirements cause the generators to be tried *only* when we're building
517 # lib target and there's 'search' feature. This seems ugly --- all we want
518 # is make sure SearchedLibGenerator is not invoked deep in transformation
519 # search.
520 generators.Generator.__init__ (self, id, composing, source_types, target_types_and_names, requirements)
521
522 def run(self, project, name, prop_set, sources):
523 assert isinstance(project, targets.ProjectTarget)
524 assert isinstance(name, basestring) or name is None
525 assert isinstance(prop_set, property_set.PropertySet)
526 assert is_iterable_typed(sources, virtual_target.VirtualTarget)
527
528 if not name:
529 return None
530
531 # If name is empty, it means we're called not from top-level.
532 # In this case, we just fail immediately, because SearchedLibGenerator
533 # cannot be used to produce intermediate targets.
534
535 properties = prop_set.raw ()
536 shared = '<link>shared' in properties
537
538 a = virtual_target.NullAction (project.manager(), prop_set)
539
540 real_name = feature.get_values ('<name>', properties)
541 if real_name:
542 real_name = real_name[0]
543 else:
544 real_name = name
545 search = feature.get_values('<search>', properties)
546 usage_requirements = property_set.create(['<xdll-path>' + p for p in search])
547 t = SearchedLibTarget(real_name, project, shared, search, a)
548
549 # We return sources for a simple reason. If there's
550 # lib png : z : <name>png ;
551 # the 'z' target should be returned, so that apps linking to
552 # 'png' will link to 'z', too.
553 return(usage_requirements, [b2.manager.get_manager().virtual_targets().register(t)] + sources)
554
555 generators.register (SearchedLibGenerator ())
556
557 class PrebuiltLibGenerator(generators.Generator):
558
559 def __init__(self, id, composing, source_types, target_types_and_names, requirements):
560 generators.Generator.__init__ (self, id, composing, source_types, target_types_and_names, requirements)
561
562 def run(self, project, name, properties, sources):
563 assert isinstance(project, targets.ProjectTarget)
564 assert isinstance(name, basestring)
565 assert isinstance(properties, property_set.PropertySet)
566 assert is_iterable_typed(sources, virtual_target.VirtualTarget)
567
568 f = properties.get("file")
569 return f + sources
570
571 generators.register(PrebuiltLibGenerator("builtin.prebuilt", False, [],
572 ["LIB"], ["<file>"]))
573
574 generators.override("builtin.prebuilt", "builtin.lib-generator")
575
576
577 class CompileAction (virtual_target.Action):
578 def __init__ (self, manager, sources, action_name, prop_set):
579 virtual_target.Action.__init__ (self, manager, sources, action_name, prop_set)
580
581 def adjust_properties (self, prop_set):
582 """ For all virtual targets for the same dependency graph as self,
583 i.e. which belong to the same main target, add their directories
584 to include path.
585 """
586 assert isinstance(prop_set, property_set.PropertySet)
587 s = self.targets () [0].creating_subvariant ()
588
589 return prop_set.add_raw (s.implicit_includes ('include', 'H'))
590
591 class CCompilingGenerator (generators.Generator):
592 """ Declare a special compiler generator.
593 The only thing it does is changing the type used to represent
594 'action' in the constructed dependency graph to 'CompileAction'.
595 That class in turn adds additional include paths to handle a case
596 when a source file includes headers which are generated themselfs.
597 """
598 def __init__ (self, id, composing, source_types, target_types_and_names, requirements):
599 # TODO: (PF) What to do with optional_properties? It seemed that, in the bjam version, the arguments are wrong.
600 generators.Generator.__init__ (self, id, composing, source_types, target_types_and_names, requirements)
601
602 def action_class (self):
603 return CompileAction
604
605 def register_c_compiler (id, source_types, target_types, requirements, optional_properties = []):
606 g = CCompilingGenerator (id, False, source_types, target_types, requirements + optional_properties)
607 return generators.register (g)
608
609
610 class LinkingGenerator (generators.Generator):
611 """ The generator class for handling EXE and SHARED_LIB creation.
612 """
613 def __init__ (self, id, composing, source_types, target_types_and_names, requirements):
614 generators.Generator.__init__ (self, id, composing, source_types, target_types_and_names, requirements)
615
616 def run (self, project, name, prop_set, sources):
617 assert isinstance(project, targets.ProjectTarget)
618 assert isinstance(name, basestring) or name is None
619 assert isinstance(prop_set, property_set.PropertySet)
620 assert is_iterable_typed(sources, virtual_target.VirtualTarget)
621
622 # create a copy since sources is being modified
623 sources = list(sources)
624 sources.extend(prop_set.get('<library>'))
625
626 # Add <library-path> properties for all searched libraries
627 extra = []
628 for s in sources:
629 if s.type () == 'SEARCHED_LIB':
630 search = s.search()
631 extra.extend(property.Property('<library-path>', sp) for sp in search)
632
633 # It's possible that we have libraries in sources which did not came
634 # from 'lib' target. For example, libraries which are specified
635 # just as filenames as sources. We don't have xdll-path properties
636 # for such target, but still need to add proper dll-path properties.
637 extra_xdll_path = []
638 for s in sources:
639 if type.is_derived (s.type (), 'SHARED_LIB') and not s.action ():
640 # Unfortunately, we don't have a good way to find the path
641 # to a file, so use this nasty approach.
642 p = s.project()
643 location = path.root(s.name(), p.get('source-location')[0])
644 extra_xdll_path.append(os.path.dirname(location))
645
646 # Hardcode DLL paths only when linking executables.
647 # Pros: do not need to relink libraries when installing.
648 # Cons: "standalone" libraries (plugins, python extensions) can not
649 # hardcode paths to dependent libraries.
650 if prop_set.get('<hardcode-dll-paths>') == ['true'] \
651 and type.is_derived(self.target_types_ [0], 'EXE'):
652 xdll_path = prop_set.get('<xdll-path>')
653 extra.extend(property.Property('<dll-path>', sp) \
654 for sp in extra_xdll_path)
655 extra.extend(property.Property('<dll-path>', sp) \
656 for sp in xdll_path)
657
658 if extra:
659 prop_set = prop_set.add_raw (extra)
660 result = generators.Generator.run(self, project, name, prop_set, sources)
661
662 if result:
663 ur = self.extra_usage_requirements(result, prop_set)
664 ur = ur.add(property_set.create(['<xdll-path>' + p for p in extra_xdll_path]))
665 else:
666 return None
667 return (ur, result)
668
669 def extra_usage_requirements (self, created_targets, prop_set):
670 assert is_iterable_typed(created_targets, virtual_target.VirtualTarget)
671 assert isinstance(prop_set, property_set.PropertySet)
672
673 result = property_set.empty ()
674 extra = []
675
676 # Add appropriate <xdll-path> usage requirements.
677 raw = prop_set.raw ()
678 if '<link>shared' in raw:
679 paths = []
680
681 # TODO: is it safe to use the current directory? I think we should use
682 # another mechanism to allow this to be run from anywhere.
683 pwd = os.getcwd()
684
685 for t in created_targets:
686 if type.is_derived(t.type(), 'SHARED_LIB'):
687 paths.append(path.root(path.make(t.path()), pwd))
688
689 extra += replace_grist(paths, '<xdll-path>')
690
691 # We need to pass <xdll-path> features that we've got from sources,
692 # because if shared library is built, exe which uses it must know paths
693 # to other shared libraries this one depends on, to be able to find them
694 # all at runtime.
695
696 # Just pass all features in property_set, it's theorically possible
697 # that we'll propagate <xdll-path> features explicitly specified by
698 # the user, but then the user's to blaim for using internal feature.
699 values = prop_set.get('<xdll-path>')
700 extra += replace_grist(values, '<xdll-path>')
701
702 if extra:
703 result = property_set.create(extra)
704
705 return result
706
707 def generated_targets (self, sources, prop_set, project, name):
708 assert is_iterable_typed(sources, virtual_target.VirtualTarget)
709 assert isinstance(prop_set, property_set.PropertySet)
710 assert isinstance(project, targets.ProjectTarget)
711 assert isinstance(name, basestring)
712 # sources to pass to inherited rule
713 sources2 = []
714 # sources which are libraries
715 libraries = []
716
717 # Searched libraries are not passed as argument to linker
718 # but via some option. So, we pass them to the action
719 # via property.
720 fsa = []
721 fst = []
722 for s in sources:
723 if type.is_derived(s.type(), 'SEARCHED_LIB'):
724 n = s.name()
725 if s.shared():
726 fsa.append(n)
727
728 else:
729 fst.append(n)
730
731 else:
732 sources2.append(s)
733
734 add = []
735 if fsa:
736 add.append("<find-shared-library>" + '&&'.join(fsa))
737 if fst:
738 add.append("<find-static-library>" + '&&'.join(fst))
739
740 spawn = generators.Generator.generated_targets(self, sources2, prop_set.add_raw(add), project, name)
741 return spawn
742
743
744 def register_linker(id, source_types, target_types, requirements):
745 g = LinkingGenerator(id, True, source_types, target_types, requirements)
746 generators.register(g)
747
748 class ArchiveGenerator (generators.Generator):
749 """ The generator class for handling STATIC_LIB creation.
750 """
751 def __init__ (self, id, composing, source_types, target_types_and_names, requirements):
752 generators.Generator.__init__ (self, id, composing, source_types, target_types_and_names, requirements)
753
754 def run (self, project, name, prop_set, sources):
755 assert isinstance(project, targets.ProjectTarget)
756 assert isinstance(name, basestring) or name is None
757 assert isinstance(prop_set, property_set.PropertySet)
758 assert is_iterable_typed(sources, virtual_target.VirtualTarget)
759
760 # create a copy since this modifies the sources list
761 sources = list(sources)
762 sources.extend(prop_set.get('<library>'))
763
764 result = generators.Generator.run (self, project, name, prop_set, sources)
765
766 usage_requirements = []
767 link = prop_set.get('<link>')
768 if 'static' in link:
769 for t in sources:
770 if type.is_derived(t.type(), 'LIB'):
771 usage_requirements.append(property.Property('<library>', t))
772
773 usage_requirements = property_set.create(usage_requirements)
774
775 return usage_requirements, result
776
777
778 def register_archiver(id, source_types, target_types, requirements):
779 g = ArchiveGenerator(id, True, source_types, target_types, requirements)
780 generators.register(g)
781
782 class DummyGenerator(generators.Generator):
783 """Generator that accepts everything and produces nothing. Useful as a general
784 fallback for toolset-specific actions like PCH generation.
785 """
786 def run (self, project, name, prop_set, sources):
787 return (property_set.empty(), [])
788
789
790 get_manager().projects().add_rule("variant", variant)
791
792 import stage
793 import symlink
794 import message