2
0
mirror of https://github.com/boostorg/build.git synced 2026-02-15 13:02:11 +00:00

Enabled sorting of BBv2 modules into subdirectories

build-system.jam - moved from tools/build/new to tools/build

boost-build.jam - moved from tools/build/new to tools/build/kernel
bootstrap.jam
errors.jam
modules.jam

test/BoostBuild.py   - adjusted for the above modification
test/boost-build.jam

project-root.jam - renamed to "project-roots.jam" to avoid confusion
                   and conflict with the user's project-root.jam file

project.jam                           - adjusted for the above renaming
test/project-test1/project-test1.jam

type.jam - broke a circular module dependency


[SVN r18575]
This commit is contained in:
Dave Abrahams
2003-05-28 01:33:38 +00:00
parent 7035a065ab
commit d9d8785236
26 changed files with 1306 additions and 123 deletions

19
new/build-system.jam → build-system.jam Normal file → Executable file
View File

@@ -1,7 +1,16 @@
# (C) Copyright David Abrahams 2001. 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.
# (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 sequence ;
import modules ;
@@ -64,7 +73,7 @@ project.load "." ;
if [ MATCH (--dump-projects) : [ modules.peek : ARGV ] ]
{
project-root.print ;
project-roots.print ;
}
if ! [ feature.values toolset ]

6
kernel/boost-build.jam Executable file
View File

@@ -0,0 +1,6 @@
# Copyright David Abrahams 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.
boost-build . ;

95
kernel/bootstrap.jam Executable file
View File

@@ -0,0 +1,95 @@
# (C) Copyright David Abrahams 2001. 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.
# First of all, check the jam version
if $(JAM_VERSION:J="") < 030105
{
ECHO "error: Boost.Jam version 3.1.5 or later required" ;
EXIT ;
}
# Bootstrap the module system. Then bring the import rule into the global module.
#
SEARCH on <module@>modules.jam = $(.bootstrap-file:D) ;
module modules { include <module@>modules.jam ; }
IMPORT modules : import : : import ;
{
# Add module subdirectories to the BOOST_BUILD_PATH, which allows
# us to make an incremental refactoring step by moving modules to
# the appropriate subdirectories, thereby achieving some physical
# separation of different layers without changing all of our code
# to specify subdirectories in import statements or use an extra
# level of qualification on imported names.
local subdirs =
kernel # only the most-intrinsic modules: modules, errors
util # low-level substrate: string/number handling, etc.
core # essential elements of the build system architecture
tools # toolsets for handling specific build jobs and targets.
new # until we get everything sorted out, there is
# still some code here
. # build-system.jam lives here
;
local whereami = $(.bootstrap-file:D) ;
BOOST_BUILD_PATH += $(whereami:D)/$(subdirs) ;
}
# Reload the modules, to clean up things. The modules module can tolerate
# being included twice.
#
import modules ;
# Check command-line args as soon as possible. This is first action,
# so that we can interrupt the regular build process if the user is
# asking for help.
for local arg in [ MATCH ^--([^-=].*) : $(ARGV) ]
{
local split = [ MATCH ^([^-=]+([^=]*))(=?)(.*)$ : $(arg) ] ;
local full-name = $(split[1]) ;
local prefix = $(split[2]) ;
local value ;
if $(split[3])
{
value = $(split[4]) ;
}
# look in options subdirectories of BOOST_BUILD_PATH for modules
# matching the full option name and then its prefix.
local plugin-dir = options ;
local option-files = [
GLOB $(plugin-dir:D=$(BOOST_BUILD_PATH)) : $(full-name).jam $(prefix).jam
] ;
if $(option-files)
{
# load the file into a module named for the option
local f = $(option-files[1]) ;
local module-name = --$(f:D=:S=) ;
modules.load $(module-name) : $(f:D=) : $(f:D) ;
# if there's a process rule, call it with the full option name
# and its value (if any). If there was no "=" in the option,
# the value will be empty.
if process in [ RULENAMES $(module-name) ]
{
modules.call-in $(module-name) : process --$(full-name) : $(value) ;
}
}
}
# Allow users to override the build system file from the
# command-line (mostly for testing)
local build-system = [ MATCH --build-system=(.*) : $(ARGV) ] ;
build-system ?= build-system ;
# Use last element in case of multiple command-line options
import $(build-system[-2]) ;

0
new/errors.jam → kernel/errors.jam Normal file → Executable file
View File

85
v2/modules.jam → kernel/modules.jam Normal file → Executable file
View File

@@ -129,6 +129,12 @@ rule load (
local rules = [ RULENAMES $(__name__) ] ;
IMPORT $(__name__) : $(rules) : $(__name__) : $(__name__).$(rules) ;
}
if $(module-name) != modules && ! [ binding $(module-name) ]
{
import errors ;
errors.error "couldn't find module" $(module-name) in $(search) ;
}
# Pop the loading stack. Must happen before testing or we'll find a circular loading dependency
.loading = $(.loading[1--2]) ;
@@ -184,6 +190,58 @@ rule record-binding ( module-target : binding )
$(.loading[-1]).__binding__ = $(binding) ;
}
# Transform each path in the list, with all backslashes converted to
# forward slashes and all detectable redundancy removed. Something
# like this is probably needed in path.jam, but I'm not sure of that,
# I don't understand it, and I'm not ready to move all of path.jam
# into the kernel.
local rule normalize-raw-paths ( paths * )
{
local result ;
for p in $(paths:T)
{
local elements ; # the simplified path elements
local dotdots ; # a stack of .. elements we've seen
# consume the last path element in p until there's nothing
# left
while $(p)
{
local split = [ MATCH ^(.+)/(.*)$ : $(p) ] ;
if ! $(split)
{ # no further slashes; prepend the last element
elements = $(p) $(elements) ;
}
else if $(split[2]) = .
{ # ignore the identity directory
}
else if $(split[2]) = ..
{ # prepare to absorb the next named element
dotdots += .. ; # push parent onto stack
}
else if $(dotdots)
{ # absorb a named element
dotdots = $(dotdots[2-]) ; # pop parent off stack
}
else if $(split[2]) # if the element was empty, ignore it
{ # to drop a trailing slash
elements = $(split[2]) $(elements) ;
}
# drop the last element of p
p = $(split[1]) ;
}
# prepend any unused parent directories
elements = $(dotdots) $(elements) ;
# If everything cancelled out, it's the identity directory.
elements ?= . ;
result += $(elements:J=/) ;
}
return $(result) ;
}
# load the indicated module and import rule names into the current
# module. Any members of rules-opt will be available without
# qualification in the caller's module. Any members of rename-opt will
@@ -207,16 +265,32 @@ rule import ( module-names + : rules-opt * : rename-opt * )
errors.error when loading multiple modules, no specific rules or renaming is allowed ;
}
# if the importing module isn't already in the BOOST_BUILD_PATH,
# prepend it to the path. We don't want to invert the search
# order of modules that are already there.
local caller = [ CALLER_MODULE ] ;
local cwd = [ PWD ] ;
local caller-location ;
if $(caller)
{
caller-location = [ binding $(caller) ] ;
caller-location = $(caller-location:D) ;
caller-location = [ normalize-raw-paths $(caller-location:R=$(cwd)) ] ;
}
local search = [ peek : BOOST_BUILD_PATH ] ;
search = [ normalize-raw-paths $(search:R=$(cwd)) ] ;
if $(caller-location) && ! $(caller-location) in $(search)
{
search = $(caller-location) $(search) ;
}
# Import each specified module
for local m in $(module-names)
{
load $(m) : : $(caller-location:D) [ peek : BOOST_BUILD_PATH ] ;
load $(m) : : $(search) ;
local all-rules = [ RULENAMES $(m) ] ;
# import all the rules with qualification
@@ -264,6 +338,7 @@ IMPORT modules : $(globalize) : : modules.$(globalize) ;
local rule __test__ ( )
{
import assert ;
import modules : normalize-raw-paths ;
module modules.__test__
{
@@ -273,6 +348,14 @@ local rule __test__ ( )
assert.result bar : peek modules.__test__ : foo ;
poke modules.__test__ : foo : bar baz ;
assert.result bar baz : peek modules.__test__ : foo ;
assert.result c:/foo/bar : normalize-raw-paths c:/x/../foo/./xx/yy/../../bar ;
assert.result . : normalize-raw-paths . ;
assert.result .. : normalize-raw-paths .. ;
assert.result ../.. : normalize-raw-paths ../.. ;
assert.result / / : normalize-raw-paths / \\ ;
assert.result a : normalize-raw-paths a ;
assert.result a : normalize-raw-paths a/ ;
assert.result /a : normalize-raw-paths /a/ ;
}

View File

@@ -1,42 +0,0 @@
# (C) Copyright David Abrahams 2001. 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.
# First of all, check the jam version
if $(JAM_VERSION:J="") < 030105
{
ECHO "error: Boost.Jam version 3.1.5 or later required" ;
EXIT ;
}
# Bootstrap the module system. And bring the import rule into the global module.
#
SEARCH on <module@>modules.jam = $(BOOST_BUILD_PATH) ;
module modules { include <module@>modules.jam ; }
IMPORT modules : import : : import ;
# Reload the modules, to clean up things. The modules module can tolerate
# being included twice.
#
import modules ;
# Check to see if the user is asking for help as soon as possible.
# This is first action, so that we can interrupt the regular build
# process if they are asking for help.
#
import doc ;
if ! [ doc.help ]
{
# No help requested, go ahead and load and build the users
# project.
# Allow users to override the build system file from the
# command-line (mostly for testing)
local build-system = [ MATCH --build-system=(.*) : $(ARGV) ] ;
build-system ?= build-system ;
# Use last element in case of multiple command-line options
import $(build-system[-2]) ;
}

349
new/project-roots.jam Executable file
View File

@@ -0,0 +1,349 @@
# Copyright (C) Rene Rivera 2002. 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.
# Represents the projet-root of a collection of projects. This maintains
# information about the root, and pointers to the project defined within
# the root. Each project-root gets it's own module to put things into. For
# instance declared constants which also get interned into each loaded project.
import modules ;
import path ;
import class ;
import set ;
import regex ;
# Load the project-root file for the given directory. The directory can
# be either the project-root itself, or any subdirectory. Fails if it can't
# find the project-root. We return the project-root module.
#
rule load (
dir # The directory to obtain the project-root for.
)
{
# Find the project-root.jam corresponding to this directory.
#
local location = [ path.glob $(dir) : project-root.jam ] ;
if ! $(location)
{
location = [ path.glob-in-parents $(dir) : project-root.jam ] ;
}
# No project-root file found.
#
if ! $(location)
{
ECHO "Failed to find the project root for directory '$(dir)'." ;
ECHO "Did not find a project-root.jam file there or in any of its parent"
"directories." ;
EXIT "Please consult the documentation at 'http://www.boost.org'." ;
}
location = [ path.parent [ path.make $(location) ] ] ;
local module-name = project-root<$(location)> ;
# Only bother with the rest if the project-root isn't loaded yet.
#
if ! [ modules.peek $(module-name) : .project-root ]
{
# Create the project-root, and remember it.
#
local root = [ class.new project-root-object $(location) ] ;
modules.poke $(module-name) : .project-root : $(root) ;
.roots += $(root) ;
# Let the project root initialize and load the contents.
#
$(root).initialize ;
}
# Return the module for the project.
#
return $(module-name) ;
}
# Print out all the project-roots.
#
rule print ( )
{
import sequence ;
import print ;
local rule compare-project-roots ( r1 r2 )
{
if [ $(r1).get-module ] < [ $(r2).get-module ]
{
return true ;
}
}
print.section "Project Roots" ;
local roots = [ sequence.insertion-sort $(.roots) : compare-project-roots ] ;
for local root in $(roots)
{
$(root).print ;
}
}
# Class encapsulating settings for a single project root.
#
rule project-root-object (
location # The root location.
)
{
import path ;
import set ;
# The module name of the project-root.
self.module = project-root<$(location)> ;
# The location of the project-root, as a path.
self.location = $(location) ;
# The set of projects registered in this project-root.
self.projects = ;
# The set of interned constants for this project-root.
self.constants = ;
# Accessor, the module of the project root.
rule get-module ( )
{
return $(self.module) ;
}
# Accessor, the location of the porject root.
rule get-location ( )
{
return $(self.location) ;
}
# Accessor, the project modules under this project root.
rule get-projects ( )
{
return $(self.projects) ;
}
# Accessor, the constants to intern into the project root.
rule get-constants ( )
{
return $(self.constants) ;
}
# Initialize the project root, also loads the project root file.
rule initialize ( )
{
# Give the new module all the rules from project-root-context
#
modules.clone-rules project-root-context $(self.module) ;
# Load it within a module specifically for the project root.
# The module system handles checking for multiple includes.
#
modules.load $(self.module)
: project-root.jam : [ path.native $(self.location) ] ;
}
# Accessor, add a constant.
rule add-constant (
name # Variable name of the constant.
: value # Value of the constant.
: type ? # Optional type of value.
)
{
switch $(type)
{
case path :
value = [ path.root [ path.native $(value) ] $(self.location) ] ;
# Now make the value absolute path
value = [ path.root $(value) [ path.pwd ] ] ;
}
if ! $(name) in $(self.constants)
{
self.constants += $(name) ;
}
self.constant.$(name) = $(value) ;
}
# Register a project under this project-root. This does any setup
# in the module of the project, including interning the project-root
# constants. Multiple calls on the same project are allowed and will
# not disturb the previous calls.
#
rule register-project (
project-module # The module of the project to register.
)
{
if ! $(project-module) in $(self.projects)
{
self.projects += $(project-module) ;
intern-constants $(project-module) ;
modules.clone-rules project-context $(project-module) ;
# Import project-root rules declared by teh user into each project.
#
local user-rules = [ set.difference
[ RULENAMES $(self.module) ] :
[ RULENAMES project-root-context ] ] ;
IMPORT $(self.module) : $(user-rules) : $(project-module) : $(user-rules) ;
}
}
# Intern the constants from this project-root into the calling context.
#
rule intern-constants (
context ? # The module to intern into the current module.
)
{
local intern-module = $(context) ;
intern-module ?= [ CALLER_MODULE ] ;
for local c in $(self.constants)
{
modules.poke $(intern-module) : $(c) : $(self.constant.$(c)) ;
}
}
# Print out info about this project root. Calls print on the
# individual projects in this project-root.
#
rule print ( )
{
import sequence ;
import print ;
import project ;
# Needed to get deterministic order of output, which makes testing simpler
local rule compare-projects ( p1 p2 )
{
local id1 = [ project.attribute $(p1) id ] ;
local id2 = [ project.attribute $(p2) id ] ;
if $(id1) < $(id2)
{
return true ;
}
else
{
if $(id1) = $(id2) && $(p1) < $(p2)
{
return true ;
}
}
}
print.section "'"$(self.location)"'" Module for project-root is "'"$(self.module)"'" ;
if $(self.constants)
{
print.section Constants ;
print.list-start ;
local constants = [ sequence.insertion-sort $(self.constants) ] ;
for local c in $(constants)
{
print.list-item $(c) "=" $(self.constant.$(c)) ;
}
print.list-end ;
}
if $(self.projects)
{
print.section Projects ;
local projects = [ sequence.insertion-sort $(self.projects) : compare-projects ] ;
for local p in $(projects)
{
local attributes = [ project.attributes $(p) ] ;
$(attributes).print ;
}
}
}
}
class.class project-root-object ;
# Rules callable by the user in the context of the project-root.jam of a project.
#
module project-root-context
{
# Make toolset.using accessible in project-root.
import toolset : using ;
EXPORT project-root-context : using ;
# Access to project root object and shortcut for it's methods. The
# optional argument is a shortcut to execute the given method on the
# object. This saves the hasle of creating local vars to call on the
# singleton.
#
rule project-root (
method ? # The optional method.
args * # The arguments.
: * # The rest.
)
{
if $(method)
{
return [ $(.project-root).$(method) $(args) : $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) ] ;
}
else
{
return $(.project-root) ;
}
}
# Declare and set a project global constant. Project global constants are
# normal variables but should not be changed. They are applied to each
# Jamfile that is loaded under it's corresponding project-root.
#
rule constant (
name # Variable name of the constant.
: value # Value of the constant.
)
{
project-root add-constant $(name) : $(value) ;
}
# Declare and set a project global constant, whose value is a path. The
# path is adjusted to be relative to the invocation directory. The given
# value path is taken to be either absolute, or relative to this project root.
#
rule path-constant (
name # Variable name of the constant.
: value # Value of the constant.
)
{
project-root add-constant $(name) : $(value) : path ;
}
# Load and use a project in this project root.
#
rule use-project (
id # The ID of the project.
: location # The location of the project.
)
{
import project ;
import path ;
project.use $(id) : [ path.root
[ path.make $(location) ] [ project-root get-location ] ] ;
}
}
# Project root specific rules callable in the context of a project file. These
# get imported into each project.
#
module project-context
{
# Access to project root object and shortcut for it's methods. The
# optional argument is a shortcut to execute the given method on the
# object. This saves the hasle of creating local vars to call on the
# singleton.
#
rule project-root (
method ? # The optional method.
args * # The arguments.
: * # The rest.
)
{
import project ;
local attributes = [ project.attributes $(__name__) ] ;
local project-root-module = [ $(attributes).get project-root-module ] ;
return [ $(project-root-module).project-root
$(method) $(args) : $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) ] ;
}
}

View File

@@ -41,7 +41,8 @@ import numbers ;
import path ;
import sequence ;
import errors : error ;
import project-root ;
import project-roots ;
import print ;
import class : class new ;
import errors ;
@@ -56,7 +57,7 @@ import property-set ;
rule load ( jamfile-location )
{
# Load project root, first. It might decide to act as Jamfile.
project-root.load $(jamfile-location) ;
project-roots.load $(jamfile-location) ;
local module-name = [ module-name $(jamfile-location) ] ;
# If Jamfile is already loaded, don't try again.
@@ -403,7 +404,7 @@ rule initialize (
# Make sure we've loaded the project-root corresponding to this
# Jamfile.
#
local project-root-module = [ project-root.load $(location) ] ;
local project-root-module = [ project-roots.load $(location) ] ;
local project-root = [ $(project-root-module).project-root get-location ] ;
local parent = [ find-jamfile $(location) $(project-root) ] ;

View File

@@ -12,7 +12,10 @@ import class : class new ;
import errors ;
import property ;
import scanner ;
import targets ;
# This creates a circular dependency
# project-test1 -> project -> project-root -> builtin -> type -> targets -> project
# import targets ;
# The feature is optional so that it never implicitly added.
# It's used only for internal purposes, and in all cases we
@@ -227,6 +230,8 @@ rule main-target-rule ( name : sources * : requirements * : default-build *
# a project.
local project = [ CALLER_MODULE ] ;
# This is a circular module dependency, so it must be imported here
import targets ;
targets.main-target-alternative
[ new typed-target $(name) : $(project) : $(.main-target-type.$(rulename))
: $(sources)

View File

@@ -92,12 +92,7 @@ class Tester(TestCmd.TestCmd):
raise "Don't know directory where jam is build for this system"
if boost_build_path is None:
boost_build_path = os.path.join(self.original_workdir,
"..", "new")
if os.name == 'nt':
boost_build_path += ";" + self.original_workdir
else:
boost_build_path += ":" + self.original_workdir
boost_build_path = self.original_workdir
verbosity = ['-d0', '--quiet']

View File

@@ -1,2 +1,2 @@
# Find the boost build system in the ../new directory.
boost-build ../new ;
# Find the boost build system in the ../kernel directory.
boost-build ../kernel ;

View File

@@ -3,9 +3,9 @@ import targets ;
import assert ;
project.load project-test1 ;
import project-root ;
import project-roots ;
project-root.print ;
project-roots.print ;
assert.result Jamfile<project-test1/dir2> : project.lookup @/cool-library : "." ;
assert.result Jamfile<project-test1/dir2> : project.lookup project-test1@/cool-library : "." ;

View File

@@ -1,13 +1,13 @@
import project ;
import targets ;
import assert ;
import project-root ;
import project-roots ;
project.load "." ;
import standalone-project ;
project-root.print ;
project-roots.print ;
assert.result Jamfile<dir2> : project.lookup @/cool-library : "." ;
assert.result Jamfile<dir> : project.lookup dir@ : "." ;

View File

@@ -1,42 +0,0 @@
# (C) Copyright David Abrahams 2001. 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.
# First of all, check the jam version
if $(JAM_VERSION:J="") < 030105
{
ECHO "error: Boost.Jam version 3.1.5 or later required" ;
EXIT ;
}
# Bootstrap the module system. And bring the import rule into the global module.
#
SEARCH on <module@>modules.jam = $(BOOST_BUILD_PATH) ;
module modules { include <module@>modules.jam ; }
IMPORT modules : import : : import ;
# Reload the modules, to clean up things. The modules module can tolerate
# being included twice.
#
import modules ;
# Check to see if the user is asking for help as soon as possible.
# This is first action, so that we can interrupt the regular build
# process if they are asking for help.
#
import doc ;
if ! [ doc.help ]
{
# No help requested, go ahead and load and build the users
# project.
# Allow users to override the build system file from the
# command-line (mostly for testing)
local build-system = [ MATCH --build-system=(.*) : $(ARGV) ] ;
build-system ?= build-system ;
# Use last element in case of multiple command-line options
import $(build-system[-2]) ;
}

190
v2/build-system.jam Executable file
View File

@@ -0,0 +1,190 @@
# (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 sequence ;
import modules ;
import feature ;
import property-set ;
import build-request ;
import errors : error ;
import class : new ;
import builtin ;
import make ;
import os ;
import version ;
# Check if we can load 'test-config.jam'. If we can, load it and
# ignore user configs.
local test-config = [ GLOB [ modules.peek : BOOST_BUILD_PATH ] : test-config.jam ] ;
if $(test-config)
{
import test-config ;
}
if ! $(test-config) && ! --ignore-config in [ modules.peek : ARGV ]
{
module site-config
{
import toolset : using ;
}
module user-config
{
import toolset : using ;
}
local user-path = [ modules.peek : HOME ] [ modules.peek : BOOST_BUILD_PATH ] ;
if [ os.name ] in NT CYGWIN
{
modules.load site-config : : [ modules.peek : SystemRoot ] $(user-path) ;
modules.load user-config : : $(user-path) ;
}
else
{
modules.load site-config : : /etc $(user-path) ;
modules.load user-config : : $(user-path) ;
}
}
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.
project.load "." ;
if [ MATCH (--dump-projects) : [ modules.peek : ARGV ] ]
{
project-roots.print ;
}
if ! [ feature.values toolset ]
{
ECHO "warning: no toolsets are configured." ;
ECHO "warning: you won't be able to build C++ programs." ;
ECHO "warning: please consult the documentation." ;
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) ;
}
local target-ids = [ $(build-request).get-at 1 ] ;
local targets
local clean ;
if "--clean" in [ modules.peek : ARGV ]
{
clean = true ;
}
for local id in $(target-ids)
{
if $(id) = clean
{
clean = true ;
}
else
{
local t = [ project.find-target $(id) : "." ] ;
if ! $(t)
{
error target $(id) does not exist ;
}
else
{
targets += $(t) ;
}
}
}
if ! $(targets)
{
targets += [ project.target [ project.module-name "." ] ] ;
}
virtual-targets = ;
if $(expanded)
{
local dr-adjuster = [ new directly-requested-properties-adjuster ] ;
for local p in $(expanded)
{
$(dr-adjuster).add-requested-property-set $(p) ;
}
for local t in $(targets)
{
$(t).set-property-adjuster $(dr-adjuster) ;
}
for local p in $(expanded)
{
for local t in $(targets)
{
virtual-targets += [ $(t).generate $(p) ] ;
}
}
}
else
{
for local t in $(targets)
{
virtual-targets += [ $(t).generate [ property-set.empty ] ] ;
}
}
actual-targets = ;
for t in $(virtual-targets)
{
actual-targets += [ $(t).actualize ] ;
}
NOTFILE all ;
DEPENDS all : $(actual-targets) ;
if $(clean)
{
UPDATE clean ;
}
else
{
UPDATE all ;
}

349
v2/build/project-roots.jam Executable file
View File

@@ -0,0 +1,349 @@
# Copyright (C) Rene Rivera 2002. 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.
# Represents the projet-root of a collection of projects. This maintains
# information about the root, and pointers to the project defined within
# the root. Each project-root gets it's own module to put things into. For
# instance declared constants which also get interned into each loaded project.
import modules ;
import path ;
import class ;
import set ;
import regex ;
# Load the project-root file for the given directory. The directory can
# be either the project-root itself, or any subdirectory. Fails if it can't
# find the project-root. We return the project-root module.
#
rule load (
dir # The directory to obtain the project-root for.
)
{
# Find the project-root.jam corresponding to this directory.
#
local location = [ path.glob $(dir) : project-root.jam ] ;
if ! $(location)
{
location = [ path.glob-in-parents $(dir) : project-root.jam ] ;
}
# No project-root file found.
#
if ! $(location)
{
ECHO "Failed to find the project root for directory '$(dir)'." ;
ECHO "Did not find a project-root.jam file there or in any of its parent"
"directories." ;
EXIT "Please consult the documentation at 'http://www.boost.org'." ;
}
location = [ path.parent [ path.make $(location) ] ] ;
local module-name = project-root<$(location)> ;
# Only bother with the rest if the project-root isn't loaded yet.
#
if ! [ modules.peek $(module-name) : .project-root ]
{
# Create the project-root, and remember it.
#
local root = [ class.new project-root-object $(location) ] ;
modules.poke $(module-name) : .project-root : $(root) ;
.roots += $(root) ;
# Let the project root initialize and load the contents.
#
$(root).initialize ;
}
# Return the module for the project.
#
return $(module-name) ;
}
# Print out all the project-roots.
#
rule print ( )
{
import sequence ;
import print ;
local rule compare-project-roots ( r1 r2 )
{
if [ $(r1).get-module ] < [ $(r2).get-module ]
{
return true ;
}
}
print.section "Project Roots" ;
local roots = [ sequence.insertion-sort $(.roots) : compare-project-roots ] ;
for local root in $(roots)
{
$(root).print ;
}
}
# Class encapsulating settings for a single project root.
#
rule project-root-object (
location # The root location.
)
{
import path ;
import set ;
# The module name of the project-root.
self.module = project-root<$(location)> ;
# The location of the project-root, as a path.
self.location = $(location) ;
# The set of projects registered in this project-root.
self.projects = ;
# The set of interned constants for this project-root.
self.constants = ;
# Accessor, the module of the project root.
rule get-module ( )
{
return $(self.module) ;
}
# Accessor, the location of the porject root.
rule get-location ( )
{
return $(self.location) ;
}
# Accessor, the project modules under this project root.
rule get-projects ( )
{
return $(self.projects) ;
}
# Accessor, the constants to intern into the project root.
rule get-constants ( )
{
return $(self.constants) ;
}
# Initialize the project root, also loads the project root file.
rule initialize ( )
{
# Give the new module all the rules from project-root-context
#
modules.clone-rules project-root-context $(self.module) ;
# Load it within a module specifically for the project root.
# The module system handles checking for multiple includes.
#
modules.load $(self.module)
: project-root.jam : [ path.native $(self.location) ] ;
}
# Accessor, add a constant.
rule add-constant (
name # Variable name of the constant.
: value # Value of the constant.
: type ? # Optional type of value.
)
{
switch $(type)
{
case path :
value = [ path.root [ path.native $(value) ] $(self.location) ] ;
# Now make the value absolute path
value = [ path.root $(value) [ path.pwd ] ] ;
}
if ! $(name) in $(self.constants)
{
self.constants += $(name) ;
}
self.constant.$(name) = $(value) ;
}
# Register a project under this project-root. This does any setup
# in the module of the project, including interning the project-root
# constants. Multiple calls on the same project are allowed and will
# not disturb the previous calls.
#
rule register-project (
project-module # The module of the project to register.
)
{
if ! $(project-module) in $(self.projects)
{
self.projects += $(project-module) ;
intern-constants $(project-module) ;
modules.clone-rules project-context $(project-module) ;
# Import project-root rules declared by teh user into each project.
#
local user-rules = [ set.difference
[ RULENAMES $(self.module) ] :
[ RULENAMES project-root-context ] ] ;
IMPORT $(self.module) : $(user-rules) : $(project-module) : $(user-rules) ;
}
}
# Intern the constants from this project-root into the calling context.
#
rule intern-constants (
context ? # The module to intern into the current module.
)
{
local intern-module = $(context) ;
intern-module ?= [ CALLER_MODULE ] ;
for local c in $(self.constants)
{
modules.poke $(intern-module) : $(c) : $(self.constant.$(c)) ;
}
}
# Print out info about this project root. Calls print on the
# individual projects in this project-root.
#
rule print ( )
{
import sequence ;
import print ;
import project ;
# Needed to get deterministic order of output, which makes testing simpler
local rule compare-projects ( p1 p2 )
{
local id1 = [ project.attribute $(p1) id ] ;
local id2 = [ project.attribute $(p2) id ] ;
if $(id1) < $(id2)
{
return true ;
}
else
{
if $(id1) = $(id2) && $(p1) < $(p2)
{
return true ;
}
}
}
print.section "'"$(self.location)"'" Module for project-root is "'"$(self.module)"'" ;
if $(self.constants)
{
print.section Constants ;
print.list-start ;
local constants = [ sequence.insertion-sort $(self.constants) ] ;
for local c in $(constants)
{
print.list-item $(c) "=" $(self.constant.$(c)) ;
}
print.list-end ;
}
if $(self.projects)
{
print.section Projects ;
local projects = [ sequence.insertion-sort $(self.projects) : compare-projects ] ;
for local p in $(projects)
{
local attributes = [ project.attributes $(p) ] ;
$(attributes).print ;
}
}
}
}
class.class project-root-object ;
# Rules callable by the user in the context of the project-root.jam of a project.
#
module project-root-context
{
# Make toolset.using accessible in project-root.
import toolset : using ;
EXPORT project-root-context : using ;
# Access to project root object and shortcut for it's methods. The
# optional argument is a shortcut to execute the given method on the
# object. This saves the hasle of creating local vars to call on the
# singleton.
#
rule project-root (
method ? # The optional method.
args * # The arguments.
: * # The rest.
)
{
if $(method)
{
return [ $(.project-root).$(method) $(args) : $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) ] ;
}
else
{
return $(.project-root) ;
}
}
# Declare and set a project global constant. Project global constants are
# normal variables but should not be changed. They are applied to each
# Jamfile that is loaded under it's corresponding project-root.
#
rule constant (
name # Variable name of the constant.
: value # Value of the constant.
)
{
project-root add-constant $(name) : $(value) ;
}
# Declare and set a project global constant, whose value is a path. The
# path is adjusted to be relative to the invocation directory. The given
# value path is taken to be either absolute, or relative to this project root.
#
rule path-constant (
name # Variable name of the constant.
: value # Value of the constant.
)
{
project-root add-constant $(name) : $(value) : path ;
}
# Load and use a project in this project root.
#
rule use-project (
id # The ID of the project.
: location # The location of the project.
)
{
import project ;
import path ;
project.use $(id) : [ path.root
[ path.make $(location) ] [ project-root get-location ] ] ;
}
}
# Project root specific rules callable in the context of a project file. These
# get imported into each project.
#
module project-context
{
# Access to project root object and shortcut for it's methods. The
# optional argument is a shortcut to execute the given method on the
# object. This saves the hasle of creating local vars to call on the
# singleton.
#
rule project-root (
method ? # The optional method.
args * # The arguments.
: * # The rest.
)
{
import project ;
local attributes = [ project.attributes $(__name__) ] ;
local project-root-module = [ $(attributes).get project-root-module ] ;
return [ $(project-root-module).project-root
$(method) $(args) : $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) ] ;
}
}

View File

@@ -41,7 +41,8 @@ import numbers ;
import path ;
import sequence ;
import errors : error ;
import project-root ;
import project-roots ;
import print ;
import class : class new ;
import errors ;
@@ -56,7 +57,7 @@ import property-set ;
rule load ( jamfile-location )
{
# Load project root, first. It might decide to act as Jamfile.
project-root.load $(jamfile-location) ;
project-roots.load $(jamfile-location) ;
local module-name = [ module-name $(jamfile-location) ] ;
# If Jamfile is already loaded, don't try again.
@@ -403,7 +404,7 @@ rule initialize (
# Make sure we've loaded the project-root corresponding to this
# Jamfile.
#
local project-root-module = [ project-root.load $(location) ] ;
local project-root-module = [ project-roots.load $(location) ] ;
local project-root = [ $(project-root-module).project-root get-location ] ;
local parent = [ find-jamfile $(location) $(project-root) ] ;

View File

@@ -12,7 +12,10 @@ import class : class new ;
import errors ;
import property ;
import scanner ;
import targets ;
# This creates a circular dependency
# project-test1 -> project -> project-root -> builtin -> type -> targets -> project
# import targets ;
# The feature is optional so that it never implicitly added.
# It's used only for internal purposes, and in all cases we
@@ -227,6 +230,8 @@ rule main-target-rule ( name : sources * : requirements * : default-build *
# a project.
local project = [ CALLER_MODULE ] ;
# This is a circular module dependency, so it must be imported here
import targets ;
targets.main-target-alternative
[ new typed-target $(name) : $(project) : $(.main-target-type.$(rulename))
: $(sources)

6
v2/kernel/boost-build.jam Executable file
View File

@@ -0,0 +1,6 @@
# Copyright David Abrahams 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.
boost-build . ;

95
v2/kernel/bootstrap.jam Executable file
View File

@@ -0,0 +1,95 @@
# (C) Copyright David Abrahams 2001. 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.
# First of all, check the jam version
if $(JAM_VERSION:J="") < 030105
{
ECHO "error: Boost.Jam version 3.1.5 or later required" ;
EXIT ;
}
# Bootstrap the module system. Then bring the import rule into the global module.
#
SEARCH on <module@>modules.jam = $(.bootstrap-file:D) ;
module modules { include <module@>modules.jam ; }
IMPORT modules : import : : import ;
{
# Add module subdirectories to the BOOST_BUILD_PATH, which allows
# us to make an incremental refactoring step by moving modules to
# the appropriate subdirectories, thereby achieving some physical
# separation of different layers without changing all of our code
# to specify subdirectories in import statements or use an extra
# level of qualification on imported names.
local subdirs =
kernel # only the most-intrinsic modules: modules, errors
util # low-level substrate: string/number handling, etc.
core # essential elements of the build system architecture
tools # toolsets for handling specific build jobs and targets.
new # until we get everything sorted out, there is
# still some code here
. # build-system.jam lives here
;
local whereami = $(.bootstrap-file:D) ;
BOOST_BUILD_PATH += $(whereami:D)/$(subdirs) ;
}
# Reload the modules, to clean up things. The modules module can tolerate
# being included twice.
#
import modules ;
# Check command-line args as soon as possible. This is first action,
# so that we can interrupt the regular build process if the user is
# asking for help.
for local arg in [ MATCH ^--([^-=].*) : $(ARGV) ]
{
local split = [ MATCH ^([^-=]+([^=]*))(=?)(.*)$ : $(arg) ] ;
local full-name = $(split[1]) ;
local prefix = $(split[2]) ;
local value ;
if $(split[3])
{
value = $(split[4]) ;
}
# look in options subdirectories of BOOST_BUILD_PATH for modules
# matching the full option name and then its prefix.
local plugin-dir = options ;
local option-files = [
GLOB $(plugin-dir:D=$(BOOST_BUILD_PATH)) : $(full-name).jam $(prefix).jam
] ;
if $(option-files)
{
# load the file into a module named for the option
local f = $(option-files[1]) ;
local module-name = --$(f:D=:S=) ;
modules.load $(module-name) : $(f:D=) : $(f:D) ;
# if there's a process rule, call it with the full option name
# and its value (if any). If there was no "=" in the option,
# the value will be empty.
if process in [ RULENAMES $(module-name) ]
{
modules.call-in $(module-name) : process --$(full-name) : $(value) ;
}
}
}
# Allow users to override the build system file from the
# command-line (mostly for testing)
local build-system = [ MATCH --build-system=(.*) : $(ARGV) ] ;
build-system ?= build-system ;
# Use last element in case of multiple command-line options
import $(build-system[-2]) ;

0
v2/errors.jam → v2/kernel/errors.jam Normal file → Executable file
View File

85
new/modules.jam → v2/kernel/modules.jam Normal file → Executable file
View File

@@ -129,6 +129,12 @@ rule load (
local rules = [ RULENAMES $(__name__) ] ;
IMPORT $(__name__) : $(rules) : $(__name__) : $(__name__).$(rules) ;
}
if $(module-name) != modules && ! [ binding $(module-name) ]
{
import errors ;
errors.error "couldn't find module" $(module-name) in $(search) ;
}
# Pop the loading stack. Must happen before testing or we'll find a circular loading dependency
.loading = $(.loading[1--2]) ;
@@ -184,6 +190,58 @@ rule record-binding ( module-target : binding )
$(.loading[-1]).__binding__ = $(binding) ;
}
# Transform each path in the list, with all backslashes converted to
# forward slashes and all detectable redundancy removed. Something
# like this is probably needed in path.jam, but I'm not sure of that,
# I don't understand it, and I'm not ready to move all of path.jam
# into the kernel.
local rule normalize-raw-paths ( paths * )
{
local result ;
for p in $(paths:T)
{
local elements ; # the simplified path elements
local dotdots ; # a stack of .. elements we've seen
# consume the last path element in p until there's nothing
# left
while $(p)
{
local split = [ MATCH ^(.+)/(.*)$ : $(p) ] ;
if ! $(split)
{ # no further slashes; prepend the last element
elements = $(p) $(elements) ;
}
else if $(split[2]) = .
{ # ignore the identity directory
}
else if $(split[2]) = ..
{ # prepare to absorb the next named element
dotdots += .. ; # push parent onto stack
}
else if $(dotdots)
{ # absorb a named element
dotdots = $(dotdots[2-]) ; # pop parent off stack
}
else if $(split[2]) # if the element was empty, ignore it
{ # to drop a trailing slash
elements = $(split[2]) $(elements) ;
}
# drop the last element of p
p = $(split[1]) ;
}
# prepend any unused parent directories
elements = $(dotdots) $(elements) ;
# If everything cancelled out, it's the identity directory.
elements ?= . ;
result += $(elements:J=/) ;
}
return $(result) ;
}
# load the indicated module and import rule names into the current
# module. Any members of rules-opt will be available without
# qualification in the caller's module. Any members of rename-opt will
@@ -207,16 +265,32 @@ rule import ( module-names + : rules-opt * : rename-opt * )
errors.error when loading multiple modules, no specific rules or renaming is allowed ;
}
# if the importing module isn't already in the BOOST_BUILD_PATH,
# prepend it to the path. We don't want to invert the search
# order of modules that are already there.
local caller = [ CALLER_MODULE ] ;
local cwd = [ PWD ] ;
local caller-location ;
if $(caller)
{
caller-location = [ binding $(caller) ] ;
caller-location = $(caller-location:D) ;
caller-location = [ normalize-raw-paths $(caller-location:R=$(cwd)) ] ;
}
local search = [ peek : BOOST_BUILD_PATH ] ;
search = [ normalize-raw-paths $(search:R=$(cwd)) ] ;
if $(caller-location) && ! $(caller-location) in $(search)
{
search = $(caller-location) $(search) ;
}
# Import each specified module
for local m in $(module-names)
{
load $(m) : : $(caller-location:D) [ peek : BOOST_BUILD_PATH ] ;
load $(m) : : $(search) ;
local all-rules = [ RULENAMES $(m) ] ;
# import all the rules with qualification
@@ -264,6 +338,7 @@ IMPORT modules : $(globalize) : : modules.$(globalize) ;
local rule __test__ ( )
{
import assert ;
import modules : normalize-raw-paths ;
module modules.__test__
{
@@ -273,6 +348,14 @@ local rule __test__ ( )
assert.result bar : peek modules.__test__ : foo ;
poke modules.__test__ : foo : bar baz ;
assert.result bar baz : peek modules.__test__ : foo ;
assert.result c:/foo/bar : normalize-raw-paths c:/x/../foo/./xx/yy/../../bar ;
assert.result . : normalize-raw-paths . ;
assert.result .. : normalize-raw-paths .. ;
assert.result ../.. : normalize-raw-paths ../.. ;
assert.result / / : normalize-raw-paths / \\ ;
assert.result a : normalize-raw-paths a ;
assert.result a : normalize-raw-paths a/ ;
assert.result /a : normalize-raw-paths /a/ ;
}

View File

@@ -92,12 +92,7 @@ class Tester(TestCmd.TestCmd):
raise "Don't know directory where jam is build for this system"
if boost_build_path is None:
boost_build_path = os.path.join(self.original_workdir,
"..", "new")
if os.name == 'nt':
boost_build_path += ";" + self.original_workdir
else:
boost_build_path += ":" + self.original_workdir
boost_build_path = self.original_workdir
verbosity = ['-d0', '--quiet']

View File

@@ -1,2 +1,2 @@
# Find the boost build system in the ../new directory.
boost-build ../new ;
# Find the boost build system in the ../kernel directory.
boost-build ../kernel ;

View File

@@ -3,9 +3,9 @@ import targets ;
import assert ;
project.load project-test1 ;
import project-root ;
import project-roots ;
project-root.print ;
project-roots.print ;
assert.result Jamfile<project-test1/dir2> : project.lookup @/cool-library : "." ;
assert.result Jamfile<project-test1/dir2> : project.lookup project-test1@/cool-library : "." ;

View File

@@ -1,13 +1,13 @@
import project ;
import targets ;
import assert ;
import project-root ;
import project-roots ;
project.load "." ;
import standalone-project ;
project-root.print ;
project-roots.print ;
assert.result Jamfile<dir2> : project.lookup @/cool-library : "." ;
assert.result Jamfile<dir> : project.lookup dir@ : "." ;