📄 virtual-target.jam
字号:
# File is either source, which will be searched for, or is not a file at
# all. Use the location of project for distinguishing.
local project-location = [ project.attribute $(self.project) location ] ;
local location-grist =
[ sequence.join [ regex.split $(project-location) "/" ] : "!" ] ;
if $(self.action)
{
local ps = [ $(self.action).properties ] ;
local property-grist = [ $(ps).as-path ] ;
location-grist = $(location-grist)/$(property-grist) ;
}
return l$(location-grist) ;
}
}
# Helper to actual-name, above. Compute the 'basename' of the filename
# of the actual created file.
rule actual-basename ( )
{
local name = [ path.native $(self.name) ] ;
if $(self.suffix)
{
name = $(name).$(self.suffix) ;
}
else if $(self.type)
{
local properties ;
if $(self.action)
{
local ps = [ $(self.action).properties ] ;
properties = [ $(ps).raw ] ;
}
local suffix = [ type.generated-target-suffix $(self.type) :
$(properties) ] ;
if $(suffix)
{
name = $(name).$(suffix) ;
}
}
return $(name) ;
}
}
# File target with explicitly known location.
#
# The file path is determined as
# - value passed to the 'set-path' method, if any
# - for derived files, project's build dir, joined with components
# that describe action's properties. If the free properties
# are not equal to the project's reference properties
# an element with name of main target is added.
# - for source files, project's source dir
#
# The file suffix is
# - the value passed to the 'suffix' method, if any, or
# - the suffix which correspond to the target's type.
#
class file-target : abstract-file-target
{
import common ;
import errors ;
rule __init__ (
name
: type ? # Optional type for this target
: project
)
{
abstract-file-target.__init__ $(name) : $(type) : $(project) ;
}
rule actualize-location ( target )
{
if $(self.action)
{
# This is a derived file.
local path = [ path ] ;
LOCATE on $(target) = $(path) ;
# Make sure the path exists.
DEPENDS $(target) : $(path) ;
common.MkDir $(path) ;
}
else
{
# This is a source file.
SEARCH on $(target) =
[ path.native [ project.attribute $(self.project) source-location ] ] ;
}
}
# Returns the directory for this target
rule path ( )
{
if ! $(self.path)
{
if $(self.action)
{
local build-dir = [ project.attribute $(self.project) build-dir ] ;
if ! $(build-dir)
{
build-dir = [ path.join
[ project.attribute $(self.project) location ]
bin
] ;
}
local path = [ path.join
$(build-dir)
[ $(self.action).path ]
] ;
# Store the computed path, so that it's not recomputed
# any more
self.path = [ path.native $(path) ] ;
}
}
return $(self.path) ;
}
}
class notfile-target : abstract-file-target
{
rule __init__ ( name : project )
{
abstract-file-target.__init__ $(name) : : $(project) ;
}
rule actualize-location ( target )
{
NOTFILE $(target) ;
ALWAYS $(target) ;
}
}
# Class which represents an action.
# Both 'targets' and 'sources' should list instances of 'virtual-target'.
# Action name should name a rule with this prototype
# rule action-name ( targets + : sources * : properties * )
# Targets and sources are passed as actual jam targets. The rule may
# not establish dependency relationship, but should do everything else.
class action
{
import type toolset property-set indirect class path ;
rule __init__ ( targets + : sources * : action-name + : property-set ? )
{
self.targets = $(targets) ;
self.sources = $(sources) ;
self.action-name = [ indirect.make-qualified $(action-name) ] ;
if ! $(property-set)
{
property-set = [ property-set.empty ] ;
}
if ! [ class.is-instance $(property-set) ]
{
errors.error "Property set instance required" ;
}
self.properties = $(property-set) ;
}
rule targets ( )
{
return $(self.targets) ;
}
rule sources ( )
{
return $(self.sources) ;
}
rule action-name ( )
{
return $(self.action-name) ;
}
rule properties ( )
{
return $(self.properties) ;
}
# Generates actual build instructions.
rule actualize ( )
{
if ! $(self.actualized)
{
self.actualized = true ;
local ps = [ properties ] ;
local properties = [ adjust-properties [ $(ps).raw ] ] ;
local actual-targets ;
for local i in [ targets ]
{
actual-targets += [ $(i).actualize ] ;
}
actualize-sources [ sources ] ;
DEPENDS $(actual-targets) : $(self.actual-sources) $(self.dependency-only-sources) ;
# Action name can include additional argument to rule, which should not
# be passed to 'set-target-variables'
toolset.set-target-variables
[ indirect.get-rule $(self.action-name[1]) ] $(actual-targets)
: $(properties) ;
indirect.call $(self.action-name)
$(actual-targets) : $(self.actual-sources) : $(properties)
;
# Since we set up creating action here, we also set up
# action for cleaning up
common.Clean clean : $(actual-targets) ;
}
}
# Helper for 'actualize-sources'.
# For each passed source, actualizes it with the appropriate scanner.
# Returns the actualized virtual targets.
rule actualize-source-type ( sources * )
{
local result = ;
for local i in $(sources)
{
local scanner ;
if [ $(i).type ]
{
scanner =
[ type.get-scanner [ $(i).type ] : $(properties) ] ;
}
result += [ $(i).actualize $(scanner) ] ;
}
return $(result) ;
}
# Creates actual jam targets for sources. Initialized two member
# variables:.
# 'self.actual-sources' -- sources which are passed to updating action
# 'self.dependency-only-sources' -- sources which are made dependencies, but
# are not used otherwise.
#
# New values will be *appended* to the variables. They may be non-empty,
# if caller wants it.
rule actualize-sources ( sources * )
{
local dependencies = [ $(self.properties).get <dependency> ] ;
self.dependency-only-sources += [ actualize-source-type $(dependencies) ] ;
self.actual-sources += [ actualize-source-type $(sources) ] ;
}
rule path ( )
{
local p = [ $(self.properties).as-path ] ;
# Really, an ugly hack. Boost regression test system requires
# specific target paths, and it seems that changing it to handle
# other directory layout is really hard. For that reason,
# we teach V2 to do the things regression system requires.
# The value o '<location-prefix>' is predended to the path.
local prefix = [ $(self.properties).get <location-prefix> ] ;
if $(prefix)
{
p = [ path.join $(prefix) $(p) ] ;
}
return $(p) ;
}
# Determined real properties when trying building with 'properties'.
# This is last chance to fix properties, for example to adjust includes
# to get generated headers correctly. Default implementation returns
# its argument.
rule adjust-properties ( properties * )
{
return $(properties) ;
}
rule set-targets ( targets * )
{
self.targets = $(targets) ;
}
}
# Action class which does nothing --- it produces the targets with
# specific properties out of nowhere. It's needed to distinguish virtual
# targets with different properties that are known to exist, and have no
# actions which create them.
class null-action : action
{
rule __init__ ( targets + : property-set ? )
{
action.__init__ $(targets) : : .no-action : $(property-set) ;
}
rule actualize ( )
{
if ! $(self.actualized)
{
self.actualized = true ;
for local i in [ targets ]
{
$(i).actualize ;
}
}
}
}
# Creates a virtual target with approariate name and type from 'file'.
# If a target with that name in that project was already created, returns that already
# created target.
# FIXME: more correct way would be to compute path to the file, based on name and source location
# for the project, and use that path to determine if the target was already created.
# TODO: passing project with all virtual targets starts to be annoying.
rule from-file ( file : project )
{
import type ; # had to do this here to break a circular dependency
if $(.files.$(file).$(project))
{
return $(.files.$(file).$(project)) ;
}
else
{
local name = [ path.make $(file:S=) ] ;
local type = [ type.type $(file) ] ;
local result ;
if ! $(type)
{
# warning "cannot determine type for file $(file)" ;
result = [ new file-target $(file) : : $(project) ] ;
}
else
{
local v = [ new file-target $(name) : $(type) : $(project) ] ;
$(v).suffix [ MATCH ^.(.*)$ : $(file:S) ] ;
result = $(v) ;
}
.files.$(file).$(project) = $(result) ;
return $(result) ;
}
}
# Registers a new virtual target. Checks if there's already registered target, with the same
# name, type, project and subvariant properties, and also with the same sources
# and equal action. If such target is found it is retured and 'target' is not registers.
# Otherwise, 'target' is registered and returned.
rule register ( target )
{
local signature = [ sequence.join
[ $(target).project ] [ $(target).name ] [ $(target).type ] : - ] ;
local result ;
for local t in $(.cache.$(signature))
{
local a1 = [ $(t).action ] ;
local a2 = [ $(target).action ] ;
if ! $(result)
{
if ! $(a1) && ! $(a2)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -