# (C) Copyright David Abrahams 2001-2003. Permission to copy, use, # modify, sell and distribute this software is granted provided this # copyright notice appears in all copies. This software is provided # "as is" without express or implied warranty, and with no claim as # to its suitability for any purpose. # This file is part of Boost.Build version 2. You can think of it as # forming the main() routine. It is invoked by the bootstrapping code # in bootstrap.jam. # # The version of bootstrap.jam invoking this lives in # tools/build/kernel until BBv1 is retired, so that BBv1 can have its # bootstrap.jam in this directory. import project ; import targets ; import sequence ; import modules ; import feature ; import property-set ; import build-request ; import errors : error ; import virtual-target ; import "class" : new ; import builtin ; import make ; import os ; import version ; # Returns the location of the build system. The primary use case # is building Boost, where it's sometimes needed to get location # of other components (like BoostBook files), and it's convenient # to use location relatively to Boost.Build path. rule location ( ) { local r = [ modules.binding build-system ] ; return $(r:P) ; } # Check if we can load 'test-config.jam'. If we can, load it and # ignore user configs. local test-config = [ GLOB [ os.environ BOOST_BUILD_PATH ] : test-config.jam ] ; if $(test-config) { if --debug-configuration in [ modules.peek : ARGV ] { ECHO "notice: loading test-config.jam from" [ NORMALIZE_PATH $(test-config[1]) ] ; ECHO "notice: user-config.jam and site-config.jam will be ignored" ; } module test-config { import toolset : using : using ; } import test-config ; } local ignore-config ; if $(test-config) || --ignore-config in [ modules.peek : ARGV ] { ignore-config = true ; } local user-path = [ os.home-directories ] [ os.environ BOOST_BUILD_PATH ] ; # Load site-config. module site-config { import project : initialize ; initialize site-config ; } if ! $(ignore-config) { local path ; if [ os.name ] in NT CYGWIN { path = [ modules.peek : SystemRoot ] $(user-path) ; } else { path = /etc $(user-path) ; } if --debug-configuration in [ modules.peek : ARGV ] { local where = [ GLOB $(path) : site-config.jam ] ; if $(where) { ECHO "notice: loading site-config.jam from" [ NORMALIZE_PATH $(where[1]) ] ; } } modules.load site-config : : $(path) ; project.load-used-projects site-config ; } # Load user-config. module user-config { import project : initialize ; initialize user-config ; } if ! $(ignore-config) { if --debug-configuration in [ modules.peek : ARGV ] { local where = [ GLOB $(user-path) : user-config.jam ] ; if $(where) { ECHO "notice: loading user-config.jam from" [ NORMALIZE_PATH $(where[1]) ] ; } } modules.load user-config : : $(user-path) ; project.load-used-projects user-config ; } if USER_MODULE in [ RULENAMES ] { USER_MODULE site-config user-config ; } if --version in [ modules.peek : ARGV ] { version.print ; EXIT ; } # We always load project in "." so that 'use-project' directives has # any chance of been seen. Otherwise, we won't be able to refer to # subprojects using target ids. if [ project.find "." : "." ] { current-project = [ project.target [ project.load "." ] ] ; } if ! [ feature.values ] { ECHO "warning: no toolsets are configured." ; ECHO "warning: you won't be able to build C++ programs." ; ECHO "warning: please consult the documentation at" ; ECHO "warning: http://boost.org/boost-build2/doc/html/bbv2/advanced/configuration.html" ; ECHO ; } build-request = [ build-request.from-command-line [ modules.peek : ARGV ] ] ; properties = [ $(build-request).get-at 2 ] ; if $(properties) { expanded = [ build-request.expand-no-defaults $(properties) ] ; local xexpanded ; for local e in $(expanded) { xexpanded += [ property-set.create [ feature.split $(e) ] ] ; } expanded = $(xexpanded) ; } else { expanded = [ property-set.empty ] ; } local target-ids = [ $(build-request).get-at 1 ] ; local targets local clean ; if "--clean-all" in [ modules.peek : ARGV ] { cleanall = true ; } if "--clean" in [ modules.peek : ARGV ] { clean = true ; } local bjam-targets ; # Given a target it, try to find and return corresponding target. # This is only invoked when there's no Jamfile in "." # This code somewhat duplicates code in project-target.find but we can't reuse # that code without project-targets instance. rule find-target ( target-id ) { local split = [ MATCH (.*)//(.*) : $(target-id) ] ; local pm ; if $(split) { pm = [ project.find $(split[1]) : "." ] ; } else { pm = [ project.find $(target-id) : "." ] ; } local result ; if $(pm) { result = [ project.target $(pm) ] ; } if $(split) { result = [ $(result).find $(split[2]) ] ; } return $(result) ; } if ! $(current-project) { if ! $(target-ids) { ECHO "error: no Jamfile in current directory found, and no target references specified." ; EXIT ; } } for local id in $(target-ids) { if $(id) = clean { clean = true ; } else { local t ; if $(current-project) { t = [ $(current-project).find $(id) : no-error ] ; } else { t = [ find-target $(id) ] ; } if ! $(t) { ECHO "notice: could not find main target " $(id) ; ECHO "notice: assuming it's a name of file to create " ; bjam-targets += $(id) ; } else { targets += $(t) ; } } } if ! $(targets) { targets += [ project.target [ project.module-name "." ] ] ; } virtual-targets = ; # Virtual targets obtained when building main targets references on # the command line. When running # # bjam --clean main_target # # we want to clean the files that belong only to that main target, # so we need to record which targets are produced. local results-of-main-targets ; for local p in $(expanded) { for local t in $(targets) { local g = [ $(t).generate $(p) ] ; if ! [ class.is-a $(t) : project-target ] { results-of-main-targets += $(g[2-]) ; } virtual-targets += $(g[2-]) ; } } # The cleaning is tricky. Say, if # user says: # # bjam --clean foo # # where 'foo' is a directory, then we want to clean targets # which are in 'foo' or in any children Jamfiles, but not in any # unrelated Jamfiles. So, we collect the list of project under which # cleaning is allowed. # local projects-to-clean ; local targets-to-clean ; if $(clean) || $(clean-all) { for local t in $(targets) { if [ class.is-a $(t) : project-target ] { projects-to-clean += [ $(t).project-module ] ; } } local subvariants ; for local t in $(results-of-main-targets) { # Don't include roots or sources. targets-to-clean += [ virtual-target.traverse $(t) ] ; } targets-to-clean = [ sequence.unique $(targets-to-clean) ] ; } # Returns 'true' if 'project' is a child of 'current-project', # possibly indirect, or is equal to 'project'. # Returns 'false' otherwise. rule is-child ( project ) { if ! $(.is-child.$(project)) { local r = false ; if $(project) in $(projects-to-clean) { r = true ; } else { local parent = [ project.attribute $(project) parent-module ] ; if $(parent) && $(parent) != user-config { r = [ is-child $(parent) ] ; } } .is-child.$(project) = $(r) ; } return $(.is-child.$(project)) ; } actual-targets = ; for t in $(virtual-targets) { actual-targets += [ $(t).actualize ] ; } NOTFILE all ; DEPENDS all : $(actual-targets) ; if $(bjam-targets) { UPDATE $(bjam-targets:G=e) ; } else if $(cleanall) { UPDATE clean-all ; } else if $(clean) { local to-clean ; for local t in [ virtual-target.all-targets ] { local p = [ $(t).project ] ; # Remove only derived targets. if [ $(t).action ] { if $(t) in $(targets-to-clean) || [ is-child [ $(p).project-module ] ] = true { to-clean += $(t) ; } } } local to-clean-actual ; for local t in $(to-clean) { to-clean-actual += [ $(t).actualize ] ; } common.Clean clean : $(to-clean-actual) ; UPDATE clean ; } else { UPDATE all ; }