| # 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 ; |
| |
| 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="")- ; |
| } |
| 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'. |
| # |
| local rule find-tool ( name : additional-paths * : path-last ? ) |
| { |
| 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 comand 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.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.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 |
| { |
| RM = del /f /q ; |
| CP = copy /b ; |
| IGNORE = "2>nul >nul & setlocal" ; |
| 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 |
| { |
| RM = rm -f ; |
| CP = cp ; |
| LN = ln ; |
| } |
| |
| |
| rule rm-command ( ) |
| { |
| return $(RM) ; |
| } |
| |
| |
| rule copy-command ( ) |
| { |
| return $(CP) ; |
| } |
| |
| |
| if "\n" = "n" |
| { |
| # Escape characters are not supported. Use ugly hacks that won't work, |
| # see below. |
| nl = " |
| " ; |
| q = "" ; |
| } |
| else |
| { |
| nl = "\n" ; |
| q = "\"" ; |
| } |
| |
| # 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 we don't have escape characters support in bjam, the 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 |
| { |
| 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 |
| { |
| 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 mkdir |
| { |
| if not exist "$(<)\\" mkdir "$(<)" |
| } |
| } |
| else |
| { |
| actions 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) |
| } |
| |
| |
| # 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 <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=) ; |
| } |
| } |
| result = [ virtual-target.add-prefix-and-suffix $(result:J=) : $(type) : |
| $(property-set) ] ; |
| return $(result) ; |
| } |
| |
| |
| 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 como* : tag += como ; |
| case cw : tag += cw ; |
| case darwin* : tag += xgcc ; |
| case edg* : tag += edg ; |
| case gcc* : |
| { |
| switch [ $(property-set).get <toolset-gcc:flavor> ] |
| { |
| case *mingw* : 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 ; |
| } |
| } |
| # 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 ) |
| { |
| local tag = ; |
| local properties = [ $(property-set).raw ] ; |
| if <threading>multi in $(properties) { tag = mt ; } |
| |
| return $(tag:J=) ; |
| } |
| |
| |
| 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 properties = [ $(property-set).get <qt> ] ; |
| local version = [ MATCH "([0123456789]+)[.]?([0123456789]*)[.]?([0123456789]*)" |
| : $(properties) ] ; |
| local tag = "qt"$(version:J=) ; |
| return $(tag) ; |
| } |
| |
| # Create a tag for the address-model |
| # <address-model>64 will simply generate "64" |
| local rule address-model-tag ( name : type ? : property-set ) |
| { |
| local tag = ; |
| local version = [ $(property-set).get <address-model> ] ; |
| return $(version) ; |
| } |
| |
| rule __test__ ( ) |
| { |
| import assert ; |
| |
| local nl = " |
| " ; |
| |
| local save-os = [ modules.peek os : .name ] ; |
| |
| modules.poke os : .name : LINUX ; |
| |
| assert.result "PATH=\"foo:bar:baz\"$(nl)export PATH$(nl)" |
| : path-variable-setting-command PATH : foo bar baz ; |
| |
| assert.result "PATH=\"foo:bar:$PATH\"$(nl)export PATH$(nl)" |
| : prepend-path-variable-command PATH : foo bar ; |
| |
| modules.poke os : .name : NT ; |
| |
| assert.result "set PATH=foo;bar;baz$(nl)" |
| : path-variable-setting-command PATH : foo bar baz ; |
| |
| assert.result "set PATH=foo;bar;%PATH%$(nl)" |
| : prepend-path-variable-command PATH : foo bar ; |
| |
| modules.poke os : .name : $(save-os) ; |
| } |