]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/tools/build/src/tools/common.jam
update sources to v12.2.3
[ceph.git] / ceph / src / boost / tools / build / src / tools / common.jam
1 # Copyright 2003, 2005 Dave Abrahams
2 # Copyright 2005, 2006 Rene Rivera
3 # Copyright 2005 Toon Knapen
4 # Copyright 2002, 2003, 2004, 2005, 2006 Vladimir Prus
5 # Distributed under the Boost Software License, Version 1.0.
6 # (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
7
8 # Provides actions common to all toolsets, such as creating directories and
9 # removing files.
10
11 import os ;
12 import modules ;
13 import utility ;
14 import print ;
15 import type ;
16 import feature ;
17 import errors ;
18 import path ;
19 import sequence ;
20 import toolset ;
21 import virtual-target ;
22
23 if [ MATCH (--debug-configuration) : [ modules.peek : ARGV ] ]
24 {
25 .debug-configuration = true ;
26 }
27 if [ MATCH (--show-configuration) : [ modules.peek : ARGV ] ]
28 {
29 .show-configuration = true ;
30 }
31
32 # Configurations
33 #
34 # The following class helps to manage toolset configurations. Each configuration
35 # has a unique ID and one or more parameters. A typical example of a unique ID
36 # is a condition generated by 'common.check-init-parameters' rule. Other kinds
37 # of IDs can be used. Parameters may include any details about the configuration
38 # like 'command', 'path', etc.
39 #
40 # A toolset configuration may be in one of the following states:
41 #
42 # - registered
43 # Configuration has been registered (e.g. explicitly or by auto-detection
44 # code) but has not yet been marked as used, i.e. 'toolset.using' rule has
45 # not yet been called for it.
46 # - used
47 # Once called 'toolset.using' rule marks the configuration as 'used'.
48 #
49 # The main difference between the states above is that while a configuration is
50 # 'registered' its options can be freely changed. This is useful in particular
51 # for autodetection code - all detected configurations may be safely overwritten
52 # by user code.
53
54 class configurations
55 {
56 import errors ;
57
58 rule __init__ ( )
59 {
60 }
61
62 # Registers a configuration.
63 #
64 # Returns 'true' if the configuration has been added and an empty value if
65 # it already exists. Reports an error if the configuration is 'used'.
66 #
67 rule register ( id )
68 {
69 if $(id) in $(self.used)
70 {
71 errors.error "common: the configuration '$(id)' is in use" ;
72 }
73
74 local retval ;
75
76 if ! $(id) in $(self.all)
77 {
78 self.all += $(id) ;
79
80 # Indicate that a new configuration has been added.
81 retval = true ;
82 }
83
84 return $(retval) ;
85 }
86
87 # Mark a configuration as 'used'.
88 #
89 # Returns 'true' if the state of the configuration has been changed to
90 # 'used' and an empty value if it the state has not been changed. Reports an
91 # error if the configuration is not known.
92 #
93 rule use ( id )
94 {
95 if ! $(id) in $(self.all)
96 {
97 errors.error "common: the configuration '$(id)' is not known" ;
98 }
99
100 local retval ;
101
102 if ! $(id) in $(self.used)
103 {
104 self.used += $(id) ;
105
106 # Indicate that the configuration has been marked as 'used'.
107 retval = true ;
108 }
109
110 return $(retval) ;
111 }
112
113 # Return all registered configurations.
114 #
115 rule all ( )
116 {
117 return $(self.all) ;
118 }
119
120 # Return all used configurations.
121 #
122 rule used ( )
123 {
124 return $(self.used) ;
125 }
126
127 # Returns the value of a configuration parameter.
128 #
129 rule get ( id : param )
130 {
131 return $(self.$(param).$(id)) ;
132 }
133
134 # Sets the value of a configuration parameter.
135 #
136 rule set ( id : param : value * )
137 {
138 self.$(param).$(id) = $(value) ;
139 }
140 }
141
142
143 # The rule for checking toolset parameters. Trailing parameters should all be
144 # parameter name/value pairs. The rule will check that each parameter either has
145 # a value in each invocation or has no value in each invocation. Also, the rule
146 # will check that the combination of all parameter values is unique in all
147 # invocations.
148 #
149 # Each parameter name corresponds to a subfeature. This rule will declare a
150 # subfeature the first time a non-empty parameter value is passed and will
151 # extend it with all the values.
152 #
153 # The return value from this rule is a condition to be used for flags settings.
154 #
155 rule check-init-parameters ( toolset requirement * : * )
156 {
157 local sig = $(toolset) ;
158 local condition = <toolset>$(toolset) ;
159 local subcondition ;
160 for local index in 2 3 4 5 6 7 8 9
161 {
162 local name = $($(index)[1]) ;
163 local value = $($(index)[2]) ;
164
165 if $(value)-is-not-empty
166 {
167 condition = $(condition)-$(value) ;
168 if $(.had-unspecified-value.$(toolset).$(name))
169 {
170 errors.user-error
171 "$(toolset) initialization: parameter '$(name)'"
172 "inconsistent" : "no value was specified in earlier"
173 "initialization" : "an explicit value is specified now" ;
174 }
175 # The below logic is for intel compiler. It calls this rule with
176 # 'intel-linux' and 'intel-win' as toolset, so we need to get the
177 # base part of toolset name. We can not pass 'intel' as toolset
178 # because in that case it will be impossible to register versionless
179 # intel-linux and intel-win toolsets of a specific version.
180 local t = $(toolset) ;
181 local m = [ MATCH ([^-]*)- : $(toolset) ] ;
182 if $(m)
183 {
184 t = $(m[1]) ;
185 }
186 if ! $(.had-value.$(toolset).$(name))
187 {
188 if ! $(.declared-subfeature.$(t).$(name))
189 {
190 feature.subfeature toolset $(t) : $(name) : : propagated ;
191 .declared-subfeature.$(t).$(name) = true ;
192 }
193 .had-value.$(toolset).$(name) = true ;
194 }
195 feature.extend-subfeature toolset $(t) : $(name) : $(value) ;
196 subcondition += <toolset-$(t):$(name)>$(value) ;
197 }
198 else
199 {
200 if $(.had-value.$(toolset).$(name))
201 {
202 errors.user-error
203 "$(toolset) initialization: parameter '$(name)'"
204 "inconsistent" : "an explicit value was specified in an"
205 "earlier initialization" : "no value is specified now" ;
206 }
207 .had-unspecified-value.$(toolset).$(name) = true ;
208 }
209 sig = $(sig)$(value:E="")- ;
210 }
211 # We also need to consider requirements on the toolset as we can
212 # configure the same toolset multiple times with different options that
213 # are selected with the requirements.
214 if $(requirement)
215 {
216 sig = $(sig)$(requirement:J=,) ;
217 }
218 if $(sig) in $(.all-signatures)
219 {
220 local message =
221 "duplicate initialization of $(toolset) with the following parameters: " ;
222 for local index in 2 3 4 5 6 7 8 9
223 {
224 local p = $($(index)) ;
225 if $(p)
226 {
227 message += "$(p[1]) = $(p[2]:E=<unspecified>)" ;
228 }
229 }
230 message += "previous initialization at $(.init-loc.$(sig))" ;
231 errors.user-error
232 $(message[1]) : $(message[2]) : $(message[3]) : $(message[4]) :
233 $(message[5]) : $(message[6]) : $(message[7]) : $(message[8]) ;
234 }
235 .all-signatures += $(sig) ;
236 .init-loc.$(sig) = [ errors.nearest-user-location ] ;
237
238 # If we have a requirement, this version should only be applied under that
239 # condition. To accomplish this we add a toolset requirement that imposes
240 # the toolset subcondition, which encodes the version.
241 if $(requirement)
242 {
243 local r = <toolset>$(toolset) $(requirement) ;
244 r = $(r:J=,) ;
245 toolset.add-requirements $(r):$(subcondition) ;
246 }
247
248 # We add the requirements, if any, to the condition to scope the toolset
249 # variables and options to this specific version.
250 condition += $(requirement) ;
251
252 if $(.show-configuration)
253 {
254 ECHO notice: $(condition) ;
255 }
256 return $(condition:J=/) ;
257 }
258
259
260 # A helper rule to get the command to invoke some tool. If
261 # 'user-provided-command' is not given, tries to find binary named 'tool' in
262 # PATH and in the passed 'additional-path'. Otherwise, verifies that the first
263 # element of 'user-provided-command' is an existing program.
264 #
265 # This rule returns the command to be used when invoking the tool. If we can not
266 # find the tool, a warning is issued. If 'path-last' is specified, PATH is
267 # checked after 'additional-paths' when searching for 'tool'.
268 #
269 rule get-invocation-command-nodefault ( toolset : tool :
270 user-provided-command * : additional-paths * : path-last ? )
271 {
272 local command ;
273 if ! $(user-provided-command)
274 {
275 command = [ find-tool $(tool) : $(additional-paths) : $(path-last) ] ;
276 if ! $(command) && $(.debug-configuration)
277 {
278 ECHO warning: toolset $(toolset) initialization: can not find tool
279 $(tool) ;
280 ECHO warning: initialized from [ errors.nearest-user-location ] ;
281 }
282 }
283 else
284 {
285 command = [ check-tool $(user-provided-command) ] ;
286 if ! $(command) && $(.debug-configuration)
287 {
288 ECHO warning: toolset $(toolset) initialization: ;
289 ECHO warning: can not find user-provided command
290 '$(user-provided-command)' ;
291 ECHO warning: initialized from [ errors.nearest-user-location ] ;
292 }
293 }
294
295 return $(command) ;
296 }
297
298
299 # Same as get-invocation-command-nodefault, except that if no tool is found,
300 # returns either the user-provided-command, if present, or the 'tool' parameter.
301 #
302 rule get-invocation-command ( toolset : tool : user-provided-command * :
303 additional-paths * : path-last ? )
304 {
305 local result = [ get-invocation-command-nodefault $(toolset) : $(tool) :
306 $(user-provided-command) : $(additional-paths) : $(path-last) ] ;
307
308 if ! $(result)
309 {
310 if $(user-provided-command)
311 {
312 result = $(user-provided-command) ;
313 }
314 else
315 {
316 result = $(tool) ;
317 }
318 }
319 return $(result) ;
320 }
321
322
323 # Given an invocation command return the absolute path to the command. This
324 # works even if command has no path element and was found on the PATH.
325 #
326 rule get-absolute-tool-path ( command )
327 {
328 if $(command:D)
329 {
330 return $(command:D) ;
331 }
332 else
333 {
334 local m = [ GLOB [ modules.peek : PATH Path path ] : $(command)
335 $(command).exe ] ;
336 return $(m[1]:D) ;
337 }
338 }
339
340
341 # Attempts to find tool (binary) named 'name' in PATH and in 'additional-paths'.
342 # If found in PATH, returns 'name' and if found in additional paths, returns
343 # absolute name. If the tool is found in several directories, returns the first
344 # path found. Otherwise, returns an empty string. If 'path-last' is specified,
345 # PATH is searched after 'additional-paths'.
346 #
347 rule find-tool ( name : additional-paths * : path-last ? )
348 {
349 if $(name:D)
350 {
351 return [ check-tool-aux $(name) ] ;
352 }
353 local path = [ path.programs-path ] ;
354 local match = [ path.glob $(path) : $(name) $(name).exe ] ;
355 local additional-match = [ path.glob $(additional-paths) : $(name)
356 $(name).exe ] ;
357
358 local result ;
359 if $(path-last)
360 {
361 result = $(additional-match) ;
362 if ! $(result) && $(match)
363 {
364 result = $(name) ;
365 }
366 }
367 else
368 {
369 if $(match)
370 {
371 result = $(name) ;
372 }
373 else
374 {
375 result = $(additional-match) ;
376 }
377 }
378 if $(result)
379 {
380 return [ path.native $(result[1]) ] ;
381 }
382 }
383
384 # Checks if 'command' can be found either in path or is a full name to an
385 # existing file.
386 #
387 local rule check-tool-aux ( command )
388 {
389 if $(command:D)
390 {
391 if [ path.exists $(command) ]
392 # Both NT and Cygwin will run .exe files by their unqualified names.
393 || ( [ os.on-windows ] && [ path.exists $(command).exe ] )
394 # Only NT will run .bat & .cmd files by their unqualified names.
395 || ( ( [ os.name ] = NT ) && ( [ path.exists $(command).bat ] ||
396 [ path.exists $(command).cmd ] ) )
397 {
398 return $(command) ;
399 }
400 }
401 else
402 {
403 if [ GLOB [ modules.peek : PATH Path path ] : $(command) ]
404 {
405 return $(command) ;
406 }
407 }
408 }
409
410
411 # Checks that a tool can be invoked by 'command'. If command is not an absolute
412 # path, checks if it can be found in 'path'. If comand is an absolute path,
413 # check that it exists. Returns 'command' if ok or empty string otherwise.
414 #
415 local rule check-tool ( xcommand + )
416 {
417 if [ check-tool-aux $(xcommand[1]) ] ||
418 [ check-tool-aux $(xcommand[-1]) ]
419 {
420 return $(xcommand) ;
421 }
422 }
423
424
425 # Handle common options for toolset, specifically sets the following flag
426 # variables:
427 # - CONFIG_COMMAND to $(command)
428 # - OPTIONS for compile to the value of <compileflags> in $(options)
429 # - OPTIONS for compile.c to the value of <cflags> in $(options)
430 # - OPTIONS for compile.c++ to the value of <cxxflags> in $(options)
431 # - OPTIONS for compile.fortran to the value of <fflags> in $(options)
432 # - OPTIONS for link to the value of <linkflags> in $(options)
433 #
434 rule handle-options ( toolset : condition * : command * : options * )
435 {
436 if $(.debug-configuration)
437 {
438 ECHO notice: will use '$(command)' for $(toolset), condition
439 $(condition:E=(empty)) ;
440 }
441
442 # The last parameter ('unchecked') says it is OK to set flags for another
443 # module.
444 toolset.flags $(toolset) CONFIG_COMMAND $(condition) : $(command)
445 : unchecked ;
446
447 toolset.flags $(toolset).compile OPTIONS $(condition) :
448 [ feature.get-values <compileflags> : $(options) ] : unchecked ;
449
450 toolset.flags $(toolset).compile.c OPTIONS $(condition) :
451 [ feature.get-values <cflags> : $(options) ] : unchecked ;
452
453 toolset.flags $(toolset).compile.c++ OPTIONS $(condition) :
454 [ feature.get-values <cxxflags> : $(options) ] : unchecked ;
455
456 toolset.flags $(toolset).compile.fortran OPTIONS $(condition) :
457 [ feature.get-values <fflags> : $(options) ] : unchecked ;
458
459 toolset.flags $(toolset).link OPTIONS $(condition) :
460 [ feature.get-values <linkflags> : $(options) ] : unchecked ;
461 }
462
463
464 # Returns the location of the "program files" directory on a Windows platform.
465 #
466 rule get-program-files-dir ( )
467 {
468 local ProgramFiles = [ modules.peek : ProgramFiles ] ;
469 if $(ProgramFiles)
470 {
471 ProgramFiles = "$(ProgramFiles:J= )" ;
472 }
473 else
474 {
475 ProgramFiles = "c:\\Program Files" ;
476 }
477 return $(ProgramFiles) ;
478 }
479
480
481 if [ os.name ] = NT
482 {
483 NULL_DEVICE = "NUL" ;
484 IGNORE = "2>$(NULL_DEVICE) >$(NULL_DEVICE) & setlocal" ;
485 RM = del /f /q ;
486 CP = copy /b ;
487 LN ?= $(CP) ;
488 # Ugly hack to convince copy to set the timestamp of the destination to the
489 # current time by concatenating the source with a nonexistent file. Note
490 # that this requires /b (binary) as the default when concatenating files is
491 # /a (ascii).
492 WINDOWS-CP-HACK = "+ this-file-does-not-exist-A698EE7806899E69" ;
493 }
494 else if [ os.name ] = VMS
495 {
496 NULL_DEVICE = "NL:" ;
497 PIPE = PIPE ;
498 IGNORE = "2>$(NULL_DEVICE) >$(NULL_DEVICE)" ;
499 RM = DELETE /NOCONF ;
500 CP = COPY /OVERWRITE ;
501 LN = $(CP) ;
502 }
503 else
504 {
505 NULL_DEVICE = "/dev/null" ;
506 IGNORE = "2>$(NULL_DEVICE) >$(NULL_DEVICE)" ;
507 RM = rm -f ;
508 CP = cp ;
509 LN = ln ;
510 }
511
512 NULL_OUT = ">$(NULL_DEVICE)" ;
513
514 rule null-device ( )
515 {
516 return $(NULL_DEVICE) ;
517 }
518
519
520 rule rm-command ( )
521 {
522 return $(RM) ;
523 }
524
525
526 rule copy-command ( )
527 {
528 return $(CP) ;
529 }
530
531
532 if "\n" = "n"
533 {
534 # Escape characters not supported so use ugly hacks. Will not work on Cygwin
535 # - see below.
536 nl = "
537 " ;
538 q = "" ;
539 }
540 else
541 {
542 nl = "\n" ;
543 q = "\"" ;
544 }
545
546
547 rule newline-char ( )
548 {
549 return $(nl) ;
550 }
551
552
553 # Returns the command needed to set an environment variable on the current
554 # platform. The variable setting persists through all following commands and is
555 # visible in the environment seen by subsequently executed commands. In other
556 # words, on Unix systems, the variable is exported, which is consistent with the
557 # only possible behavior on Windows systems.
558 #
559 rule variable-setting-command ( variable : value )
560 {
561 if [ os.name ] = NT
562 {
563 return "set $(variable)=$(value)$(nl)" ;
564 }
565 else if [ os.name ] = VMS
566 {
567 return "$(variable) == $(q)$(value)$(q)$(nl)" ;
568 }
569 else
570 {
571 # If we do not have escape character support in bjam, the cod below
572 # blows up on CYGWIN, since the $(nl) variable holds a Windows new-line
573 # \r\n sequence that messes up the executed export command which then
574 # reports that the passed variable name is incorrect.
575 # But we have a check for cygwin in kernel/bootstrap.jam already.
576 return "$(variable)=$(q)$(value)$(q)$(nl)export $(variable)$(nl)" ;
577 }
578 }
579
580
581 # Returns a command to sets a named shell path variable to the given NATIVE
582 # paths on the current platform.
583 #
584 rule path-variable-setting-command ( variable : paths * )
585 {
586 local sep = [ os.path-separator ] ;
587 return [ variable-setting-command $(variable) : $(paths:J=$(sep)) ] ;
588 }
589
590
591 # Returns a command that prepends the given paths to the named path variable on
592 # the current platform.
593 #
594 rule prepend-path-variable-command ( variable : paths * )
595 {
596 return [ path-variable-setting-command $(variable)
597 : $(paths) [ os.expand-variable $(variable) ] ] ;
598 }
599
600
601 # Return a command which can create a file. If 'r' is result of invocation, then
602 # 'r foobar' will create foobar with unspecified content. What happens if file
603 # already exists is unspecified.
604 #
605 rule file-creation-command ( )
606 {
607 if [ os.name ] = NT
608 {
609 # A few alternative implementations on Windows:
610 #
611 # 'type NUL >> '
612 # That would construct an empty file instead of a file containing
613 # a space and an end-of-line marker but it would also not change
614 # the target's timestamp in case the file already exists.
615 #
616 # 'type NUL > '
617 # That would construct an empty file instead of a file containing
618 # a space and an end-of-line marker but it would also destroy an
619 # already existing file by overwriting it with an empty one.
620 #
621 # I guess the best solution would be to allow Boost Jam to define
622 # built-in functions such as 'create a file', 'touch a file' or 'copy a
623 # file' which could be used from inside action code. That would allow
624 # completely portable operations without this kind of kludge.
625 # (22.02.2009.) (Jurko)
626 return "echo. > " ;
627 }
628 else if [ os.name ] = VMS
629 {
630 return "APPEND /NEW NL: " ;
631 }
632 else
633 {
634 return "touch " ;
635 }
636 }
637
638
639 # Returns a command that may be used for 'touching' files. It is not a real
640 # 'touch' command on NT because it adds an empty line at the end of file but it
641 # works with source files.
642 #
643 rule file-touch-command ( )
644 {
645 if [ os.name ] = NT
646 {
647 return "echo. >> " ;
648 }
649 else if [ os.name ] = VMS
650 {
651 return "APPEND /NEW NL: " ;
652 }
653 else
654 {
655 return "touch " ;
656 }
657 }
658
659
660 rule MkDir
661 {
662 # If dir exists, do not update it. Do this even for $(DOT).
663 NOUPDATE $(<) ;
664
665 if $(<) != $(DOT) && ! $($(<)-mkdir)
666 {
667 # Cheesy gate to prevent multiple invocations on same dir.
668 $(<)-mkdir = true ;
669
670 # Schedule the mkdir build action.
671 common.mkdir $(<) ;
672
673 # Prepare a Jam 'dirs' target that can be used to make the build only
674 # construct all the target directories.
675 DEPENDS dirs : $(<) ;
676
677 # Recursively create parent directories. $(<:P) = $(<)'s parent & we
678 # recurse until root.
679
680 local s = $(<:P) ;
681 if [ os.name ] = NT
682 {
683 switch $(s)
684 {
685 case *: : s = ;
686 case *:\\ : s = ;
687 }
688 }
689
690 if $(s)
691 {
692 if $(s) != $(<)
693 {
694 DEPENDS $(<) : $(s) ;
695 MkDir $(s) ;
696 }
697 else
698 {
699 NOTFILE $(s) ;
700 }
701 }
702 }
703 }
704
705
706 #actions MkDir1
707 #{
708 # mkdir "$(<)"
709 #}
710
711 # The following quick-fix actions should be replaced using the original MkDir1
712 # action once Boost Jam gets updated to correctly detect different paths leading
713 # up to the same filesystem target and triggers their build action only once.
714 # (todo) (04.07.2008.) (Jurko)
715
716 if [ os.name ] = NT
717 {
718 actions quietly mkdir
719 {
720 if not exist "$(<)\\" mkdir "$(<)"
721 }
722 }
723 else
724 {
725 actions quietly mkdir
726 {
727 mkdir -p "$(<)"
728 }
729 }
730
731
732 actions piecemeal together existing Clean
733 {
734 $(RM) "$(>)"
735 }
736
737
738 rule copy
739 {
740 }
741
742
743 actions copy
744 {
745 $(CP) "$(>)" $(WINDOWS-CP-HACK) "$(<)"
746 }
747
748
749 rule RmTemps
750 {
751 }
752
753
754 actions quietly updated piecemeal together RmTemps
755 {
756 $(RM) "$(>)" $(IGNORE)
757 }
758
759
760 actions hard-link
761 {
762 $(RM) "$(<)" 2$(NULL_OUT) $(NULL_OUT)
763 $(LN) "$(>)" "$(<)" $(NULL_OUT)
764 }
765
766
767 if [ os.name ] = VMS
768 {
769 actions mkdir
770 {
771 IF F$PARSE("$(<:W)") .EQS. "" THEN CREATE /DIR $(<:W)
772 }
773
774 actions piecemeal together existing Clean
775 {
776 $(RM) $(>:WJ=;*,);*
777 }
778
779 actions copy
780 {
781 $(CP) $(>:WJ=,) $(<:W)
782 }
783
784 actions quietly updated piecemeal together RmTemps
785 {
786 $(PIPE) $(RM) $(>:WJ=;*,);* $(IGNORE)
787 }
788
789 actions hard-link
790 {
791 $(PIPE) $(RM) $(>[1]:W);* $(IGNORE)
792 $(PIPE) $(LN) $(>[1]:W) $(<:W) $(NULL_OUT)
793 }
794 }
795
796 # Given a target, as given to a custom tag rule, returns a string formatted
797 # according to the passed format. Format is a list of properties that is
798 # represented in the result. For each element of format the corresponding target
799 # information is obtained and added to the result string. For all, but the
800 # literal, the format value is taken as the as string to prepend to the output
801 # to join the item to the rest of the result. If not given "-" is used as a
802 # joiner.
803 #
804 # The format options can be:
805 #
806 # <base>[joiner]
807 # :: The basename of the target name.
808 # <toolset>[joiner]
809 # :: The abbreviated toolset tag being used to build the target.
810 # <threading>[joiner]
811 # :: Indication of a multi-threaded build.
812 # <runtime>[joiner]
813 # :: Collective tag of the build runtime.
814 # <version:/version-feature | X.Y[.Z]/>[joiner]
815 # :: Short version tag taken from the given "version-feature" in the
816 # build properties. Or if not present, the literal value as the
817 # version number.
818 # <property:/property-name/>[joiner]
819 # :: Direct lookup of the given property-name value in the build
820 # properties. /property-name/ is a regular expression. E.g.
821 # <property:toolset-.*:flavor> will match every toolset.
822 # /otherwise/
823 # :: The literal value of the format argument.
824 #
825 # For example this format:
826 #
827 # boost_ <base> <toolset> <threading> <runtime> <version:boost-version>
828 #
829 # Might return:
830 #
831 # boost_thread-vc80-mt-gd-1_33.dll, or
832 # boost_regex-vc80-gd-1_33.dll
833 #
834 # The returned name also has the target type specific prefix and suffix which
835 # puts it in a ready form to use as the value from a custom tag rule.
836 #
837 rule format-name ( format * : name : type ? : property-set )
838 {
839 local result = "" ;
840 for local f in $(format)
841 {
842 switch $(f:G)
843 {
844 case <base> :
845 result += $(name:B) ;
846
847 case <toolset> :
848 result += [ join-tag $(f:G=) : [ toolset-tag $(name) : $(type) :
849 $(property-set) ] ] ;
850
851 case <threading> :
852 result += [ join-tag $(f:G=) : [ threading-tag $(name) : $(type)
853 : $(property-set) ] ] ;
854
855 case <runtime> :
856 result += [ join-tag $(f:G=) : [ runtime-tag $(name) : $(type) :
857 $(property-set) ] ] ;
858
859 case <qt> :
860 result += [ join-tag $(f:G=) : [ qt-tag $(name) : $(type) :
861 $(property-set) ] ] ;
862
863 case <address-model> :
864 result += [ join-tag $(f:G=) : [ address-model-tag $(name) :
865 $(type) : $(property-set) ] ] ;
866
867 case <arch-and-model> :
868 result += [ join-tag $(f:G=) : [ arch-and-model-tag $(name) :
869 $(type) : $(property-set) ] ] ;
870
871 case <version:*> :
872 local key = [ MATCH <version:(.*)> : $(f:G) ] ;
873 local version = [ $(property-set).get <$(key)> ] ;
874 version ?= $(key) ;
875 version = [ MATCH "^([^.]+)[.]([^.]+)[.]?([^.]*)" : $(version) ] ;
876 result += [ join-tag $(f:G=) : $(version[1])_$(version[2]) ] ;
877
878 case <property:*> :
879 local key = [ MATCH <property:(.*)> : $(f:G) ] ;
880 local p0 = [ MATCH <($(key))> : [ $(property-set).raw ] ] ;
881 if $(p0)
882 {
883 local p = [ $(property-set).get <$(p0)> ] ;
884 if $(p)
885 {
886 result += [ join-tag $(f:G=) : $(p) ] ;
887 }
888 }
889
890 case * :
891 result += $(f:G=) ;
892 }
893 }
894 return [ virtual-target.add-prefix-and-suffix $(result:J=) : $(type) :
895 $(property-set) ] ;
896 }
897
898
899 local rule join-tag ( joiner ? : tag ? )
900 {
901 if ! $(joiner) { joiner = - ; }
902 return $(joiner)$(tag) ;
903 }
904
905
906 local rule toolset-tag ( name : type ? : property-set )
907 {
908 local tag = ;
909
910 local properties = [ $(property-set).raw ] ;
911 switch [ $(property-set).get <toolset> ]
912 {
913 case borland* : tag += bcb ;
914 case clang* :
915 {
916 switch [ $(property-set).get <toolset-clang:platform> ]
917 {
918 case darwin : tag += clang-darwin ;
919 case linux : tag += clang ;
920 }
921 }
922 case como* : tag += como ;
923 case cw : tag += cw ;
924 case darwin* : tag += xgcc ;
925 case edg* : tag += edg ;
926 case gcc* :
927 {
928 switch [ $(property-set).get <toolset-gcc:flavor> ]
929 {
930 case *mingw* : tag += mgw ;
931 case * : tag += gcc ;
932 }
933 }
934 case intel :
935 if [ $(property-set).get <toolset-intel:platform> ] = win
936 {
937 tag += iw ;
938 }
939 else
940 {
941 tag += il ;
942 }
943 case kcc* : tag += kcc ;
944 case kylix* : tag += bck ;
945 #case metrowerks* : tag += cw ;
946 #case mingw* : tag += mgw ;
947 case mipspro* : tag += mp ;
948 case msvc* : tag += vc ;
949 case qcc* : tag += qcc ;
950 case sun* : tag += sw ;
951 case tru64cxx* : tag += tru ;
952 case vacpp* : tag += xlc ;
953 }
954 local version = [ MATCH <toolset.*version>([0123456789]+)[.]([0123456789]*)
955 : $(properties) ] ;
956 # For historical reasons, vc6.0 and vc7.0 use different naming.
957 if $(tag) = vc
958 {
959 if $(version[1]) = 6
960 {
961 # Cancel minor version.
962 version = 6 ;
963 }
964 else if $(version[1]) = 7 && $(version[2]) = 0
965 {
966 version = 7 ;
967 }
968 }
969 # On intel, version is not added, because it does not matter and it is the
970 # version of vc used as backend that matters. Ideally, we should encode the
971 # backend version but that would break compatibility with V1.
972 if $(tag) = iw
973 {
974 version = ;
975 }
976
977 # On borland, version is not added for compatibility with V1.
978 if $(tag) = bcb
979 {
980 version = ;
981 }
982
983 tag += $(version) ;
984
985 return $(tag:J=) ;
986 }
987
988
989 local rule threading-tag ( name : type ? : property-set )
990 {
991 if <threading>multi in [ $(property-set).raw ]
992 {
993 return mt ;
994 }
995 }
996
997
998 local rule runtime-tag ( name : type ? : property-set )
999 {
1000 local tag = ;
1001
1002 local properties = [ $(property-set).raw ] ;
1003 if <runtime-link>static in $(properties) { tag += s ; }
1004
1005 # This is an ugly thing. In V1, there is code to automatically detect which
1006 # properties affect a target. So, if <runtime-debugging> does not affect gcc
1007 # toolset, the tag rules will not even see <runtime-debugging>. Similar
1008 # functionality in V2 is not implemented yet, so we just check for toolsets
1009 # known to care about runtime debugging.
1010 if ( <toolset>msvc in $(properties) ) ||
1011 ( <stdlib>stlport in $(properties) ) ||
1012 ( <toolset-intel:platform>win in $(properties) )
1013 {
1014 if <runtime-debugging>on in $(properties) { tag += g ; }
1015 }
1016
1017 if <python-debugging>on in $(properties) { tag += y ; }
1018 if <variant>debug in $(properties) { tag += d ; }
1019 if <stdlib>stlport in $(properties) { tag += p ; }
1020 if <stdlib-stlport:iostream>hostios in $(properties) { tag += n ; }
1021
1022 return $(tag:J=) ;
1023 }
1024
1025
1026 # Create a tag for the Qt library version
1027 # "<qt>4.6.0" will result in tag "qt460"
1028 local rule qt-tag ( name : type ? : property-set )
1029 {
1030 local v = [ MATCH ([0123456789]+)[.]?([0123456789]*)[.]?([0123456789]*) :
1031 [ $(property-set).get <qt> ] ] ;
1032 return qt$(v:J=) ;
1033 }
1034
1035
1036 # Create a tag for the address-model
1037 # <address-model>64 will simply generate "64"
1038 local rule address-model-tag ( name : type ? : property-set )
1039 {
1040 return [ $(property-set).get <address-model> ] ;
1041 }
1042
1043 # Create a tag for the architecture and model
1044 # <architecture>x86 <address-model>32 would generate "x32"
1045 # This relies on the fact that all architectures start with
1046 # unique letters.
1047 local rule arch-and-model-tag ( name : type ? : property-set )
1048 {
1049 local architecture = [ $(property-set).get <architecture> ] ;
1050 local address-model = [ $(property-set).get <address-model> ] ;
1051
1052 local arch = [ MATCH ^(.) : $(architecture) ] ;
1053
1054 return $(arch)$(address-model) ;
1055 }
1056
1057 rule __test__ ( )
1058 {
1059 import assert ;
1060
1061 local save-os = [ modules.peek os : .name ] ;
1062
1063 modules.poke os : .name : LINUX ;
1064 assert.result "PATH=\"foo:bar:baz\"\nexport PATH\n"
1065 : path-variable-setting-command PATH : foo bar baz ;
1066 assert.result "PATH=\"foo:bar:$PATH\"\nexport PATH\n"
1067 : prepend-path-variable-command PATH : foo bar ;
1068
1069 modules.poke os : .name : NT ;
1070 assert.result "set PATH=foo;bar;baz\n"
1071 : path-variable-setting-command PATH : foo bar baz ;
1072 assert.result "set PATH=foo;bar;%PATH%\n"
1073 : prepend-path-variable-command PATH : foo bar ;
1074
1075 modules.poke os : .name : $(save-os) ;
1076 }