📄 targets.jam
字号:
# Copyright (C) Vladimir Prus 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.
# Supports 'abstract' targets, which are targets explicitly defined in Jamfile.
#
# Abstract targets are represented by classes derived from 'abstract-target' class.
# The first abstract target is 'project-target', which is created for each
# Jamfile, and can be obtained by the 'target' rule in the Jamfile's module.
# (see project.jam).
#
# Project targets keep a list of 'main-target' instances.
# A main target is what the user explicitly defines in a Jamfile. It is
# possible to have several definitions for a main target, for example to have
# different lists of sources for different platforms. So, main targets
# keep a list of alternatives.
#
# Each alternative is an instance of 'abstract-target'. When a main target
# subvariant is defined by some rule, that rule will decide what class to
# use, create an instance of that class and add it to the list of alternatives
# for the main target.
#
# Rules supplied by the build system will use only targets derived
# from 'basic-target' class, which will provide some default behaviour.
# There will be two classes derived from it, 'make-target', created by the
# 'make' rule, and 'typed-target', created by rules such as 'exe' and 'dll'.
#
# +------------------------+
# |abstract-target |
# +========================+
# |name |
# |project |
# | |
# |generate(properties) = 0|
# +-----------+------------+
# |
# ^
# / \
# +-+-+
# |
# |
# +------------------------+------+------------------------------+
# | | |
# | | |
# +----------+-----------+ +------+------+ +------+-------+
# | project-target | | main-target | | basic-target |
# +======================+ 1 * +=============+ alternatives +==============+
# | generate(properties) |o-----------+ generate |<>------------->| generate |
# | main-target | +-------------+ | construct = 0|
# +----------------------+ +--------------+
# |
# ^
# / \
# +-+-+
# |
# |
# ...--+----------------+------------------+----------------+---+
# | | | |
# | | | |
# ... ---+-----+ +------+-------+ +------+------+ +--------+-----+
# | | typed-target | | make-target | | stage-target |
# . +==============+ +=============+ +==============+
# . | construct | | construct | | construct |
# +--------------+ +-------------+ +--------------+
import "class" : new ;
import sequence ;
import regex ;
import property ;
import errors ;
import common ;
import property-set ;
import project ;
import feature ;
import virtual-target ;
import path ;
import set ;
import assert ;
# Base class for all abstract targets.
class abstract-target
{
import project assert "class" errors ;
rule __init__ ( name # name of the target in Jamfile
: project-target # the project target to which this one belongs
)
{
assert.true class.is-a $(project-target) : project-target ;
# Note: it might seem that we don't need either name or project at all.
# However, there are places where we really need it. One example is error
# messages which should name problematic targets. Another is setting correct
# paths for sources and generated files.
self.name = $(name) ;
self.project = $(project-target) ;
self.location = [ errors.nearest-user-location ] ;
}
# Returns the name of this target.
rule name ( )
{
return $(self.name) ;
}
# Returns the project for this target.
rule project ( )
{
return $(self.project) ;
}
# Return the location where the target was declared
rule location ( )
{
return $(self.location) ;
}
# Returns a user-readable name for this target.
rule full-name ( )
{
local location = [ $(self.project).get location ] ;
return $(location)/$(self.name) ;
}
# Takes a property set. Generates virtual targets for this abstract
# target, using the specified properties, unless a different value of some
# feature is required by the target.
# On
# success, returns:
# - a property-set with the usage requirements to be
# applied to dependents
# - a list of produced virtual targets, which may be
# empty.
# If 'property-set' are empty, performs default build of this
# target, in a way specific to derived class.
rule generate ( property-set )
{
errors.error "method should be defined in derived classes" ;
}
rule rename ( new-name )
{
self.name = $(new-name) ;
}
}
if --debug-building in [ modules.peek : ARGV ]
{
modules.poke : .debug-building : true ;
}
rule indent ( )
{
return $(.indent:J="") ;
}
rule increase-indent ( )
{
.indent += " " ;
}
rule decrease-indent ( )
{
.indent = $(.indent[2-]) ;
}
# Project target class (derived from 'abstract-target')
#
# This class these responsibilities:
# - maintaining a list of main target in this project and
# building it
#
# Main targets are constructed in two stages:
# - When Jamfile is read, a number of calls to 'add-alternative' is made.
# At that time, alternatives can also be renamed to account for inline
# targets.
# - The first time 'main-target' or 'has-main-target' rule is called,
# all alternatives are enumerated an main targets are created.
class project-target : abstract-target
{
import project targets ;
import path ;
import print ;
import property-set ;
import set : difference : set.difference ;
import sequence ;
import "class" : new ;
import errors ;
rule __init__ ( name : project-module parent-project ?
: requirements * : default-build * )
{
abstract-target.__init__ $(name) : $(__name__) ;
self.project-module = $(project-module) ;
self.location = [ project.attribute $(project-module) location ] ;
self.requirements = $(requirements) ;
self.default-build = $(default-build) ;
if $(parent-project)
{
inherit $(parent-project) ;
}
}
# This is needed only by the 'make' rule. Need to find the
# way to make 'make' work without this method.
rule project-module ( )
{
return $(self.project-module) ;
}
rule get ( attribute )
{
return [ project.attribute $(self.project-module) $(attribute) ] ;
}
rule build-dir ( )
{
if ! $(self.build-dir)
{
self.build-dir = [ get build-dir ] ;
if ! $(self.build-dir)
{
self.build-dir = [ path.join
[ $(self.project).get location ]
bin
] ;
}
}
return $(self.build-dir) ;
}
# Generates all possible targets contained in this project.
rule generate ( property-set * )
{
if [ modules.peek : .debug-building ]
{
ECHO [ targets.indent ] "building project" [ name ] " ('$(__name__)') with" [ $(property-set).raw ] ;
targets.increase-indent ;
}
local usage-requirements = [ property-set.empty ] ;
local targets ;
for local t in [ targets-to-build ]
{
local g = [ $(t).generate $(property-set) ] ;
usage-requirements = [ $(usage-requirements).add $(g[1]) ] ;
targets += $(g[2-]) ;
}
targets.decrease-indent ;
return $(usage-requirements) [ sequence.unique $(targets) ] ;
}
# Computes and returns a list of abstract-target instances which
# must be built when this project is built.
rule targets-to-build ( )
{
local result ;
if ! $(self.built-main-targets)
{
build-main-targets ;
}
# Collect all main targets here, except for "explicit" ones.
for local t in $(self.main-targets)
{
if ! [ $(t).name ] in $(self.explicit-targets)
{
result += $(t) ;
}
}
# Collect all projects referenced via "projects-to-build" attribute.
local self-location = [ get location ] ;
for local pn in [ get projects-to-build ]
{
local p = [ project.module-name [ path.join $(self-location) $(pn) ] ] ;
result += [ project.target $(p) ] ;
}
return $(result) ;
}
# Add 'target' to the list of targets in this project that should be build
# only by explicit request
rule mark-target-as-explicit ( target-name )
{
# Record the name of the target, not instance, since this
# rule is called before main target instaces are created.
self.explicit-targets += $(target-name) ;
}
# Add new target alternative
rule add-alternative ( target-instance )
{
if $(self.built-main-targets)
{
errors.error "add-alternative called when main targets are already created."
: "in project" [ full-name ] ;
}
self.alternatives += $(target-instance) ;
}
# Returns a 'main-target' class instance corresponding to the 'name'.
rule main-target ( name )
{
if ! $(self.built-main-targets)
{
build-main-targets ;
}
return $(self.main-target.$(name)) ;
}
# Tells if a main target with the specified name exists.
rule has-main-target ( name )
{
if ! $(self.built-main-targets)
{
build-main-targets ;
}
if $(self.main-target.$(name))
{
return true ;
}
}
# Find and return the target with the specified id, treated
# relative to self.
rule find-really ( id )
{
local result ;
local project = $(self.project) ;
local current-location = [ get location ] ;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -