1 # Copyright 2003, 2005 Dave Abrahams
2 # Copyright 2005, 2006 Rene Rivera
3 # Copyright 2005 Toon Knapen
4 # Copyright 2002, 2003, 2004, 2005, 2006 Vladimir Prus
5 # Distributed under the Boost Software License, Version 1.0.
6 # (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
8 # Provides actions common to all toolsets, such as creating directories and
21 import virtual-target ;
23 if [ MATCH (--debug-configuration) : [ modules.peek : ARGV ] ]
25 .debug-configuration = true ;
27 if [ MATCH (--show-configuration) : [ modules.peek : ARGV ] ]
29 .show-configuration = true ;
34 # The following class helps to manage toolset configurations. Each configuration
35 # has a unique ID and one or more parameters. A typical example of a unique ID
36 # is a condition generated by 'common.check-init-parameters' rule. Other kinds
37 # of IDs can be used. Parameters may include any details about the configuration
38 # like 'command', 'path', etc.
40 # A toolset configuration may be in one of the following states:
43 # Configuration has been registered (e.g. explicitly or by auto-detection
44 # code) but has not yet been marked as used, i.e. 'toolset.using' rule has
45 # not yet been called for it.
47 # Once called 'toolset.using' rule marks the configuration as 'used'.
49 # The main difference between the states above is that while a configuration is
50 # 'registered' its options can be freely changed. This is useful in particular
51 # for autodetection code - all detected configurations may be safely overwritten
62 # Registers a configuration.
64 # Returns 'true' if the configuration has been added and an empty value if
65 # it already exists. Reports an error if the configuration is 'used'.
69 if $(id) in $(self.used)
71 errors.error "common: the configuration '$(id)' is in use" ;
76 if ! $(id) in $(self.all)
80 # Indicate that a new configuration has been added.
87 # Mark a configuration as 'used'.
89 # Returns 'true' if the state of the configuration has been changed to
90 # 'used' and an empty value if it the state has not been changed. Reports an
91 # error if the configuration is not known.
95 if ! $(id) in $(self.all)
97 errors.error "common: the configuration '$(id)' is not known" ;
102 if ! $(id) in $(self.used)
106 # Indicate that the configuration has been marked as 'used'.
113 # Return all registered configurations.
120 # Return all used configurations.
124 return $(self.used) ;
127 # Returns the value of a configuration parameter.
129 rule get ( id : param )
131 return $(self.$(param).$(id)) ;
134 # Sets the value of a configuration parameter.
136 rule set ( id : param : value * )
138 self.$(param).$(id) = $(value) ;
143 # The rule for checking toolset parameters. Trailing parameters should all be
144 # parameter name/value pairs. The rule will check that each parameter either has
145 # a value in each invocation or has no value in each invocation. Also, the rule
146 # will check that the combination of all parameter values is unique in all
149 # Each parameter name corresponds to a subfeature. This rule will declare a
150 # subfeature the first time a non-empty parameter value is passed and will
151 # extend it with all the values.
153 # The return value from this rule is a condition to be used for flags settings.
155 rule check-init-parameters ( toolset requirement * : * )
157 local sig = $(toolset) ;
158 local condition = <toolset>$(toolset) ;
160 for local index in 2 3 4 5 6 7 8 9
162 local name = $($(index)[1]) ;
163 local value = $($(index)[2]) ;
165 if $(value)-is-not-empty
167 condition = $(condition)-$(value) ;
168 if $(.had-unspecified-value.$(toolset).$(name))
171 "$(toolset) initialization: parameter '$(name)'"
172 "inconsistent" : "no value was specified in earlier"
173 "initialization" : "an explicit value is specified now" ;
175 # The below logic is for intel compiler. It calls this rule with
176 # 'intel-linux' and 'intel-win' as toolset, so we need to get the
177 # base part of toolset name. We can not pass 'intel' as toolset
178 # because in that case it will be impossible to register versionless
179 # intel-linux and intel-win toolsets of a specific version.
180 local t = $(toolset) ;
181 local m = [ MATCH ([^-]*)- : $(toolset) ] ;
186 if ! $(.had-value.$(toolset).$(name))
188 if ! $(.declared-subfeature.$(t).$(name))
190 feature.subfeature toolset $(t) : $(name) : : propagated ;
191 .declared-subfeature.$(t).$(name) = true ;
193 .had-value.$(toolset).$(name) = true ;
195 feature.extend-subfeature toolset $(t) : $(name) : $(value) ;
196 subcondition += <toolset-$(t):$(name)>$(value) ;
200 if $(.had-value.$(toolset).$(name))
203 "$(toolset) initialization: parameter '$(name)'"
204 "inconsistent" : "an explicit value was specified in an"
205 "earlier initialization" : "no value is specified now" ;
207 .had-unspecified-value.$(toolset).$(name) = true ;
209 sig = $(sig)$(value:E="")- ;
211 if $(sig) in $(.all-signatures)
214 "duplicate initialization of $(toolset) with the following parameters: " ;
215 for local index in 2 3 4 5 6 7 8 9
217 local p = $($(index)) ;
220 message += "$(p[1]) = $(p[2]:E=<unspecified>)" ;
223 message += "previous initialization at $(.init-loc.$(sig))" ;
225 $(message[1]) : $(message[2]) : $(message[3]) : $(message[4]) :
226 $(message[5]) : $(message[6]) : $(message[7]) : $(message[8]) ;
228 .all-signatures += $(sig) ;
229 .init-loc.$(sig) = [ errors.nearest-user-location ] ;
231 # If we have a requirement, this version should only be applied under that
232 # condition. To accomplish this we add a toolset requirement that imposes
233 # the toolset subcondition, which encodes the version.
236 local r = <toolset>$(toolset) $(requirement) ;
238 toolset.add-requirements $(r):$(subcondition) ;
241 # We add the requirements, if any, to the condition to scope the toolset
242 # variables and options to this specific version.
243 condition += $(requirement) ;
245 if $(.show-configuration)
247 ECHO notice: $(condition) ;
249 return $(condition:J=/) ;
253 # A helper rule to get the command to invoke some tool. If
254 # 'user-provided-command' is not given, tries to find binary named 'tool' in
255 # PATH and in the passed 'additional-path'. Otherwise, verifies that the first
256 # element of 'user-provided-command' is an existing program.
258 # This rule returns the command to be used when invoking the tool. If we can not
259 # find the tool, a warning is issued. If 'path-last' is specified, PATH is
260 # checked after 'additional-paths' when searching for 'tool'.
262 rule get-invocation-command-nodefault ( toolset : tool :
263 user-provided-command * : additional-paths * : path-last ? )
266 if ! $(user-provided-command)
268 command = [ find-tool $(tool) : $(additional-paths) : $(path-last) ] ;
269 if ! $(command) && $(.debug-configuration)
271 ECHO warning: toolset $(toolset) initialization: can not find tool
273 ECHO warning: initialized from [ errors.nearest-user-location ] ;
278 command = [ check-tool $(user-provided-command) ] ;
279 if ! $(command) && $(.debug-configuration)
281 ECHO warning: toolset $(toolset) initialization: ;
282 ECHO warning: can not find user-provided command
283 '$(user-provided-command)' ;
284 ECHO warning: initialized from [ errors.nearest-user-location ] ;
292 # Same as get-invocation-command-nodefault, except that if no tool is found,
293 # returns either the user-provided-command, if present, or the 'tool' parameter.
295 rule get-invocation-command ( toolset : tool : user-provided-command * :
296 additional-paths * : path-last ? )
298 local result = [ get-invocation-command-nodefault $(toolset) : $(tool) :
299 $(user-provided-command) : $(additional-paths) : $(path-last) ] ;
303 if $(user-provided-command)
305 result = $(user-provided-command) ;
316 # Given an invocation command return the absolute path to the command. This
317 # works even if command has no path element and was found on the PATH.
319 rule get-absolute-tool-path ( command )
323 return $(command:D) ;
327 local m = [ GLOB [ modules.peek : PATH Path path ] : $(command)
334 # Attempts to find tool (binary) named 'name' in PATH and in 'additional-paths'.
335 # If found in PATH, returns 'name' and if found in additional paths, returns
336 # absolute name. If the tool is found in several directories, returns the first
337 # path found. Otherwise, returns an empty string. If 'path-last' is specified,
338 # PATH is searched after 'additional-paths'.
340 rule find-tool ( name : additional-paths * : path-last ? )
342 local path = [ path.programs-path ] ;
343 local match = [ path.glob $(path) : $(name) $(name).exe ] ;
344 local additional-match = [ path.glob $(additional-paths) : $(name)
350 result = $(additional-match) ;
351 if ! $(result) && $(match)
364 result = $(additional-match) ;
369 return [ path.native $(result[1]) ] ;
374 # Checks if 'command' can be found either in path or is a full name to an
377 local rule check-tool-aux ( command )
381 if [ path.exists $(command) ]
382 # Both NT and Cygwin will run .exe files by their unqualified names.
383 || ( [ os.on-windows ] && [ path.exists $(command).exe ] )
384 # Only NT will run .bat & .cmd files by their unqualified names.
385 || ( ( [ os.name ] = NT ) && ( [ path.exists $(command).bat ] ||
386 [ path.exists $(command).cmd ] ) )
393 if [ GLOB [ modules.peek : PATH Path path ] : $(command) ]
401 # Checks that a tool can be invoked by 'command'. If command is not an absolute
402 # path, checks if it can be found in 'path'. If comand is an absolute path,
403 # check that it exists. Returns 'command' if ok or empty string otherwise.
405 local rule check-tool ( xcommand + )
407 if [ check-tool-aux $(xcommand[1]) ] ||
408 [ check-tool-aux $(xcommand[-1]) ]
415 # Handle common options for toolset, specifically sets the following flag
417 # - CONFIG_COMMAND to $(command)
418 # - OPTIONS for compile to the value of <compileflags> in $(options)
419 # - OPTIONS for compile.c to the value of <cflags> in $(options)
420 # - OPTIONS for compile.c++ to the value of <cxxflags> in $(options)
421 # - OPTIONS for compile.fortran to the value of <fflags> in $(options)
422 # - OPTIONS for link to the value of <linkflags> in $(options)
424 rule handle-options ( toolset : condition * : command * : options * )
426 if $(.debug-configuration)
428 ECHO notice: will use '$(command)' for $(toolset), condition
429 $(condition:E=(empty)) ;
432 # The last parameter ('unchecked') says it is OK to set flags for another
434 toolset.flags $(toolset) CONFIG_COMMAND $(condition) : $(command)
437 toolset.flags $(toolset).compile OPTIONS $(condition) :
438 [ feature.get-values <compileflags> : $(options) ] : unchecked ;
440 toolset.flags $(toolset).compile.c OPTIONS $(condition) :
441 [ feature.get-values <cflags> : $(options) ] : unchecked ;
443 toolset.flags $(toolset).compile.c++ OPTIONS $(condition) :
444 [ feature.get-values <cxxflags> : $(options) ] : unchecked ;
446 toolset.flags $(toolset).compile.fortran OPTIONS $(condition) :
447 [ feature.get-values <fflags> : $(options) ] : unchecked ;
449 toolset.flags $(toolset).link OPTIONS $(condition) :
450 [ feature.get-values <linkflags> : $(options) ] : unchecked ;
454 # Returns the location of the "program files" directory on a Windows platform.
456 rule get-program-files-dir ( )
458 local ProgramFiles = [ modules.peek : ProgramFiles ] ;
461 ProgramFiles = "$(ProgramFiles:J= )" ;
465 ProgramFiles = "c:\\Program Files" ;
467 return $(ProgramFiles) ;
475 IGNORE = "2>nul >nul & setlocal" ;
477 # Ugly hack to convince copy to set the timestamp of the destination to the
478 # current time by concatenating the source with a nonexistent file. Note
479 # that this requires /b (binary) as the default when concatenating files is
481 WINDOWS-CP-HACK = "+ this-file-does-not-exist-A698EE7806899E69" ;
497 rule copy-command ( )
505 # Escape characters not supported so use ugly hacks. Will not work on Cygwin
517 # Returns the command needed to set an environment variable on the current
518 # platform. The variable setting persists through all following commands and is
519 # visible in the environment seen by subsequently executed commands. In other
520 # words, on Unix systems, the variable is exported, which is consistent with the
521 # only possible behavior on Windows systems.
523 rule variable-setting-command ( variable : value )
527 return "set $(variable)=$(value)$(nl)" ;
531 # If we do not have escape character support in bjam, the cod below
532 # blows up on CYGWIN, since the $(nl) variable holds a Windows new-line
533 # \r\n sequence that messes up the executed export command which then
534 # reports that the passed variable name is incorrect.
535 # But we have a check for cygwin in kernel/bootstrap.jam already.
536 return "$(variable)=$(q)$(value)$(q)$(nl)export $(variable)$(nl)" ;
541 # Returns a command to sets a named shell path variable to the given NATIVE
542 # paths on the current platform.
544 rule path-variable-setting-command ( variable : paths * )
546 local sep = [ os.path-separator ] ;
547 return [ variable-setting-command $(variable) : $(paths:J=$(sep)) ] ;
551 # Returns a command that prepends the given paths to the named path variable on
552 # the current platform.
554 rule prepend-path-variable-command ( variable : paths * )
556 return [ path-variable-setting-command $(variable)
557 : $(paths) [ os.expand-variable $(variable) ] ] ;
561 # Return a command which can create a file. If 'r' is result of invocation, then
562 # 'r foobar' will create foobar with unspecified content. What happens if file
563 # already exists is unspecified.
565 rule file-creation-command ( )
569 # A few alternative implementations on Windows:
572 # That would construct an empty file instead of a file containing
573 # a space and an end-of-line marker but it would also not change
574 # the target's timestamp in case the file already exists.
577 # That would construct an empty file instead of a file containing
578 # a space and an end-of-line marker but it would also destroy an
579 # already existing file by overwriting it with an empty one.
581 # I guess the best solution would be to allow Boost Jam to define
582 # built-in functions such as 'create a file', 'touch a file' or 'copy a
583 # file' which could be used from inside action code. That would allow
584 # completely portable operations without this kind of kludge.
585 # (22.02.2009.) (Jurko)
595 # Returns a command that may be used for 'touching' files. It is not a real
596 # 'touch' command on NT because it adds an empty line at the end of file but it
597 # works with source files.
599 rule file-touch-command ( )
614 # If dir exists, do not update it. Do this even for $(DOT).
617 if $(<) != $(DOT) && ! $($(<)-mkdir)
619 # Cheesy gate to prevent multiple invocations on same dir.
622 # Schedule the mkdir build action.
625 # Prepare a Jam 'dirs' target that can be used to make the build only
626 # construct all the target directories.
627 DEPENDS dirs : $(<) ;
629 # Recursively create parent directories. $(<:P) = $(<)'s parent & we
630 # recurse until root.
646 DEPENDS $(<) : $(s) ;
663 # The following quick-fix actions should be replaced using the original MkDir1
664 # action once Boost Jam gets updated to correctly detect different paths leading
665 # up to the same filesystem target and triggers their build action only once.
666 # (todo) (04.07.2008.) (Jurko)
672 if not exist "$(<)\\" mkdir "$(<)"
683 actions piecemeal together existing Clean
696 $(CP) "$(>)" $(WINDOWS-CP-HACK) "$(<)"
705 actions quietly updated piecemeal together RmTemps
707 $(RM) "$(>)" $(IGNORE)
713 $(RM) "$(<)" 2$(NULL_OUT) $(NULL_OUT)
714 $(LN) "$(>)" "$(<)" $(NULL_OUT)
718 # Given a target, as given to a custom tag rule, returns a string formatted
719 # according to the passed format. Format is a list of properties that is
720 # represented in the result. For each element of format the corresponding target
721 # information is obtained and added to the result string. For all, but the
722 # literal, the format value is taken as the as string to prepend to the output
723 # to join the item to the rest of the result. If not given "-" is used as a
726 # The format options can be:
729 # :: The basename of the target name.
731 # :: The abbreviated toolset tag being used to build the target.
732 # <threading>[joiner]
733 # :: Indication of a multi-threaded build.
735 # :: Collective tag of the build runtime.
736 # <version:/version-feature | X.Y[.Z]/>[joiner]
737 # :: Short version tag taken from the given "version-feature" in the
738 # build properties. Or if not present, the literal value as the
740 # <property:/property-name/>[joiner]
741 # :: Direct lookup of the given property-name value in the build
742 # properties. /property-name/ is a regular expression. E.g.
743 # <property:toolset-.*:flavor> will match every toolset.
745 # :: The literal value of the format argument.
747 # For example this format:
749 # boost_ <base> <toolset> <threading> <runtime> <version:boost-version>
753 # boost_thread-vc80-mt-gd-1_33.dll, or
754 # boost_regex-vc80-gd-1_33.dll
756 # The returned name also has the target type specific prefix and suffix which
757 # puts it in a ready form to use as the value from a custom tag rule.
759 rule format-name ( format * : name : type ? : property-set )
762 for local f in $(format)
767 result += $(name:B) ;
770 result += [ join-tag $(f:G=) : [ toolset-tag $(name) : $(type) :
771 $(property-set) ] ] ;
774 result += [ join-tag $(f:G=) : [ threading-tag $(name) : $(type)
775 : $(property-set) ] ] ;
778 result += [ join-tag $(f:G=) : [ runtime-tag $(name) : $(type) :
779 $(property-set) ] ] ;
782 result += [ join-tag $(f:G=) : [ qt-tag $(name) : $(type) :
783 $(property-set) ] ] ;
785 case <address-model> :
786 result += [ join-tag $(f:G=) : [ address-model-tag $(name) :
787 $(type) : $(property-set) ] ] ;
790 local key = [ MATCH <version:(.*)> : $(f:G) ] ;
791 local version = [ $(property-set).get <$(key)> ] ;
793 version = [ MATCH "^([^.]+)[.]([^.]+)[.]?([^.]*)" : $(version) ] ;
794 result += [ join-tag $(f:G=) : $(version[1])_$(version[2]) ] ;
797 local key = [ MATCH <property:(.*)> : $(f:G) ] ;
798 local p0 = [ MATCH <($(key))> : [ $(property-set).raw ] ] ;
801 local p = [ $(property-set).get <$(p0)> ] ;
804 result += [ join-tag $(f:G=) : $(p) ] ;
812 return [ virtual-target.add-prefix-and-suffix $(result:J=) : $(type) :
817 local rule join-tag ( joiner ? : tag ? )
819 if ! $(joiner) { joiner = - ; }
820 return $(joiner)$(tag) ;
824 local rule toolset-tag ( name : type ? : property-set )
828 local properties = [ $(property-set).raw ] ;
829 switch [ $(property-set).get <toolset> ]
831 case borland* : tag += bcb ;
834 switch [ $(property-set).get <toolset-clang:platform> ]
836 case darwin : tag += clang-darwin ;
837 case linux : tag += clang ;
838 case win : tag += clang-win ;
841 case como* : tag += como ;
842 case cw : tag += cw ;
843 case darwin* : tag += xgcc ;
844 case edg* : tag += edg ;
847 switch [ $(property-set).get <toolset-gcc:flavor> ]
849 case *mingw* : tag += mgw ;
850 case * : tag += gcc ;
854 if [ $(property-set).get <toolset-intel:platform> ] = win
862 case kcc* : tag += kcc ;
863 case kylix* : tag += bck ;
864 #case metrowerks* : tag += cw ;
865 #case mingw* : tag += mgw ;
866 case mipspro* : tag += mp ;
867 case msvc* : tag += vc ;
868 case qcc* : tag += qcc ;
869 case sun* : tag += sw ;
870 case tru64cxx* : tag += tru ;
871 case vacpp* : tag += xlc ;
873 local version = [ MATCH <toolset.*version>([0123456789]+)[.]([0123456789]*)
875 # For historical reasons, vc6.0 and vc7.0 use different naming.
880 # Cancel minor version.
883 else if $(version[1]) = 7 && $(version[2]) = 0
888 # On intel, version is not added, because it does not matter and it is the
889 # version of vc used as backend that matters. Ideally, we should encode the
890 # backend version but that would break compatibility with V1.
895 if $(tag) = clang-win
897 local my_tmp = [ $(property-set).get <toolset-clang:compatibility> ] ;
898 version = $(version[1])_$(version[2])_$(my_tmp) ;
901 # On borland, version is not added for compatibility with V1.
913 local rule threading-tag ( name : type ? : property-set )
915 if <threading>multi in [ $(property-set).raw ]
922 local rule runtime-tag ( name : type ? : property-set )
926 local properties = [ $(property-set).raw ] ;
927 if <runtime-link>static in $(properties) { tag += s ; }
929 # This is an ugly thing. In V1, there is code to automatically detect which
930 # properties affect a target. So, if <runtime-debugging> does not affect gcc
931 # toolset, the tag rules will not even see <runtime-debugging>. Similar
932 # functionality in V2 is not implemented yet, so we just check for toolsets
933 # known to care about runtime debugging.
934 if ( <toolset>msvc in $(properties) ) ||
935 ( <stdlib>stlport in $(properties) ) ||
936 ( <toolset-intel:platform>win in $(properties) )
938 if <runtime-debugging>on in $(properties) { tag += g ; }
941 if <python-debugging>on in $(properties) { tag += y ; }
942 if <variant>debug in $(properties) { tag += d ; }
943 if <stdlib>stlport in $(properties) { tag += p ; }
944 if <stdlib-stlport:iostream>hostios in $(properties) { tag += n ; }
950 # Create a tag for the Qt library version
951 # "<qt>4.6.0" will result in tag "qt460"
952 local rule qt-tag ( name : type ? : property-set )
954 local v = [ MATCH ([0123456789]+)[.]?([0123456789]*)[.]?([0123456789]*) :
955 [ $(property-set).get <qt> ] ] ;
960 # Create a tag for the address-model
961 # <address-model>64 will simply generate "64"
962 local rule address-model-tag ( name : type ? : property-set )
964 return [ $(property-set).get <address-model> ] ;
972 local save-os = [ modules.peek os : .name ] ;
974 modules.poke os : .name : LINUX ;
975 assert.result "PATH=\"foo:bar:baz\"\nexport PATH\n"
976 : path-variable-setting-command PATH : foo bar baz ;
977 assert.result "PATH=\"foo:bar:$PATH\"\nexport PATH\n"
978 : prepend-path-variable-command PATH : foo bar ;
980 modules.poke os : .name : NT ;
981 assert.result "set PATH=foo;bar;baz\n"
982 : path-variable-setting-command PATH : foo bar baz ;
983 assert.result "set PATH=foo;bar;%PATH%\n"
984 : prepend-path-variable-command PATH : foo bar ;
986 modules.poke os : .name : $(save-os) ;