1 # Status: minor updates by Steven Watanabe to make gcc work
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.
8 """ Defines standard features and rules.
11 import b2
.build
.targets
as targets
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
18 from b2
.manager
import get_manager
21 # Records explicit properties for a variant.
22 # The key is the variant name.
23 __variant_explicit_properties
= {}
26 """ Clear the module state. This is mainly for testing purposes.
28 global __variant_explicit_properties
30 __variant_explicit_properties
= {}
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.
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.
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.
53 if not explicit_properties
:
54 explicit_properties
= parents_or_properties
56 parents
= parents_or_properties
58 inherited
= property_set
.empty()
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.
64 raise BaseException ("Multiple base variants are not yet supported")
67 # TODO: the check may be stricter
68 if not feature
.is_implicit_value (p
):
69 raise BaseException ("Invalid base variant '%s'" % p
)
71 inherited
= __variant_explicit_properties
[p
]
73 explicit_properties
= property_set
.create_with_validation(explicit_properties
)
74 explicit_properties
= inherited
.refine(explicit_properties
)
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
81 feature
.extend('variant', [name
])
82 feature
.compose ("<variant>" + name
, explicit_properties
.all())
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
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.
93 def default_host_os():
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()
110 def register_globals ():
111 """ Registers all features and variants declared by this module.
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?
118 feature
.feature ('os', [os
], ['propagated', 'link-incompatible'])
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())
129 feature
.feature('target-os', __os_names
, ['propagated', 'link-incompatible'])
130 feature
.set_default('target-os', default_host_os())
132 feature
.feature ('toolset', [], ['implicit', 'propagated' ,'symmetric'])
134 feature
.feature ('stdlib', ['native'], ['propagated', 'composite'])
136 feature
.feature ('link', ['shared', 'static'], ['propagated'])
137 feature
.feature ('runtime-link', ['shared', 'static'], ['propagated'])
138 feature
.feature ('runtime-debugging', ['on', 'off'], ['propagated'])
141 feature
.feature ('optimization', ['off', 'speed', 'space'], ['propagated'])
142 feature
.feature ('profiling', ['off', 'on'], ['propagated'])
143 feature
.feature ('inlining', ['off', 'on', 'full'], ['propagated'])
145 feature
.feature ('threading', ['single', 'multi'], ['propagated'])
146 feature
.feature ('rtti', ['on', 'off'], ['propagated'])
147 feature
.feature ('exception-handling', ['on', 'off'], ['propagated'])
149 # Whether there is support for asynchronous EH (e.g. catching SEGVs).
150 feature
.feature ('asynch-exceptions', ['off', 'on'], ['propagated'])
152 # Whether all extern "C" functions are considered nothrow by default.
153 feature
.feature ('extern-c-nothrow', ['off', 'on'], ['propagated'])
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'])
166 feature
.feature ('location-prefix', [], ['free'])
168 feature
.feature ('action', [], ['free'])
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:
176 # unit-test a : a.cpp : <use>b ;
179 # Here, if <use> is not incidental, we'll decide we have two
180 # targets for a.obj with different properties, and will complain.
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
185 feature
.feature ('use', [], ['free', 'dependency', 'incidental'])
186 feature
.feature ('dependency', [], ['free', 'dependency', 'incidental'])
187 feature
.feature ('implicit-dependency', [], ['free', 'dependency', 'incidental'])
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'])
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'])
200 feature
.feature('coverage', [
201 'off', # Disable coverage generation for the tool.
202 'on'], # Enable coverage generation for the tool.
203 ['incidental', 'propagated'])
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.
211 ['incidental', 'optional', 'propagated'])
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 ;
220 feature
.feature ('library-file', [], ['free', 'dependency'])
222 feature
.feature ('name', [], ['free'])
223 feature
.feature ('tag', [], ['free'])
224 feature
.feature ('search', [], ['free', 'path']) #order-sensitive ;
225 feature
.feature ('location', [], ['free', 'path'])
227 feature
.feature ('dll-path', [], ['free', 'path'])
228 feature
.feature ('hardcode-dll-paths', ['true', 'false'], ['incidental'])
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'])
237 #provides means to specify def-file for windows dlls.
238 feature
.feature ('def-file', [], ['free', 'dependency'])
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
244 feature
.feature ('allow', [], ['free'])
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'])
250 # Type of CPU architecture to compile for.
251 feature
.feature('architecture', [
265 'mips', 'mips1', 'mips2', 'mips3', 'mips4', 'mips32', 'mips32r2', 'mips64',
270 # Advanced RISC Machines
273 # z Systems (aka s390x)
276 # Combined architectures for platforms/toolsets that support building for
277 # multiple architectures at once. "combined" would be the default multi-arch
280 'combined-x86-power'],
282 ['propagated', 'optional'])
284 # The specific instruction set in an architecture to compile.
285 feature
.feature('instruction-set', [
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',
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',
300 'itanium', 'itanium1', 'merced', 'itanium2', 'mckinley',
303 'v7', 'cypress', 'v8', 'supersparc', 'sparclite', 'hypersparc', 'sparclite86x', 'f930', 'f934',
304 'sparclet', 'tsc701', 'v9', 'ultrasparc', 'ultrasparc3',
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',
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',
328 '700', '7100', '7100lc', '7200', '7300', '8000',
330 # Advanced RISC Machines
331 'armv2', 'armv2a', 'armv3', 'armv3m', 'armv4', 'armv4t', 'armv5',
332 'armv5t', 'armv5te', 'armv6', 'armv6j', 'iwmmxt', 'ep9312',
334 # z Systems (aka s390x)
335 'z196', 'zEC12', 'z13', 'z13', 'z14', 'z15'],
337 ['propagated', 'optional'])
339 feature
.feature('conditional', [], ['incidental', 'free'])
341 # The value of 'no' prevents building of a target.
342 feature
.feature('build', ['yes', 'no'], ['optional'])
344 # Windows-specific features
345 feature
.feature ('user-interface', ['console', 'gui', 'wince', 'native', 'auto'], [])
346 feature
.feature ('variant', [], ['implicit', 'composite', 'propagated', 'symmetric'])
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'])
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
)
362 self
.shared_
= shared
363 self
.search_
= search
371 def actualize_location (self
, target
):
372 bjam
.call("NOTFILE", target
)
375 #FIXME: several functions rely on this not being None
379 class CScanner (scanner
.Scanner
):
380 def __init__ (self
, includes
):
381 scanner
.Scanner
.__init
__ (self
)
386 self
.includes_
.extend(i
.split("&&"))
389 return r
'#[ \t]*include[ ]*(<(.*)>|"(.*)")'
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.
400 for match
in matches
:
402 angle
.append(match
.strip('<>'))
404 quoted
.append(match
.strip('"'))
407 b
= os
.path
.normpath(os
.path
.dirname(binding
[0]))
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
419 g2
= '<%s#%s>' % (g
, b
)
422 angle
= [g
+ x
for x
in angle
]
423 quoted
= [g2
+ x
for x
in quoted
]
426 bjam
.call("mark-included", target
, all
)
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>"
434 include_paths
= [i
[9:] for i
in self
.includes_
]
436 engine
= get_manager().engine()
437 engine
.set_target_variable(angle
, "SEARCH", include_paths
)
438 engine
.set_target_variable(quoted
, "SEARCH", [b
] + include_paths
)
440 # Just propagate current scanner to includes, in a hope
441 # that includes do not change scanners.
442 get_manager().scanners().propagate(self
, all
)
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
)
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
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
)
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
470 properties
= prop_set
.raw()
471 # Determine the needed target type
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
:
480 elif '<link>shared' in properties
:
481 actual_type
= 'SHARED_LIB'
483 actual_type
= 'STATIC_LIB'
485 prop_set
= prop_set
.add_raw(['<main-target-type>LIB'])
487 # Construct the target.
488 return generators
.construct(project
, name
, actual_type
, prop_set
, sources
)
490 def viable_source_types(self
):
493 generators
.register(LibGenerator("builtin.lib-generator"))
495 generators
.override("builtin.prebuilt", "builtin.lib-generator")
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
)
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.")
511 get_manager().errors()("When several names are given to the 'lib' rule\n" +
512 "it is not allowed to specify sources.")
514 project
= get_manager().projects().current()
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
)
525 result
.append(targets
.create_typed_metatarget(name
, "LIB", sources
,
531 get_manager().projects().add_rule("lib", lib
)
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
542 generators
.Generator
.__init
__ (self
, id, composing
, source_types
, target_types_and_names
, requirements
)
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
)
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.
557 properties
= prop_set
.raw ()
558 shared
= '<link>shared' in properties
560 a
= virtual_target
.NullAction (project
.manager(), prop_set
)
562 real_name
= feature
.get_values ('<name>', properties
)
564 real_name
= real_name
[0]
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
)
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
)
577 generators
.register (SearchedLibGenerator ())
579 class PrebuiltLibGenerator(generators
.Generator
):
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
)
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
)
590 f
= properties
.get("file")
593 generators
.register(PrebuiltLibGenerator("builtin.prebuilt", False, [],
594 ["LIB"], ["<file>"]))
596 generators
.override("builtin.prebuilt", "builtin.lib-generator")
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
)
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
608 assert isinstance(prop_set
, property_set
.PropertySet
)
609 s
= self
.targets () [0].creating_subvariant ()
611 return prop_set
.add_raw (s
.implicit_includes ('include', 'H'))
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.
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
)
624 def action_class (self
):
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
)
632 class LinkingGenerator (generators
.Generator
):
633 """ The generator class for handling EXE and SHARED_LIB creation.
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
)
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
)
644 # create a copy since sources is being modified
645 sources
= list(sources
)
646 sources
.extend(prop_set
.get('<library>'))
648 # Add <library-path> properties for all searched libraries
651 if s
.type () == 'SEARCHED_LIB':
653 extra
.extend(property.Property('<library-path>', sp
) for sp
in search
)
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.
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.
665 location
= path
.root(s
.name(), p
.get('source-location')[0])
666 extra_xdll_path
.append(os
.path
.dirname(location
))
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
) \
681 prop_set
= prop_set
.add_raw (extra
)
682 result
= generators
.Generator
.run(self
, project
, name
, prop_set
, sources
)
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
]))
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
)
695 result
= property_set
.empty ()
698 # Add appropriate <xdll-path> usage requirements.
699 raw
= prop_set
.raw ()
700 if '<link>shared' in raw
:
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.
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
))
711 extra
+= replace_grist(paths
, '<xdll-path>')
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
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>')
725 result
= property_set
.create(extra
)
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
736 # sources which are libraries
739 # Searched libraries are not passed as argument to linker
740 # but via some option. So, we pass them to the action
745 if type.is_derived(s
.type(), 'SEARCHED_LIB'):
758 add
.append("<find-shared-library>" + '&&'.join(fsa
))
760 add
.append("<find-static-library>" + '&&'.join(fst
))
762 spawn
= generators
.Generator
.generated_targets(self
, sources2
, prop_set
.add_raw(add
), project
, name
)
766 def register_linker(id, source_types
, target_types
, requirements
):
767 g
= LinkingGenerator(id, True, source_types
, target_types
, requirements
)
768 generators
.register(g
)
770 class ArchiveGenerator (generators
.Generator
):
771 """ The generator class for handling STATIC_LIB creation.
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
)
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
)
782 # create a copy since this modifies the sources list
783 sources
= list(sources
)
784 sources
.extend(prop_set
.get('<library>'))
786 result
= generators
.Generator
.run (self
, project
, name
, prop_set
, sources
)
788 usage_requirements
= []
789 link
= prop_set
.get('<link>')
792 if type.is_derived(t
.type(), 'LIB'):
793 usage_requirements
.append(property.Property('<library>', t
))
795 usage_requirements
= property_set
.create(usage_requirements
)
797 return usage_requirements
, result
800 def register_archiver(id, source_types
, target_types
, requirements
):
801 g
= ArchiveGenerator(id, True, source_types
, target_types
, requirements
)
802 generators
.register(g
)
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.
808 def run (self
, project
, name
, prop_set
, sources
):
809 return (property_set
.empty(), [])
812 get_manager().projects().add_rule("variant", variant
)