📄 project.jam
字号:
# Copyright (C) Vladimir Prus and 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.
# Implements project representation and loading.
# Each project is represented by
# - a module where all the Jamfile content live.
# - an instance of 'project-attributes' class.
# (given module name, can be obtained by 'attributes' rule)
# - an instance of 'project-target' class (from targets.jam)
# (given a module name, can be obtained by 'target' rule)
#
# Typically, projects are created as result of loading Jamfile, which is
# do by rules 'load' and 'initialize', below. First, module for Jamfile
# is loaded and new project-attributes instance is created. Some rules
# necessary for project are added to the module (see 'project-rules' module)
# at the bottom of this file.
# Default project attributes are set (inheriting attributes of parent project, if
# it exists). After that, Jamfile is read. It can declare its own attributes,
# via 'project' rule, which will be combined with already set attributes.
#
#
# The 'project' rule can also declare project id, which will be associated with
# the project module.
#
# There can also be 'standalone' projects. They are created by calling 'initialize'
# on arbitrary module, and not specifying location. After the call, the module can
# call 'project' rule, declare main target and behave as regular projects. However,
# since it's not associated with any location, it's better declare only prebuilt
# targets.
#
# The list of all loaded Jamfile is stored in variable .project-locations. It's possible
# to obtain module name for a location using 'module-name' rule. The standalone projects
# are not recorded, the only way to use them is by project id.
import modules : peek poke ;
import numbers ;
import path ;
import sequence ;
import errors : error ;
import print ;
import "class" : new ;
import errors ;
import assert ;
import property-set ;
#
# Loads jamfile at the given location. After loading, project global
# file and jamfile needed by the loaded one will be loaded recursively.
# If the jamfile at that location is loaded already, does nothing.
# Returns the project module for the Jamfile.
#
rule load ( jamfile-location )
{
if --debug-loading in [ modules.peek : ARGV ]
{
ECHO "Loading Jamfile at" '$(jamfile-location)' ;
}
local module-name = [ module-name $(jamfile-location) ] ;
# If Jamfile is already loaded, don't try again.
if ! $(module-name) in $(.jamfile-modules)
{
load-jamfile $(jamfile-location) ;
# We want to make sure that child project are loaded only
# after parent projects. In particular, because parent projects
# define attributes whch are inherited by children, and we don't
# want children to be loaded before parents has defined everything.
# So, for "build-project" and "use-project" we only record relevant
# information, and actually load the mentioned projects after
# loading the current Jamfile.
for local p in [ attribute $(module-name) projects-to-build ]
{
load [ path.join $(jamfile-location) $(p) ] ;
}
local used = [ modules.peek $(module-name) : .used-projects ] ;
import project ;
while $(used)
{
local id = $(used[1]) ;
local where = $(used[2]) ;
project.use $(id) : [ path.root
[ path.make $(where) ] $(jamfile-location) ] ;
used = $(used[3-]) ;
}
}
return $(module-name) ;
}
# Note the use of character groups, as opposed to listing
# 'Jamroot' and 'jamroot'. With the latter, we'd get duplicate
# matches on windows and would have to eliminate duplicates.
JAMROOT = project-root.jam [Jj]amroot [Jj]amroot.jam ;
# Loads parent of Jamfile at 'location'. Issues an error if nothing is found.
rule load-parent ( location )
{
local found = [ path.glob-in-parents $(location) :
$(JAMROOT) $(JAMFILE) ] ;
if ! $(found)
{
ECHO "error: Could not find parent for project at '$(location)'" ;
ECHO "error: Did not find Jamfile or project-root.jam in any parent directory." ;
EXIT ;
}
return [ load $(found[1]:D) ] ;
}
# Makes the specified 'module' act as if it were a regularly loaded Jamfile
# at 'location'. If Jamfile is already located for that location, it's an
# error.
rule act-as-jamfile ( module : location )
{
if [ module-name $(location) ] in $(.jamfile-modules)
{
errors.error "Jamfile was already loaded for '$(location)'" ;
}
# Set up non-default mapping from location to module.
.module.$(location) = $(module) ;
# Add the location to the list of project locations
# so that we don't try to load Jamfile in future
.jamfile-modules += [ module-name $(location) ] ;
initialize $(module) : $(location) ;
}
# Given 'name' which can be project-id or plain directory name,
# return project module corresponding to that id or directory.
# Returns nothing of project is not found.
rule find ( name : current-location )
{
local project-module ;
# Try interpreting name as project id.
if [ path.is-rooted $(name) ]
{
project-module = $($(name).jamfile-module) ;
}
if ! $(project-module)
{
local location = [ path.root
[ path.make $(name) ] $(current-location) ] ;
# If no project is registered for the given location, try to
# load it. First see if we have Jamfile. If not we might have project
# root, willing to act as Jamfile. In that case, project-root
# must be placed in the directory referred by id.
project-module = [ module-name $(location) ] ;
if ! $(project-module) in $(.jamfile-modules)
{
if [ path.glob $(location) : $(JAMROOT) $(JAMFILE) ]
{
project-module = [ load $(location) ] ;
}
else
{
project-module = ;
}
}
}
return $(project-module) ;
}
#
# Returns the name of module corresponding to 'jamfile-location'.
# If no module corresponds to location yet, associates default
# module name with that location.
#
rule module-name ( jamfile-location )
{
if ! $(.module.$(jamfile-location))
{
# Root the path, so that locations are always umbiguious.
# Without this, we can't decide if '../../exe/program1' and '.'
# are the same paths, or not.
jamfile-location = [ path.root $(jamfile-location) [ path.pwd ] ] ;
.module.$(jamfile-location) = Jamfile<$(jamfile-location)> ;
}
return $(.module.$(jamfile-location)) ;
}
# Default patterns to search for the Jamfiles to use for build
# declarations.
#
JAMFILE = [ modules.peek : JAMFILE ] ;
JAMFILE ?= [Jj]amfile.v2 [Jj]amfile [Jj]amfile.jam ;
# Find the Jamfile at the given location. This returns the exact names of
# all the Jamfiles in the given directory. The optional parent-root argument
# causes this to search not the given directory but the ones above it up
# to the directory given in it.
#
local rule find-jamfile (
dir # The directory(s) to look for a Jamfile.
parent-root ? # Optional flag indicating to search for the parent Jamfile.
: no-errors ?
)
{
# Glob for all the possible Jamfiles according to the match pattern.
#
local jamfile-glob = ;
if $(parent-root)
{
if ! $(.parent-jamfile.$(dir))
{
.parent-jamfile.$(dir) =
[ path.glob-in-parents $(dir) : $(JAMFILE) ] ;
}
jamfile-glob = $(.parent-jamfile.$(dir)) ;
}
else
{
if ! $(.jamfile.$(dir))
{
.jamfile.$(dir) = [ path.glob $(dir) : $(JAMFILE) ] ;
}
jamfile-glob = $(.jamfile.$(dir)) ;
}
local jamfile-to-load = $(jamfile-glob) ;
# Multiple Jamfiles found in the same place. Warn about this.
# And ensure we use only one of them.
# As a temporary convenience measure, if there's Jamfile.v2 amount
# found files, suppress the warning and use it.
#
if $(jamfile-to-load[2-])
{
local v2-jamfiles = [ MATCH (.*[Jj]amfile\\.v2) : $(jamfile-to-load) ] ;
if $(v2-jamfiles) && ! $(v2-jamfiles[2])
{
jamfile-to-load = $(v2-jamfiles) ;
}
else
{
ECHO
"warning: Found multiple Jamfiles at '"$(dir)"'!"
"Loading the first one: '" [ path.basename $(jamfile-to-load[1]) ] "'." ;
}
jamfile-to-load = $(jamfile-to-load[1]) ;
}
# Could not find it, error.
#
if ! $(no-errors) && ! $(jamfile-to-load)
{
errors.error
"Unable to load Jamfile." :
"Could not find a Jamfile in directory '$(dir)'". :
"Attempted to find it with pattern '"$(JAMFILE:J=" ")"'." :
"Please consult the documentation at 'http://www.boost.org'." ;
}
return $(jamfile-to-load) ;
}
# Load a Jamfile at the given directory. Returns nothing.
# Will attempt to load the file as indicated by the JAMFILE patterns.
# Effect of calling this rule twice with the same 'dir' is underfined.
local rule load-jamfile (
dir # The directory of the project Jamfile.
)
{
# See if the Jamfile is where it should be.
#
local jamfile-to-load = [ path.glob $(dir) : $(JAMROOT) ] ;
if ! $(jamfile-to-load)
{
jamfile-to-load = [ find-jamfile $(dir) ] ;
}
# The module of the jamfile.
#
local jamfile-module = [ module-name [ path.parent $(jamfile-to-load) ] ] ;
# Initialize the jamfile module before loading.
#
initialize $(jamfile-module) : [ path.parent $(jamfile-to-load) ]
: $(jamfile-to-load:BS) ;
local saved-project = $(.current-project) ;
# Now load the Jamfile in it's own context.
# Initialization might have load parent Jamfiles, which might have
# loaded the current Jamfile with use-project. Do a final check to make
# sure it's not loaded already.
if ! $(jamfile-module) in $(.jamfile-modules)
{
.jamfile-modules += $(jamfile-module) ;
mark-as-user $(jamfile-module) ;
modules.load $(jamfile-module) : [ path.native $(jamfile-to-load) ] : . ;
if $(jamfile-to-load:BS) = project-root.jam
{
jamfile = [ find-jamfile $(dir) : no-errors ] ;
if $(jamfile)
{
load-aux $(jamfile-module) : [ path.native $(jamfile) ] ;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -