📄 virtual-target.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.
# Implements virtual targets, which correspond to actual files created during
# build, but are not yet targets in Jam sense. They are needed, for example,
# when searching for possible transormation sequences, when it's not known
# if particular target should be created at all.
import "class" : new ;
import path property-set utility sequence errors set type os ;
# +--------------------------+
# | virtual-target |
# +==========================+
# | actualize |
# +--------------------------+
# | actualize-action() = 0 |
# | actualize-location() = 0 |
# +----------------+---------+
# |
# ^
# / \
# +-+-+
# |
# +---------------------+ +-------+--------------+
# | action | | abstract-file-target |
# +=====================| * +======================+
# | action-name | +--+ action |
# | properties | | +----------------------+
# +---------------------+--+ | actualize-action() |
# | actualize() |0..1 +-----------+----------+
# | path() | |
# | adjust-properties() | sources |
# | actualize-sources() | targets |
# +------+--------------+ ^
# | / \
# ^ +-+-+
# / \ |
# +-+-+ +-------------+-------------+
# | | |
# | +------+---------------+ +--------+-------------+
# | | file-target | | searched-lib-target |
# | +======================+ +======================+
# | | actualize-location() | | actualize-location() |
# | +----------------------+ +----------------------+
# |
# +-+------------------------------+
# | |
# +----+----------------+ +---------+-----------+
# | compile-action | | link-action |
# +=====================+ +=====================+
# | adjust-properties() | | adjust-properties() |
# +---------------------+ | actualize-sources() |
# +---------------------+
#
# The 'compile-action' and 'link-action' classes are defined not here,
# but in builtin.jam modules. They are shown in the diagram to give
# the big picture.
# Potential target. It can be converted into jam target and used in
# building, if needed. However, it can be also dropped, which allows
# to search for different transformation and select only one.
#
class virtual-target
{
import virtual-target utility scanner ;
rule __init__ ( name # Name of this target -- specifies the name of
: project # Project to which this target belongs
)
{
self.name = $(name) ;
self.project = $(project) ;
self.dependencies = ;
}
# Name of this target.
rule name ( ) { return $(self.name) ; }
# Project of this target.
rule project ( ) { return $(self.project) ; }
# Adds additional instances of 'virtual-target' that this
# one depends on.
rule depends ( d + )
{
self.dependencies = [ sequence.merge $(self.dependencies)
: [ sequence.insertion-sort $(d) ] ] ;
}
rule dependencies ( )
{
return $(self.dependencies) ;
}
# Generates all the actual targets and sets up build actions for
# this target.
#
# If 'scanner' is specified, creates an additional target
# with the same location as actual target, which will depend on the
# actual target and be associated with 'scanner'. That additional
# target is returned. See the docs (#dependency_scanning) for rationale.
# Target must correspond to a file if 'scanner' is specified.
#
# If scanner is not specified, then actual target is returned.
rule actualize ( scanner ? )
{
local actual-name = [ actualize-no-scanner ] ;
if ! $(scanner)
{
return $(actual-name) ;
}
else
{
# Add the scanner instance to the grist for name.
local g = [ sequence.join
[ utility.ungrist $(actual-name:G) ] $(scanner) : - ] ;
local name = $(actual-name:G=$(g)) ;
if ! $(self.made.$(name)) {
self.made.$(name) = true ;
DEPENDS $(name) : $(actual-name) ;
actualize-location $(name) ;
scanner.install $(scanner) : $(name) $(__name__) ;
}
return $(name) ;
}
}
# private: (overridables)
# Sets up build actions for 'target'. Should call appropriate rules
# and set target variables.
rule actualize-action ( target )
{
errors.error "method should be defined in derived classes" ;
}
# Sets up variables on 'target' which specify its location.
rule actualize-location ( target )
{
errors.error "method should be defined in derived classes" ;
}
# If the target is generated one, returns the path where it will be
# generated. Otherwise, returns empty list.
rule path ( )
{
errors.error "method should be defined in derived classes" ;
}
# Return that actual target name that should be used
# (for the case where no scanner is involved)
rule actual-name ( )
{
errors.error "method should be defined in derived classes" ;
}
# implementation
rule actualize-no-scanner ( )
{
local name = [ actual-name ] ;
# Do anything only on the first invocation
if ! $(self.made.$(name)) {
self.made.$(name) = true ;
virtual-target.register-actual-name $(name) : $(__name__) ;
for local i in $(self.dependencies) {
DEPENDS $(name) : [ $(i).actualize ] ;
}
actualize-location $(name) ;
actualize-action $(name) ;
}
return $(name) ;
}
}
# Target which correspond to a file. The exact mapping for file
# is not yet specified in this class. (TODO: Actually, the class name
# could be better...)
#
# May be a source file (when no action is specified), or
# derived file (otherwise).
#
# The target's grist is concatenation of project's location,
# properties of action (for derived files), and, optionally,
# value identifying the main target.
class abstract-file-target : virtual-target
{
import project regex sequence path type ;
import property-set ;
import indirect ;
rule __init__ (
name # Name for this target
exact ? # If non-empty, the name is exactly the name
# created file should have. Otherwise, the '__init__'
# method will add suffix obtained from 'type' by
# calling 'type.generated-target-suffix'.
: type ? # The type of this target.
: project
: action ?
)
{
virtual-target.__init__ $(name) : $(project) ;
self.type = $(type) ;
self.action = $(action) ;
if $(action)
{
$(action).add-targets $(__name__) ;
if $(self.type) && ! $(exact)
{
_adjust-name $(name) ;
}
}
}
rule type ( ) { return $(self.type) ; }
# Sets the path. When generating target name, it will override any path
# computation from properties.
rule set-path ( path )
{
self.path = [ path.native $(path) ] ;
}
# If 'a' is supplied, sets action to 'a'.
# Returns the action currently set.
rule action ( )
{
return $(self.action) ;
}
# Sets/gets the 'root' flag. Target is root is it directly correspods to some
# variant of a main target.
rule root ( set ? )
{
if $(set)
{
self.root = true ;
}
return $(self.root) ;
}
# Gets or sets the subvariant which created this target. Subvariant
# is set when target is brought into existance, and is never changed
# after that. In particual, if target is shared by subvariant, only
# the first is stored.
rule creating-subvariant ( s ? # If specified, specified the value to set,
# which should be instance of 'subvariant'
# class.
)
{
if $(s) && ( ! $(self.creating-subvariant) && ! $(overwrite) )
{
if $(self.creating-subvariant)
{
errors.error "Attempt to change 'dg'" ;
}
else
{
self.creatin-subvariant = $(s) ;
}
}
return $(self.creatin-subvariant) ;
}
rule actualize-action ( target )
{
if $(self.action)
{
$(self.action).actualize ;
}
}
# Return a human-readable representation of this target
#
# If this target has an action, that's:
#
# { <action-name>-<self.name>.<self.type> <action-sources>... }
#
# otherwise, it's:
#
# { <self.name>.<self.type> }
#
rule str ( )
{
local action = [ action ] ;
local name-dot-type = [ sequence.join $(self.name) "." $(self.type) ] ;
if $(action)
{
local sources = [ $(action).sources ] ;
local action-name = [ $(action).action-name ] ;
local ss ;
for local s in $(sources)
{
ss += [ $(s).str ] ;
}
return "{" $(action-name)-$(name-dot-type) $(ss) "}" ;
}
else
{
return "{" $(name-dot-type) "}" ;
}
}
rule less ( a )
{
if [ str ] < [ $(a).str ]
{
return true ;
}
}
rule equal ( a )
{
if [ str ] = [ $(a).str ]
{
return true ;
}
}
# private:
rule actual-name ( )
{
if ! $(self.actual-name)
{
local grist = [ grist ] ;
local basename = [ path.native $(self.name) ] ;
self.actual-name = <$(grist)>$(basename) ;
}
return $(self.actual-name) ;
}
# Helper to 'actual-name', above. Compute unique prefix used to distinguish
# this target from other targets with the same name which create different
# file.
rule grist ( )
{
# Depending on target, there may be different approaches to generating
# unique prefixes. We'll generate prefixes in the form
# <one letter approach code> <the actual prefix>
local path = [ path ] ;
if $(path)
{
# The target will be generated to a known path. Just use the path
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -