mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-31 04:31:15 -06:00 
			
		
		
		
	 a688719e72
			
		
	
	
		a688719e72
		
	
	
	
	
		
			
			This reverts commitf5b28201fe, reversing changes made tod9e9fb2206. # Conflicts: # version.inc
		
			
				
	
	
		
			1095 lines
		
	
	
	
		
			31 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
			
		
		
	
	
			1095 lines
		
	
	
	
		
			31 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
| # 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) ;
 | |
| }
 |