123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095 |
- # Copyright 2003, 2005 Dave Abrahams
- # Copyright 2005, 2006 Rene Rivera
- # Copyright 2005 Toon Knapen
- # Copyright 2002, 2003, 2004, 2005, 2006 Vladimir Prus
- # Distributed under the Boost Software License, Version 1.0.
- # (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
- # Provides actions common to all toolsets, such as creating directories and
- # removing files.
- import os ;
- import modules ;
- import utility ;
- import print ;
- import type ;
- import feature ;
- import errors ;
- import path ;
- import sequence ;
- import toolset ;
- import virtual-target ;
- import numbers ;
- if [ MATCH (--debug-configuration) : [ modules.peek : ARGV ] ]
- {
- .debug-configuration = true ;
- }
- if [ MATCH (--show-configuration) : [ modules.peek : ARGV ] ]
- {
- .show-configuration = true ;
- }
- # Configurations
- #
- # The following class helps to manage toolset configurations. Each configuration
- # has a unique ID and one or more parameters. A typical example of a unique ID
- # is a condition generated by 'common.check-init-parameters' rule. Other kinds
- # of IDs can be used. Parameters may include any details about the configuration
- # like 'command', 'path', etc.
- #
- # A toolset configuration may be in one of the following states:
- #
- # - registered
- # Configuration has been registered (e.g. explicitly or by auto-detection
- # code) but has not yet been marked as used, i.e. 'toolset.using' rule has
- # not yet been called for it.
- # - used
- # Once called 'toolset.using' rule marks the configuration as 'used'.
- #
- # The main difference between the states above is that while a configuration is
- # 'registered' its options can be freely changed. This is useful in particular
- # for autodetection code - all detected configurations may be safely overwritten
- # by user code.
- class configurations
- {
- import errors ;
- rule __init__ ( )
- {
- }
- # Registers a configuration.
- #
- # Returns 'true' if the configuration has been added and an empty value if
- # it already exists. Reports an error if the configuration is 'used'.
- #
- rule register ( id )
- {
- if $(id) in $(self.used)
- {
- errors.error "common: the configuration '$(id)' is in use" ;
- }
- local retval ;
- if ! $(id) in $(self.all)
- {
- self.all += $(id) ;
- # Indicate that a new configuration has been added.
- retval = true ;
- }
- return $(retval) ;
- }
- # Mark a configuration as 'used'.
- #
- # Returns 'true' if the state of the configuration has been changed to
- # 'used' and an empty value if it the state has not been changed. Reports an
- # error if the configuration is not known.
- #
- rule use ( id )
- {
- if ! $(id) in $(self.all)
- {
- errors.error "common: the configuration '$(id)' is not known" ;
- }
- local retval ;
- if ! $(id) in $(self.used)
- {
- self.used += $(id) ;
- # Indicate that the configuration has been marked as 'used'.
- retval = true ;
- }
- return $(retval) ;
- }
- # Return all registered configurations.
- #
- rule all ( )
- {
- return $(self.all) ;
- }
- # Return all used configurations.
- #
- rule used ( )
- {
- return $(self.used) ;
- }
- # Returns the value of a configuration parameter.
- #
- rule get ( id : param )
- {
- return $(self.$(param).$(id)) ;
- }
- # Sets the value of a configuration parameter.
- #
- rule set ( id : param : value * )
- {
- self.$(param).$(id) = $(value) ;
- }
- }
- # The rule for checking toolset parameters. Trailing parameters should all be
- # parameter name/value pairs. The rule will check that each parameter either has
- # a value in each invocation or has no value in each invocation. Also, the rule
- # will check that the combination of all parameter values is unique in all
- # invocations.
- #
- # Each parameter name corresponds to a subfeature. This rule will declare a
- # subfeature the first time a non-empty parameter value is passed and will
- # extend it with all the values.
- #
- # The return value from this rule is a condition to be used for flags settings.
- #
- rule check-init-parameters ( toolset requirement * : * )
- {
- local sig = $(toolset) ;
- local condition = <toolset>$(toolset) ;
- local subcondition ;
- for local index in 2 3 4 5 6 7 8 9
- {
- local name = $($(index)[1]) ;
- local value = $($(index)[2]) ;
- if $(value)-is-not-empty
- {
- condition = $(condition)-$(value) ;
- if $(.had-unspecified-value.$(toolset).$(name))
- {
- errors.user-error
- "$(toolset) initialization: parameter '$(name)'"
- "inconsistent" : "no value was specified in earlier"
- "initialization" : "an explicit value is specified now" ;
- }
- # The below logic is for intel compiler. It calls this rule with
- # 'intel-linux' and 'intel-win' as toolset, so we need to get the
- # base part of toolset name. We can not pass 'intel' as toolset
- # because in that case it will be impossible to register versionless
- # intel-linux and intel-win toolsets of a specific version.
- local t = $(toolset) ;
- local m = [ MATCH "([^-]*)-" : $(toolset) ] ;
- if $(m)
- {
- t = $(m[1]) ;
- }
- if ! $(.had-value.$(toolset).$(name))
- {
- if ! $(.declared-subfeature.$(t).$(name))
- {
- feature.subfeature toolset $(t) : $(name) : : propagated ;
- .declared-subfeature.$(t).$(name) = true ;
- }
- .had-value.$(toolset).$(name) = true ;
- }
- feature.extend-subfeature toolset $(t) : $(name) : $(value) ;
- subcondition += <toolset-$(t):$(name)>$(value) ;
- }
- else
- {
- if $(.had-value.$(toolset).$(name))
- {
- errors.user-error
- "$(toolset) initialization: parameter '$(name)'"
- "inconsistent" : "an explicit value was specified in an"
- "earlier initialization" : "no value is specified now" ;
- }
- .had-unspecified-value.$(toolset).$(name) = true ;
- }
- sig = $(sig)$(value:E="")- ;
- }
- # We also need to consider requirements on the toolset as we can
- # configure the same toolset multiple times with different options that
- # are selected with the requirements.
- if $(requirement)
- {
- sig = $(sig)$(requirement:J=,) ;
- }
- if $(sig) in $(.all-signatures)
- {
- local message =
- "duplicate initialization of $(toolset) with the following parameters: " ;
- for local index in 2 3 4 5 6 7 8 9
- {
- local p = $($(index)) ;
- if $(p)
- {
- message += "$(p[1]) = $(p[2]:E=<unspecified>)" ;
- }
- }
- message += "previous initialization at $(.init-loc.$(sig))" ;
- errors.user-error
- $(message[1]) : $(message[2]) : $(message[3]) : $(message[4]) :
- $(message[5]) : $(message[6]) : $(message[7]) : $(message[8]) ;
- }
- .all-signatures += $(sig) ;
- .init-loc.$(sig) = [ errors.nearest-user-location ] ;
- # If we have a requirement, this version should only be applied under that
- # condition. To accomplish this we add a toolset requirement that imposes
- # the toolset subcondition, which encodes the version.
- if $(requirement)
- {
- local r = <toolset>$(toolset) $(requirement) ;
- r = $(r:J=,) ;
- toolset.add-requirements "$(r):$(subcondition)" ;
- }
- # We add the requirements, if any, to the condition to scope the toolset
- # variables and options to this specific version.
- condition += $(requirement) ;
- if $(.show-configuration)
- {
- ECHO "notice:" $(condition) ;
- }
- return $(condition:J=/) ;
- }
- # A helper rule to get the command to invoke some tool. If
- # 'user-provided-command' is not given, tries to find binary named 'tool' in
- # PATH and in the passed 'additional-path'. Otherwise, verifies that the first
- # element of 'user-provided-command' is an existing program.
- #
- # This rule returns the command to be used when invoking the tool. If we can not
- # find the tool, a warning is issued. If 'path-last' is specified, PATH is
- # checked after 'additional-paths' when searching for 'tool'.
- #
- rule get-invocation-command-nodefault ( toolset : tool :
- user-provided-command * : additional-paths * : path-last ? )
- {
- local command ;
- if ! $(user-provided-command)
- {
- command = [ find-tool $(tool) : $(additional-paths) : $(path-last) ] ;
- if ! $(command) && $(.debug-configuration)
- {
- ECHO "warning:" toolset $(toolset) "initialization:" can not find tool
- $(tool) ;
- ECHO "warning:" initialized from [ errors.nearest-user-location ] ;
- }
- }
- else
- {
- command = [ check-tool $(user-provided-command) ] ;
- if ! $(command) && $(.debug-configuration)
- {
- ECHO "warning:" toolset $(toolset) "initialization:" ;
- ECHO "warning:" can not find user-provided command
- '$(user-provided-command)' ;
- ECHO "warning:" initialized from [ errors.nearest-user-location ] ;
- }
- }
- return $(command) ;
- }
- # Same as get-invocation-command-nodefault, except that if no tool is found,
- # returns either the user-provided-command, if present, or the 'tool' parameter.
- #
- rule get-invocation-command ( toolset : tool : user-provided-command * :
- additional-paths * : path-last ? )
- {
- local result = [ get-invocation-command-nodefault $(toolset) : $(tool) :
- $(user-provided-command) : $(additional-paths) : $(path-last) ] ;
- if ! $(result)
- {
- if $(user-provided-command)
- {
- result = $(user-provided-command) ;
- }
- else
- {
- result = $(tool) ;
- }
- }
- return $(result) ;
- }
- # Given an invocation command return the absolute path to the command. This
- # works even if command has no path element and was found on the PATH.
- #
- rule get-absolute-tool-path ( command )
- {
- if $(command:D)
- {
- return $(command:D) ;
- }
- else
- {
- local m = [ GLOB [ modules.peek : PATH Path path ] : $(command)
- $(command).exe ] ;
- return $(m[1]:D) ;
- }
- }
- # Attempts to find tool (binary) named 'name' in PATH and in 'additional-paths'.
- # If found in PATH, returns 'name' and if found in additional paths, returns
- # absolute name. If the tool is found in several directories, returns the first
- # path found. Otherwise, returns an empty string. If 'path-last' is specified,
- # PATH is searched after 'additional-paths'.
- #
- rule find-tool ( name : additional-paths * : path-last ? )
- {
- if $(name:D)
- {
- return [ check-tool-aux $(name) ] ;
- }
- local path = [ path.programs-path ] ;
- local match = [ path.glob $(path) : $(name) $(name).exe ] ;
- local additional-match = [ path.glob $(additional-paths) : $(name)
- $(name).exe ] ;
- local result ;
- if $(path-last)
- {
- result = $(additional-match) ;
- if ! $(result) && $(match)
- {
- result = $(name) ;
- }
- }
- else
- {
- if $(match)
- {
- result = $(name) ;
- }
- else
- {
- result = $(additional-match) ;
- }
- }
- if $(result)
- {
- return [ path.native $(result[1]) ] ;
- }
- }
- # Checks if 'command' can be found either in path or is a full name to an
- # existing file.
- #
- local rule check-tool-aux ( command )
- {
- if $(command:D)
- {
- if [ path.exists $(command) ]
- # Both NT and Cygwin will run .exe files by their unqualified names.
- || ( [ os.on-windows ] && [ path.exists $(command).exe ] )
- # Only NT will run .bat & .cmd files by their unqualified names.
- || ( ( [ os.name ] = NT ) && ( [ path.exists $(command).bat ] ||
- [ path.exists $(command).cmd ] ) )
- {
- return $(command) ;
- }
- }
- else
- {
- if [ GLOB [ modules.peek : PATH Path path ] : $(command) ]
- {
- return $(command) ;
- }
- }
- }
- # Checks that a tool can be invoked by 'command'. If command is not an absolute
- # path, checks if it can be found in 'path'. If command is an absolute path,
- # check that it exists. Returns 'command' if ok or empty string otherwise.
- #
- local rule check-tool ( xcommand + )
- {
- if [ check-tool-aux $(xcommand[1]) ] ||
- [ check-tool-aux $(xcommand[-1]) ]
- {
- return $(xcommand) ;
- }
- }
- # Handle common options for toolset, specifically sets the following flag
- # variables:
- # - CONFIG_COMMAND to $(command)
- # - OPTIONS for compile to the value of <compileflags> in $(options)
- # - OPTIONS for compile.c to the value of <cflags> in $(options)
- # - OPTIONS for compile.c++ to the value of <cxxflags> in $(options)
- # - OPTIONS for compile.asm to the value of <asmflags> in $(options)
- # - OPTIONS for compile.fortran to the value of <fflags> in $(options)
- # - OPTIONS for link to the value of <linkflags> in $(options)
- #
- rule handle-options ( toolset : condition * : command * : options * )
- {
- if $(.debug-configuration)
- {
- ECHO "notice:" will use '$(command)' for $(toolset), condition
- $(condition:E=(empty)) ;
- }
- # The last parameter ('unchecked') says it is OK to set flags for another
- # module.
- toolset.flags $(toolset) CONFIG_COMMAND $(condition) : $(command)
- : unchecked ;
- toolset.flags $(toolset).compile OPTIONS $(condition) :
- [ feature.get-values <compileflags> : $(options) ] : unchecked ;
- toolset.flags $(toolset).compile.c OPTIONS $(condition) :
- [ feature.get-values <cflags> : $(options) ] : unchecked ;
- toolset.flags $(toolset).compile.c++ OPTIONS $(condition) :
- [ feature.get-values <cxxflags> : $(options) ] : unchecked ;
- toolset.flags $(toolset).compile.asm OPTIONS $(condition) :
- [ feature.get-values <asmflags> : $(options) ] : unchecked ;
- toolset.flags $(toolset).compile.fortran OPTIONS $(condition) :
- [ feature.get-values <fflags> : $(options) ] : unchecked ;
- toolset.flags $(toolset).link OPTIONS $(condition) :
- [ feature.get-values <linkflags> : $(options) ] : unchecked ;
- }
- # Returns the location of the "program files" directory on a Windows platform.
- #
- rule get-program-files-dir ( )
- {
- local ProgramFiles = [ modules.peek : ProgramFiles ] ;
- if $(ProgramFiles)
- {
- ProgramFiles = "$(ProgramFiles:J= )" ;
- }
- else
- {
- ProgramFiles = "c:\\Program Files" ;
- }
- return $(ProgramFiles) ;
- }
- if [ os.name ] = NT
- {
- NULL_DEVICE = "NUL" ;
- IGNORE = "2>$(NULL_DEVICE) >$(NULL_DEVICE) & setlocal" ;
- RM = del /f /q ;
- CP = copy /b ;
- LN ?= $(CP) ;
- # Ugly hack to convince copy to set the timestamp of the destination to the
- # current time by concatenating the source with a nonexistent file. Note
- # that this requires /b (binary) as the default when concatenating files is
- # /a (ascii).
- WINDOWS-CP-HACK = "+ this-file-does-not-exist-A698EE7806899E69" ;
- }
- else if [ os.name ] = VMS
- {
- NULL_DEVICE = "NL:" ;
- PIPE = PIPE ;
- IGNORE = "2>$(NULL_DEVICE) >$(NULL_DEVICE)" ;
- RM = DELETE /NOCONF ;
- CP = COPY /OVERWRITE ;
- LN = $(CP) ;
- }
- else
- {
- NULL_DEVICE = "/dev/null" ;
- IGNORE = "2>$(NULL_DEVICE) >$(NULL_DEVICE)" ;
- RM = rm -f ;
- CP = cp ;
- LN = ln ;
- }
- NULL_OUT = ">$(NULL_DEVICE)" ;
- rule null-device ( )
- {
- return $(NULL_DEVICE) ;
- }
- rule rm-command ( )
- {
- return $(RM) ;
- }
- rule copy-command ( )
- {
- return $(CP) ;
- }
- if "\n" = "n"
- {
- # Escape characters not supported so use ugly hacks. Will not work on Cygwin
- # - see below.
- nl = "
- " ;
- q = "" ;
- }
- else
- {
- nl = "\n" ;
- q = "\"" ;
- }
- rule newline-char ( )
- {
- return $(nl) ;
- }
- # Returns the command needed to set an environment variable on the current
- # platform. The variable setting persists through all following commands and is
- # visible in the environment seen by subsequently executed commands. In other
- # words, on Unix systems, the variable is exported, which is consistent with the
- # only possible behavior on Windows systems.
- #
- rule variable-setting-command ( variable : value )
- {
- if [ os.name ] = NT
- {
- return "set $(variable)=$(value)$(nl)" ;
- }
- else if [ os.name ] = VMS
- {
- return "$(variable) == $(q)$(value)$(q)$(nl)" ;
- }
- else
- {
- # If we do not have escape character support in bjam, the cod below
- # blows up on CYGWIN, since the $(nl) variable holds a Windows new-line
- # \r\n sequence that messes up the executed export command which then
- # reports that the passed variable name is incorrect.
- # But we have a check for cygwin in kernel/bootstrap.jam already.
- return "$(variable)=$(q)$(value)$(q)$(nl)export $(variable)$(nl)" ;
- }
- }
- # Returns a command to sets a named shell path variable to the given NATIVE
- # paths on the current platform.
- #
- rule path-variable-setting-command ( variable : paths * )
- {
- local sep = [ os.path-separator ] ;
- return [ variable-setting-command $(variable) : $(paths:J=$(sep)) ] ;
- }
- # Returns a command that prepends the given paths to the named path variable on
- # the current platform.
- #
- rule prepend-path-variable-command ( variable : paths * )
- {
- return [ path-variable-setting-command $(variable)
- : $(paths) [ os.expand-variable $(variable) ] ] ;
- }
- # Return a command which can create a file. If 'r' is result of invocation, then
- # 'r foobar' will create foobar with unspecified content. What happens if file
- # already exists is unspecified.
- #
- rule file-creation-command ( )
- {
- if [ os.name ] = NT
- {
- # A few alternative implementations on Windows:
- #
- # 'type NUL >> '
- # That would construct an empty file instead of a file containing
- # a space and an end-of-line marker but it would also not change
- # the target's timestamp in case the file already exists.
- #
- # 'type NUL > '
- # That would construct an empty file instead of a file containing
- # a space and an end-of-line marker but it would also destroy an
- # already existing file by overwriting it with an empty one.
- #
- # I guess the best solution would be to allow Boost Jam to define
- # built-in functions such as 'create a file', 'touch a file' or 'copy a
- # file' which could be used from inside action code. That would allow
- # completely portable operations without this kind of kludge.
- # (22.02.2009.) (Jurko)
- return "echo. > " ;
- }
- else if [ os.name ] = VMS
- {
- return "APPEND /NEW NL: " ;
- }
- else
- {
- return "touch " ;
- }
- }
- # Returns a command that may be used for 'touching' files. It is not a real
- # 'touch' command on NT because it adds an empty line at the end of file but it
- # works with source files.
- #
- rule file-touch-command ( )
- {
- if [ os.name ] = NT
- {
- return "echo. >> " ;
- }
- else if [ os.name ] = VMS
- {
- return "APPEND /NEW NL: " ;
- }
- else
- {
- return "touch " ;
- }
- }
- rule MkDir
- {
- # If dir exists, do not update it. Do this even for $(DOT).
- NOUPDATE $(<) ;
- if $(<) != $(DOT) && ! $($(<)-mkdir)
- {
- # Cheesy gate to prevent multiple invocations on same dir.
- $(<)-mkdir = true ;
- # Schedule the mkdir build action.
- common.mkdir $(<) ;
- # Prepare a Jam 'dirs' target that can be used to make the build only
- # construct all the target directories.
- DEPENDS dirs : $(<) ;
- # Recursively create parent directories. $(<:P) = $(<)'s parent & we
- # recurse until root.
- local s = $(<:P) ;
- if [ os.name ] = NT
- {
- switch $(s)
- {
- case "*:" : s = ;
- case "*:\\" : s = ;
- }
- }
- if $(s)
- {
- if $(s) != $(<)
- {
- DEPENDS $(<) : $(s) ;
- MkDir $(s) ;
- }
- else
- {
- NOTFILE $(s) ;
- }
- }
- }
- }
- #actions MkDir1
- #{
- # mkdir "$(<)"
- #}
- # The following quick-fix actions should be replaced using the original MkDir1
- # action once Boost Jam gets updated to correctly detect different paths leading
- # up to the same filesystem target and triggers their build action only once.
- # (todo) (04.07.2008.) (Jurko)
- if [ os.name ] = NT
- {
- actions quietly mkdir
- {
- if not exist "$(<)\\" mkdir "$(<)"
- }
- }
- else
- {
- actions quietly mkdir
- {
- mkdir -p "$(<)"
- }
- }
- actions piecemeal together existing Clean
- {
- $(RM) "$(>)"
- }
- rule copy
- {
- }
- actions copy
- {
- $(CP) "$(>)" $(WINDOWS-CP-HACK) "$(<)"
- }
- rule RmTemps
- {
- }
- actions quietly updated piecemeal together RmTemps
- {
- $(RM) "$(>)" $(IGNORE)
- }
- actions hard-link
- {
- $(RM) "$(<)" 2$(NULL_OUT) $(NULL_OUT)
- $(LN) "$(>)" "$(<)" $(NULL_OUT)
- }
- if [ os.name ] = VMS
- {
- actions mkdir
- {
- IF F$PARSE("$(<:W)") .EQS. "" THEN CREATE /DIR $(<:W)
- }
- actions piecemeal together existing Clean
- {
- $(RM) $(>:WJ=;*,);*
- }
- actions copy
- {
- $(CP) $(>:WJ=,) $(<:W)
- }
- actions quietly updated piecemeal together RmTemps
- {
- $(PIPE) $(RM) $(>:WJ=;*,);* $(IGNORE)
- }
- actions hard-link
- {
- $(PIPE) $(RM) $(>[1]:W);* $(IGNORE)
- $(PIPE) $(LN) $(>[1]:W) $(<:W) $(NULL_OUT)
- }
- }
- # Given a target, as given to a custom tag rule, returns a string formatted
- # according to the passed format. Format is a list of properties that is
- # represented in the result. For each element of format the corresponding target
- # information is obtained and added to the result string. For all, but the
- # literal, the format value is taken as the as string to prepend to the output
- # to join the item to the rest of the result. If not given "-" is used as a
- # joiner.
- #
- # The format options can be:
- #
- # <base>[joiner]
- # :: The basename of the target name.
- # <toolset>[joiner]
- # :: The abbreviated toolset tag being used to build the target.
- # <threading>[joiner]
- # :: Indication of a multi-threaded build.
- # <runtime>[joiner]
- # :: Collective tag of the build runtime.
- # <version:/version-feature | X.Y[.Z]/>[joiner]
- # :: Short version tag taken from the given "version-feature" in the
- # build properties. Or if not present, the literal value as the
- # version number.
- # <property:/property-name/>[joiner]
- # :: Direct lookup of the given property-name value in the build
- # properties. /property-name/ is a regular expression. E.g.
- # <property:toolset-.*:flavor> will match every toolset.
- # /otherwise/
- # :: The literal value of the format argument.
- #
- # For example this format:
- #
- # boost_ <base> <toolset> <threading> <runtime> <version:boost-version>
- #
- # Might return:
- #
- # boost_thread-vc80-mt-gd-1_33.dll, or
- # boost_regex-vc80-gd-1_33.dll
- #
- # The returned name also has the target type specific prefix and suffix which
- # puts it in a ready form to use as the value from a custom tag rule.
- #
- rule format-name ( format * : name : type ? : property-set )
- {
- local result = "" ;
- for local f in $(format)
- {
- switch $(f:G)
- {
- case <base> :
- result += $(name:B) ;
- case <toolset> :
- result += [ join-tag $(f:G=) : [ toolset-tag $(name) : $(type) :
- $(property-set) ] ] ;
- case <threading> :
- result += [ join-tag $(f:G=) : [ threading-tag $(name) : $(type)
- : $(property-set) ] ] ;
- case <runtime> :
- result += [ join-tag $(f:G=) : [ runtime-tag $(name) : $(type) :
- $(property-set) ] ] ;
- case <qt> :
- result += [ join-tag $(f:G=) : [ qt-tag $(name) : $(type) :
- $(property-set) ] ] ;
- case <address-model> :
- result += [ join-tag $(f:G=) : [ address-model-tag $(name) :
- $(type) : $(property-set) ] ] ;
- case <arch-and-model> :
- result += [ join-tag $(f:G=) : [ arch-and-model-tag $(name) :
- $(type) : $(property-set) ] ] ;
- case <version:*> :
- local key = [ MATCH <version:(.*)> : $(f:G) ] ;
- local version = [ $(property-set).get <$(key)> ] ;
- version ?= $(key) ;
- version = [ MATCH "^([^.]+)[.]([^.]+)[.]?([^.]*)" : $(version) ] ;
- result += [ join-tag $(f:G=) : $(version[1])_$(version[2]) ] ;
- case <property:*> :
- local key = [ MATCH <property:(.*)> : $(f:G) ] ;
- local p0 = [ MATCH <($(key))> : [ $(property-set).raw ] ] ;
- if $(p0)
- {
- local p = [ $(property-set).get <$(p0)> ] ;
- if $(p)
- {
- result += [ join-tag $(f:G=) : $(p) ] ;
- }
- }
- case * :
- result += $(f:G=) ;
- }
- }
- return [ virtual-target.add-prefix-and-suffix $(result:J=) : $(type) :
- $(property-set) ] ;
- }
- local rule join-tag ( joiner ? : tag ? )
- {
- if ! $(joiner) { joiner = - ; }
- return $(joiner)$(tag) ;
- }
- local rule toolset-tag ( name : type ? : property-set )
- {
- local tag = ;
- local properties = [ $(property-set).raw ] ;
- switch [ $(property-set).get <toolset> ]
- {
- case borland* : tag += bcb ;
- case clang* :
- {
- switch [ $(property-set).get <toolset-clang:platform> ]
- {
- case darwin : tag += clang-darwin ;
- case linux : tag += clang ;
- case win : tag += clangw ;
- }
- }
- case como* : tag += como ;
- case cw : tag += cw ;
- case darwin* : tag += xgcc ;
- case edg* : tag += edg ;
- case gcc* :
- {
- switch [ $(property-set).get <target-os> ]
- {
- case *windows* : tag += mgw ;
- case * : tag += gcc ;
- }
- }
- case intel :
- if [ $(property-set).get <toolset-intel:platform> ] = win
- {
- tag += iw ;
- }
- else
- {
- tag += il ;
- }
- case kcc* : tag += kcc ;
- case kylix* : tag += bck ;
- #case metrowerks* : tag += cw ;
- #case mingw* : tag += mgw ;
- case mipspro* : tag += mp ;
- case msvc* : tag += vc ;
- case qcc* : tag += qcc ;
- case sun* : tag += sw ;
- case tru64cxx* : tag += tru ;
- case vacpp* : tag += xlc ;
- }
- local version = [ MATCH "<toolset.*version>([0123456789]+)[.]?([0123456789]*)"
- : $(properties) ] ;
- # For historical reasons, vc6.0 and vc7.0 use different naming.
- if $(tag) = vc
- {
- if $(version[1]) = 6
- {
- # Cancel minor version.
- version = 6 ;
- }
- else if $(version[1]) = 7 && $(version[2]) = 0
- {
- version = 7 ;
- }
- }
- # From GCC 5, versioning changes and minor becomes patch
- if ( $(tag) = gcc || $(tag) = mgw ) && [ numbers.less 4 $(version[1]) ]
- {
- version = $(version[1]) ;
- }
- # Ditto, from Clang 4
- if ( $(tag) = clang || $(tag) = clangw ) && [ numbers.less 3 $(version[1]) ]
- {
- version = $(version[1]) ;
- }
- # On intel, version is not added, because it does not matter and it is the
- # version of vc used as backend that matters. Ideally, we should encode the
- # backend version but that would break compatibility with V1.
- if $(tag) = iw
- {
- version = ;
- }
- # On borland, version is not added for compatibility with V1.
- if $(tag) = bcb
- {
- version = ;
- }
- tag += $(version) ;
- return $(tag:J=) ;
- }
- local rule threading-tag ( name : type ? : property-set )
- {
- if <threading>multi in [ $(property-set).raw ]
- {
- return mt ;
- }
- }
- local rule runtime-tag ( name : type ? : property-set )
- {
- local tag = ;
- local properties = [ $(property-set).raw ] ;
- if <runtime-link>static in $(properties) { tag += s ; }
- # This is an ugly thing. In V1, there is code to automatically detect which
- # properties affect a target. So, if <runtime-debugging> does not affect gcc
- # toolset, the tag rules will not even see <runtime-debugging>. Similar
- # functionality in V2 is not implemented yet, so we just check for toolsets
- # known to care about runtime debugging.
- if ( <toolset>msvc in $(properties) ) ||
- ( <stdlib>stlport in $(properties) ) ||
- ( <toolset-intel:platform>win in $(properties) )
- {
- if <runtime-debugging>on in $(properties) { tag += g ; }
- }
- if <python-debugging>on in $(properties) { tag += y ; }
- if <variant>debug in $(properties) { tag += d ; }
- if <stdlib>stlport in $(properties) { tag += p ; }
- if <stdlib-stlport:iostream>hostios in $(properties) { tag += n ; }
- return $(tag:J=) ;
- }
- # Create a tag for the Qt library version
- # "<qt>4.6.0" will result in tag "qt460"
- local rule qt-tag ( name : type ? : property-set )
- {
- local v = [ MATCH "([0123456789]+)[.]?([0123456789]*)[.]?([0123456789]*)" :
- [ $(property-set).get <qt> ] ] ;
- return qt$(v:J=) ;
- }
- # Create a tag for the address-model
- # <address-model>64 will simply generate "64"
- local rule address-model-tag ( name : type ? : property-set )
- {
- return [ $(property-set).get <address-model> ] ;
- }
- # Create a tag for the architecture and model
- # <architecture>x86 <address-model>32 would generate "x32"
- # This relies on the fact that all architectures start with
- # unique letters.
- local rule arch-and-model-tag ( name : type ? : property-set )
- {
- local architecture = [ $(property-set).get <architecture> ] ;
- local address-model = [ $(property-set).get <address-model> ] ;
- local arch = [ MATCH ^(.) : $(architecture) ] ;
- return $(arch)$(address-model) ;
- }
- rule __test__ ( )
- {
- import assert ;
- local save-os = [ modules.peek os : .name ] ;
- modules.poke os : .name : LINUX ;
- assert.result "PATH=\"foo:bar:baz\"\nexport PATH\n"
- : path-variable-setting-command PATH : foo bar baz ;
- assert.result "PATH=\"foo:bar:$PATH\"\nexport PATH\n"
- : prepend-path-variable-command PATH : foo bar ;
- modules.poke os : .name : NT ;
- assert.result "set PATH=foo;bar;baz\n"
- : path-variable-setting-command PATH : foo bar baz ;
- assert.result "set PATH=foo;bar;%PATH%\n"
- : prepend-path-variable-command PATH : foo bar ;
- modules.poke os : .name : $(save-os) ;
- }
|