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('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.
206 ['incidental', 'optional', 'propagated'])
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 ;
215 feature
.feature ('library-file', [], ['free', 'dependency'])
217 feature
.feature ('name', [], ['free'])
218 feature
.feature ('tag', [], ['free'])
219 feature
.feature ('search', [], ['free', 'path']) #order-sensitive ;
220 feature
.feature ('location', [], ['free', 'path'])
222 feature
.feature ('dll-path', [], ['free', 'path'])
223 feature
.feature ('hardcode-dll-paths', ['true', 'false'], ['incidental'])
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'])
232 #provides means to specify def-file for windows dlls.
233 feature
.feature ('def-file', [], ['free', 'dependency'])
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
239 feature
.feature ('allow', [], ['free'])
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'])
245 # Type of CPU architecture to compile for.
246 feature
.feature('architecture', [
260 'mips1', 'mips2', 'mips3', 'mips4', 'mips32', 'mips32r2', 'mips64',
265 # Advanced RISC Machines
268 # Combined architectures for platforms/toolsets that support building for
269 # multiple architectures at once. "combined" would be the default multi-arch
272 'combined-x86-power'],
274 ['propagated', 'optional'])
276 # The specific instruction set in an architecture to compile.
277 feature
.feature('instruction-set', [
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',
287 'itanium', 'itanium1', 'merced', 'itanium2', 'mckinley',
290 'v7', 'cypress', 'v8', 'supersparc', 'sparclite', 'hypersparc', 'sparclite86x', 'f930', 'f934',
291 'sparclet', 'tsc701', 'v9', 'ultrasparc', 'ultrasparc3',
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',
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',
309 '700', '7100', '7100lc', '7200', '7300', '8000',
311 # Advanced RISC Machines
312 'armv2', 'armv2a', 'armv3', 'armv3m', 'armv4', 'armv4t', 'armv5',
313 'armv5t', 'armv5te', 'armv6', 'armv6j', 'iwmmxt', 'ep9312'],
315 ['propagated', 'optional'])
317 feature
.feature('conditional', [], ['incidental', 'free'])
319 # The value of 'no' prevents building of a target.
320 feature
.feature('build', ['yes', 'no'], ['optional'])
322 # Windows-specific features
323 feature
.feature ('user-interface', ['console', 'gui', 'wince', 'native', 'auto'], [])
324 feature
.feature ('variant', [], ['implicit', 'composite', 'propagated', 'symmetric'])
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'])
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
)
340 self
.shared_
= shared
341 self
.search_
= search
349 def actualize_location (self
, target
):
350 bjam
.call("NOTFILE", target
)
353 #FIXME: several functions rely on this not being None
357 class CScanner (scanner
.Scanner
):
358 def __init__ (self
, includes
):
359 scanner
.Scanner
.__init
__ (self
)
364 self
.includes_
.extend(i
.split("&&"))
367 return r
'#[ \t]*include[ ]*(<(.*)>|"(.*)")'
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.
378 for match
in matches
:
380 angle
.append(match
.strip('<>'))
382 quoted
.append(match
.strip('"'))
385 b
= os
.path
.normpath(os
.path
.dirname(binding
[0]))
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
397 g2
= '<%s#%s>' % (g
, b
)
400 angle
= [g
+ x
for x
in angle
]
401 quoted
= [g2
+ x
for x
in quoted
]
404 bjam
.call("mark-included", target
, all
)
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>"
412 include_paths
= [i
[9:] for i
in self
.includes_
]
414 engine
= get_manager().engine()
415 engine
.set_target_variable(angle
, "SEARCH", include_paths
)
416 engine
.set_target_variable(quoted
, "SEARCH", [b
] + include_paths
)
418 # Just propagate current scanner to includes, in a hope
419 # that includes do not change scanners.
420 get_manager().scanners().propagate(self
, all
)
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
)
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
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
)
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
448 properties
= prop_set
.raw()
449 # Determine the needed target type
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
:
458 elif '<link>shared' in properties
:
459 actual_type
= 'SHARED_LIB'
461 actual_type
= 'STATIC_LIB'
463 prop_set
= prop_set
.add_raw(['<main-target-type>LIB'])
465 # Construct the target.
466 return generators
.construct(project
, name
, actual_type
, prop_set
, sources
)
468 def viable_source_types(self
):
471 generators
.register(LibGenerator("builtin.lib-generator"))
473 generators
.override("builtin.prebuilt", "builtin.lib-generator")
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
)
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.")
489 get_manager().errors()("When several names are given to the 'lib' rule\n" +
490 "it is not allowed to specify sources.")
492 project
= get_manager().projects().current()
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
)
503 result
.append(targets
.create_typed_metatarget(name
, "LIB", sources
,
509 get_manager().projects().add_rule("lib", lib
)
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
520 generators
.Generator
.__init
__ (self
, id, composing
, source_types
, target_types_and_names
, requirements
)
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
)
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.
535 properties
= prop_set
.raw ()
536 shared
= '<link>shared' in properties
538 a
= virtual_target
.NullAction (project
.manager(), prop_set
)
540 real_name
= feature
.get_values ('<name>', properties
)
542 real_name
= real_name
[0]
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
)
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
)
555 generators
.register (SearchedLibGenerator ())
557 class PrebuiltLibGenerator(generators
.Generator
):
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
)
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
)
568 f
= properties
.get("file")
571 generators
.register(PrebuiltLibGenerator("builtin.prebuilt", False, [],
572 ["LIB"], ["<file>"]))
574 generators
.override("builtin.prebuilt", "builtin.lib-generator")
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
)
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
586 assert isinstance(prop_set
, property_set
.PropertySet
)
587 s
= self
.targets () [0].creating_subvariant ()
589 return prop_set
.add_raw (s
.implicit_includes ('include', 'H'))
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.
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
)
602 def action_class (self
):
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
)
610 class LinkingGenerator (generators
.Generator
):
611 """ The generator class for handling EXE and SHARED_LIB creation.
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
)
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
)
622 # create a copy since sources is being modified
623 sources
= list(sources
)
624 sources
.extend(prop_set
.get('<library>'))
626 # Add <library-path> properties for all searched libraries
629 if s
.type () == 'SEARCHED_LIB':
631 extra
.extend(property.Property('<library-path>', sp
) for sp
in search
)
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.
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.
643 location
= path
.root(s
.name(), p
.get('source-location')[0])
644 extra_xdll_path
.append(os
.path
.dirname(location
))
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
) \
659 prop_set
= prop_set
.add_raw (extra
)
660 result
= generators
.Generator
.run(self
, project
, name
, prop_set
, sources
)
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
]))
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
)
673 result
= property_set
.empty ()
676 # Add appropriate <xdll-path> usage requirements.
677 raw
= prop_set
.raw ()
678 if '<link>shared' in raw
:
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.
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
))
689 extra
+= replace_grist(paths
, '<xdll-path>')
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
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>')
703 result
= property_set
.create(extra
)
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
714 # sources which are libraries
717 # Searched libraries are not passed as argument to linker
718 # but via some option. So, we pass them to the action
723 if type.is_derived(s
.type(), 'SEARCHED_LIB'):
736 add
.append("<find-shared-library>" + '&&'.join(fsa
))
738 add
.append("<find-static-library>" + '&&'.join(fst
))
740 spawn
= generators
.Generator
.generated_targets(self
, sources2
, prop_set
.add_raw(add
), project
, name
)
744 def register_linker(id, source_types
, target_types
, requirements
):
745 g
= LinkingGenerator(id, True, source_types
, target_types
, requirements
)
746 generators
.register(g
)
748 class ArchiveGenerator (generators
.Generator
):
749 """ The generator class for handling STATIC_LIB creation.
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
)
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
)
760 # create a copy since this modifies the sources list
761 sources
= list(sources
)
762 sources
.extend(prop_set
.get('<library>'))
764 result
= generators
.Generator
.run (self
, project
, name
, prop_set
, sources
)
766 usage_requirements
= []
767 link
= prop_set
.get('<link>')
770 if type.is_derived(t
.type(), 'LIB'):
771 usage_requirements
.append(property.Property('<library>', t
))
773 usage_requirements
= property_set
.create(usage_requirements
)
775 return usage_requirements
, result
778 def register_archiver(id, source_types
, target_types
, requirements
):
779 g
= ArchiveGenerator(id, True, source_types
, target_types
, requirements
)
780 generators
.register(g
)
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.
786 def run (self
, project
, name
, prop_set
, sources
):
787 return (property_set
.empty(), [])
790 get_manager().projects().add_rule("variant", variant
)