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 iphone linux netbsd
86 openbsd osf qnx qnxnto sgi solaris sun sunos svr4 sysv ultrix unix unixware
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 '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', 'k6', 'k6-2', 'k6-3', 'athlon', 'athlon-tbird', 'athlon-4', 'athlon-xp',
291 'athlon-mp', 'k8', 'opteron', 'athlon64', 'athlon-fx', 'k8-sse3', 'opteron-sse3', 'athlon64-sse3', 'amdfam10', 'barcelona',
292 'bdver1', 'bdver2', 'bdver3', 'btver1', 'btver2', 'winchip-c6', 'winchip2', 'c3', 'c3-2', 'atom',
295 'itanium', 'itanium1', 'merced', 'itanium2', 'mckinley',
298 'v7', 'cypress', 'v8', 'supersparc', 'sparclite', 'hypersparc', 'sparclite86x', 'f930', 'f934',
299 'sparclet', 'tsc701', 'v9', 'ultrasparc', 'ultrasparc3',
302 '401', '403', '405', '405fp', '440', '440fp', '505', '601', '602',
303 '603', '603e', '604', '604e', '620', '630', '740', '7400',
304 '7450', '750', '801', '821', '823', '860', '970', '8540',
305 'power-common', 'ec603e', 'g3', 'g4', 'g5', 'power', 'power2',
306 'power3', 'power4', 'power5', 'powerpc', 'powerpc64', 'rios',
307 'rios1', 'rsc', 'rios2', 'rs64a',
310 '4kc', '4kp', '5kc', '20kc', 'm4k', 'r2000', 'r3000', 'r3900', 'r4000',
311 'r4100', 'r4300', 'r4400', 'r4600', 'r4650',
312 'r6000', 'r8000', 'rm7000', 'rm9000', 'orion', 'sb1', 'vr4100',
313 'vr4111', 'vr4120', 'vr4130', 'vr4300',
314 'vr5000', 'vr5400', 'vr5500',
317 '700', '7100', '7100lc', '7200', '7300', '8000',
319 # Advanced RISC Machines
320 'armv2', 'armv2a', 'armv3', 'armv3m', 'armv4', 'armv4t', 'armv5',
321 'armv5t', 'armv5te', 'armv6', 'armv6j', 'iwmmxt', 'ep9312',
323 # z Systems (aka s390x)
324 'z196', 'zEC12', 'z13', 'z13', 'z14'],
326 ['propagated', 'optional'])
328 feature
.feature('conditional', [], ['incidental', 'free'])
330 # The value of 'no' prevents building of a target.
331 feature
.feature('build', ['yes', 'no'], ['optional'])
333 # Windows-specific features
334 feature
.feature ('user-interface', ['console', 'gui', 'wince', 'native', 'auto'], [])
335 feature
.feature ('variant', [], ['implicit', 'composite', 'propagated', 'symmetric'])
338 variant ('debug', ['<optimization>off', '<debug-symbols>on', '<inlining>off', '<runtime-debugging>on'])
339 variant ('release', ['<optimization>speed', '<debug-symbols>off', '<inlining>full',
340 '<runtime-debugging>off', '<define>NDEBUG'])
341 variant ('profile', ['release'], ['<profiling>on', '<debug-symbols>on'])
347 class SearchedLibTarget (virtual_target
.AbstractFileTarget
):
348 def __init__ (self
, name
, project
, shared
, search
, action
):
349 virtual_target
.AbstractFileTarget
.__init
__ (self
, name
, 'SEARCHED_LIB', project
, action
)
351 self
.shared_
= shared
352 self
.search_
= search
360 def actualize_location (self
, target
):
361 bjam
.call("NOTFILE", target
)
364 #FIXME: several functions rely on this not being None
368 class CScanner (scanner
.Scanner
):
369 def __init__ (self
, includes
):
370 scanner
.Scanner
.__init
__ (self
)
375 self
.includes_
.extend(i
.split("&&"))
378 return r
'#[ \t]*include[ ]*(<(.*)>|"(.*)")'
380 def process (self
, target
, matches
, binding
):
381 # since it's possible for this function to be called
382 # thousands to millions of times (depending on how many
383 # header files there are), as such, there are some
384 # optimizations that have been used here. Anything that
385 # is slightly out of the ordinary for Python code
386 # has been commented.
389 for match
in matches
:
391 angle
.append(match
.strip('<>'))
393 quoted
.append(match
.strip('"'))
396 b
= os
.path
.normpath(os
.path
.dirname(binding
[0]))
398 # Attach binding of including file to included targets.
399 # When target is directly created from virtual target
400 # this extra information is unnecessary. But in other
401 # cases, it allows to distinguish between two headers of the
402 # same name included from different places.
403 # We don't need this extra information for angle includes,
404 # since they should not depend on including file (we can't
405 # get literal "." in include path).
406 # Note: string interpolation is slightly faster
408 g2
= '<%s#%s>' % (g
, b
)
411 angle
= [g
+ x
for x
in angle
]
412 quoted
= [g2
+ x
for x
in quoted
]
415 bjam
.call("mark-included", target
, all
)
417 # each include in self.includes_ looks something like this:
418 # <include>path/to/somewhere
419 # calling get_value(include) is super slow,
420 # calling .replace('<include>', '') is much faster
421 # however, i[9:] is the fastest way of stripping off the "<include>"
423 include_paths
= [i
[9:] for i
in self
.includes_
]
425 engine
= get_manager().engine()
426 engine
.set_target_variable(angle
, "SEARCH", include_paths
)
427 engine
.set_target_variable(quoted
, "SEARCH", [b
] + include_paths
)
429 # Just propagate current scanner to includes, in a hope
430 # that includes do not change scanners.
431 get_manager().scanners().propagate(self
, all
)
433 scanner
.register (CScanner
, 'include')
434 type.set_scanner ('CPP', CScanner
)
435 type.set_scanner ('C', CScanner
)
436 type.set_scanner('H', CScanner
)
437 type.set_scanner('HPP', CScanner
)
439 # Ported to trunk@47077
440 class LibGenerator (generators
.Generator
):
441 """ The generator class for libraries (target type LIB). Depending on properties it will
442 request building of the approapriate specific type -- SHARED_LIB, STATIC_LIB or
446 def __init__(self
, id, composing
= True, source_types
= [], target_types_and_names
= ['LIB'], requirements
= []):
447 generators
.Generator
.__init
__(self
, id, composing
, source_types
, target_types_and_names
, requirements
)
449 def run(self
, project
, name
, prop_set
, sources
):
450 assert isinstance(project
, targets
.ProjectTarget
)
451 assert isinstance(name
, basestring
) or name
is None
452 assert isinstance(prop_set
, property_set
.PropertySet
)
453 assert is_iterable_typed(sources
, virtual_target
.VirtualTarget
)
454 # The lib generator is composing, and can be only invoked with
455 # explicit name. This check is present in generator.run (and so in
456 # builtin.LinkingGenerator), but duplicate it here to avoid doing
459 properties
= prop_set
.raw()
460 # Determine the needed target type
462 properties_grist
= get_grist(properties
)
463 if '<source>' not in properties_grist
and \
464 ('<search>' in properties_grist
or '<name>' in properties_grist
):
465 actual_type
= 'SEARCHED_LIB'
466 elif '<file>' in properties_grist
:
469 elif '<link>shared' in properties
:
470 actual_type
= 'SHARED_LIB'
472 actual_type
= 'STATIC_LIB'
474 prop_set
= prop_set
.add_raw(['<main-target-type>LIB'])
476 # Construct the target.
477 return generators
.construct(project
, name
, actual_type
, prop_set
, sources
)
479 def viable_source_types(self
):
482 generators
.register(LibGenerator("builtin.lib-generator"))
484 generators
.override("builtin.prebuilt", "builtin.lib-generator")
486 def lib(names
, sources
=[], requirements
=[], default_build
=[], usage_requirements
=[]):
487 """The implementation of the 'lib' rule. Beyond standard syntax that rule allows
488 simplified: 'lib a b c ;'."""
489 assert is_iterable_typed(names
, basestring
)
490 assert is_iterable_typed(sources
, basestring
)
491 assert is_iterable_typed(requirements
, basestring
)
492 assert is_iterable_typed(default_build
, basestring
)
493 assert is_iterable_typed(usage_requirements
, basestring
)
495 if any(r
.startswith('<name>') for r
in requirements
):
496 get_manager().errors()("When several names are given to the 'lib' rule\n" +
497 "it is not allowed to specify the <name> feature.")
500 get_manager().errors()("When several names are given to the 'lib' rule\n" +
501 "it is not allowed to specify sources.")
503 project
= get_manager().projects().current()
509 # Support " lib a ; " and " lib a b c ; " syntax.
510 if not sources
and not any(r
.startswith("<name>") for r
in requirements
) \
511 and not any(r
.startswith("<file") for r
in requirements
):
512 r
.append("<name>" + name
)
514 result
.append(targets
.create_typed_metatarget(name
, "LIB", sources
,
520 get_manager().projects().add_rule("lib", lib
)
523 # Updated to trunk@47077
524 class SearchedLibGenerator (generators
.Generator
):
525 def __init__ (self
, id = 'SearchedLibGenerator', composing
= False, source_types
= [], target_types_and_names
= ['SEARCHED_LIB'], requirements
= []):
526 # TODO: the comment below looks strange. There are no requirements!
527 # The requirements cause the generators to be tried *only* when we're building
528 # lib target and there's 'search' feature. This seems ugly --- all we want
529 # is make sure SearchedLibGenerator is not invoked deep in transformation
531 generators
.Generator
.__init
__ (self
, id, composing
, source_types
, target_types_and_names
, requirements
)
533 def run(self
, project
, name
, prop_set
, sources
):
534 assert isinstance(project
, targets
.ProjectTarget
)
535 assert isinstance(name
, basestring
) or name
is None
536 assert isinstance(prop_set
, property_set
.PropertySet
)
537 assert is_iterable_typed(sources
, virtual_target
.VirtualTarget
)
542 # If name is empty, it means we're called not from top-level.
543 # In this case, we just fail immediately, because SearchedLibGenerator
544 # cannot be used to produce intermediate targets.
546 properties
= prop_set
.raw ()
547 shared
= '<link>shared' in properties
549 a
= virtual_target
.NullAction (project
.manager(), prop_set
)
551 real_name
= feature
.get_values ('<name>', properties
)
553 real_name
= real_name
[0]
556 search
= feature
.get_values('<search>', properties
)
557 usage_requirements
= property_set
.create(['<xdll-path>' + p
for p
in search
])
558 t
= SearchedLibTarget(real_name
, project
, shared
, search
, a
)
560 # We return sources for a simple reason. If there's
561 # lib png : z : <name>png ;
562 # the 'z' target should be returned, so that apps linking to
563 # 'png' will link to 'z', too.
564 return(usage_requirements
, [b2
.manager
.get_manager().virtual_targets().register(t
)] + sources
)
566 generators
.register (SearchedLibGenerator ())
568 class PrebuiltLibGenerator(generators
.Generator
):
570 def __init__(self
, id, composing
, source_types
, target_types_and_names
, requirements
):
571 generators
.Generator
.__init
__ (self
, id, composing
, source_types
, target_types_and_names
, requirements
)
573 def run(self
, project
, name
, properties
, sources
):
574 assert isinstance(project
, targets
.ProjectTarget
)
575 assert isinstance(name
, basestring
)
576 assert isinstance(properties
, property_set
.PropertySet
)
577 assert is_iterable_typed(sources
, virtual_target
.VirtualTarget
)
579 f
= properties
.get("file")
582 generators
.register(PrebuiltLibGenerator("builtin.prebuilt", False, [],
583 ["LIB"], ["<file>"]))
585 generators
.override("builtin.prebuilt", "builtin.lib-generator")
588 class CompileAction (virtual_target
.Action
):
589 def __init__ (self
, manager
, sources
, action_name
, prop_set
):
590 virtual_target
.Action
.__init
__ (self
, manager
, sources
, action_name
, prop_set
)
592 def adjust_properties (self
, prop_set
):
593 """ For all virtual targets for the same dependency graph as self,
594 i.e. which belong to the same main target, add their directories
597 assert isinstance(prop_set
, property_set
.PropertySet
)
598 s
= self
.targets () [0].creating_subvariant ()
600 return prop_set
.add_raw (s
.implicit_includes ('include', 'H'))
602 class CCompilingGenerator (generators
.Generator
):
603 """ Declare a special compiler generator.
604 The only thing it does is changing the type used to represent
605 'action' in the constructed dependency graph to 'CompileAction'.
606 That class in turn adds additional include paths to handle a case
607 when a source file includes headers which are generated themselves.
609 def __init__ (self
, id, composing
, source_types
, target_types_and_names
, requirements
):
610 # TODO: (PF) What to do with optional_properties? It seemed that, in the bjam version, the arguments are wrong.
611 generators
.Generator
.__init
__ (self
, id, composing
, source_types
, target_types_and_names
, requirements
)
613 def action_class (self
):
616 def register_c_compiler (id, source_types
, target_types
, requirements
, optional_properties
= []):
617 g
= CCompilingGenerator (id, False, source_types
, target_types
, requirements
+ optional_properties
)
618 return generators
.register (g
)
621 class LinkingGenerator (generators
.Generator
):
622 """ The generator class for handling EXE and SHARED_LIB creation.
624 def __init__ (self
, id, composing
, source_types
, target_types_and_names
, requirements
):
625 generators
.Generator
.__init
__ (self
, id, composing
, source_types
, target_types_and_names
, requirements
)
627 def run (self
, project
, name
, prop_set
, sources
):
628 assert isinstance(project
, targets
.ProjectTarget
)
629 assert isinstance(name
, basestring
) or name
is None
630 assert isinstance(prop_set
, property_set
.PropertySet
)
631 assert is_iterable_typed(sources
, virtual_target
.VirtualTarget
)
633 # create a copy since sources is being modified
634 sources
= list(sources
)
635 sources
.extend(prop_set
.get('<library>'))
637 # Add <library-path> properties for all searched libraries
640 if s
.type () == 'SEARCHED_LIB':
642 extra
.extend(property.Property('<library-path>', sp
) for sp
in search
)
644 # It's possible that we have libraries in sources which did not came
645 # from 'lib' target. For example, libraries which are specified
646 # just as filenames as sources. We don't have xdll-path properties
647 # for such target, but still need to add proper dll-path properties.
650 if type.is_derived (s
.type (), 'SHARED_LIB') and not s
.action ():
651 # Unfortunately, we don't have a good way to find the path
652 # to a file, so use this nasty approach.
654 location
= path
.root(s
.name(), p
.get('source-location')[0])
655 extra_xdll_path
.append(os
.path
.dirname(location
))
657 # Hardcode DLL paths only when linking executables.
658 # Pros: do not need to relink libraries when installing.
659 # Cons: "standalone" libraries (plugins, python extensions) can not
660 # hardcode paths to dependent libraries.
661 if prop_set
.get('<hardcode-dll-paths>') == ['true'] \
662 and type.is_derived(self
.target_types_
[0], 'EXE'):
663 xdll_path
= prop_set
.get('<xdll-path>')
664 extra
.extend(property.Property('<dll-path>', sp
) \
665 for sp
in extra_xdll_path
)
666 extra
.extend(property.Property('<dll-path>', sp
) \
670 prop_set
= prop_set
.add_raw (extra
)
671 result
= generators
.Generator
.run(self
, project
, name
, prop_set
, sources
)
674 ur
= self
.extra_usage_requirements(result
, prop_set
)
675 ur
= ur
.add(property_set
.create(['<xdll-path>' + p
for p
in extra_xdll_path
]))
680 def extra_usage_requirements (self
, created_targets
, prop_set
):
681 assert is_iterable_typed(created_targets
, virtual_target
.VirtualTarget
)
682 assert isinstance(prop_set
, property_set
.PropertySet
)
684 result
= property_set
.empty ()
687 # Add appropriate <xdll-path> usage requirements.
688 raw
= prop_set
.raw ()
689 if '<link>shared' in raw
:
692 # TODO: is it safe to use the current directory? I think we should use
693 # another mechanism to allow this to be run from anywhere.
696 for t
in created_targets
:
697 if type.is_derived(t
.type(), 'SHARED_LIB'):
698 paths
.append(path
.root(path
.make(t
.path()), pwd
))
700 extra
+= replace_grist(paths
, '<xdll-path>')
702 # We need to pass <xdll-path> features that we've got from sources,
703 # because if shared library is built, exe which uses it must know paths
704 # to other shared libraries this one depends on, to be able to find them
707 # Just pass all features in property_set, it's theorically possible
708 # that we'll propagate <xdll-path> features explicitly specified by
709 # the user, but then the user's to blame for using internal feature.
710 values
= prop_set
.get('<xdll-path>')
711 extra
+= replace_grist(values
, '<xdll-path>')
714 result
= property_set
.create(extra
)
718 def generated_targets (self
, sources
, prop_set
, project
, name
):
719 assert is_iterable_typed(sources
, virtual_target
.VirtualTarget
)
720 assert isinstance(prop_set
, property_set
.PropertySet
)
721 assert isinstance(project
, targets
.ProjectTarget
)
722 assert isinstance(name
, basestring
)
723 # sources to pass to inherited rule
725 # sources which are libraries
728 # Searched libraries are not passed as argument to linker
729 # but via some option. So, we pass them to the action
734 if type.is_derived(s
.type(), 'SEARCHED_LIB'):
747 add
.append("<find-shared-library>" + '&&'.join(fsa
))
749 add
.append("<find-static-library>" + '&&'.join(fst
))
751 spawn
= generators
.Generator
.generated_targets(self
, sources2
, prop_set
.add_raw(add
), project
, name
)
755 def register_linker(id, source_types
, target_types
, requirements
):
756 g
= LinkingGenerator(id, True, source_types
, target_types
, requirements
)
757 generators
.register(g
)
759 class ArchiveGenerator (generators
.Generator
):
760 """ The generator class for handling STATIC_LIB creation.
762 def __init__ (self
, id, composing
, source_types
, target_types_and_names
, requirements
):
763 generators
.Generator
.__init
__ (self
, id, composing
, source_types
, target_types_and_names
, requirements
)
765 def run (self
, project
, name
, prop_set
, sources
):
766 assert isinstance(project
, targets
.ProjectTarget
)
767 assert isinstance(name
, basestring
) or name
is None
768 assert isinstance(prop_set
, property_set
.PropertySet
)
769 assert is_iterable_typed(sources
, virtual_target
.VirtualTarget
)
771 # create a copy since this modifies the sources list
772 sources
= list(sources
)
773 sources
.extend(prop_set
.get('<library>'))
775 result
= generators
.Generator
.run (self
, project
, name
, prop_set
, sources
)
777 usage_requirements
= []
778 link
= prop_set
.get('<link>')
781 if type.is_derived(t
.type(), 'LIB'):
782 usage_requirements
.append(property.Property('<library>', t
))
784 usage_requirements
= property_set
.create(usage_requirements
)
786 return usage_requirements
, result
789 def register_archiver(id, source_types
, target_types
, requirements
):
790 g
= ArchiveGenerator(id, True, source_types
, target_types
, requirements
)
791 generators
.register(g
)
793 class DummyGenerator(generators
.Generator
):
794 """Generator that accepts everything and produces nothing. Useful as a general
795 fallback for toolset-specific actions like PCH generation.
797 def run (self
, project
, name
, prop_set
, sources
):
798 return (property_set
.empty(), [])
801 get_manager().projects().add_rule("variant", variant
)