1 # Status: being ported by Steven Watanabe
4 # Copyright (C) Vladimir Prus 2002. Permission to copy, use, modify, sell and
5 # distribute this software is granted provided this copyright notice appears in
6 # all copies. This software is provided "as is" without express or implied
7 # warranty, and with no claim as to its suitability for any purpose.
9 """ Provides actions common to all toolsets, such as creating directories and
19 # for some reason this fails on Python 2.7(r27:82525)
20 # from b2.build import virtual_target
21 import b2
.build
.virtual_target
22 from b2
.build
import feature
, type
23 from b2
.util
.utility
import *
24 from b2
.util
import path
, is_iterable_typed
26 __re__before_first_dash
= re
.compile ('([^-]*)-')
29 """ Clear the module state. This is mainly for testing purposes.
30 Note that this must be called _after_ resetting the module 'feature'.
32 global __had_unspecified_value
, __had_value
, __declared_subfeature
34 global __all_signatures
, __debug_configuration
, __show_configuration
36 # Stores toolsets without specified initialization values.
37 __had_unspecified_value
= {}
39 # Stores toolsets with specified initialization values.
42 # Stores toolsets with declared subfeatures.
43 __declared_subfeature
= {}
45 # Stores all signatures of the toolsets.
48 # Stores the initialization locations of each toolset
51 __debug_configuration
= '--debug-configuration' in bjam
.variable('ARGV')
52 __show_configuration
= '--show-configuration' in bjam
.variable('ARGV')
54 global __executable_path_variable
55 OS
= bjam
.call("peek", [], "OS")[0]
57 # On Windows the case and capitalization of PATH is not always predictable, so
58 # let's find out what variable name was really set.
60 if n
.lower() == "path":
61 __executable_path_variable
= n
64 __executable_path_variable
= "PATH"
66 m
= {"NT": __executable_path_variable
,
68 "MACOSX": "DYLD_LIBRARY_PATH",
70 "HAIKU": "LIBRARY_PATH"}
71 global __shared_library_path_variable
72 __shared_library_path_variable
= m
.get(OS
, "LD_LIBRARY_PATH")
76 def shared_library_path_variable():
77 return __shared_library_path_variable
79 # ported from trunk@47174
80 class Configurations(object):
82 This class helps to manage toolset configurations. Each configuration
83 has a unique ID and one or more parameters. A typical example of a unique ID
84 is a condition generated by 'common.check-init-parameters' rule. Other kinds
85 of IDs can be used. Parameters may include any details about the configuration
86 like 'command', 'path', etc.
88 A toolset configuration may be in one of the following states:
91 Configuration has been registered (e.g. by autodetection code) but has
92 not yet been marked as used, i.e. 'toolset.using' rule has not yet been
95 Once called 'toolset.using' rule marks the configuration as 'used'.
97 The main difference between the states above is that while a configuration is
98 'registered' its options can be freely changed. This is useful in particular
99 for autodetection code - all detected configurations may be safely overwritten
108 def register(self
, id):
110 Registers a configuration.
112 Returns True if the configuration has been added and False if
113 it already exists. Reports an error if the configuration is 'used'.
115 assert isinstance(id, basestring
)
118 errors
.error("common: the configuration '$(id)' is in use")
120 if id not in self
.all_
:
123 # Indicate that a new configuration has been added.
130 Mark a configuration as 'used'.
132 Returns True if the state of the configuration has been changed to
133 'used' and False if it the state wasn't changed. Reports an error
134 if the configuration isn't known.
136 assert isinstance(id, basestring
)
137 if id not in self
.all_
:
139 errors
.error("common: the configuration '$(id)' is not known")
141 if id not in self
.used_
:
144 # indicate that the configuration has been marked as 'used'
150 """ Return all registered configurations. """
154 """ Return all used configurations. """
157 def get(self
, id, param
):
158 """ Returns the value of a configuration parameter. """
159 assert isinstance(id, basestring
)
160 assert isinstance(param
, basestring
)
161 return self
.params_
.get(param
, {}).get(id)
163 def set (self
, id, param
, value
):
164 """ Sets the value of a configuration parameter. """
165 assert isinstance(id, basestring
)
166 assert isinstance(param
, basestring
)
167 assert is_iterable_typed(value
, basestring
)
168 self
.params_
.setdefault(param
, {})[id] = value
170 # Ported from trunk@47174
171 def check_init_parameters(toolset
, requirement
, *args
):
172 """ The rule for checking toolset parameters. Trailing parameters should all be
173 parameter name/value pairs. The rule will check that each parameter either has
174 a value in each invocation or has no value in each invocation. Also, the rule
175 will check that the combination of all parameter values is unique in all
178 Each parameter name corresponds to a subfeature. This rule will declare a
179 subfeature the first time a non-empty parameter value is passed and will
180 extend it with all the values.
182 The return value from this rule is a condition to be used for flags settings.
184 assert isinstance(toolset
, basestring
)
185 assert is_iterable_typed(requirement
, basestring
) or requirement
is None
186 from b2
.build
import toolset
as b2_toolset
187 if requirement
is None:
190 condition
= replace_grist(toolset
, '<toolset>')
194 assert(isinstance(arg
, tuple))
195 assert(len(arg
) == 2)
198 assert(isinstance(name
, str))
199 assert(isinstance(value
, str) or value
is None)
201 str_toolset_name
= str((toolset
, name
))
203 # FIXME: is this the correct translation?
204 ### if $(value)-is-not-empty
205 if value
is not None:
206 condition
= condition
+ '-' + value
207 if str_toolset_name
in __had_unspecified_value
:
208 raise BaseException("'%s' initialization: parameter '%s' inconsistent\n" \
209 "no value was specified in earlier initialization\n" \
210 "an explicit value is specified now" % (toolset
, name
))
212 # The logic below is for intel compiler. It calls this rule
213 # with 'intel-linux' and 'intel-win' as toolset, so we need to
214 # get the base part of toolset name.
215 # We can't pass 'intel' as toolset, because it that case it will
216 # be impossible to register versionles intel-linux and
217 # intel-win of specific version.
219 m
= __re__before_first_dash
.match(toolset
)
223 if str_toolset_name
not in __had_value
:
224 if str((t
, name
)) not in __declared_subfeature
:
225 feature
.subfeature('toolset', t
, name
, [], ['propagated'])
226 __declared_subfeature
[str((t
, name
))] = True
228 __had_value
[str_toolset_name
] = True
230 feature
.extend_subfeature('toolset', t
, name
, [value
])
231 subcondition
+= ['<toolset-' + t
+ ':' + name
+ '>' + value
]
234 if str_toolset_name
in __had_value
:
235 raise BaseException ("'%s' initialization: parameter '%s' inconsistent\n" \
236 "an explicit value was specified in an earlier initialization\n" \
237 "no value is specified now" % (toolset
, name
))
239 __had_unspecified_value
[str_toolset_name
] = True
241 if value
== None: value
= ''
243 sig
= sig
+ value
+ '-'
245 # if a requirement is specified, the signature should be unique
246 # with that requirement
248 sig
+= '-' + '-'.join(requirement
)
250 if sig
in __all_signatures
:
251 message
= "duplicate initialization of '%s' with the following parameters: " % toolset
256 if value
== None: value
= '<unspecified>'
258 message
+= "'%s' = '%s'\n" % (name
, value
)
260 raise BaseException(message
)
262 __all_signatures
[sig
] = True
264 __init_loc
[sig
] = "User location unknown" #[ errors.nearest-user-location ] ;
266 # If we have a requirement, this version should only be applied under that
267 # condition. To accomplish this we add a toolset requirement that imposes
268 # the toolset subcondition, which encodes the version.
270 r
= ['<toolset>' + toolset
] + requirement
272 b2_toolset
.add_requirements([r
+ ':' + c
for c
in subcondition
])
274 # We add the requirements, if any, to the condition to scope the toolset
275 # variables and options to this specific version.
276 condition
= [condition
]
278 condition
+= requirement
280 if __show_configuration
:
281 print "notice:", condition
282 return ['/'.join(condition
)]
284 # Ported from trunk@47077
285 def get_invocation_command_nodefault(
286 toolset
, tool
, user_provided_command
=[], additional_paths
=[], path_last
=False):
288 A helper rule to get the command to invoke some tool. If
289 'user-provided-command' is not given, tries to find binary named 'tool' in
290 PATH and in the passed 'additional-path'. Otherwise, verifies that the first
291 element of 'user-provided-command' is an existing program.
293 This rule returns the command to be used when invoking the tool. If we can't
294 find the tool, a warning is issued. If 'path-last' is specified, PATH is
295 checked after 'additional-paths' when searching for 'tool'.
297 assert isinstance(toolset
, basestring
)
298 assert isinstance(tool
, basestring
)
299 assert is_iterable_typed(user_provided_command
, basestring
)
300 assert is_iterable_typed(additional_paths
, basestring
) or additional_paths
is None
301 assert isinstance(path_last
, (int, bool))
303 if not user_provided_command
:
304 command
= find_tool(tool
, additional_paths
, path_last
)
305 if not command
and __debug_configuration
:
306 print "warning: toolset", toolset
, "initialization: can't find tool, tool"
308 #print "warning: initialized from" [ errors.nearest-user-location ] ;
310 command
= check_tool(user_provided_command
)
311 if not command
and __debug_configuration
:
312 print "warning: toolset", toolset
, "initialization:"
313 print "warning: can't find user-provided command", user_provided_command
315 #ECHO "warning: initialized from" [ errors.nearest-user-location ]
318 command
= ' '.join(command
)
322 # ported from trunk@47174
323 def get_invocation_command(toolset
, tool
, user_provided_command
= [],
324 additional_paths
= [], path_last
= False):
325 """ Same as get_invocation_command_nodefault, except that if no tool is found,
326 returns either the user-provided-command, if present, or the 'tool' parameter.
328 assert isinstance(toolset
, basestring
)
329 assert isinstance(tool
, basestring
)
330 assert is_iterable_typed(user_provided_command
, basestring
)
331 assert is_iterable_typed(additional_paths
, basestring
) or additional_paths
is None
332 assert isinstance(path_last
, (int, bool))
334 result
= get_invocation_command_nodefault(toolset
, tool
,
335 user_provided_command
,
340 if user_provided_command
:
341 result
= user_provided_command
[0]
345 assert(isinstance(result
, str))
349 # ported from trunk@47281
350 def get_absolute_tool_path(command
):
352 Given an invocation command,
353 return the absolute path to the command. This works even if commnad
354 has not path element and is present in PATH.
356 assert isinstance(command
, basestring
)
357 if os
.path
.dirname(command
):
358 return os
.path
.dirname(command
)
360 programs
= path
.programs_path()
361 m
= path
.glob(programs
, [command
, command
+ '.exe' ])
363 if __debug_configuration
:
364 print "Could not find:", command
, "in", programs
366 return os
.path
.dirname(m
[0])
368 # ported from trunk@47174
369 def find_tool(name
, additional_paths
= [], path_last
= False):
370 """ Attempts to find tool (binary) named 'name' in PATH and in
371 'additional-paths'. If found in path, returns 'name'. If
372 found in additional paths, returns full name. If the tool
373 is found in several directories, returns the first path found.
374 Otherwise, returns the empty string. If 'path_last' is specified,
375 path is checked after 'additional_paths'.
377 assert isinstance(name
, basestring
)
378 assert is_iterable_typed(additional_paths
, basestring
)
379 assert isinstance(path_last
, (int, bool))
381 programs
= path
.programs_path()
382 match
= path
.glob(programs
, [name
, name
+ '.exe'])
383 additional_match
= path
.glob(additional_paths
, [name
, name
+ '.exe'])
387 result
= additional_match
388 if not result
and match
:
395 elif additional_match
:
396 result
= additional_match
399 return path
.native(result
[0])
403 #ported from trunk@47281
404 def check_tool_aux(command
):
405 """ Checks if 'command' can be found either in path
406 or is a full name to an existing file.
408 assert isinstance(command
, basestring
)
409 dirname
= os
.path
.dirname(command
)
411 if os
.path
.exists(command
):
413 # Both NT and Cygwin will run .exe files by their unqualified names.
414 elif on_windows() and os
.path
.exists(command
+ '.exe'):
416 # Only NT will run .bat files by their unqualified names.
417 elif os_name() == 'NT' and os
.path
.exists(command
+ '.bat'):
420 paths
= path
.programs_path()
421 if path
.glob(paths
, [command
]):
424 # ported from trunk@47281
425 def check_tool(command
):
426 """ Checks that a tool can be invoked by 'command'.
427 If command is not an absolute path, checks if it can be found in 'path'.
428 If comand is absolute path, check that it exists. Returns 'command'
429 if ok and empty string otherwise.
431 assert is_iterable_typed(command
, basestring
)
432 #FIXME: why do we check the first and last elements????
433 if check_tool_aux(command
[0]) or check_tool_aux(command
[-1]):
436 # ported from trunk@47281
437 def handle_options(tool
, condition
, command
, options
):
438 """ Handle common options for toolset, specifically sets the following
440 - CONFIG_COMMAND to 'command'
441 - OPTIOns for compile to the value of <compileflags> in options
442 - OPTIONS for compile.c to the value of <cflags> in options
443 - OPTIONS for compile.c++ to the value of <cxxflags> in options
444 - OPTIONS for compile.fortran to the value of <fflags> in options
445 - OPTIONs for link to the value of <linkflags> in options
447 from b2
.build
import toolset
449 assert isinstance(tool
, basestring
)
450 assert is_iterable_typed(condition
, basestring
)
451 assert command
and isinstance(command
, basestring
)
452 assert is_iterable_typed(options
, basestring
)
453 toolset
.flags(tool
, 'CONFIG_COMMAND', condition
, [command
])
454 toolset
.flags(tool
+ '.compile', 'OPTIONS', condition
, feature
.get_values('<compileflags>', options
))
455 toolset
.flags(tool
+ '.compile.c', 'OPTIONS', condition
, feature
.get_values('<cflags>', options
))
456 toolset
.flags(tool
+ '.compile.c++', 'OPTIONS', condition
, feature
.get_values('<cxxflags>', options
))
457 toolset
.flags(tool
+ '.compile.fortran', 'OPTIONS', condition
, feature
.get_values('<fflags>', options
))
458 toolset
.flags(tool
+ '.link', 'OPTIONS', condition
, feature
.get_values('<linkflags>', options
))
460 # ported from trunk@47281
461 def get_program_files_dir():
462 """ returns the location of the "program files" directory on a windows
465 ProgramFiles
= bjam
.variable("ProgramFiles")
467 ProgramFiles
= ' '.join(ProgramFiles
)
469 ProgramFiles
= "c:\\Program Files"
472 # ported from trunk@47281
476 # ported from trunk@47281
480 # ported from trunk@47281
481 def variable_setting_command(variable
, value
):
483 Returns the command needed to set an environment variable on the current
484 platform. The variable setting persists through all following commands and is
485 visible in the environment seen by subsequently executed commands. In other
486 words, on Unix systems, the variable is exported, which is consistent with the
487 only possible behavior on Windows systems.
489 assert isinstance(variable
, basestring
)
490 assert isinstance(value
, basestring
)
492 if os_name() == 'NT':
493 return "set " + variable
+ "=" + value
+ os
.linesep
496 # The following does not work on CYGWIN and needs to be fixed. On
497 # CYGWIN the $(nl) variable holds a Windows new-line \r\n sequence that
498 # messes up the executed export command which then reports that the
499 # passed variable name is incorrect. This is most likely due to the
500 # extra \r character getting interpreted as a part of the variable name.
502 # Several ideas pop to mind on how to fix this:
503 # * One way would be to separate the commands using the ; shell
504 # command separator. This seems like the quickest possible
505 # solution but I do not know whether this would break code on any
506 # platforms I I have no access to.
507 # * Another would be to not use the terminating $(nl) but that would
508 # require updating all the using code so it does not simply
509 # prepend this variable to its own commands.
510 # * I guess the cleanest solution would be to update Boost Jam to
511 # allow explicitly specifying \n & \r characters in its scripts
512 # instead of always relying only on the 'current OS native newline
515 # Some code found to depend on this behaviour:
516 # * This Boost Build module.
518 # * path-variable-setting-command rule.
519 # * python.jam toolset.
520 # * xsltproc.jam toolset.
522 # (todo) (07.07.2008.) (Jurko)
524 # I think that this works correctly in python -- Steven Watanabe
525 return variable
+ "=" + value
+ os
.linesep
+ "export " + variable
+ os
.linesep
527 def path_variable_setting_command(variable
, paths
):
529 Returns a command to sets a named shell path variable to the given NATIVE
530 paths on the current platform.
532 assert isinstance(variable
, basestring
)
533 assert is_iterable_typed(paths
, basestring
)
534 sep
= os
.path
.pathsep
535 return variable_setting_command(variable
, sep
.join(paths
))
537 def prepend_path_variable_command(variable
, paths
):
539 Returns a command that prepends the given paths to the named path variable on
540 the current platform.
542 assert isinstance(variable
, basestring
)
543 assert is_iterable_typed(paths
, basestring
)
544 return path_variable_setting_command(
545 variable
, paths
+ [expand_variable(variable
)])
548 def expand_variable(variable
):
549 """Produce a string that expands the shell variable."""
551 return '%{}%'.format(variable
)
552 return '${%s}' % variable
555 def file_creation_command():
557 Return a command which can create a file. If 'r' is result of invocation, then
558 'r foobar' will create foobar with unspecified content. What happens if file
559 already exists is unspecified.
561 if os_name() == 'NT':
566 #FIXME: global variable
568 __re_windows_drive
= re
.compile(r
'^.*:\$')
570 def mkdir(engine
, target
):
571 assert isinstance(target
, basestring
)
572 # If dir exists, do not update it. Do this even for $(DOT).
573 bjam
.call('NOUPDATE', target
)
577 # FIXME: Where is DOT defined?
578 #if $(<) != $(DOT) && ! $($(<)-mkdir):
579 if target
!= '.' and target
not in __mkdir_set
:
580 # Cheesy gate to prevent multiple invocations on same dir.
581 __mkdir_set
.add(target
)
583 # Schedule the mkdir build action.
584 engine
.set_update_action("common.MkDir", target
, [])
586 # Prepare a Jam 'dirs' target that can be used to make the build only
587 # construct all the target directories.
588 engine
.add_dependency('dirs', target
)
590 # Recursively create parent directories. $(<:P) = $(<)'s parent & we
591 # recurse until root.
593 s
= os
.path
.dirname(target
)
594 if os_name() == 'NT':
595 if(__re_windows_drive
.match(s
)):
600 engine
.add_dependency(target
, s
)
603 bjam
.call('NOTFILE', s
)
605 __re_version
= re
.compile(r
'^([^.]+)[.]([^.]+)[.]?([^.]*)')
607 def format_name(format
, name
, target_type
, prop_set
):
608 """ Given a target, as given to a custom tag rule, returns a string formatted
609 according to the passed format. Format is a list of properties that is
610 represented in the result. For each element of format the corresponding target
611 information is obtained and added to the result string. For all, but the
612 literal, the format value is taken as the as string to prepend to the output
613 to join the item to the rest of the result. If not given "-" is used as a
616 The format options can be:
619 :: The basename of the target name.
621 :: The abbreviated toolset tag being used to build the target.
623 :: Indication of a multi-threaded build.
625 :: Collective tag of the build runtime.
626 <version:/version-feature | X.Y[.Z]/>[joiner]
627 :: Short version tag taken from the given "version-feature"
628 in the build properties. Or if not present, the literal
629 value as the version number.
630 <property:/property-name/>[joiner]
631 :: Direct lookup of the given property-name value in the
632 build properties. /property-name/ is a regular expression.
633 e.g. <property:toolset-.*:flavor> will match every toolset.
635 :: The literal value of the format argument.
637 For example this format:
639 boost_ <base> <toolset> <threading> <runtime> <version:boost-version>
643 boost_thread-vc80-mt-gd-1_33.dll, or
644 boost_regex-vc80-gd-1_33.dll
646 The returned name also has the target type specific prefix and suffix which
647 puts it in a ready form to use as the value from a custom tag rule.
650 from ..build
.property_set
import PropertySet
651 assert is_iterable_typed(format
, basestring
)
652 assert isinstance(name
, basestring
)
653 assert isinstance(target_type
, basestring
)
654 assert isinstance(prop_set
, PropertySet
)
655 # assert(isinstance(prop_set, property_set.PropertySet))
656 if type.is_derived(target_type
, 'LIB'):
660 if grist
== '<base>':
661 result
+= os
.path
.basename(name
)
662 elif grist
== '<toolset>':
663 result
+= join_tag(get_value(f
),
664 toolset_tag(name
, target_type
, prop_set
))
665 elif grist
== '<threading>':
666 result
+= join_tag(get_value(f
),
667 threading_tag(name
, target_type
, prop_set
))
668 elif grist
== '<runtime>':
669 result
+= join_tag(get_value(f
),
670 runtime_tag(name
, target_type
, prop_set
))
671 elif grist
.startswith('<version:'):
672 key
= grist
[len('<version:'):-1]
673 version
= prop_set
.get('<' + key
+ '>')
676 version
= __re_version
.match(version
)
677 result
+= join_tag(get_value(f
), version
[1] + '_' + version
[2])
678 elif grist
.startswith('<property:'):
679 key
= grist
[len('<property:'):-1]
680 property_re
= re
.compile('<(' + key
+ ')>')
682 for prop
in prop_set
.raw():
683 match
= property_re
.match(prop
)
688 p
= prop_set
.get('<' + p0
+ '>')
691 result
+= join_tag(ungrist(f
), p
)
695 result
= b2
.build
.virtual_target
.add_prefix_and_suffix(
696 ''.join(result
), target_type
, prop_set
)
699 def join_tag(joiner
, tag
):
700 assert isinstance(joiner
, basestring
)
701 assert isinstance(tag
, basestring
)
703 if not joiner
: joiner
= '-'
707 __re_toolset_version
= re
.compile(r
"<toolset.*version>(\d+)[.](\d*)")
709 def toolset_tag(name
, target_type
, prop_set
):
711 from ..build
.property_set
import PropertySet
712 assert isinstance(name
, basestring
)
713 assert isinstance(target_type
, basestring
)
714 assert isinstance(prop_set
, PropertySet
)
717 properties
= prop_set
.raw()
718 tools
= prop_set
.get('<toolset>')
719 assert(len(tools
) == 1)
721 if tools
.startswith('borland'): tag
+= 'bcb'
722 elif tools
.startswith('como'): tag
+= 'como'
723 elif tools
.startswith('cw'): tag
+= 'cw'
724 elif tools
.startswith('darwin'): tag
+= 'xgcc'
725 elif tools
.startswith('edg'): tag
+= 'edg'
726 elif tools
.startswith('gcc'):
727 flavor
= prop_set
.get('<toolset-gcc:flavor>')
729 if flavor
.find('mingw') != -1:
733 elif tools
== 'intel':
734 if prop_set
.get('<toolset-intel:platform>') == ['win']:
738 elif tools
.startswith('kcc'): tag
+= 'kcc'
739 elif tools
.startswith('kylix'): tag
+= 'bck'
740 #case metrowerks* : tag += cw ;
741 #case mingw* : tag += mgw ;
742 elif tools
.startswith('mipspro'): tag
+= 'mp'
743 elif tools
.startswith('msvc'): tag
+= 'vc'
744 elif tools
.startswith('sun'): tag
+= 'sw'
745 elif tools
.startswith('tru64cxx'): tag
+= 'tru'
746 elif tools
.startswith('vacpp'): tag
+= 'xlc'
748 for prop
in properties
:
749 match
= __re_toolset_version
.match(prop
)
753 version_string
= None
754 # For historical reasons, vc6.0 and vc7.0 use different naming.
756 if version
.group(1) == '6':
757 # Cancel minor version.
759 elif version
.group(1) == '7' and version
.group(2) == '0':
762 # On intel, version is not added, because it does not matter and it's the
763 # version of vc used as backend that matters. Ideally, we'd encode the
764 # backend version but that would break compatibility with V1.
768 # On borland, version is not added for compatibility with V1.
772 if version_string
is None:
773 version
= version
.group(1) + version
.group(2)
780 def threading_tag(name
, target_type
, prop_set
):
782 from ..build
.property_set
import PropertySet
783 assert isinstance(name
, basestring
)
784 assert isinstance(target_type
, basestring
)
785 assert isinstance(prop_set
, PropertySet
)
787 properties
= prop_set
.raw()
788 if '<threading>multi' in properties
: tag
= 'mt'
793 def runtime_tag(name
, target_type
, prop_set
):
795 from ..build
.property_set
import PropertySet
796 assert isinstance(name
, basestring
)
797 assert isinstance(target_type
, basestring
)
798 assert isinstance(prop_set
, PropertySet
)
801 properties
= prop_set
.raw()
802 if '<runtime-link>static' in properties
: tag
+= 's'
804 # This is an ugly thing. In V1, there's a code to automatically detect which
805 # properties affect a target. So, if <runtime-debugging> does not affect gcc
806 # toolset, the tag rules won't even see <runtime-debugging>. Similar
807 # functionality in V2 is not implemented yet, so we just check for toolsets
808 # which are known to care about runtime debug.
809 if '<toolset>msvc' in properties \
810 or '<stdlib>stlport' in properties \
811 or '<toolset-intel:platform>win' in properties
:
812 if '<runtime-debugging>on' in properties
: tag
+= 'g'
814 if '<python-debugging>on' in properties
: tag
+= 'y'
815 if '<variant>debug' in properties
: tag
+= 'd'
816 if '<stdlib>stlport' in properties
: tag
+= 'p'
817 if '<stdlib-stlport:iostream>hostios' in properties
: tag
+= 'n'
823 global __RM
, __CP
, __IGNORE
, __LN
824 engine
= manager
.engine()
826 # register the make() and alias() rules globally
828 import b2
.build
.alias
831 # ported from trunk@47281
832 if os_name() == 'NT':
835 windows_hack
= '+ this-file-does-not-exist-A698EE7806899E69'
836 __IGNORE
= '2>nul >nul & setlocal'
840 MKDIR
= 'if not exist "$(<)\\" mkdir "$(<)"'
846 MKDIR
= 'mkdir -p "$(<)"'
848 engine
.register_action("common.MkDir", MKDIR
+ __IGNORE
)
850 engine
.register_action(
851 "common.Clean", __RM
+ ' "$(>)"', flags
=['piecemeal', 'together', 'existing'])
852 engine
.register_action("common.copy", '{} "$(>)" {} "$(<)"'.format(__CP
, windows_hack
))
853 engine
.register_action("common.RmTemps", __RM
+ ' "$(>)" ' + __IGNORE
,
854 flags
=['quietly', 'updated', 'piecemeal', 'together'])
856 engine
.register_action("common.hard-link",
857 __RM
+ ' "$(<)" 2$(NULL_OUT) $(NULL_OUT)' + os
.linesep
+
858 __LN
+ ' "$(>)" "$(<)" $(NULL_OUT)')