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