# Copyright (c) 2010 Vladimir Prus. # # Use, modification and distribution is subject to the Boost Software # License Version 1.0. (See accompanying file LICENSE_1_0.txt or # http://www.boost.org/LICENSE_1_0.txt) # This module defines function to help with two main tasks: # # - Discovering build-time configuration for the purposes of adjusting the build # process. # - Reporting what is built, and how it is configured. import "class" : new ; import common ; import path ; import property ; import property-set ; import targets ; import config-cache ; rule log-summary ( ) { } .width = 30 ; rule set-width ( width ) { .width = $(width) ; } # Declare that the components specified by the parameter exist. # rule register-components ( components * ) { .components += $(components) ; } # Declare that the components specified by the parameters will be built. # rule components-building ( components * ) { .built-components += $(components) ; } # Report something about component configuration that the user should better # know. # rule log-component-configuration ( component : message ) { # FIXME: Implement per-property-set logs. .component-logs.$(component) += $(message) ; } rule log-check-result ( result ) { if ! $(.announced-checks) { ECHO "Performing configuration checks\n" ; .announced-checks = 1 ; } ECHO $(result) ; # FIXME: Unfinished code. Nothing seems to set .check-results at the moment. #.check-results += $(result) ; } rule log-library-search-result ( library : result ) { local x = [ PAD " - $(library)" : $(.width) ] ; log-check-result "$(x) : $(result)" ; } rule print-component-configuration ( ) { # FIXME: See what was intended with this initial assignment. # local c = [ sequence.unique $(.components) ] ; ECHO "\nComponent configuration:\n" ; local c ; for c in $(.components) { local s ; if $(c) in $(.built-components) { s = "building" ; } else { s = "not building" ; } ECHO [ PAD " - $(c)" : $(.width) ] ": $(s)" ; for local m in $(.component-logs.$(c)) { ECHO " -" $(m) ; } } ECHO ; } rule print-configure-checks-summary ( ) { # FIXME: The problem with this approach is that the user sees the checks # summary when all checks are done, and has no progress reporting while the # checks are being executed. if $(.check-results) { ECHO "Configuration checks summary\n" ; for local r in $(.check-results) { ECHO $(r) ; } ECHO ; } } # Attempts to build a set of virtual targets rule try-build ( targets * : ps : what : retry ? ) { local cache-name = $(what) [ $(ps).raw ] ; cache-name = $(cache-name:J=-) ; local value = [ config-cache.get $(cache-name) ] ; local result ; local jam-targets ; for local t in $(targets) { jam-targets += [ $(t).actualize ] ; } if $(value) { local x = [ PAD " - $(what)" : $(.width) ] ; if $(value) = true { .$(what)-supported.$(ps) = yes ; result = true ; log-check-result "$(x) : yes (cached)" ; } else { log-check-result "$(x) : no (cached)" ; } } else if ! UPDATE_NOW in [ RULENAMES ] { # Cannot determine. Assume existance. } else { local x = [ PAD " - $(what)" : $(.width) ] ; if [ UPDATE_NOW $(jam-targets) : $(.log-fd) : ignore-minus-n : ignore-minus-q ] { .$(what)-supported.$(ps) = yes ; result = true ; log-check-result "$(x) : yes" ; } else { log-check-result "$(x) : no" ; } } if ! $(value) { if $(result) { config-cache.set $(cache-name) : true ; } else { config-cache.set $(cache-name) : false ; } } return $(result) ; } # Attempt to build a metatarget named by 'metatarget-reference' # in context of 'project' with properties 'ps'. # Returns non-empty value if build is OK. rule builds-raw ( metatarget-reference : project : ps : what : retry ? ) { local result ; if ! $(retry) && ! $(.$(what)-tested.$(ps)) { .$(what)-tested.$(ps) = true ; local targets = [ targets.generate-from-reference $(metatarget-reference) : $(project) : $(ps) ] ; result = [ try-build $(targets[2-]) : $(ps) : $(what) : $(retry) ] ; .$(what)-supported.$(ps) = $(result) ; return $(result) ; } else { return $(.$(what)-supported.$(ps)) ; } } rule builds ( metatarget-reference : properties * : what ? : retry ? ) { # FIXME: This should not be hardcoded. Other checks might want to consider a # different set of features as relevant. local toolset = [ property.select : $(properties) ] ; local toolset-version-property = "" ; local relevant = [ property.select $(toolset-version-property) : $(properties) ] ; local ps = [ property-set.create $(relevant) ] ; local t = [ targets.current ] ; local p = [ $(t).project ] ; if ! $(what) { local resolved = [ targets.resolve-reference $(metatarget-reference) : $(p) ] ; local name = [ $(resolved[1]).name ] ; what = "$(name) builds" ; } return [ builds-raw $(metatarget-reference) : $(p) : $(ps) : $(what) : $(retry) ] ; } # Called by Boost.Build startup code to specify the file to receive the # configuration check results. Should never be called by user code. # rule set-log-file ( log-file ) { path.makedirs [ path.parent $(log-file) ] ; .log-fd = [ FILE_OPEN $(log-file) : "w" ] ; } # Frontend rules class check-target-builds-worker { import configure ; import property-set ; import targets ; import property ; rule __init__ ( target message ? : true-properties * : false-properties * ) { self.target = $(target) ; self.message = $(message) ; self.true-properties = $(true-properties) ; self.false-properties = $(false-properties) ; } rule check ( properties * ) { local choosen ; if [ configure.builds $(self.target) : $(properties) : $(self.message) ] { choosen = $(self.true-properties) ; } else { choosen = $(self.false-properties) ; } return [ property.evaluate-conditionals-in-context $(choosen) : $(properties) ] ; } } rule check-target-builds ( target message ? : true-properties * : false-properties * ) { local instance = [ new check-target-builds-worker $(target) $(message) : $(true-properties) : $(false-properties) ] ; return @$(instance).check ; } IMPORT $(__name__) : check-target-builds : : check-target-builds ;