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

Introduce the 'property-set' class, which is used instead of

plain old lists of properties in most cases where we need property sets.

The changes are too numerous and mostly automatic to comment each one.


[SVN r17305]
This commit is contained in:
Vladimir Prus
2003-02-10 14:40:38 +00:00
parent 6944a6cb23
commit 8e8891b7dd
15 changed files with 459 additions and 350 deletions

View File

@@ -6,6 +6,7 @@ import project ;
import sequence ;
import modules ;
import feature ;
import property-set ;
import build-request ;
import errors : error ;
@@ -109,8 +110,9 @@ if $(expanded)
for local p in $(expanded)
{
for local t in $(targets)
{
$(t).direct-build-request [ feature.split $(p) ] ;
{
$(t).direct-build-request
[ property-set.create [ feature.split $(p) ] ] ;
}
}
@@ -118,7 +120,8 @@ if $(expanded)
{
for local t in $(targets)
{
virtual-targets += [ $(t).generate [ feature.split $(p) ] ] ;
virtual-targets += [ $(t).generate
[ property-set.create [ feature.split $(p) ] ] ] ;
}
}
}
@@ -126,7 +129,7 @@ else
{
for local t in $(targets)
{
virtual-targets += [ $(t).generate ] ;
virtual-targets += [ $(t).generate [ property-set.empty ] ] ;
}
}

View File

@@ -293,8 +293,9 @@ rule lib-generator ( )
{
composing-generator.__init__ lib-generator : : LIB : <main-target-type>LIB ;
rule run ( project name ? : properties * : sources * )
rule run ( project name ? : property-set : sources * )
{
local properties = [ $(property-set).raw ] ;
# Determine the needed target type
local actual-type ;
if <search> in $(properties:G) || <name> in $(properties:G)
@@ -311,8 +312,8 @@ rule lib-generator ( )
}
# Construct the target. Pass 'allow-composing', since generators for
# library types are composing and we need to find them.
return [ generators.construct $(project) $(name) : $(actual-type) : $(properties)
: $(sources) : allow-composing ] ;
return [ generators.construct $(project) $(name) : $(actual-type)
: $(property-set) : $(sources) : allow-composing ] ;
}
}

View File

@@ -157,6 +157,7 @@ rule generator (
# in returned set must be present in build properties if this
# generator is to be used. If result has grist-only element,
# that build properties must include some value of that feature.
# XXX: remove this method?
rule requirements ( )
{
return $(self.requirements) ;
@@ -173,7 +174,7 @@ rule generator (
# Returns a number telling how good generator's properties match
# the passed properties, or empty list if generator can't be run
# at all.
rule match-rank ( properties * )
rule match-rank ( property-set )
{
# See if generator's requirements are satisfied by 'properties'.
# Treat feature name in requirements (i.e. grist-only element),
@@ -192,7 +193,8 @@ rule generator (
features += $(r) ;
}
}
local properties = [ $(property-set).raw ] ;
if $(requirements) in $(properties) && $(features) in $(properties:G)
{
return [ sequence.length [ set.intersection
@@ -217,7 +219,7 @@ rule generator (
rule run ( project # Project for which the targets are generated
name ? # Determines the name of 'name' attribute for
# all generated targets. See 'generated-targets' method.
: properties * # Desired properties for generated targets.
: property-set # Desired properties for generated targets.
: sources + : # Source targets.
multiple ? # Allows the rule to run generator several times and return
# multiple targets of the same type. When this argument is not
@@ -230,7 +232,7 @@ rule generator (
{
generators.dout [ indent ] " generator" $(self.id) ;
generators.dout [ indent ] " multiple:" $(mutliple) ;
# Ordinary generators take only one source targets
if $(sources[2])
{
@@ -248,7 +250,7 @@ rule generator (
local bypassed = ;
convert-to-consumable-types $(project) $(name) :
$(properties) : $(sources) : $(multiple)
$(property-set) : $(sources) : $(multiple)
:
: consumed bypassed ;
@@ -256,7 +258,7 @@ rule generator (
if $(consumed)
{
result = [ construct-result $(consumed) : $(project) $(name)
: $(properties) ] ;
: $(property-set) ] ;
}
if $(result)
@@ -301,7 +303,7 @@ rule generator (
# Otherwise, might contain several targets with the type of
# $(self.source-types[1])
: project name ?
: properties * # Properties to be used for all actions create here
: property-set # Properties to be used for all actions create here
)
{
local result ;
@@ -311,7 +313,7 @@ rule generator (
generators.dout [ indent ] "alt1" ;
for local r in $(consumed)
{
result += [ generated-targets $(r) : $(properties) : $(project) $(name) ] ; #(targets) ;
result += [ generated-targets $(r) : $(property-set) : $(project) $(name) ] ; #(targets) ;
}
}
else
@@ -320,7 +322,8 @@ rule generator (
generators.dout [ indent ] "alt2 : consumed is" [ $(v).str ] ;
if $(consumed)
{
result += [ generated-targets $(consumed) : $(properties) : $(project) $(name) ] ;
result += [ generated-targets $(consumed) : $(property-set)
: $(project) $(name) ] ;
}
}
return $(result) ;
@@ -346,7 +349,7 @@ rule generator (
# Note that this pattern mechanism has nothing to do with implicit patterns
# in make. It's a way to produce target which name is different for name of
# source.
rule generated-targets ( sources + : properties * : project name ? )
rule generated-targets ( sources + : property-set : project name ? )
{
if ! $(name)
{
@@ -382,7 +385,8 @@ rule generator (
}
# Assign an action for each target
local action = [ action-class ] ;
local a = [ new $(action) $(targets) : $(sources) : $(self.id) : $(properties) ] ;
local a = [ new $(action) $(targets) : $(sources) : $(self.id) :
$(property-set) ] ;
for local t in $(targets)
{
$(t).action $(a) ;
@@ -395,7 +399,7 @@ rule generator (
# handle. The intention is to produce the set of targets can should be
# used when generator is run.
rule convert-to-consumable-types ( project name ? :
properties * : source : multiple ?
property-set : source : multiple ?
: only-one ? # convert 'source' to only one of source types
# if there's more that one possibility, report an
# error
@@ -449,7 +453,7 @@ rule generator (
if $(missing-types)
{
local transformed = [ generators.construct-types $(project) $(name)
: $(missing-types) : $(multiple) : $(properties) : $(source) ] ;
: $(missing-types) : $(multiple) : $(property-set) : $(source) ] ;
# Add targets of right type to 'consumed'. Add others to
# 'bypassed'. The 'generators.construct' rule has done
@@ -468,8 +472,7 @@ rule generator (
}
}
}
$(consumed-var) += $(_consumed) ;
$(bypassed-var) += $(_bypassed) ;
}
@@ -492,7 +495,7 @@ rule composing-generator ( id : source-types * : target-types + :
generator.__init__ $(id) : $(source-types) : $(target-types) :
$(requirements) ;
rule run ( project name ? : properties * : sources + )
rule run ( project name ? : property-set : sources + )
{
generators.dout [ indent ] " composing generator" $(self.id) ;
@@ -507,7 +510,7 @@ rule composing-generator ( id : source-types * : target-types + :
local c ;
local b ;
# TODO: need to check for failure on each source.
convert-to-consumable-types $(project) : $(properties)
convert-to-consumable-types $(project) : $(property-set)
: $(sources[1]) : * : true : c b ;
if ! $(c)
{
@@ -523,7 +526,8 @@ rule composing-generator ( id : source-types * : target-types + :
if ! $(failed)
{
generators.dout [ indent ] " SUCCESS" ;
result += [ generated-targets $(consumed) : $(properties) : $(project) $(name) ] ;
result += [ generated-targets $(consumed) : $(property-set)
: $(project) $(name) ] ;
result += $(bypassed) ;
}
else
@@ -622,9 +626,9 @@ rule base-to-derived-type-conversion ( targets * : target-types +
rule try-one-generator ( project name ? : generator multiple ? :
target-types + : properties * : sources * )
target-types + : property-set : sources * )
{
local targets = [ $(generator).run $(project) $(name) : $(properties) : $(sources)
local targets = [ $(generator).run $(project) $(name) : $(property-set) : $(sources)
: $(multiple) ] ;
# Generated targets that are of required types
@@ -644,8 +648,8 @@ rule try-one-generator ( project name ? : generator multiple ? :
{
for local e in $(extra)
{
local try2 = [ construct-types $(project) $(name) : $(target-types) : : $(properties)
: $(e) ] ;
local try2 = [ construct-types $(project) $(name)
: $(target-types) : : $(property-set) : $(e) ] ;
result += $(try2) ;
}
@@ -662,13 +666,13 @@ rule try-one-generator ( project name ? : generator multiple ? :
}
rule construct-types ( project name ? : target-types + : multiple ? :
properties * : source )
property-set : source )
{
local result ;
local matched-types ;
for local t in $(target-types)
{
local r = [ construct $(project) $(name) : $(t) $(multiple) : $(properties) :
local r = [ construct $(project) $(name) : $(t) $(multiple) : $(property-set) :
$(source) ] ;
if $(r)
{
@@ -719,7 +723,7 @@ local rule ensure-type ( targets * )
#
# Note: this algorithm explicitly ignores generators for base classes if there's
# at least one generator for requested target-type.
local rule find-viable-generators ( target-type : properties * : allow-composing ? )
local rule find-viable-generators ( target-type : property-set : allow-composing ? )
{
# Select generators that can create the required target type.
local viable-generators = ;
@@ -738,7 +742,7 @@ local rule find-viable-generators ( target-type : properties * : allow-composing
if ! $(g) in $(.active-generators)
&& ! ( [ is-a $(g) : composing-generator ] && ! $(allow-composing) )
{
local m = [ $(g).match-rank $(properties) ] ;
local m = [ $(g).match-rank $(property-set) ] ;
if $(m)
{
viable-generators += $(g) ;
@@ -803,7 +807,7 @@ local rule select-dependency-graph ( options )
# Attempt to construct the target by looking at transformation cache.
local rule construct-with-caching (
project name ? : target-type multiple ? : properties * : sources * )
project name ? : target-type multiple ? : property-set : sources * )
{
local result ;
if ! $(.caching) && ! $(sources[2]) && $(sources[1]) && ! $(name)
@@ -812,7 +816,7 @@ local rule construct-with-caching (
local t = $(sources[1]) ;
local signature = [ sequence.join [ $(t).type ] $(target-type) $(properties) : - ] ;
local signature = [ sequence.join [ $(t).type ] $(target-type) $(property-set) : - ] ;
# Get a transformation template from cache or create it.
local cresult ;
@@ -823,7 +827,8 @@ local rule construct-with-caching (
else
{
local ut = [ new file-target % : [ $(t).type ] : "no project" ] ;
cresult = [ construct $(project) : $(target-type) $(multiple) : $(properties) : $(ut) ] ;
cresult = [ construct $(project) : $(target-type) $(multiple)
: $(property-set) : $(ut) ] ;
.transformation.cache.$(signature) = $(cresult) ;
}
@@ -846,9 +851,9 @@ local rule construct-with-caching (
# Attempts to construct target by finding viable generators, running them
# and selecting the dependency graph
local rule construct-without-caching (
project name ? : target-type multiple ? : properties * : sources * )
project name ? : target-type multiple ? : property-set : sources * )
{
viable-generators = [ find-viable-generators $(target-type) : $(properties)
viable-generators = [ find-viable-generators $(target-type) : $(property-set)
: $(allow-composing) ] ;
local results = [ new vector ] ;
@@ -862,7 +867,7 @@ local rule construct-without-caching (
local .active-generators = $(g) $(.active-generators) ;
local r = [ try-one-generator $(project) $(name) : $(g) $(multiple) : $(target-type) :
$(properties) : $(sources) ] ;
$(property-set) : $(sources) ] ;
if $(r)
{
@@ -885,7 +890,7 @@ local rule construct-without-caching (
# 'construct' in stack, returns only targets of requested 'target-type',
# otherwise, returns also unused sources and additionally generated
# targets.
rule construct ( project name ? : target-type multiple ? : properties * : sources *
rule construct ( project name ? : target-type multiple ? : property-set * : sources *
: allow-composing ? # Allows to use composing generators for constructing this
# target. This will be typically set when creating main targets,
# and unset when called recursively from 'run' method of
@@ -905,8 +910,8 @@ rule construct ( project name ? : target-type multiple ? : properties * : source
usage-requirements += [ $(e).usage-requirements ] ;
}
}
properties += $(usage-requirements) ;
properties = [ sequence.unique $(properties) ] ;
property-set = [ $(property-set).add
[ property-set.create $(usage-requirements) ] ] ;
.construct-stack += 1 ;
@@ -926,11 +931,11 @@ rule construct ( project name ? : target-type multiple ? : properties * : source
generators.dout [ indent ] " properties:" $(properties) ;
local result = [ construct-with-caching $(project) $(name)
: $(target-type) $(multiple) : $(properties) : $(sources) ] ;
: $(target-type) $(multiple) : $(property-set) : $(sources) ] ;
if ! $(result) {
result = [ construct-without-caching $(project) $(name)
: $(target-type) $(multiple) : $(properties) : $(sources) ] ;
: $(target-type) $(multiple) : $(property-set) : $(sources) ] ;
}
decrease-indent ;
@@ -940,8 +945,8 @@ rule construct ( project name ? : target-type multiple ? : properties * : source
if ! $(.construct-stack) # This is first invocation in stack
{
# Make roots of dependency graph depend on all 'dependency' features.
local dp = [ property.take dependency : $(properties) ] ;
local dp = [ $(property-set).dependency ] ;
if $(dp)
{
for local t in $(result)

View File

@@ -12,21 +12,23 @@ import property ;
import errors : error ;
import type : type ;
import regex ;
import property-set ;
rule make-target-class ( name : project : sources * : requirements *
: make-rule + : default-build * )
{
basic-target.__init__ $(name) : $(project) : $(sources) : $(requirements)
: $(default-build) ;
self.make-rule = $(make-rule) ;
rule construct ( source-targets * : properties * )
rule construct ( source-targets * : property-set )
{
local t = [ new file-target $(self.name:S=) : [ type.type $(self.name:S) ]
: $(self.project) ] ;
$(t).suffix [ regex.match .(.*) : $(self.name:S) ] ;
local a = [ new action $(t) : $(source-targets) : $(self.make-rule)
: $(properties) ] ;
: $(property-set) ] ;
$(t).action $(a) ;
return $(t) ;
}

View File

@@ -21,8 +21,9 @@ rule prebuilt-file-generator
{
generator.__init__ prebuilt-file-generator : : * : <file> ;
rule run ( project name ? : properties * : sources * )
rule run ( project name ? : property-set : sources * )
{
local properties = [ $(property-set).raw ] ;
local name = [ feature.get-values <file> : $(properties) ] ;
local type = [ type.type $(name:S) ] ;
if ! $(type)
@@ -42,7 +43,7 @@ rule prebuilt-file-generator
# Therefore, we encode properties via 'extra-grist', which is ugly.
# Maybe, we should just introduce 'do-nothing-action', which only
# keps properties.
$(t).extra-grist [ property.as-path $(properties) ] ;
$(t).extra-grist [ $(property-set).as-path ] ;
$(t).suffix [ MATCH .(.*) : $(name:S) ] ;
return $(t) ;

View File

@@ -386,6 +386,14 @@ local rule initialize (
[ path.relative $(our-dir) $(parent-dir) ] ] : exact ;
}
}
else
{
$(attributes).set requirements
: [ property-set.empty ] : exact ;
$(attributes).set usage-requirements
: [ property-set.empty ] : exact ;
}
}
# Associate the given id with the given location
@@ -416,9 +424,16 @@ rule project-attributes ( location )
{
specification = [ property.translate-paths $(specification)
: $(self.location) ] ;
local current = $(self.requirements) ;
local result = [ property.refine $(current) :
[ property.make $(specification) ] ] ;
specification = [ property.make $(specification) ] ;
result = [ property-set.create $(specification) ] ;
# If we have inherited properties, need to refine them with the
# specified.
local current = $(self.requirements) ;
if $(current)
{
result = [ $(current).refine $(result) ] ;
}
if $(result[1]) = "@error"
{
@@ -439,8 +454,17 @@ rule project-attributes ( location )
{
errors.error "usage-requirements" $($(real-pos2)) "have non-free properties" $(non-free) ;
}
self.usage-requirements += [ property.translate-paths $(specification)
local t = [ property.translate-paths $(specification)
: $(self.location) ] ;
if $(self.usage-requirements)
{
self.usage-requirements = [ property-set.create
[ $(self.usage-requirements).raw ] $(t) ] ;
}
else
{
self.usage-requirements = [ property-set.create $(t) ] ;
}
}
else if $(attribute) = "source-location"
{
@@ -480,7 +504,7 @@ rule project-attributes ( location )
print.list-start ;
print.list-item "Project root:" $(self.project-root) ;
print.list-item "Parent project:" $(parent) ;
print.list-item "Requirements:" $(self.requirements) ;
print.list-item "Requirements:" [ $(self.requirements).raw ] ;
print.list-item "Default build:" $(self.default-build) ;
print.list-item "Source location:" $(self.source-location) ;
print.list-item "Projects to build:"

View File

@@ -72,6 +72,7 @@ import regex ;
import property ;
import errors ;
import common ;
import property-set ;
# Base class for all abstract targets.
@@ -109,7 +110,7 @@ rule abstract-target ( name # name of the target in Jamfile
# Adds one more direct build request for this target. If later generate
# is called with the same non-free non-incidental properties as in one
# of direct build requests, then that build request is used instead.
rule direct-build-request ( properties * )
rule direct-build-request ( property-set )
{
}
@@ -122,7 +123,7 @@ rule abstract-target ( name # name of the target in Jamfile
#
# If 'properties' are empty, performs default build of this target, in a way specific
# to derived class.
rule generate ( properties * )
rule generate ( property-set )
{
errors.error "method should be defined in derived classes" ;
}
@@ -137,29 +138,30 @@ rule project-target ( name : project : requirements * : default-build * )
self.requirements = $(requirements) ;
self.default-build = $(default-build) ;
rule direct-build-request ( properties * )
rule direct-build-request ( property-set )
{
for local name in $(self.main-targets)
{
local t = [ main-target $(name) ] ;
result += [ $(t).direct-build-request $(properties) ] ;
result += [ $(t).direct-build-request $(property-set) ] ;
}
for local pn in [ project.attribute $(self.project) projects-to-build ]
{
local p = [ project.module-name $(pn) ] ;
local t = [ project.target [ project.attribute $(p) location ] ] ;
result += [ $(t).direct-build-request $(properties) ] ;
result += [ $(t).direct-build-request $(property-set) ] ;
}
}
# Generates all possible targets contained in this project.
rule generate ( properties * )
rule generate ( property-set * )
{
# Project properties are directly imposed on all main targets.
# However, we'd need to check if this project can be build at
# all.
local xproperties =
[ property.refine $(properties) : $(self.requirements) ] ;
local xproperties = [ $(property-set).refine $(self.requirements) ] ;
if $(xproperties[1]) = "@error"
{
local id = [ project.attribute $(self.project) id ] ;
@@ -168,7 +170,7 @@ rule project-target ( name : project : requirements * : default-build * )
"due to unsatisfied requirements." ;
print.wrapped-text "warning: explanation: " $(xproperties[2-]) ;
print.wrapped-text "warning: build-request: " $(properties) ;
print.wrapped-text "warning: requirements: " $(self.requirements) ;
print.wrapped-text "warning: requirements: " [ $(self.requirements).raw ] ;
}
else
{
@@ -176,14 +178,14 @@ rule project-target ( name : project : requirements * : default-build * )
for local name in $(self.main-targets)
{
local t = [ main-target $(name) ] ;
result += [ $(t).generate $(properties) ] ;
result += [ $(t).generate $(property-set) ] ;
}
local self-location = [ project.attribute $(self.project) location ] ;
for local pn in [ project.attribute $(self.project) projects-to-build ]
{
local p = [ project.module-name [ path.join $(self-location) $(pn) ] ] ;
local t = [ project.target [ project.attribute $(p) location ] ] ;
result += [ $(t).generate $(properties) ] ;
result += [ $(t).generate $(property-set) ] ;
}
return $(result) ;
}
@@ -215,19 +217,19 @@ rule project-target ( name : project : requirements * : default-build * )
# target in this project, if generation with
# 'properties' is requested, and that main target
# does not have any requirements of its own.
rule reference-properties ( properties * )
rule reference-properties ( property-set )
{
# Note that free properties can appear on 'properties' only
# from direct build request, because free properties are not
# allowed to be propagated.
local ref = [ project.attribute $(self.project) requirements ] ;
ref = [ property.refine $(properties) : $(ref) ] ;
ref = [ property.evaluate-conditionals $(ref) ] ;
ref = [ property.take free : [ property.remove incidental : $(ref) ] ] ;
ref = [ targets.generate-dependencies $(ref) : $(self.project) ] ;
return $(ref) ;
}
if ! $(self.ref-props.$(property-set))
{
local ref = [ project.attribute $(self.project) requirements ] ;
local ps = [ $(property-set).refine $(ref) ] ;
ps = [ $(ps).evaluate-conditionals ] ;
ps = [ targets.generate-dependencies $(ps) : $(self.project) : $(ps) ] ;
self.ref-props.$(property-set) = $(ps) ;
}
return $(self.ref-props.$(property-set)) ;
}
}
class project-target : abstract-target ;
@@ -246,9 +248,9 @@ rule main-target ( name : project )
self.alternatives += $(target) ;
}
rule direct-build-request ( properties * )
rule direct-build-request ( property-set )
{
local base = [ property.remove free incidental : $(properties) ] ;
local base = [ $(property-set).base ] ;
local ep = $(self.direct-request.$(base:J=-)) ;
if $(ep) && $(ep) != $(properties)
{
@@ -256,7 +258,7 @@ rule main-target ( name : project )
}
else
{
self.direct-request.$(base:J=-) = $(properties) ;
self.direct-request.$(base:J=-) = $(property-set) ;
}
}
@@ -265,13 +267,13 @@ rule main-target ( name : project )
# which requirements are satisfied by 'properties' and picking the one with
# longest requirements set.
# Returns the result of calling 'generate' on that alternative.
rule generate ( properties * )
rule generate ( property-set )
{
local base = [ property.remove free incidental : $(properties) ] ;
local base = [ $(property-set).base ] ;
local ep = $(self.direct-request.$(base:J=-)) ;
if $(ep)
{
properties = $(ep) ;
property-set = $(ep) ;
}
# Try to generate all the alternatives.
@@ -279,7 +281,7 @@ rule main-target ( name : project )
for local v in $(self.alternatives)
{
local vtargets = [ $(v).generate $(properties) ] ;
local vtargets = [ $(v).generate $(property-set) ] ;
if $(vtargets) && $(vtargets[1]) != "@error"
{
$(alternatives).push-back [ new vector $(v) $(vtargets) ] ;
@@ -291,7 +293,7 @@ rule main-target ( name : project )
# why it can't be build.
print.wrapped-text
"warning: skipped build of" [ full-name ]
"with properties" $(properties) ;
"with properties" [ $(property-set).raw ] ;
} else {
local result ;
if [ $(alternatives).size ] = 1
@@ -314,9 +316,9 @@ rule main-target ( name : project )
# have 'requirements' method.
# assert.equal [ is-a $(target) : basic-target ] : true ;
local req = [ $(target).requirements ] ;
req = [ property.remove free incidental : $(req) ] ;
req = [ $(req).base ] ;
req-length += [ sequence.length
[ set.intersection $(req) : $(properties) ] ] ;
[ set.intersection $(req) : [ $(property-set).raw ] ] ] ;
}
local best = [ sequence.select-highest-ranked $(r) : $(req-length) ] ;
@@ -343,7 +345,7 @@ rule main-target ( name : project )
# is created.
local all-targets =
[ sequence.transform virtual-target.traverse : $(result) ] ;
local dg = [ new subvariant-dg $(__name__) : $(properties) : $(all-targets) ] ;
local dg = [ new subvariant-dg $(__name__) : $(property-set) : $(all-targets) ] ;
for local v in $(all-targets)
{
$(v).dg $(dg) ;
@@ -361,7 +363,7 @@ class main-target : abstract-target ;
# reference.
rule generate ( target-reference # Target reference
: project # Project where the reference is made
: properties * # Properties of the main target that
: property-set # Properties of the main target that
# makes the reference
)
{
@@ -382,8 +384,9 @@ rule generate ( target-reference # Target reference
if $(main-target) {
# Take properties which should be propagated and refine them
# with source-specific requirements.
local propagated = [ property.take propagated : $(properties) ] ;
local rproperties = [ property.refine $(propagated) : $(sproperties) ] ;
local propagated = [ $(property-set).propagated ] ;
local rproperties = [ $(propagated).refine
[ property-set.create $(sproperties) ] ] ;
if $(rproperties[1]) = "@error"
{
errors.error
@@ -395,42 +398,32 @@ rule generate ( target-reference # Target reference
}
}
# Returns a list of properties, where all dependency properties are
# replaced as follows:
# - the value of dependency property is treated as target reference,
# which is generated with 'properties' + 'extra-properties'
# - the created virtual target's become replace the property value,
# for example <library>a/b might become
# <library>object(virtual-target)@1
# In addition, usage requirements for all created virtual targets
# are added to the properties.
# Returns new property set which inclues all properties from
# 'property-set', except that all dependency properties are
# generated with 'generation-ps', and the obtained virtual targets
# are added as the values of original features.
#
# The purpose of 'extra-properties' is to be able to replace dependency
# features only in certain set of properties, which does not include
# all build properties. A concrete example is when we process use properties.
# Dependency features must be replaced using full build properties of target,
# but we don't want to add build properties to usage requirements.
rule generate-dependencies ( properties * : project : extra-properties * )
# For example, <library>a/b might become <library>object(virtual-target)@1
# In addition, usage requirements for all created virtual targets
# are added to the created property set.
rule generate-dependencies ( property-set : project : generation-ps )
{
local xproperties ;
for local p in $(properties)
local xproperties ;
for local p in [ $(property-set).dependency ]
{
if dependency in [ feature.attributes $(p:G) ]
local g = [ targets.generate $(p:TG=) : $(project) : $(generation-ps) ] ;
if ! $(g)
{
local g = [ targets.generate $(p:TG=) : $(project)
: $(properties) $(extra-properties) ] ;
if ! $(g)
{
errors.error "cannot generate dependency " $(p) ;
}
xproperties += $(p:G)$(g) [ $(g).usage-requirements ] ;
errors.error "cannot generate dependency " $(p) ;
}
else
{
xproperties += $(p) ;
}
xproperties += $(p:G)$(g) [ $(g).usage-requirements ] ;
}
return $(xproperties) ;
local r = [ property-set.create
[ $(property-set).base ]
[ $(property-set).free ]
$(xproperties)
[ $(property-set).incidental ] ] ;
return $(r) ;
}
@@ -448,8 +441,15 @@ rule basic-target ( name : project
abstract-target.__init__ $(name) : $(project) ;
self.sources = $(sources) ;
if ! $(requirements) {
requirements = [ property-set.empty ] ;
}
self.requirements = $(requirements) ;
self.default-build = $(default-build) ;
if ! $(usage-requirements)
{
usage-requirements = [ property-set.empty ] ;
}
self.usage-requirements = $(usage-requirements) ;
if $(sources:G)
@@ -463,35 +463,31 @@ rule basic-target ( name : project
# Generates sources. Calls 'construct'
# This method should not be overriden.
#
rule generate ( properties * )
rule generate ( property-set )
{
if ! $(properties) || $(properties:G) = <toolset>
if ! [ $(property-set).raw ]
{
# CONSIDER: I'm really not sure if this is correct...
# FIXME: as in 'build-system' we stick default toolset
properties = [ build-request.expand $(properties)
$(self.default-build) ] ;
properties = [ build-request.expand $(self.default-build) ] ;
local result = ;
for local p in $(properties)
{
result += [ generate [ feature.split $(p) ] ] ;
result += [ generate [ property-set.create [ feature.split $(p) ] ] ] ;
}
return $(result) ;
} else {
property-path = [ property.as-path
[ property.remove free incidental : $(properties) ] ] ;
property-path = [ property.as-path [ $(property-set).base ] ] ;
if ! $(property-path)
{
property-path = X ;
}
if ! $(self.generated.$(property-path))
{
local rproperties =
[ property.refine $(properties) : $(self.requirements) ] ;
rproperties = [ property.evaluate-conditionals $(rproperties) ] ;
local rproperties = [ $(property-set).refine $(self.requirements) ] ;
if $(rproperties[1]) != "@error"
{
@@ -503,9 +499,12 @@ rule basic-target ( name : project
# requirements may also code from dependencies. However, when they
# come from dependencies, the value is not target id, but rather
# virtual target names, so generators.construct can use them.
rproperties = [ $(rproperties).evaluate-conditionals ] ;
local xproperties =
[ targets.generate-dependencies $(rproperties) : $(self.project) ] ;
[ targets.generate-dependencies $(rproperties) : $(self.project)
: $(rproperties) ] ;
local source-targets ;
@@ -513,7 +512,7 @@ rule basic-target ( name : project
{
# Try treating this source as reference to main target
local more-targets =
[ targets.generate $(s) : $(self.project) : $(properties) ] ;
[ targets.generate $(s) : $(self.project) : $(property-set) ] ;
if $(more-targets)
{
source-targets += $(more-targets) ;
@@ -529,16 +528,19 @@ rule basic-target ( name : project
# unqual to project's reference properties. As the
# result, we create per-target bin directory while
# it's not really needed.
xproperties = [ feature.run-actions $(xproperties) ] ;
xproperties = [ $(xproperties).run-actions ] ;
self.generated.$(property-path) =
[ construct $(source-targets) : $(xproperties) ] ;
# Apply use requirement of this target to all generated
# virtual targets.
local xusage-requirements =
[ targets.generate-dependencies $(self.usage-requirements)
[ targets.generate-dependencies
$(self.usage-requirements)
: $(self.project) : $(rproperties) ] ;
xusage-requirements = [ $(xusage-requirements).raw ] ;
for local e in $(self.generated.$(property-path))
{
@@ -579,11 +581,11 @@ rule typed-target ( name : project : type
self.type = $(type) ;
rule construct ( source-targets * : properties * )
rule construct ( source-targets * : property-set )
{
local r = [ generators.construct $(self.project) $(self.name) : $(self.type)
: $(properties) # [ feature.expand
<main-target-type>$(self.type)
: [ property-set.create [ $(property-set).raw ] # [ feature.expand
<main-target-type>$(self.type) ]
# ]
: $(source-targets)
: allow-composing ] ;
@@ -609,8 +611,9 @@ rule main-target-requirements (
{
local loc = [ project.attribute $(project) location ] ;
local requirements = [ property.translate-paths $(specification) : $(loc) ] ;
local requirements = [ property-set.create $(requirements) ] ;
local project-requirements = [ project.attribute $(project) requirements ] ;
requirements = [ property.refine $(project-requirements) : $(requirements) ] ;
requirements = [ $(project-requirements).refine $(requirements) ] ;
if $(requirements[1]) = "@error"
{
errors.error "Conflicting requirements for target:" $(requirements) ;
@@ -629,11 +632,11 @@ rule main-target-usage-requirements (
{
local loc = [ project.attribute $(project) location ] ;
local project-usage-requirements = [ project.attribute $(project) usage-requirements ] ;
local usage-requirements = [ property.translate-paths $(specification) : $(loc) ] ;
usage-requirements += $(project-usage-requirements) ;
return $(usage-requirements) ;
local usage-requirements = [ property-set.create
[ property.translate-paths $(specification) : $(loc) ] ] ;
return [ $(project-usage-requirements).add $(usage-requirements) ] ;
}
# Return the default build value to use when declaring a main target,

View File

@@ -10,6 +10,8 @@
import class : class new ;
import type ;
import property-set ;
import utility ;
# +--------------------------+
# | virtual-target |
@@ -349,8 +351,8 @@ rule abstract-file-target ( name
local properties ;
if $(self.action)
{
properties = [ property.remove free incidental : [ $(self.action).properties ] ] ;
local property-grist = [ property.as-path $(properties) ] ;
local ps = [ $(self.action).properties-ps ] ;
local property-grist = [ $(ps).as-path ] ;
grist = $(location-grist)/$(property-grist) ;
}
if ! $(grist)
@@ -447,21 +449,16 @@ rule file-target (
{
if $(self.action)
{
local properties = [ property.take free : [ property.remove incidental :
[ $(self.action).properties ] ] ] ;
local ps = [ $(self.action).properties-ps ] ;
local main-target = [ $(self.dg).main-target ] ;
local project = [ $(main-target).project ] ;
local plocation = [ project.attribute $(project) location ] ;
local ptarget = [ project.target $(plocation) ] ;
local ref = [ $(ptarget).reference-properties [ $(self.dg).properties ] ] ;
local ref-ps = [ $(ptarget).reference-properties [ $(self.dg).properties-ps ] ] ;
properties = [ sequence.insertion-sort
[ sequence.unique $(properties) ] ] ;
ref = [ sequence.insertion-sort
[ sequence.unique $(ref) ] ] ;
if $(properties) != $(ref)
if [ $(ps).free ] != [ $(ref-ps).free ]
{
self.extra-path = [ sequence.join main-target- [ $(main-target).name ] ] ;
}
@@ -491,7 +488,7 @@ rule file-target (
[ $(self.action).path ]
$(self.extra-path)
] ;
return [ path.native $(path) ] ;
}
}
@@ -522,13 +519,24 @@ rule remember-binding ( target : bound-path )
# 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.
rule action ( targets + : sources * : action-name : properties * )
rule action ( targets + : sources * : action-name : property-set ? )
{
self.targets = $(targets) ;
self.sources = $(sources) ;
self.action-name = $(action-name) ;
self.properties = $(properties) ;
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) ;
@@ -544,7 +552,7 @@ rule action ( targets + : sources * : action-name : properties * )
return $(self.action-name) ;
}
rule properties ( )
rule properties-ps ( )
{
return $(self.properties) ;
}
@@ -556,7 +564,8 @@ rule action ( targets + : sources * : action-name : properties * )
{
self.actualized = true ;
local properties = [ adjust-properties [ properties ] ] ;
local ps = [ properties-ps ] ;
local properties = [ adjust-properties [ $(ps).raw ] ] ;
local actual-targets ;
@@ -601,12 +610,10 @@ rule action ( targets + : sources * : action-name : properties * )
rule path ( )
{
local subvariant = [ property.remove free incidental : $(self.properties) ] ;
local pp = [ property.as-path $(subvariant) ] ;
return $(pp) ;
local p = [ $(self.properties).as-path ] ;
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
@@ -678,7 +685,7 @@ rule register ( target )
result = $(t) ;
}
else if $(a1) && $(a2) && [ $(a1).action-name ] = [ $(a2).action-name ]
&& [ $(a1).properties ] = [ $(a2).properties ] && [ $(a1).sources ] = [ $(a2).sources ]
&& [ $(a1).properties-ps ] = [ $(a2).properties-ps ] && [ $(a1).sources ] = [ $(a2).sources ]
{
result = $(t) ;
}
@@ -801,18 +808,19 @@ local rule clone-action-template ( action from cloned-from : new-source )
local action-class = [ modules.peek $(action) : __class__ ] ;
local ps = [ $(action).properties-ps ] ;
local cloned = [ new $(action-class) [ $(action).targets ] : $(sources)
: [ $(action).action-name ] : [ $(action).properties ] ] ;
: [ $(action).action-name ] : $(ps) ] ;
return $(cloned) ;
}
local rule subvariant-dg ( main-target # The instance of main-target class
: properties * # Properties requested for this target
: property-set # Properties requested for this target
: virtual-targets * )
{
self.main-target = $(main-target) ;
self.properties = $(properties) ;
self.properties = $(property-set) ;
self.virtual-targets = $(virtual-targets) ;
# Pre-compose the list of other dependency graphs, on which this one
@@ -836,19 +844,28 @@ local rule subvariant-dg ( main-target # The instance of main-target class
}
}
self.other-dg = [ sequence.unique $(self.other-dg) ] ;
rule main-target ( )
{
return $(self.main-target) ;
}
rule properties ( )
rule properties-ps ( )
{
return $(self.properties) ;
}
rule all-target-directories ( )
{
if ! $(self.target-directories)
{
compute-target-directories ;
}
return $(self.target-directories) ;
}
rule compute-target-directories ( )
{
local result ;
for local t in $(self.virtual-targets)
{
@@ -858,8 +875,8 @@ local rule subvariant-dg ( main-target # The instance of main-target class
{
result += [ $(d).all-target-directories ] ;
}
return $(result) ;
}
self.target-directories = $(result) ;
}
}
class subvariant-dg ;

View File

@@ -157,6 +157,7 @@ rule generator (
# in returned set must be present in build properties if this
# generator is to be used. If result has grist-only element,
# that build properties must include some value of that feature.
# XXX: remove this method?
rule requirements ( )
{
return $(self.requirements) ;
@@ -173,7 +174,7 @@ rule generator (
# Returns a number telling how good generator's properties match
# the passed properties, or empty list if generator can't be run
# at all.
rule match-rank ( properties * )
rule match-rank ( property-set )
{
# See if generator's requirements are satisfied by 'properties'.
# Treat feature name in requirements (i.e. grist-only element),
@@ -192,7 +193,8 @@ rule generator (
features += $(r) ;
}
}
local properties = [ $(property-set).raw ] ;
if $(requirements) in $(properties) && $(features) in $(properties:G)
{
return [ sequence.length [ set.intersection
@@ -217,7 +219,7 @@ rule generator (
rule run ( project # Project for which the targets are generated
name ? # Determines the name of 'name' attribute for
# all generated targets. See 'generated-targets' method.
: properties * # Desired properties for generated targets.
: property-set # Desired properties for generated targets.
: sources + : # Source targets.
multiple ? # Allows the rule to run generator several times and return
# multiple targets of the same type. When this argument is not
@@ -230,7 +232,7 @@ rule generator (
{
generators.dout [ indent ] " generator" $(self.id) ;
generators.dout [ indent ] " multiple:" $(mutliple) ;
# Ordinary generators take only one source targets
if $(sources[2])
{
@@ -248,7 +250,7 @@ rule generator (
local bypassed = ;
convert-to-consumable-types $(project) $(name) :
$(properties) : $(sources) : $(multiple)
$(property-set) : $(sources) : $(multiple)
:
: consumed bypassed ;
@@ -256,7 +258,7 @@ rule generator (
if $(consumed)
{
result = [ construct-result $(consumed) : $(project) $(name)
: $(properties) ] ;
: $(property-set) ] ;
}
if $(result)
@@ -301,7 +303,7 @@ rule generator (
# Otherwise, might contain several targets with the type of
# $(self.source-types[1])
: project name ?
: properties * # Properties to be used for all actions create here
: property-set # Properties to be used for all actions create here
)
{
local result ;
@@ -311,7 +313,7 @@ rule generator (
generators.dout [ indent ] "alt1" ;
for local r in $(consumed)
{
result += [ generated-targets $(r) : $(properties) : $(project) $(name) ] ; #(targets) ;
result += [ generated-targets $(r) : $(property-set) : $(project) $(name) ] ; #(targets) ;
}
}
else
@@ -320,7 +322,8 @@ rule generator (
generators.dout [ indent ] "alt2 : consumed is" [ $(v).str ] ;
if $(consumed)
{
result += [ generated-targets $(consumed) : $(properties) : $(project) $(name) ] ;
result += [ generated-targets $(consumed) : $(property-set)
: $(project) $(name) ] ;
}
}
return $(result) ;
@@ -346,7 +349,7 @@ rule generator (
# Note that this pattern mechanism has nothing to do with implicit patterns
# in make. It's a way to produce target which name is different for name of
# source.
rule generated-targets ( sources + : properties * : project name ? )
rule generated-targets ( sources + : property-set : project name ? )
{
if ! $(name)
{
@@ -382,7 +385,8 @@ rule generator (
}
# Assign an action for each target
local action = [ action-class ] ;
local a = [ new $(action) $(targets) : $(sources) : $(self.id) : $(properties) ] ;
local a = [ new $(action) $(targets) : $(sources) : $(self.id) :
$(property-set) ] ;
for local t in $(targets)
{
$(t).action $(a) ;
@@ -395,7 +399,7 @@ rule generator (
# handle. The intention is to produce the set of targets can should be
# used when generator is run.
rule convert-to-consumable-types ( project name ? :
properties * : source : multiple ?
property-set : source : multiple ?
: only-one ? # convert 'source' to only one of source types
# if there's more that one possibility, report an
# error
@@ -449,7 +453,7 @@ rule generator (
if $(missing-types)
{
local transformed = [ generators.construct-types $(project) $(name)
: $(missing-types) : $(multiple) : $(properties) : $(source) ] ;
: $(missing-types) : $(multiple) : $(property-set) : $(source) ] ;
# Add targets of right type to 'consumed'. Add others to
# 'bypassed'. The 'generators.construct' rule has done
@@ -468,8 +472,7 @@ rule generator (
}
}
}
$(consumed-var) += $(_consumed) ;
$(bypassed-var) += $(_bypassed) ;
}
@@ -492,7 +495,7 @@ rule composing-generator ( id : source-types * : target-types + :
generator.__init__ $(id) : $(source-types) : $(target-types) :
$(requirements) ;
rule run ( project name ? : properties * : sources + )
rule run ( project name ? : property-set : sources + )
{
generators.dout [ indent ] " composing generator" $(self.id) ;
@@ -507,7 +510,7 @@ rule composing-generator ( id : source-types * : target-types + :
local c ;
local b ;
# TODO: need to check for failure on each source.
convert-to-consumable-types $(project) : $(properties)
convert-to-consumable-types $(project) : $(property-set)
: $(sources[1]) : * : true : c b ;
if ! $(c)
{
@@ -523,7 +526,8 @@ rule composing-generator ( id : source-types * : target-types + :
if ! $(failed)
{
generators.dout [ indent ] " SUCCESS" ;
result += [ generated-targets $(consumed) : $(properties) : $(project) $(name) ] ;
result += [ generated-targets $(consumed) : $(property-set)
: $(project) $(name) ] ;
result += $(bypassed) ;
}
else
@@ -622,9 +626,9 @@ rule base-to-derived-type-conversion ( targets * : target-types +
rule try-one-generator ( project name ? : generator multiple ? :
target-types + : properties * : sources * )
target-types + : property-set : sources * )
{
local targets = [ $(generator).run $(project) $(name) : $(properties) : $(sources)
local targets = [ $(generator).run $(project) $(name) : $(property-set) : $(sources)
: $(multiple) ] ;
# Generated targets that are of required types
@@ -644,8 +648,8 @@ rule try-one-generator ( project name ? : generator multiple ? :
{
for local e in $(extra)
{
local try2 = [ construct-types $(project) $(name) : $(target-types) : : $(properties)
: $(e) ] ;
local try2 = [ construct-types $(project) $(name)
: $(target-types) : : $(property-set) : $(e) ] ;
result += $(try2) ;
}
@@ -662,13 +666,13 @@ rule try-one-generator ( project name ? : generator multiple ? :
}
rule construct-types ( project name ? : target-types + : multiple ? :
properties * : source )
property-set : source )
{
local result ;
local matched-types ;
for local t in $(target-types)
{
local r = [ construct $(project) $(name) : $(t) $(multiple) : $(properties) :
local r = [ construct $(project) $(name) : $(t) $(multiple) : $(property-set) :
$(source) ] ;
if $(r)
{
@@ -719,7 +723,7 @@ local rule ensure-type ( targets * )
#
# Note: this algorithm explicitly ignores generators for base classes if there's
# at least one generator for requested target-type.
local rule find-viable-generators ( target-type : properties * : allow-composing ? )
local rule find-viable-generators ( target-type : property-set : allow-composing ? )
{
# Select generators that can create the required target type.
local viable-generators = ;
@@ -738,7 +742,7 @@ local rule find-viable-generators ( target-type : properties * : allow-composing
if ! $(g) in $(.active-generators)
&& ! ( [ is-a $(g) : composing-generator ] && ! $(allow-composing) )
{
local m = [ $(g).match-rank $(properties) ] ;
local m = [ $(g).match-rank $(property-set) ] ;
if $(m)
{
viable-generators += $(g) ;
@@ -803,7 +807,7 @@ local rule select-dependency-graph ( options )
# Attempt to construct the target by looking at transformation cache.
local rule construct-with-caching (
project name ? : target-type multiple ? : properties * : sources * )
project name ? : target-type multiple ? : property-set : sources * )
{
local result ;
if ! $(.caching) && ! $(sources[2]) && $(sources[1]) && ! $(name)
@@ -812,7 +816,7 @@ local rule construct-with-caching (
local t = $(sources[1]) ;
local signature = [ sequence.join [ $(t).type ] $(target-type) $(properties) : - ] ;
local signature = [ sequence.join [ $(t).type ] $(target-type) $(property-set) : - ] ;
# Get a transformation template from cache or create it.
local cresult ;
@@ -823,7 +827,8 @@ local rule construct-with-caching (
else
{
local ut = [ new file-target % : [ $(t).type ] : "no project" ] ;
cresult = [ construct $(project) : $(target-type) $(multiple) : $(properties) : $(ut) ] ;
cresult = [ construct $(project) : $(target-type) $(multiple)
: $(property-set) : $(ut) ] ;
.transformation.cache.$(signature) = $(cresult) ;
}
@@ -846,9 +851,9 @@ local rule construct-with-caching (
# Attempts to construct target by finding viable generators, running them
# and selecting the dependency graph
local rule construct-without-caching (
project name ? : target-type multiple ? : properties * : sources * )
project name ? : target-type multiple ? : property-set : sources * )
{
viable-generators = [ find-viable-generators $(target-type) : $(properties)
viable-generators = [ find-viable-generators $(target-type) : $(property-set)
: $(allow-composing) ] ;
local results = [ new vector ] ;
@@ -862,7 +867,7 @@ local rule construct-without-caching (
local .active-generators = $(g) $(.active-generators) ;
local r = [ try-one-generator $(project) $(name) : $(g) $(multiple) : $(target-type) :
$(properties) : $(sources) ] ;
$(property-set) : $(sources) ] ;
if $(r)
{
@@ -885,7 +890,7 @@ local rule construct-without-caching (
# 'construct' in stack, returns only targets of requested 'target-type',
# otherwise, returns also unused sources and additionally generated
# targets.
rule construct ( project name ? : target-type multiple ? : properties * : sources *
rule construct ( project name ? : target-type multiple ? : property-set * : sources *
: allow-composing ? # Allows to use composing generators for constructing this
# target. This will be typically set when creating main targets,
# and unset when called recursively from 'run' method of
@@ -905,8 +910,8 @@ rule construct ( project name ? : target-type multiple ? : properties * : source
usage-requirements += [ $(e).usage-requirements ] ;
}
}
properties += $(usage-requirements) ;
properties = [ sequence.unique $(properties) ] ;
property-set = [ $(property-set).add
[ property-set.create $(usage-requirements) ] ] ;
.construct-stack += 1 ;
@@ -926,11 +931,11 @@ rule construct ( project name ? : target-type multiple ? : properties * : source
generators.dout [ indent ] " properties:" $(properties) ;
local result = [ construct-with-caching $(project) $(name)
: $(target-type) $(multiple) : $(properties) : $(sources) ] ;
: $(target-type) $(multiple) : $(property-set) : $(sources) ] ;
if ! $(result) {
result = [ construct-without-caching $(project) $(name)
: $(target-type) $(multiple) : $(properties) : $(sources) ] ;
: $(target-type) $(multiple) : $(property-set) : $(sources) ] ;
}
decrease-indent ;
@@ -940,8 +945,8 @@ rule construct ( project name ? : target-type multiple ? : properties * : source
if ! $(.construct-stack) # This is first invocation in stack
{
# Make roots of dependency graph depend on all 'dependency' features.
local dp = [ property.take dependency : $(properties) ] ;
local dp = [ $(property-set).dependency ] ;
if $(dp)
{
for local t in $(result)

View File

@@ -386,6 +386,14 @@ local rule initialize (
[ path.relative $(our-dir) $(parent-dir) ] ] : exact ;
}
}
else
{
$(attributes).set requirements
: [ property-set.empty ] : exact ;
$(attributes).set usage-requirements
: [ property-set.empty ] : exact ;
}
}
# Associate the given id with the given location
@@ -416,9 +424,16 @@ rule project-attributes ( location )
{
specification = [ property.translate-paths $(specification)
: $(self.location) ] ;
local current = $(self.requirements) ;
local result = [ property.refine $(current) :
[ property.make $(specification) ] ] ;
specification = [ property.make $(specification) ] ;
result = [ property-set.create $(specification) ] ;
# If we have inherited properties, need to refine them with the
# specified.
local current = $(self.requirements) ;
if $(current)
{
result = [ $(current).refine $(result) ] ;
}
if $(result[1]) = "@error"
{
@@ -439,8 +454,17 @@ rule project-attributes ( location )
{
errors.error "usage-requirements" $($(real-pos2)) "have non-free properties" $(non-free) ;
}
self.usage-requirements += [ property.translate-paths $(specification)
local t = [ property.translate-paths $(specification)
: $(self.location) ] ;
if $(self.usage-requirements)
{
self.usage-requirements = [ property-set.create
[ $(self.usage-requirements).raw ] $(t) ] ;
}
else
{
self.usage-requirements = [ property-set.create $(t) ] ;
}
}
else if $(attribute) = "source-location"
{
@@ -480,7 +504,7 @@ rule project-attributes ( location )
print.list-start ;
print.list-item "Project root:" $(self.project-root) ;
print.list-item "Parent project:" $(parent) ;
print.list-item "Requirements:" $(self.requirements) ;
print.list-item "Requirements:" [ $(self.requirements).raw ] ;
print.list-item "Default build:" $(self.default-build) ;
print.list-item "Source location:" $(self.source-location) ;
print.list-item "Projects to build:"

View File

@@ -72,6 +72,7 @@ import regex ;
import property ;
import errors ;
import common ;
import property-set ;
# Base class for all abstract targets.
@@ -109,7 +110,7 @@ rule abstract-target ( name # name of the target in Jamfile
# Adds one more direct build request for this target. If later generate
# is called with the same non-free non-incidental properties as in one
# of direct build requests, then that build request is used instead.
rule direct-build-request ( properties * )
rule direct-build-request ( property-set )
{
}
@@ -122,7 +123,7 @@ rule abstract-target ( name # name of the target in Jamfile
#
# If 'properties' are empty, performs default build of this target, in a way specific
# to derived class.
rule generate ( properties * )
rule generate ( property-set )
{
errors.error "method should be defined in derived classes" ;
}
@@ -137,29 +138,30 @@ rule project-target ( name : project : requirements * : default-build * )
self.requirements = $(requirements) ;
self.default-build = $(default-build) ;
rule direct-build-request ( properties * )
rule direct-build-request ( property-set )
{
for local name in $(self.main-targets)
{
local t = [ main-target $(name) ] ;
result += [ $(t).direct-build-request $(properties) ] ;
result += [ $(t).direct-build-request $(property-set) ] ;
}
for local pn in [ project.attribute $(self.project) projects-to-build ]
{
local p = [ project.module-name $(pn) ] ;
local t = [ project.target [ project.attribute $(p) location ] ] ;
result += [ $(t).direct-build-request $(properties) ] ;
result += [ $(t).direct-build-request $(property-set) ] ;
}
}
# Generates all possible targets contained in this project.
rule generate ( properties * )
rule generate ( property-set * )
{
# Project properties are directly imposed on all main targets.
# However, we'd need to check if this project can be build at
# all.
local xproperties =
[ property.refine $(properties) : $(self.requirements) ] ;
local xproperties = [ $(property-set).refine $(self.requirements) ] ;
if $(xproperties[1]) = "@error"
{
local id = [ project.attribute $(self.project) id ] ;
@@ -168,7 +170,7 @@ rule project-target ( name : project : requirements * : default-build * )
"due to unsatisfied requirements." ;
print.wrapped-text "warning: explanation: " $(xproperties[2-]) ;
print.wrapped-text "warning: build-request: " $(properties) ;
print.wrapped-text "warning: requirements: " $(self.requirements) ;
print.wrapped-text "warning: requirements: " [ $(self.requirements).raw ] ;
}
else
{
@@ -176,14 +178,14 @@ rule project-target ( name : project : requirements * : default-build * )
for local name in $(self.main-targets)
{
local t = [ main-target $(name) ] ;
result += [ $(t).generate $(properties) ] ;
result += [ $(t).generate $(property-set) ] ;
}
local self-location = [ project.attribute $(self.project) location ] ;
for local pn in [ project.attribute $(self.project) projects-to-build ]
{
local p = [ project.module-name [ path.join $(self-location) $(pn) ] ] ;
local t = [ project.target [ project.attribute $(p) location ] ] ;
result += [ $(t).generate $(properties) ] ;
result += [ $(t).generate $(property-set) ] ;
}
return $(result) ;
}
@@ -215,19 +217,19 @@ rule project-target ( name : project : requirements * : default-build * )
# target in this project, if generation with
# 'properties' is requested, and that main target
# does not have any requirements of its own.
rule reference-properties ( properties * )
rule reference-properties ( property-set )
{
# Note that free properties can appear on 'properties' only
# from direct build request, because free properties are not
# allowed to be propagated.
local ref = [ project.attribute $(self.project) requirements ] ;
ref = [ property.refine $(properties) : $(ref) ] ;
ref = [ property.evaluate-conditionals $(ref) ] ;
ref = [ property.take free : [ property.remove incidental : $(ref) ] ] ;
ref = [ targets.generate-dependencies $(ref) : $(self.project) ] ;
return $(ref) ;
}
if ! $(self.ref-props.$(property-set))
{
local ref = [ project.attribute $(self.project) requirements ] ;
local ps = [ $(property-set).refine $(ref) ] ;
ps = [ $(ps).evaluate-conditionals ] ;
ps = [ targets.generate-dependencies $(ps) : $(self.project) : $(ps) ] ;
self.ref-props.$(property-set) = $(ps) ;
}
return $(self.ref-props.$(property-set)) ;
}
}
class project-target : abstract-target ;
@@ -246,9 +248,9 @@ rule main-target ( name : project )
self.alternatives += $(target) ;
}
rule direct-build-request ( properties * )
rule direct-build-request ( property-set )
{
local base = [ property.remove free incidental : $(properties) ] ;
local base = [ $(property-set).base ] ;
local ep = $(self.direct-request.$(base:J=-)) ;
if $(ep) && $(ep) != $(properties)
{
@@ -256,7 +258,7 @@ rule main-target ( name : project )
}
else
{
self.direct-request.$(base:J=-) = $(properties) ;
self.direct-request.$(base:J=-) = $(property-set) ;
}
}
@@ -265,13 +267,13 @@ rule main-target ( name : project )
# which requirements are satisfied by 'properties' and picking the one with
# longest requirements set.
# Returns the result of calling 'generate' on that alternative.
rule generate ( properties * )
rule generate ( property-set )
{
local base = [ property.remove free incidental : $(properties) ] ;
local base = [ $(property-set).base ] ;
local ep = $(self.direct-request.$(base:J=-)) ;
if $(ep)
{
properties = $(ep) ;
property-set = $(ep) ;
}
# Try to generate all the alternatives.
@@ -279,7 +281,7 @@ rule main-target ( name : project )
for local v in $(self.alternatives)
{
local vtargets = [ $(v).generate $(properties) ] ;
local vtargets = [ $(v).generate $(property-set) ] ;
if $(vtargets) && $(vtargets[1]) != "@error"
{
$(alternatives).push-back [ new vector $(v) $(vtargets) ] ;
@@ -291,7 +293,7 @@ rule main-target ( name : project )
# why it can't be build.
print.wrapped-text
"warning: skipped build of" [ full-name ]
"with properties" $(properties) ;
"with properties" [ $(property-set).raw ] ;
} else {
local result ;
if [ $(alternatives).size ] = 1
@@ -314,9 +316,9 @@ rule main-target ( name : project )
# have 'requirements' method.
# assert.equal [ is-a $(target) : basic-target ] : true ;
local req = [ $(target).requirements ] ;
req = [ property.remove free incidental : $(req) ] ;
req = [ $(req).base ] ;
req-length += [ sequence.length
[ set.intersection $(req) : $(properties) ] ] ;
[ set.intersection $(req) : [ $(property-set).raw ] ] ] ;
}
local best = [ sequence.select-highest-ranked $(r) : $(req-length) ] ;
@@ -343,7 +345,7 @@ rule main-target ( name : project )
# is created.
local all-targets =
[ sequence.transform virtual-target.traverse : $(result) ] ;
local dg = [ new subvariant-dg $(__name__) : $(properties) : $(all-targets) ] ;
local dg = [ new subvariant-dg $(__name__) : $(property-set) : $(all-targets) ] ;
for local v in $(all-targets)
{
$(v).dg $(dg) ;
@@ -361,7 +363,7 @@ class main-target : abstract-target ;
# reference.
rule generate ( target-reference # Target reference
: project # Project where the reference is made
: properties * # Properties of the main target that
: property-set # Properties of the main target that
# makes the reference
)
{
@@ -382,8 +384,9 @@ rule generate ( target-reference # Target reference
if $(main-target) {
# Take properties which should be propagated and refine them
# with source-specific requirements.
local propagated = [ property.take propagated : $(properties) ] ;
local rproperties = [ property.refine $(propagated) : $(sproperties) ] ;
local propagated = [ $(property-set).propagated ] ;
local rproperties = [ $(propagated).refine
[ property-set.create $(sproperties) ] ] ;
if $(rproperties[1]) = "@error"
{
errors.error
@@ -395,42 +398,32 @@ rule generate ( target-reference # Target reference
}
}
# Returns a list of properties, where all dependency properties are
# replaced as follows:
# - the value of dependency property is treated as target reference,
# which is generated with 'properties' + 'extra-properties'
# - the created virtual target's become replace the property value,
# for example <library>a/b might become
# <library>object(virtual-target)@1
# In addition, usage requirements for all created virtual targets
# are added to the properties.
# Returns new property set which inclues all properties from
# 'property-set', except that all dependency properties are
# generated with 'generation-ps', and the obtained virtual targets
# are added as the values of original features.
#
# The purpose of 'extra-properties' is to be able to replace dependency
# features only in certain set of properties, which does not include
# all build properties. A concrete example is when we process use properties.
# Dependency features must be replaced using full build properties of target,
# but we don't want to add build properties to usage requirements.
rule generate-dependencies ( properties * : project : extra-properties * )
# For example, <library>a/b might become <library>object(virtual-target)@1
# In addition, usage requirements for all created virtual targets
# are added to the created property set.
rule generate-dependencies ( property-set : project : generation-ps )
{
local xproperties ;
for local p in $(properties)
local xproperties ;
for local p in [ $(property-set).dependency ]
{
if dependency in [ feature.attributes $(p:G) ]
local g = [ targets.generate $(p:TG=) : $(project) : $(generation-ps) ] ;
if ! $(g)
{
local g = [ targets.generate $(p:TG=) : $(project)
: $(properties) $(extra-properties) ] ;
if ! $(g)
{
errors.error "cannot generate dependency " $(p) ;
}
xproperties += $(p:G)$(g) [ $(g).usage-requirements ] ;
errors.error "cannot generate dependency " $(p) ;
}
else
{
xproperties += $(p) ;
}
xproperties += $(p:G)$(g) [ $(g).usage-requirements ] ;
}
return $(xproperties) ;
local r = [ property-set.create
[ $(property-set).base ]
[ $(property-set).free ]
$(xproperties)
[ $(property-set).incidental ] ] ;
return $(r) ;
}
@@ -448,8 +441,15 @@ rule basic-target ( name : project
abstract-target.__init__ $(name) : $(project) ;
self.sources = $(sources) ;
if ! $(requirements) {
requirements = [ property-set.empty ] ;
}
self.requirements = $(requirements) ;
self.default-build = $(default-build) ;
if ! $(usage-requirements)
{
usage-requirements = [ property-set.empty ] ;
}
self.usage-requirements = $(usage-requirements) ;
if $(sources:G)
@@ -463,35 +463,31 @@ rule basic-target ( name : project
# Generates sources. Calls 'construct'
# This method should not be overriden.
#
rule generate ( properties * )
rule generate ( property-set )
{
if ! $(properties) || $(properties:G) = <toolset>
if ! [ $(property-set).raw ]
{
# CONSIDER: I'm really not sure if this is correct...
# FIXME: as in 'build-system' we stick default toolset
properties = [ build-request.expand $(properties)
$(self.default-build) ] ;
properties = [ build-request.expand $(self.default-build) ] ;
local result = ;
for local p in $(properties)
{
result += [ generate [ feature.split $(p) ] ] ;
result += [ generate [ property-set.create [ feature.split $(p) ] ] ] ;
}
return $(result) ;
} else {
property-path = [ property.as-path
[ property.remove free incidental : $(properties) ] ] ;
property-path = [ property.as-path [ $(property-set).base ] ] ;
if ! $(property-path)
{
property-path = X ;
}
if ! $(self.generated.$(property-path))
{
local rproperties =
[ property.refine $(properties) : $(self.requirements) ] ;
rproperties = [ property.evaluate-conditionals $(rproperties) ] ;
local rproperties = [ $(property-set).refine $(self.requirements) ] ;
if $(rproperties[1]) != "@error"
{
@@ -503,9 +499,12 @@ rule basic-target ( name : project
# requirements may also code from dependencies. However, when they
# come from dependencies, the value is not target id, but rather
# virtual target names, so generators.construct can use them.
rproperties = [ $(rproperties).evaluate-conditionals ] ;
local xproperties =
[ targets.generate-dependencies $(rproperties) : $(self.project) ] ;
[ targets.generate-dependencies $(rproperties) : $(self.project)
: $(rproperties) ] ;
local source-targets ;
@@ -513,7 +512,7 @@ rule basic-target ( name : project
{
# Try treating this source as reference to main target
local more-targets =
[ targets.generate $(s) : $(self.project) : $(properties) ] ;
[ targets.generate $(s) : $(self.project) : $(property-set) ] ;
if $(more-targets)
{
source-targets += $(more-targets) ;
@@ -529,16 +528,19 @@ rule basic-target ( name : project
# unqual to project's reference properties. As the
# result, we create per-target bin directory while
# it's not really needed.
xproperties = [ feature.run-actions $(xproperties) ] ;
xproperties = [ $(xproperties).run-actions ] ;
self.generated.$(property-path) =
[ construct $(source-targets) : $(xproperties) ] ;
# Apply use requirement of this target to all generated
# virtual targets.
local xusage-requirements =
[ targets.generate-dependencies $(self.usage-requirements)
[ targets.generate-dependencies
$(self.usage-requirements)
: $(self.project) : $(rproperties) ] ;
xusage-requirements = [ $(xusage-requirements).raw ] ;
for local e in $(self.generated.$(property-path))
{
@@ -579,11 +581,11 @@ rule typed-target ( name : project : type
self.type = $(type) ;
rule construct ( source-targets * : properties * )
rule construct ( source-targets * : property-set )
{
local r = [ generators.construct $(self.project) $(self.name) : $(self.type)
: $(properties) # [ feature.expand
<main-target-type>$(self.type)
: [ property-set.create [ $(property-set).raw ] # [ feature.expand
<main-target-type>$(self.type) ]
# ]
: $(source-targets)
: allow-composing ] ;
@@ -609,8 +611,9 @@ rule main-target-requirements (
{
local loc = [ project.attribute $(project) location ] ;
local requirements = [ property.translate-paths $(specification) : $(loc) ] ;
local requirements = [ property-set.create $(requirements) ] ;
local project-requirements = [ project.attribute $(project) requirements ] ;
requirements = [ property.refine $(project-requirements) : $(requirements) ] ;
requirements = [ $(project-requirements).refine $(requirements) ] ;
if $(requirements[1]) = "@error"
{
errors.error "Conflicting requirements for target:" $(requirements) ;
@@ -629,11 +632,11 @@ rule main-target-usage-requirements (
{
local loc = [ project.attribute $(project) location ] ;
local project-usage-requirements = [ project.attribute $(project) usage-requirements ] ;
local usage-requirements = [ property.translate-paths $(specification) : $(loc) ] ;
usage-requirements += $(project-usage-requirements) ;
return $(usage-requirements) ;
local usage-requirements = [ property-set.create
[ property.translate-paths $(specification) : $(loc) ] ] ;
return [ $(project-usage-requirements).add $(usage-requirements) ] ;
}
# Return the default build value to use when declaring a main target,

View File

@@ -10,6 +10,8 @@
import class : class new ;
import type ;
import property-set ;
import utility ;
# +--------------------------+
# | virtual-target |
@@ -349,8 +351,8 @@ rule abstract-file-target ( name
local properties ;
if $(self.action)
{
properties = [ property.remove free incidental : [ $(self.action).properties ] ] ;
local property-grist = [ property.as-path $(properties) ] ;
local ps = [ $(self.action).properties-ps ] ;
local property-grist = [ $(ps).as-path ] ;
grist = $(location-grist)/$(property-grist) ;
}
if ! $(grist)
@@ -447,21 +449,16 @@ rule file-target (
{
if $(self.action)
{
local properties = [ property.take free : [ property.remove incidental :
[ $(self.action).properties ] ] ] ;
local ps = [ $(self.action).properties-ps ] ;
local main-target = [ $(self.dg).main-target ] ;
local project = [ $(main-target).project ] ;
local plocation = [ project.attribute $(project) location ] ;
local ptarget = [ project.target $(plocation) ] ;
local ref = [ $(ptarget).reference-properties [ $(self.dg).properties ] ] ;
local ref-ps = [ $(ptarget).reference-properties [ $(self.dg).properties-ps ] ] ;
properties = [ sequence.insertion-sort
[ sequence.unique $(properties) ] ] ;
ref = [ sequence.insertion-sort
[ sequence.unique $(ref) ] ] ;
if $(properties) != $(ref)
if [ $(ps).free ] != [ $(ref-ps).free ]
{
self.extra-path = [ sequence.join main-target- [ $(main-target).name ] ] ;
}
@@ -491,7 +488,7 @@ rule file-target (
[ $(self.action).path ]
$(self.extra-path)
] ;
return [ path.native $(path) ] ;
}
}
@@ -522,13 +519,24 @@ rule remember-binding ( target : bound-path )
# 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.
rule action ( targets + : sources * : action-name : properties * )
rule action ( targets + : sources * : action-name : property-set ? )
{
self.targets = $(targets) ;
self.sources = $(sources) ;
self.action-name = $(action-name) ;
self.properties = $(properties) ;
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) ;
@@ -544,7 +552,7 @@ rule action ( targets + : sources * : action-name : properties * )
return $(self.action-name) ;
}
rule properties ( )
rule properties-ps ( )
{
return $(self.properties) ;
}
@@ -556,7 +564,8 @@ rule action ( targets + : sources * : action-name : properties * )
{
self.actualized = true ;
local properties = [ adjust-properties [ properties ] ] ;
local ps = [ properties-ps ] ;
local properties = [ adjust-properties [ $(ps).raw ] ] ;
local actual-targets ;
@@ -601,12 +610,10 @@ rule action ( targets + : sources * : action-name : properties * )
rule path ( )
{
local subvariant = [ property.remove free incidental : $(self.properties) ] ;
local pp = [ property.as-path $(subvariant) ] ;
return $(pp) ;
local p = [ $(self.properties).as-path ] ;
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
@@ -678,7 +685,7 @@ rule register ( target )
result = $(t) ;
}
else if $(a1) && $(a2) && [ $(a1).action-name ] = [ $(a2).action-name ]
&& [ $(a1).properties ] = [ $(a2).properties ] && [ $(a1).sources ] = [ $(a2).sources ]
&& [ $(a1).properties-ps ] = [ $(a2).properties-ps ] && [ $(a1).sources ] = [ $(a2).sources ]
{
result = $(t) ;
}
@@ -801,18 +808,19 @@ local rule clone-action-template ( action from cloned-from : new-source )
local action-class = [ modules.peek $(action) : __class__ ] ;
local ps = [ $(action).properties-ps ] ;
local cloned = [ new $(action-class) [ $(action).targets ] : $(sources)
: [ $(action).action-name ] : [ $(action).properties ] ] ;
: [ $(action).action-name ] : $(ps) ] ;
return $(cloned) ;
}
local rule subvariant-dg ( main-target # The instance of main-target class
: properties * # Properties requested for this target
: property-set # Properties requested for this target
: virtual-targets * )
{
self.main-target = $(main-target) ;
self.properties = $(properties) ;
self.properties = $(property-set) ;
self.virtual-targets = $(virtual-targets) ;
# Pre-compose the list of other dependency graphs, on which this one
@@ -836,19 +844,28 @@ local rule subvariant-dg ( main-target # The instance of main-target class
}
}
self.other-dg = [ sequence.unique $(self.other-dg) ] ;
rule main-target ( )
{
return $(self.main-target) ;
}
rule properties ( )
rule properties-ps ( )
{
return $(self.properties) ;
}
rule all-target-directories ( )
{
if ! $(self.target-directories)
{
compute-target-directories ;
}
return $(self.target-directories) ;
}
rule compute-target-directories ( )
{
local result ;
for local t in $(self.virtual-targets)
{
@@ -858,8 +875,8 @@ local rule subvariant-dg ( main-target # The instance of main-target class
{
result += [ $(d).all-target-directories ] ;
}
return $(result) ;
}
self.target-directories = $(result) ;
}
}
class subvariant-dg ;

View File

@@ -293,8 +293,9 @@ rule lib-generator ( )
{
composing-generator.__init__ lib-generator : : LIB : <main-target-type>LIB ;
rule run ( project name ? : properties * : sources * )
rule run ( project name ? : property-set : sources * )
{
local properties = [ $(property-set).raw ] ;
# Determine the needed target type
local actual-type ;
if <search> in $(properties:G) || <name> in $(properties:G)
@@ -311,8 +312,8 @@ rule lib-generator ( )
}
# Construct the target. Pass 'allow-composing', since generators for
# library types are composing and we need to find them.
return [ generators.construct $(project) $(name) : $(actual-type) : $(properties)
: $(sources) : allow-composing ] ;
return [ generators.construct $(project) $(name) : $(actual-type)
: $(property-set) : $(sources) : allow-composing ] ;
}
}

View File

@@ -12,21 +12,23 @@ import property ;
import errors : error ;
import type : type ;
import regex ;
import property-set ;
rule make-target-class ( name : project : sources * : requirements *
: make-rule + : default-build * )
{
basic-target.__init__ $(name) : $(project) : $(sources) : $(requirements)
: $(default-build) ;
self.make-rule = $(make-rule) ;
rule construct ( source-targets * : properties * )
rule construct ( source-targets * : property-set )
{
local t = [ new file-target $(self.name:S=) : [ type.type $(self.name:S) ]
: $(self.project) ] ;
$(t).suffix [ regex.match .(.*) : $(self.name:S) ] ;
local a = [ new action $(t) : $(source-targets) : $(self.make-rule)
: $(properties) ] ;
: $(property-set) ] ;
$(t).action $(a) ;
return $(t) ;
}

View File

@@ -21,8 +21,9 @@ rule prebuilt-file-generator
{
generator.__init__ prebuilt-file-generator : : * : <file> ;
rule run ( project name ? : properties * : sources * )
rule run ( project name ? : property-set : sources * )
{
local properties = [ $(property-set).raw ] ;
local name = [ feature.get-values <file> : $(properties) ] ;
local type = [ type.type $(name:S) ] ;
if ! $(type)
@@ -42,7 +43,7 @@ rule prebuilt-file-generator
# Therefore, we encode properties via 'extra-grist', which is ugly.
# Maybe, we should just introduce 'do-nothing-action', which only
# keps properties.
$(t).extra-grist [ property.as-path $(properties) ] ;
$(t).extra-grist [ $(property-set).as-path ] ;
$(t).suffix [ MATCH .(.*) : $(name:S) ] ;
return $(t) ;