From 52c57c06f5f1e0739fa71babbd19f0e16de545da Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Fri, 13 Sep 2002 12:16:17 +0000 Subject: [PATCH] Forgotten file. [SVN r15301] --- src/build/virtual-target.jam | 317 +++++++++++++++++++++++++++++++++++ 1 file changed, 317 insertions(+) create mode 100644 src/build/virtual-target.jam diff --git a/src/build/virtual-target.jam b/src/build/virtual-target.jam new file mode 100644 index 000000000..534c9c51f --- /dev/null +++ b/src/build/virtual-target.jam @@ -0,0 +1,317 @@ +# 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 target in Jam sense. They are needed, for example, +# when searching for possible transormation sequences, when it's not known +# if particular target should be create at all. + +import class : class new ; +import type ; + +# Class which represents a virtual target +rule virtual-target ( name : type ? : project + : subvariant * # Property sets which define this subvariant + ) +{ + self.name = $(name) ; + self.type = $(type) ; + self.subvariant = $(subvariant) ; + self.project = $(project) ; + + self.includes = ; + self.dependencies = ; + self.action = ; + + self.actual-name = ; + + + # Name of the target + rule name ( ) { return $(self.name) ; } + + rule type ( ) { return $(self.type) ; } + + # Sets the suffix. When generating target name, it will be used in preference to + # the suffix that is associated with 'type' + rule suffix ( suffix ) + { + self.suffix = $(suffix) ; + } + + # Property set that distinguished different variants of a target. + # May be a subset of the property set that is used for building. + # Determines the location of target, in an unspecified way. + rule subvariant ( ) { return $(self.subvariant) ; } + + # Project where this target was declared + rule project ( ) { return $(self.project) ; } + + rule includes ( ) { return $(self.includes) ; } + rule add_includes ( i + ) + { + self.includes = [ sequence.merge $(self.includes) + : [ sequence.insertion-sort $(i) ] ] ; + } + + rule dependencies ( ) { return $(self.dependencies) ; } + rule depends ( d + ) + { + self.dependencies = [ sequence.merge $(self.dependencies) + : [ sequence.insertion-sort $(d) ] ] ; + } + + # If 'a' is supplied, sets action to 'a'. + # Returns the action currently set. + rule action ( a ? ) + { + if $(a) { + self.action = $(a) ; + } + return $(self.action) ; + } + + # Specified an extra element to be added to the target path. + rule extra-path ( p ) + { + self.extra-path = $(p) ; + } + + # Generates all the actual targets and build instructions needed to build + # this target. Returns the actual target name. Can be called several times. + # Does no processing for other targets that 'action' will generate. + # Rationale: we might need only one file from the set created by an + # action, and there's no need to run the action if the file is up-to-date, + # only because some other file in set is out-of-date. + rule actualize ( ) + { + if ! $(self.actual-name) { + + self.actual-name = [ actual-name ] ; + for local i in $(dependencies) { + DEPENDS $(name) : [ $(i).actualize ] ; + } + for local i in $(includes) { + INCLUDES $(name) : [ $(i).actualize ] ; + } + local a = [ action ] ; + if $(a) { + $(a).actualize ; + local path = [ path.join [ project.attribute $(self.project) location ] + "bin" [ property.as-path [ subvariant ] ] + $(self.extra-path) ] ; + path = [ path.native $(path) ] ; + LOCATE on $(self.actual-name) = $(path) ; + DEPENDS $(self.actual-name) : $(path) ; + common.MkDir $(path) ; + common.Clean clean : $(self.actual-name) ; + } else { + SEARCH on $(self.actual-name) = + [ path.native [ project.attribute $(self.project) source-location ] ] ; + } + } + return $(self.actual-name) ; + } + + rule str ( ) + { + local action = [ action ] ; + local filename = [ sequence.join $(self.name) "." $(self.type) ] ; + if $(action) + { + local sources = [ $(action).sources ] ; + + local ss ; + for local s in $(sources) + { + ss += [ $(s).str ] ; + } + + local name = [ $(action).action-name ] ; + return "{" $(name)-$(filename) $(ss) "}" ; + } + else + { + return "{" $(filename) "}" ; + } + } + + 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 project-location = [ project.attribute $(self.project) location ] ; + local location-grist = + [ sequence.join [ regex.split $(project-location) "/" ] : "!" ] ; + local property-grist = + [ property.as-path $(self.subvariant) ] ; + # Set empty value to avoid eating adjacent text + local grist = $(location-grist)/$(property-grist) ; + if ! $(self.subvariant) { + grist = $(location-grist) ; + } + if $(self.suffix) + { + self.actual-name = [ sequence.join <$(grist)>$(self.name) + $(self.suffix) : "." ] ; + } + else if $(self.type) + { + self.actual-name = [ sequence.join <$(grist)>$(self.name) + [ type.generated-target-suffix $(self.type) ] : "." ] ; + } + else + { + self.actual-name = <$(grist)>$(self.name) ; + } + } + return $(self.actual-name) ; + } +} +class virtual-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. +rule action ( targets + : sources * : action-name : properties * ) +{ + self.targets = $(targets) ; + self.sources = $(sources) ; + self.action-name = $(action-name) ; + self.properties = $(properties) ; + + 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 actual-targets ; + for local i in [ targets ] + { + actual-targets += [ $(i).actualize ] ; + } + + local actual-sources ; + for local i in [ sources ] + { + actual-sources += [ $(i).actualize ] ; + } + + DEPENDS $(actual-targets) : $(actual-sources) ; + + $(self.action-name) + $(actual-targets) : $(actual-sources) : [ properties ] ; + } + } +} +class action ; + +# 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 ) +{ + if $(.files.$(file).$(project)) + { + return $(.files.$(file).$(project)) ; + } + else + { + local name = $(file:S=) ; + local type = [ type.type $(file:S) ] ; + local result ; + if ! $(type) + { + # warning "cannot determine type for file $(file)" ; + result = [ new virtual-target $(file) : : $(project) ] ; + } + else + { + local v = [ new virtual-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 ] [ $(target).subvariant ] : - ] ; + local result ; + for local t in $(.cache.$(signature)) + { + local a1 = [ $(t).action ] ; + local a2 = [ $(target).action ] ; + if ! $(result) && [ $(a1).action-name ] = [ $(a2).action-name ] && [ $(a1).properties ] = [ $(a2).properties ] + && [ $(a1).sources ] = [ $(a2).sources ] + { + result = $(t) ; + } + } + if ! $(result) + { + .cache.$(signature) += $(target) ; + result = $(target) ; + } + + return $(result) ; +} + + + + + +