]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/tools/build/src/tools/builtin.py
update ceph source to reef 18.1.2
[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 hurd iphone linux
86 netbsd openbsd osf qnx qnxnto sgi solaris sun sunos svr4 sysv ultrix unix
87 unixware 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 'mips', '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', 'broadwell', 'skylake', 'skylake-avx512', 'cannonlake',
291 'icelake-client', 'icelake-server', 'cascadelake', 'cooperlake', 'tigerlake',
292 'atom',
293 'k6', 'k6-2', 'k6-3', 'athlon', 'athlon-tbird', 'athlon-4', 'athlon-xp', 'athlon-mp', 'k8', 'opteron', 'athlon64', 'athlon-fx',
294 'k8-sse3', 'opteron-sse3', 'athlon64-sse3', 'amdfam10', 'barcelona', 'bdver1', 'bdver2', 'bdver3', 'btver1',
295 'btver2', 'znver1', 'znver2',
296 'winchip-c6', 'winchip2',
297 'c3', 'c3-2', 'c7',
298
299 # ia64
300 'itanium', 'itanium1', 'merced', 'itanium2', 'mckinley',
301
302 # Sparc
303 'v7', 'cypress', 'v8', 'supersparc', 'sparclite', 'hypersparc', 'sparclite86x', 'f930', 'f934',
304 'sparclet', 'tsc701', 'v9', 'ultrasparc', 'ultrasparc3',
305
306 # RS/6000 & PowerPC
307 '401', '403', '405', '405fp', '440', '440fp', '505', '601', '602',
308 '603', '603e', '604', '604e', '620', '630', '740', '7400',
309 '7450', '750', '801', '821', '823', '860', '970', '8540',
310 'power-common', 'ec603e', 'g3', 'g4', 'g5', 'power', 'power2',
311 'power3', 'power4', 'power5', 'powerpc', 'powerpc64', 'rios',
312 'rios1', 'rsc', 'rios2', 'rs64a',
313
314 # MIPS
315 '4kc', '4km', '4kp', '4ksc', '4kec', '4kem', '4kep', '4ksd', '5kc',
316 '5kf', '20kc', '24kc', '24kf2_1', '24kf1_1', '24kec', '24kef2_1',
317 '24kef1_1', '34kc', '34kf2_1', '34kf1_1', '34kn', '74kc', '74kf2_1',
318 '74kf1_1', '74kf3_2', '1004kc', '1004kf2_1', '1004kf1_1', 'i6400',
319 'i6500', 'interaptiv', 'loongson2e', 'loongson2f', 'loongson3a',
320 'gs464', 'gs464e', 'gs264e', 'm4k', 'm14k', 'm14kc', 'm14ke', 'm14kec',
321 'm5100', 'm5101', 'octeon', 'octeon+', 'octeon2', 'octeon3', 'orion',
322 'p5600', 'p6600', 'r2000', 'r3000', 'r3900', 'r4000', 'r4400', 'r4600', 'r4650',
323 'r4700', 'r5900', 'r6000', 'r8000', 'rm7000', 'rm9000', 'r10000', 'r12000',
324 'r14000', 'r16000', 'sb1', 'sr71000', 'vr4100', 'vr4111', 'vr4120', 'vr4130',
325 'vr4300', 'vr5000', 'vr5400', 'vr5500', 'xlr', 'xlp',
326
327 # HP/PA-RISC
328 '700', '7100', '7100lc', '7200', '7300', '8000',
329
330 # Advanced RISC Machines
331 'armv2', 'armv2a', 'armv3', 'armv3m', 'armv4', 'armv4t', 'armv5',
332 'armv5t', 'armv5te', 'armv6', 'armv6j', 'iwmmxt', 'ep9312',
333
334 # z Systems (aka s390x)
335 'z196', 'zEC12', 'z13', 'z13', 'z14', 'z15'],
336
337 ['propagated', 'optional'])
338
339 feature.feature('conditional', [], ['incidental', 'free'])
340
341 # The value of 'no' prevents building of a target.
342 feature.feature('build', ['yes', 'no'], ['optional'])
343
344 # Windows-specific features
345 feature.feature ('user-interface', ['console', 'gui', 'wince', 'native', 'auto'], [])
346 feature.feature ('variant', [], ['implicit', 'composite', 'propagated', 'symmetric'])
347
348
349 variant ('debug', ['<optimization>off', '<debug-symbols>on', '<inlining>off', '<runtime-debugging>on'])
350 variant ('release', ['<optimization>speed', '<debug-symbols>off', '<inlining>full',
351 '<runtime-debugging>off', '<define>NDEBUG'])
352 variant ('profile', ['release'], ['<profiling>on', '<debug-symbols>on'])
353
354
355 reset ()
356 register_globals ()
357
358 class SearchedLibTarget (virtual_target.AbstractFileTarget):
359 def __init__ (self, name, project, shared, search, action):
360 virtual_target.AbstractFileTarget.__init__ (self, name, 'SEARCHED_LIB', project, action)
361
362 self.shared_ = shared
363 self.search_ = search
364
365 def shared (self):
366 return self.shared_
367
368 def search (self):
369 return self.search_
370
371 def actualize_location (self, target):
372 bjam.call("NOTFILE", target)
373
374 def path (self):
375 #FIXME: several functions rely on this not being None
376 return ""
377
378
379 class CScanner (scanner.Scanner):
380 def __init__ (self, includes):
381 scanner.Scanner.__init__ (self)
382
383 self.includes_ = []
384
385 for i in includes:
386 self.includes_.extend(i.split("&&"))
387
388 def pattern (self):
389 return r'#[ \t]*include[ ]*(<(.*)>|"(.*)")'
390
391 def process (self, target, matches, binding):
392 # since it's possible for this function to be called
393 # thousands to millions of times (depending on how many
394 # header files there are), as such, there are some
395 # optimizations that have been used here. Anything that
396 # is slightly out of the ordinary for Python code
397 # has been commented.
398 angle = []
399 quoted = []
400 for match in matches:
401 if '<' in match:
402 angle.append(match.strip('<>'))
403 elif '"' in match:
404 quoted.append(match.strip('"'))
405
406 g = id(self)
407 b = os.path.normpath(os.path.dirname(binding[0]))
408
409 # Attach binding of including file to included targets.
410 # When target is directly created from virtual target
411 # this extra information is unnecessary. But in other
412 # cases, it allows to distinguish between two headers of the
413 # same name included from different places.
414 # We don't need this extra information for angle includes,
415 # since they should not depend on including file (we can't
416 # get literal "." in include path).
417 # Note: string interpolation is slightly faster
418 # than .format()
419 g2 = '<%s#%s>' % (g, b)
420 g = "<%s>" % g
421
422 angle = [g + x for x in angle]
423 quoted = [g2 + x for x in quoted]
424
425 all = angle + quoted
426 bjam.call("mark-included", target, all)
427
428 # each include in self.includes_ looks something like this:
429 # <include>path/to/somewhere
430 # calling get_value(include) is super slow,
431 # calling .replace('<include>', '') is much faster
432 # however, i[9:] is the fastest way of stripping off the "<include>"
433 # substring.
434 include_paths = [i[9:] for i in self.includes_]
435
436 engine = get_manager().engine()
437 engine.set_target_variable(angle, "SEARCH", include_paths)
438 engine.set_target_variable(quoted, "SEARCH", [b] + include_paths)
439
440 # Just propagate current scanner to includes, in a hope
441 # that includes do not change scanners.
442 get_manager().scanners().propagate(self, all)
443
444 scanner.register (CScanner, 'include')
445 type.set_scanner ('CPP', CScanner)
446 type.set_scanner ('C', CScanner)
447 type.set_scanner('H', CScanner)
448 type.set_scanner('HPP', CScanner)
449
450 # Ported to trunk@47077
451 class LibGenerator (generators.Generator):
452 """ The generator class for libraries (target type LIB). Depending on properties it will
453 request building of the approapriate specific type -- SHARED_LIB, STATIC_LIB or
454 SHARED_LIB.
455 """
456
457 def __init__(self, id, composing = True, source_types = [], target_types_and_names = ['LIB'], requirements = []):
458 generators.Generator.__init__(self, id, composing, source_types, target_types_and_names, requirements)
459
460 def run(self, project, name, prop_set, sources):
461 assert isinstance(project, targets.ProjectTarget)
462 assert isinstance(name, basestring) or name is None
463 assert isinstance(prop_set, property_set.PropertySet)
464 assert is_iterable_typed(sources, virtual_target.VirtualTarget)
465 # The lib generator is composing, and can be only invoked with
466 # explicit name. This check is present in generator.run (and so in
467 # builtin.LinkingGenerator), but duplicate it here to avoid doing
468 # extra work.
469 if name:
470 properties = prop_set.raw()
471 # Determine the needed target type
472 actual_type = None
473 properties_grist = get_grist(properties)
474 if '<source>' not in properties_grist and \
475 ('<search>' in properties_grist or '<name>' in properties_grist):
476 actual_type = 'SEARCHED_LIB'
477 elif '<file>' in properties_grist:
478 # The generator for
479 actual_type = 'LIB'
480 elif '<link>shared' in properties:
481 actual_type = 'SHARED_LIB'
482 else:
483 actual_type = 'STATIC_LIB'
484
485 prop_set = prop_set.add_raw(['<main-target-type>LIB'])
486
487 # Construct the target.
488 return generators.construct(project, name, actual_type, prop_set, sources)
489
490 def viable_source_types(self):
491 return ['*']
492
493 generators.register(LibGenerator("builtin.lib-generator"))
494
495 generators.override("builtin.prebuilt", "builtin.lib-generator")
496
497 def lib(names, sources=[], requirements=[], default_build=[], usage_requirements=[]):
498 """The implementation of the 'lib' rule. Beyond standard syntax that rule allows
499 simplified: 'lib a b c ;'."""
500 assert is_iterable_typed(names, basestring)
501 assert is_iterable_typed(sources, basestring)
502 assert is_iterable_typed(requirements, basestring)
503 assert is_iterable_typed(default_build, basestring)
504 assert is_iterable_typed(usage_requirements, basestring)
505 if len(names) > 1:
506 if any(r.startswith('<name>') for r in requirements):
507 get_manager().errors()("When several names are given to the 'lib' rule\n" +
508 "it is not allowed to specify the <name> feature.")
509
510 if sources:
511 get_manager().errors()("When several names are given to the 'lib' rule\n" +
512 "it is not allowed to specify sources.")
513
514 project = get_manager().projects().current()
515 result = []
516
517 for name in names:
518 r = requirements[:]
519
520 # Support " lib a ; " and " lib a b c ; " syntax.
521 if not sources and not any(r.startswith("<name>") for r in requirements) \
522 and not any(r.startswith("<file") for r in requirements):
523 r.append("<name>" + name)
524
525 result.append(targets.create_typed_metatarget(name, "LIB", sources,
526 r,
527 default_build,
528 usage_requirements))
529 return result
530
531 get_manager().projects().add_rule("lib", lib)
532
533
534 # Updated to trunk@47077
535 class SearchedLibGenerator (generators.Generator):
536 def __init__ (self, id = 'SearchedLibGenerator', composing = False, source_types = [], target_types_and_names = ['SEARCHED_LIB'], requirements = []):
537 # TODO: the comment below looks strange. There are no requirements!
538 # The requirements cause the generators to be tried *only* when we're building
539 # lib target and there's 'search' feature. This seems ugly --- all we want
540 # is make sure SearchedLibGenerator is not invoked deep in transformation
541 # search.
542 generators.Generator.__init__ (self, id, composing, source_types, target_types_and_names, requirements)
543
544 def run(self, project, name, prop_set, sources):
545 assert isinstance(project, targets.ProjectTarget)
546 assert isinstance(name, basestring) or name is None
547 assert isinstance(prop_set, property_set.PropertySet)
548 assert is_iterable_typed(sources, virtual_target.VirtualTarget)
549
550 if not name:
551 return None
552
553 # If name is empty, it means we're called not from top-level.
554 # In this case, we just fail immediately, because SearchedLibGenerator
555 # cannot be used to produce intermediate targets.
556
557 properties = prop_set.raw ()
558 shared = '<link>shared' in properties
559
560 a = virtual_target.NullAction (project.manager(), prop_set)
561
562 real_name = feature.get_values ('<name>', properties)
563 if real_name:
564 real_name = real_name[0]
565 else:
566 real_name = name
567 search = feature.get_values('<search>', properties)
568 usage_requirements = property_set.create(['<xdll-path>' + p for p in search])
569 t = SearchedLibTarget(real_name, project, shared, search, a)
570
571 # We return sources for a simple reason. If there's
572 # lib png : z : <name>png ;
573 # the 'z' target should be returned, so that apps linking to
574 # 'png' will link to 'z', too.
575 return(usage_requirements, [b2.manager.get_manager().virtual_targets().register(t)] + sources)
576
577 generators.register (SearchedLibGenerator ())
578
579 class PrebuiltLibGenerator(generators.Generator):
580
581 def __init__(self, id, composing, source_types, target_types_and_names, requirements):
582 generators.Generator.__init__ (self, id, composing, source_types, target_types_and_names, requirements)
583
584 def run(self, project, name, properties, sources):
585 assert isinstance(project, targets.ProjectTarget)
586 assert isinstance(name, basestring)
587 assert isinstance(properties, property_set.PropertySet)
588 assert is_iterable_typed(sources, virtual_target.VirtualTarget)
589
590 f = properties.get("file")
591 return f + sources
592
593 generators.register(PrebuiltLibGenerator("builtin.prebuilt", False, [],
594 ["LIB"], ["<file>"]))
595
596 generators.override("builtin.prebuilt", "builtin.lib-generator")
597
598
599 class CompileAction (virtual_target.Action):
600 def __init__ (self, manager, sources, action_name, prop_set):
601 virtual_target.Action.__init__ (self, manager, sources, action_name, prop_set)
602
603 def adjust_properties (self, prop_set):
604 """ For all virtual targets for the same dependency graph as self,
605 i.e. which belong to the same main target, add their directories
606 to include path.
607 """
608 assert isinstance(prop_set, property_set.PropertySet)
609 s = self.targets () [0].creating_subvariant ()
610
611 return prop_set.add_raw (s.implicit_includes ('include', 'H'))
612
613 class CCompilingGenerator (generators.Generator):
614 """ Declare a special compiler generator.
615 The only thing it does is changing the type used to represent
616 'action' in the constructed dependency graph to 'CompileAction'.
617 That class in turn adds additional include paths to handle a case
618 when a source file includes headers which are generated themselves.
619 """
620 def __init__ (self, id, composing, source_types, target_types_and_names, requirements):
621 # TODO: (PF) What to do with optional_properties? It seemed that, in the bjam version, the arguments are wrong.
622 generators.Generator.__init__ (self, id, composing, source_types, target_types_and_names, requirements)
623
624 def action_class (self):
625 return CompileAction
626
627 def register_c_compiler (id, source_types, target_types, requirements, optional_properties = []):
628 g = CCompilingGenerator (id, False, source_types, target_types, requirements + optional_properties)
629 return generators.register (g)
630
631
632 class LinkingGenerator (generators.Generator):
633 """ The generator class for handling EXE and SHARED_LIB creation.
634 """
635 def __init__ (self, id, composing, source_types, target_types_and_names, requirements):
636 generators.Generator.__init__ (self, id, composing, source_types, target_types_and_names, requirements)
637
638 def run (self, project, name, prop_set, sources):
639 assert isinstance(project, targets.ProjectTarget)
640 assert isinstance(name, basestring) or name is None
641 assert isinstance(prop_set, property_set.PropertySet)
642 assert is_iterable_typed(sources, virtual_target.VirtualTarget)
643
644 # create a copy since sources is being modified
645 sources = list(sources)
646 sources.extend(prop_set.get('<library>'))
647
648 # Add <library-path> properties for all searched libraries
649 extra = []
650 for s in sources:
651 if s.type () == 'SEARCHED_LIB':
652 search = s.search()
653 extra.extend(property.Property('<library-path>', sp) for sp in search)
654
655 # It's possible that we have libraries in sources which did not came
656 # from 'lib' target. For example, libraries which are specified
657 # just as filenames as sources. We don't have xdll-path properties
658 # for such target, but still need to add proper dll-path properties.
659 extra_xdll_path = []
660 for s in sources:
661 if type.is_derived (s.type (), 'SHARED_LIB') and not s.action ():
662 # Unfortunately, we don't have a good way to find the path
663 # to a file, so use this nasty approach.
664 p = s.project()
665 location = path.root(s.name(), p.get('source-location')[0])
666 extra_xdll_path.append(os.path.dirname(location))
667
668 # Hardcode DLL paths only when linking executables.
669 # Pros: do not need to relink libraries when installing.
670 # Cons: "standalone" libraries (plugins, python extensions) can not
671 # hardcode paths to dependent libraries.
672 if prop_set.get('<hardcode-dll-paths>') == ['true'] \
673 and type.is_derived(self.target_types_ [0], 'EXE'):
674 xdll_path = prop_set.get('<xdll-path>')
675 extra.extend(property.Property('<dll-path>', sp) \
676 for sp in extra_xdll_path)
677 extra.extend(property.Property('<dll-path>', sp) \
678 for sp in xdll_path)
679
680 if extra:
681 prop_set = prop_set.add_raw (extra)
682 result = generators.Generator.run(self, project, name, prop_set, sources)
683
684 if result:
685 ur = self.extra_usage_requirements(result, prop_set)
686 ur = ur.add(property_set.create(['<xdll-path>' + p for p in extra_xdll_path]))
687 else:
688 return None
689 return (ur, result)
690
691 def extra_usage_requirements (self, created_targets, prop_set):
692 assert is_iterable_typed(created_targets, virtual_target.VirtualTarget)
693 assert isinstance(prop_set, property_set.PropertySet)
694
695 result = property_set.empty ()
696 extra = []
697
698 # Add appropriate <xdll-path> usage requirements.
699 raw = prop_set.raw ()
700 if '<link>shared' in raw:
701 paths = []
702
703 # TODO: is it safe to use the current directory? I think we should use
704 # another mechanism to allow this to be run from anywhere.
705 pwd = os.getcwd()
706
707 for t in created_targets:
708 if type.is_derived(t.type(), 'SHARED_LIB'):
709 paths.append(path.root(path.make(t.path()), pwd))
710
711 extra += replace_grist(paths, '<xdll-path>')
712
713 # We need to pass <xdll-path> features that we've got from sources,
714 # because if shared library is built, exe which uses it must know paths
715 # to other shared libraries this one depends on, to be able to find them
716 # all at runtime.
717
718 # Just pass all features in property_set, it's theorically possible
719 # that we'll propagate <xdll-path> features explicitly specified by
720 # the user, but then the user's to blame for using internal feature.
721 values = prop_set.get('<xdll-path>')
722 extra += replace_grist(values, '<xdll-path>')
723
724 if extra:
725 result = property_set.create(extra)
726
727 return result
728
729 def generated_targets (self, sources, prop_set, project, name):
730 assert is_iterable_typed(sources, virtual_target.VirtualTarget)
731 assert isinstance(prop_set, property_set.PropertySet)
732 assert isinstance(project, targets.ProjectTarget)
733 assert isinstance(name, basestring)
734 # sources to pass to inherited rule
735 sources2 = []
736 # sources which are libraries
737 libraries = []
738
739 # Searched libraries are not passed as argument to linker
740 # but via some option. So, we pass them to the action
741 # via property.
742 fsa = []
743 fst = []
744 for s in sources:
745 if type.is_derived(s.type(), 'SEARCHED_LIB'):
746 n = s.name()
747 if s.shared():
748 fsa.append(n)
749
750 else:
751 fst.append(n)
752
753 else:
754 sources2.append(s)
755
756 add = []
757 if fsa:
758 add.append("<find-shared-library>" + '&&'.join(fsa))
759 if fst:
760 add.append("<find-static-library>" + '&&'.join(fst))
761
762 spawn = generators.Generator.generated_targets(self, sources2, prop_set.add_raw(add), project, name)
763 return spawn
764
765
766 def register_linker(id, source_types, target_types, requirements):
767 g = LinkingGenerator(id, True, source_types, target_types, requirements)
768 generators.register(g)
769
770 class ArchiveGenerator (generators.Generator):
771 """ The generator class for handling STATIC_LIB creation.
772 """
773 def __init__ (self, id, composing, source_types, target_types_and_names, requirements):
774 generators.Generator.__init__ (self, id, composing, source_types, target_types_and_names, requirements)
775
776 def run (self, project, name, prop_set, sources):
777 assert isinstance(project, targets.ProjectTarget)
778 assert isinstance(name, basestring) or name is None
779 assert isinstance(prop_set, property_set.PropertySet)
780 assert is_iterable_typed(sources, virtual_target.VirtualTarget)
781
782 # create a copy since this modifies the sources list
783 sources = list(sources)
784 sources.extend(prop_set.get('<library>'))
785
786 result = generators.Generator.run (self, project, name, prop_set, sources)
787
788 usage_requirements = []
789 link = prop_set.get('<link>')
790 if 'static' in link:
791 for t in sources:
792 if type.is_derived(t.type(), 'LIB'):
793 usage_requirements.append(property.Property('<library>', t))
794
795 usage_requirements = property_set.create(usage_requirements)
796
797 return usage_requirements, result
798
799
800 def register_archiver(id, source_types, target_types, requirements):
801 g = ArchiveGenerator(id, True, source_types, target_types, requirements)
802 generators.register(g)
803
804 class DummyGenerator(generators.Generator):
805 """Generator that accepts everything and produces nothing. Useful as a general
806 fallback for toolset-specific actions like PCH generation.
807 """
808 def run (self, project, name, prop_set, sources):
809 return (property_set.empty(), [])
810
811
812 get_manager().projects().add_rule("variant", variant)
813
814 import stage
815 import symlink
816 import message