| 1 | # Copyright (C) Vladimir Prus 2002. Permission to copy, use, modify, sell and
|
|---|
| 2 | # distribute this software is granted provided this copyright notice appears in
|
|---|
| 3 | # all copies. This software is provided "as is" without express or implied
|
|---|
| 4 | # warranty, and with no claim as to its suitability for any purpose.
|
|---|
| 5 |
|
|---|
| 6 | # Implements virtual targets, which correspond to actual files created during
|
|---|
| 7 | # build, but are not yet targets in Jam sense. They are needed, for example,
|
|---|
| 8 | # when searching for possible transormation sequences, when it's not known
|
|---|
| 9 | # if particular target should be created at all.
|
|---|
| 10 |
|
|---|
| 11 | import "class" : new ;
|
|---|
| 12 | import path property-set utility sequence errors set type os ;
|
|---|
| 13 |
|
|---|
| 14 | # +--------------------------+
|
|---|
| 15 | # | virtual-target |
|
|---|
| 16 | # +==========================+
|
|---|
| 17 | # | actualize |
|
|---|
| 18 | # +--------------------------+
|
|---|
| 19 | # | actualize-action() = 0 |
|
|---|
| 20 | # | actualize-location() = 0 |
|
|---|
| 21 | # +----------------+---------+
|
|---|
| 22 | # |
|
|---|
| 23 | # ^
|
|---|
| 24 | # / \
|
|---|
| 25 | # +-+-+
|
|---|
| 26 | # |
|
|---|
| 27 | # +---------------------+ +-------+--------------+
|
|---|
| 28 | # | action | | abstract-file-target |
|
|---|
| 29 | # +=====================| * +======================+
|
|---|
| 30 | # | action-name | +--+ action |
|
|---|
| 31 | # | properties | | +----------------------+
|
|---|
| 32 | # +---------------------+--+ | actualize-action() |
|
|---|
| 33 | # | actualize() |0..1 +-----------+----------+
|
|---|
| 34 | # | path() | |
|
|---|
| 35 | # | adjust-properties() | sources |
|
|---|
| 36 | # | actualize-sources() | targets |
|
|---|
| 37 | # +------+--------------+ ^
|
|---|
| 38 | # | / \
|
|---|
| 39 | # ^ +-+-+
|
|---|
| 40 | # / \ |
|
|---|
| 41 | # +-+-+ +-------------+-------------+
|
|---|
| 42 | # | | |
|
|---|
| 43 | # | +------+---------------+ +--------+-------------+
|
|---|
| 44 | # | | file-target | | searched-lib-target |
|
|---|
| 45 | # | +======================+ +======================+
|
|---|
| 46 | # | | actualize-location() | | actualize-location() |
|
|---|
| 47 | # | +----------------------+ +----------------------+
|
|---|
| 48 | # |
|
|---|
| 49 | # +-+------------------------------+
|
|---|
| 50 | # | |
|
|---|
| 51 | # +----+----------------+ +---------+-----------+
|
|---|
| 52 | # | compile-action | | link-action |
|
|---|
| 53 | # +=====================+ +=====================+
|
|---|
| 54 | # | adjust-properties() | | adjust-properties() |
|
|---|
| 55 | # +---------------------+ | actualize-sources() |
|
|---|
| 56 | # +---------------------+
|
|---|
| 57 | #
|
|---|
| 58 | # The 'compile-action' and 'link-action' classes are defined not here,
|
|---|
| 59 | # but in builtin.jam modules. They are shown in the diagram to give
|
|---|
| 60 | # the big picture.
|
|---|
| 61 |
|
|---|
| 62 | # Potential target. It can be converted into jam target and used in
|
|---|
| 63 | # building, if needed. However, it can be also dropped, which allows
|
|---|
| 64 | # to search for different transformation and select only one.
|
|---|
| 65 | #
|
|---|
| 66 | class virtual-target
|
|---|
| 67 | {
|
|---|
| 68 | import virtual-target utility scanner ;
|
|---|
| 69 |
|
|---|
| 70 | rule __init__ ( name # Name of this target -- specifies the name of
|
|---|
| 71 | : project # Project to which this target belongs
|
|---|
| 72 | )
|
|---|
| 73 | {
|
|---|
| 74 | self.name = $(name) ;
|
|---|
| 75 | self.project = $(project) ;
|
|---|
| 76 | self.dependencies = ;
|
|---|
| 77 | }
|
|---|
| 78 |
|
|---|
| 79 | # Name of this target.
|
|---|
| 80 | rule name ( ) { return $(self.name) ; }
|
|---|
| 81 |
|
|---|
| 82 | # Project of this target.
|
|---|
| 83 | rule project ( ) { return $(self.project) ; }
|
|---|
| 84 |
|
|---|
| 85 | # Adds additional instances of 'virtual-target' that this
|
|---|
| 86 | # one depends on.
|
|---|
| 87 | rule depends ( d + )
|
|---|
| 88 | {
|
|---|
| 89 | self.dependencies = [ sequence.merge $(self.dependencies)
|
|---|
| 90 | : [ sequence.insertion-sort $(d) ] ] ;
|
|---|
| 91 | }
|
|---|
| 92 |
|
|---|
| 93 | rule dependencies ( )
|
|---|
| 94 | {
|
|---|
| 95 | return $(self.dependencies) ;
|
|---|
| 96 | }
|
|---|
| 97 |
|
|---|
| 98 | # Generates all the actual targets and sets up build actions for
|
|---|
| 99 | # this target.
|
|---|
| 100 | #
|
|---|
| 101 | # If 'scanner' is specified, creates an additional target
|
|---|
| 102 | # with the same location as actual target, which will depend on the
|
|---|
| 103 | # actual target and be associated with 'scanner'. That additional
|
|---|
| 104 | # target is returned. See the docs (#dependency_scanning) for rationale.
|
|---|
| 105 | # Target must correspond to a file if 'scanner' is specified.
|
|---|
| 106 | #
|
|---|
| 107 | # If scanner is not specified, then actual target is returned.
|
|---|
| 108 | rule actualize ( scanner ? )
|
|---|
| 109 | {
|
|---|
| 110 | local actual-name = [ actualize-no-scanner ] ;
|
|---|
| 111 |
|
|---|
| 112 | if ! $(scanner)
|
|---|
| 113 | {
|
|---|
| 114 | return $(actual-name) ;
|
|---|
| 115 | }
|
|---|
| 116 | else
|
|---|
| 117 | {
|
|---|
| 118 | # Add the scanner instance to the grist for name.
|
|---|
| 119 | local g = [ sequence.join
|
|---|
| 120 | [ utility.ungrist $(actual-name:G) ] $(scanner) : - ] ;
|
|---|
| 121 | local name = $(actual-name:G=$(g)) ;
|
|---|
| 122 |
|
|---|
| 123 | if ! $(self.made.$(name)) {
|
|---|
| 124 | self.made.$(name) = true ;
|
|---|
| 125 |
|
|---|
| 126 | DEPENDS $(name) : $(actual-name) ;
|
|---|
| 127 |
|
|---|
| 128 | actualize-location $(name) ;
|
|---|
| 129 |
|
|---|
| 130 | scanner.install $(scanner) : $(name) $(__name__) ;
|
|---|
| 131 | }
|
|---|
| 132 | return $(name) ;
|
|---|
| 133 | }
|
|---|
| 134 |
|
|---|
| 135 | }
|
|---|
| 136 |
|
|---|
| 137 | # private: (overridables)
|
|---|
| 138 |
|
|---|
| 139 | # Sets up build actions for 'target'. Should call appropriate rules
|
|---|
| 140 | # and set target variables.
|
|---|
| 141 | rule actualize-action ( target )
|
|---|
| 142 | {
|
|---|
| 143 | errors.error "method should be defined in derived classes" ;
|
|---|
| 144 | }
|
|---|
| 145 |
|
|---|
| 146 | # Sets up variables on 'target' which specify its location.
|
|---|
| 147 | rule actualize-location ( target )
|
|---|
| 148 | {
|
|---|
| 149 | errors.error "method should be defined in derived classes" ;
|
|---|
| 150 | }
|
|---|
| 151 |
|
|---|
| 152 | # If the target is generated one, returns the path where it will be
|
|---|
| 153 | # generated. Otherwise, returns empty list.
|
|---|
| 154 | rule path ( )
|
|---|
| 155 | {
|
|---|
| 156 | errors.error "method should be defined in derived classes" ;
|
|---|
| 157 | }
|
|---|
| 158 |
|
|---|
| 159 | # Return that actual target name that should be used
|
|---|
| 160 | # (for the case where no scanner is involved)
|
|---|
| 161 | rule actual-name ( )
|
|---|
| 162 | {
|
|---|
| 163 | errors.error "method should be defined in derived classes" ;
|
|---|
| 164 | }
|
|---|
| 165 |
|
|---|
| 166 | # implementation
|
|---|
| 167 | rule actualize-no-scanner ( )
|
|---|
| 168 | {
|
|---|
| 169 | # In fact, we just need to merge virtual-target with
|
|---|
| 170 | # abstract-virtual-target and the latter is the only class
|
|---|
| 171 | # derived from the former. But that's for later.
|
|---|
| 172 | errors.error "method should be defined in derived classes" ;
|
|---|
| 173 | }
|
|---|
| 174 | }
|
|---|
| 175 |
|
|---|
| 176 |
|
|---|
| 177 | # Target which correspond to a file. The exact mapping for file
|
|---|
| 178 | # is not yet specified in this class. (TODO: Actually, the class name
|
|---|
| 179 | # could be better...)
|
|---|
| 180 | #
|
|---|
| 181 | # May be a source file (when no action is specified), or
|
|---|
| 182 | # derived file (otherwise).
|
|---|
| 183 | #
|
|---|
| 184 | # The target's grist is concatenation of project's location,
|
|---|
| 185 | # properties of action (for derived files), and, optionally,
|
|---|
| 186 | # value identifying the main target.
|
|---|
| 187 | class abstract-file-target : virtual-target
|
|---|
| 188 | {
|
|---|
| 189 | import project regex sequence path type ;
|
|---|
| 190 | import property-set ;
|
|---|
| 191 | import indirect ;
|
|---|
| 192 |
|
|---|
| 193 | rule __init__ (
|
|---|
| 194 | name # Name for this target
|
|---|
| 195 | exact ? # If non-empty, the name is exactly the name
|
|---|
| 196 | # created file should have. Otherwise, the '__init__'
|
|---|
| 197 | # method will add suffix obtained from 'type' by
|
|---|
| 198 | # calling 'type.generated-target-suffix'.
|
|---|
| 199 | : type ? # The type of this target.
|
|---|
| 200 | : project
|
|---|
| 201 | : action ?
|
|---|
| 202 | )
|
|---|
| 203 | {
|
|---|
| 204 | virtual-target.__init__ $(name) : $(project) ;
|
|---|
| 205 |
|
|---|
| 206 | self.type = $(type) ;
|
|---|
| 207 | self.action = $(action) ;
|
|---|
| 208 | if $(action)
|
|---|
| 209 | {
|
|---|
| 210 | $(action).add-targets $(__name__) ;
|
|---|
| 211 |
|
|---|
| 212 | if $(self.type) && ! $(exact)
|
|---|
| 213 | {
|
|---|
| 214 | _adjust-name $(name) ;
|
|---|
| 215 | }
|
|---|
| 216 | }
|
|---|
| 217 | }
|
|---|
| 218 |
|
|---|
| 219 | rule type ( ) { return $(self.type) ; }
|
|---|
| 220 |
|
|---|
| 221 | # Sets the path. When generating target name, it will override any path
|
|---|
| 222 | # computation from properties.
|
|---|
| 223 | rule set-path ( path )
|
|---|
| 224 | {
|
|---|
| 225 | self.path = [ path.native $(path) ] ;
|
|---|
| 226 | }
|
|---|
| 227 |
|
|---|
| 228 | # If 'a' is supplied, sets action to 'a'.
|
|---|
| 229 | # Returns the action currently set.
|
|---|
| 230 | rule action ( )
|
|---|
| 231 | {
|
|---|
| 232 | return $(self.action) ;
|
|---|
| 233 | }
|
|---|
| 234 |
|
|---|
| 235 | # Sets/gets the 'root' flag. Target is root if it directly correspods to some
|
|---|
| 236 | # variant of a main target.
|
|---|
| 237 | rule root ( set ? )
|
|---|
| 238 | {
|
|---|
| 239 | if $(set)
|
|---|
| 240 | {
|
|---|
| 241 | self.root = true ;
|
|---|
| 242 | }
|
|---|
| 243 | return $(self.root) ;
|
|---|
| 244 | }
|
|---|
| 245 |
|
|---|
| 246 | # Gets or sets the subvariant which created this target. Subvariant
|
|---|
| 247 | # is set when target is brought into existance, and is never changed
|
|---|
| 248 | # after that. In particual, if target is shared by subvariant, only
|
|---|
| 249 | # the first is stored.
|
|---|
| 250 | rule creating-subvariant ( s ? # If specified, specified the value to set,
|
|---|
| 251 | # which should be instance of 'subvariant'
|
|---|
| 252 | # class.
|
|---|
| 253 | )
|
|---|
| 254 | {
|
|---|
| 255 | if $(s) && ( ! $(self.creating-subvariant) && ! $(overwrite) )
|
|---|
| 256 | {
|
|---|
| 257 | if $(self.creating-subvariant)
|
|---|
| 258 | {
|
|---|
| 259 | errors.error "Attempt to change 'dg'" ;
|
|---|
| 260 | }
|
|---|
| 261 | else
|
|---|
| 262 | {
|
|---|
| 263 | self.creating-subvariant = $(s) ;
|
|---|
| 264 | }
|
|---|
| 265 | }
|
|---|
| 266 | return $(self.creating-subvariant) ;
|
|---|
| 267 | }
|
|---|
| 268 |
|
|---|
| 269 | rule actualize-action ( target )
|
|---|
| 270 | {
|
|---|
| 271 | if $(self.action)
|
|---|
| 272 | {
|
|---|
| 273 | $(self.action).actualize ;
|
|---|
| 274 | }
|
|---|
| 275 | }
|
|---|
| 276 |
|
|---|
| 277 | # Return a human-readable representation of this target
|
|---|
| 278 | #
|
|---|
| 279 | # If this target has an action, that's:
|
|---|
| 280 | #
|
|---|
| 281 | # { <action-name>-<self.name>.<self.type> <action-sources>... }
|
|---|
| 282 | #
|
|---|
| 283 | # otherwise, it's:
|
|---|
| 284 | #
|
|---|
| 285 | # { <self.name>.<self.type> }
|
|---|
| 286 | #
|
|---|
| 287 | rule str ( )
|
|---|
| 288 | {
|
|---|
| 289 | local action = [ action ] ;
|
|---|
| 290 |
|
|---|
| 291 | local name-dot-type = [ sequence.join $(self.name) "." $(self.type) ] ;
|
|---|
| 292 |
|
|---|
| 293 | if $(action)
|
|---|
| 294 | {
|
|---|
| 295 | local sources = [ $(action).sources ] ;
|
|---|
| 296 |
|
|---|
| 297 | local action-name = [ $(action).action-name ] ;
|
|---|
| 298 |
|
|---|
| 299 | local ss ;
|
|---|
| 300 | for local s in $(sources)
|
|---|
| 301 | {
|
|---|
| 302 | ss += [ $(s).str ] ;
|
|---|
| 303 | }
|
|---|
| 304 |
|
|---|
| 305 | return "{" $(action-name)-$(name-dot-type) $(ss) "}" ;
|
|---|
| 306 | }
|
|---|
| 307 | else
|
|---|
| 308 | {
|
|---|
| 309 | return "{" $(name-dot-type) "}" ;
|
|---|
| 310 | }
|
|---|
| 311 | }
|
|---|
| 312 |
|
|---|
| 313 | rule less ( a )
|
|---|
| 314 | {
|
|---|
| 315 | if [ str ] < [ $(a).str ]
|
|---|
| 316 | {
|
|---|
| 317 | return true ;
|
|---|
| 318 | }
|
|---|
| 319 | }
|
|---|
| 320 |
|
|---|
| 321 | rule equal ( a )
|
|---|
| 322 | {
|
|---|
| 323 | if [ str ] = [ $(a).str ]
|
|---|
| 324 | {
|
|---|
| 325 | return true ;
|
|---|
| 326 | }
|
|---|
| 327 | }
|
|---|
| 328 |
|
|---|
| 329 | # private:
|
|---|
| 330 | rule actual-name ( )
|
|---|
| 331 | {
|
|---|
| 332 | if ! $(self.actual-name)
|
|---|
| 333 | {
|
|---|
| 334 | local grist = [ grist ] ;
|
|---|
| 335 |
|
|---|
| 336 | local basename = [ path.native $(self.name) ] ;
|
|---|
| 337 | self.actual-name = <$(grist)>$(basename) ;
|
|---|
| 338 |
|
|---|
| 339 | }
|
|---|
| 340 | return $(self.actual-name) ;
|
|---|
| 341 | }
|
|---|
| 342 |
|
|---|
| 343 | # Helper to 'actual-name', above. Compute unique prefix used to distinguish
|
|---|
| 344 | # this target from other targets with the same name which create different
|
|---|
| 345 | # file.
|
|---|
| 346 | rule grist ( )
|
|---|
| 347 | {
|
|---|
| 348 | # Depending on target, there may be different approaches to generating
|
|---|
| 349 | # unique prefixes. We'll generate prefixes in the form
|
|---|
| 350 | # <one letter approach code> <the actual prefix>
|
|---|
| 351 | local path = [ path ] ;
|
|---|
| 352 | if $(path)
|
|---|
| 353 | {
|
|---|
| 354 | # The target will be generated to a known path. Just use the path
|
|---|
| 355 | # for identification, since path is as unique as it can get.
|
|---|
| 356 | return p$(path) ;
|
|---|
| 357 | }
|
|---|
| 358 | else
|
|---|
| 359 | {
|
|---|
| 360 | # File is either source, which will be searched for, or is not a file at
|
|---|
| 361 | # all. Use the location of project for distinguishing.
|
|---|
| 362 | local project-location = [ $(self.project).get location ] ;
|
|---|
| 363 | local location-grist =
|
|---|
| 364 | [ sequence.join [ regex.split $(project-location) "/" ] : "!" ] ;
|
|---|
| 365 |
|
|---|
| 366 | if $(self.action)
|
|---|
| 367 | {
|
|---|
| 368 | local ps = [ $(self.action).properties ] ;
|
|---|
| 369 | local property-grist = [ $(ps).as-path ] ;
|
|---|
| 370 | # 'property-grist' can be empty when 'ps' is an empty
|
|---|
| 371 | # property set.
|
|---|
| 372 | if $(property-grist)
|
|---|
| 373 | {
|
|---|
| 374 | location-grist = $(location-grist)/$(property-grist) ;
|
|---|
| 375 | }
|
|---|
| 376 | }
|
|---|
| 377 |
|
|---|
| 378 | return l$(location-grist) ;
|
|---|
| 379 | }
|
|---|
| 380 | }
|
|---|
| 381 |
|
|---|
| 382 | # Given the target name specified in constructor, returns the
|
|---|
| 383 | # name which should be really used, by looking at the <tag> properties.
|
|---|
| 384 | # The tag properties come in two flavour:
|
|---|
| 385 | # - <tag>value,
|
|---|
| 386 | # - <tag>@rule-name
|
|---|
| 387 | # In the first case, value is just added to name
|
|---|
| 388 | # In the second case, the specified rule is called with specified name,
|
|---|
| 389 | # target type and properties and should return the new name.
|
|---|
| 390 | # If not <tag> property is specified, or the rule specified by
|
|---|
| 391 | # <tag> returns nothing, returns the result of calling
|
|---|
| 392 | # virtual-target.add-suffix
|
|---|
| 393 | rule _adjust-name ( specified-name )
|
|---|
| 394 | {
|
|---|
| 395 | local ps ;
|
|---|
| 396 | if $(self.action)
|
|---|
| 397 | {
|
|---|
| 398 | ps = [ $(self.action).properties ] ;
|
|---|
| 399 | }
|
|---|
| 400 | else
|
|---|
| 401 | {
|
|---|
| 402 | ps = [ property-set.empty ] ;
|
|---|
| 403 | }
|
|---|
| 404 |
|
|---|
| 405 | local tag = [ $(ps).get <tag> ] ;
|
|---|
| 406 |
|
|---|
| 407 | if $(tag)
|
|---|
| 408 | {
|
|---|
| 409 | local rule-name = [ MATCH ^@(.*) : $(tag) ] ;
|
|---|
| 410 | if $(rule-name)
|
|---|
| 411 | {
|
|---|
| 412 | if $(tag[2])
|
|---|
| 413 | {
|
|---|
| 414 | errors.error "<tag>@rulename is present but is not the only <tag> feature" ;
|
|---|
| 415 | }
|
|---|
| 416 |
|
|---|
| 417 | self.name = [ indirect.call $(rule-name) $(specified-name) :
|
|---|
| 418 | $(self.type) : $(ps) ] ;
|
|---|
| 419 | }
|
|---|
| 420 | else
|
|---|
| 421 | {
|
|---|
| 422 | errors.error
|
|---|
| 423 | "The value of the <tag> feature must be '@rule-nane'" ;
|
|---|
| 424 | }
|
|---|
| 425 | }
|
|---|
| 426 |
|
|---|
| 427 | # If there's no tag or the tag rule returned nothing.
|
|---|
| 428 | if ! $(tag) || ! $(self.name)
|
|---|
| 429 | {
|
|---|
| 430 | self.name = [ virtual-target.add-prefix-and-suffix
|
|---|
| 431 | $(specified-name) : $(self.type) : $(ps) ] ;
|
|---|
| 432 | }
|
|---|
| 433 | }
|
|---|
| 434 |
|
|---|
| 435 | rule actualize-no-scanner ( )
|
|---|
| 436 | {
|
|---|
| 437 | local name = [ actual-name ] ;
|
|---|
| 438 |
|
|---|
| 439 | # Do anything only on the first invocation
|
|---|
| 440 | if ! $(self.made.$(name)) {
|
|---|
| 441 | self.made.$(name) = true ;
|
|---|
| 442 |
|
|---|
| 443 | if $(self.action)
|
|---|
| 444 | {
|
|---|
| 445 | # For non-derived target, we don't care if there
|
|---|
| 446 | # are several virtual targets that refer to the same name.
|
|---|
| 447 | # One case when this is unavoidable is when file name is
|
|---|
| 448 | # main.cpp and two targets have types CPP (for compiling)
|
|---|
| 449 | # and MOCCABLE_CPP (for convertion to H via Qt tools).
|
|---|
| 450 | virtual-target.register-actual-name $(name) : $(__name__) ;
|
|---|
| 451 | }
|
|---|
| 452 |
|
|---|
| 453 | for local i in $(self.dependencies) {
|
|---|
| 454 | DEPENDS $(name) : [ $(i).actualize ] ;
|
|---|
| 455 | }
|
|---|
| 456 |
|
|---|
| 457 | actualize-location $(name) ;
|
|---|
| 458 | actualize-action $(name) ;
|
|---|
| 459 | }
|
|---|
| 460 | return $(name) ;
|
|---|
| 461 | }
|
|---|
| 462 |
|
|---|
| 463 | }
|
|---|
| 464 |
|
|---|
| 465 | # Appends the suffix appropriate to 'type/property-set' combination
|
|---|
| 466 | # to the specified name and returns the result.
|
|---|
| 467 | rule add-prefix-and-suffix ( specified-name : type ? : property-set )
|
|---|
| 468 | {
|
|---|
| 469 | local suffix = [ type.generated-target-suffix $(type) : $(property-set) ] ;
|
|---|
| 470 | suffix = .$(suffix) ;
|
|---|
| 471 |
|
|---|
| 472 | local prefix = [ type.generated-target-prefix $(type) : $(property-set) ] ;
|
|---|
| 473 |
|
|---|
| 474 | if [ type.is-derived $(type) LIB ] && [ os.on-unix ]
|
|---|
| 475 | {
|
|---|
| 476 | prefix = "lib" ;
|
|---|
| 477 | }
|
|---|
| 478 | if [ MATCH ^($(prefix)) : $(specified-name) ]
|
|---|
| 479 | {
|
|---|
| 480 | prefix = "" ;
|
|---|
| 481 | }
|
|---|
| 482 | return $(prefix:E="")$(specified-name)$(suffix:E="") ;
|
|---|
| 483 | }
|
|---|
| 484 |
|
|---|
| 485 |
|
|---|
| 486 | # File target with explicitly known location.
|
|---|
| 487 | #
|
|---|
| 488 | # The file path is determined as
|
|---|
| 489 | # - value passed to the 'set-path' method, if any
|
|---|
| 490 | # - for derived files, project's build dir, joined with components
|
|---|
| 491 | # that describe action's properties. If the free properties
|
|---|
| 492 | # are not equal to the project's reference properties
|
|---|
| 493 | # an element with name of main target is added.
|
|---|
| 494 | # - for source files, project's source dir
|
|---|
| 495 | #
|
|---|
| 496 | # The file suffix is
|
|---|
| 497 | # - the value passed to the 'suffix' method, if any, or
|
|---|
| 498 | # - the suffix which correspond to the target's type.
|
|---|
| 499 | #
|
|---|
| 500 | class file-target : abstract-file-target
|
|---|
| 501 | {
|
|---|
| 502 | import common ;
|
|---|
| 503 | import errors ;
|
|---|
| 504 | import "class" : new ;
|
|---|
| 505 |
|
|---|
| 506 | rule __init__ (
|
|---|
| 507 | name exact ?
|
|---|
| 508 | : type ? # Optional type for this target
|
|---|
| 509 | : project
|
|---|
| 510 | : action ?
|
|---|
| 511 | : path ?
|
|---|
| 512 | )
|
|---|
| 513 | {
|
|---|
| 514 | abstract-file-target.__init__ $(name) $(exact) : $(type) : $(project)
|
|---|
| 515 | : $(action) ;
|
|---|
| 516 |
|
|---|
| 517 | self.path = $(path) ;
|
|---|
| 518 | }
|
|---|
| 519 |
|
|---|
| 520 | rule clone-with-different-type ( new-type )
|
|---|
| 521 | {
|
|---|
| 522 | return [ new file-target $(self.name) exact : $(new-type)
|
|---|
| 523 | : $(self.project) : $(self.action) : $(self.path) ] ;
|
|---|
| 524 | }
|
|---|
| 525 |
|
|---|
| 526 | rule actualize-location ( target )
|
|---|
| 527 | {
|
|---|
| 528 | if $(self.action)
|
|---|
| 529 | {
|
|---|
| 530 | # This is a derived file.
|
|---|
| 531 | local path = [ path ] ;
|
|---|
| 532 | LOCATE on $(target) = $(path) ;
|
|---|
| 533 |
|
|---|
| 534 | # Make sure the path exists.
|
|---|
| 535 | DEPENDS $(target) : $(path) ;
|
|---|
| 536 | common.MkDir $(path) ;
|
|---|
| 537 |
|
|---|
| 538 | # It's possible that the target name includes a directory
|
|---|
| 539 | # too, for example when installing headers. Create that
|
|---|
| 540 | # directory.
|
|---|
| 541 | if $(target:D)
|
|---|
| 542 | {
|
|---|
| 543 | local d = $(target:D) ;
|
|---|
| 544 | d = $(d:R=$(path)) ;
|
|---|
| 545 | DEPENDS $(target) : $(d) ;
|
|---|
| 546 |
|
|---|
| 547 | common.MkDir $(d) ;
|
|---|
| 548 | }
|
|---|
| 549 |
|
|---|
| 550 | # For real file target, we create a fake target that
|
|---|
| 551 | # depends on the real target. This allows to run
|
|---|
| 552 | #
|
|---|
| 553 | # bjam hello.o
|
|---|
| 554 | #
|
|---|
| 555 | # without trying to guess the name of the real target.
|
|---|
| 556 | # Note the that target has no directory name, and a special
|
|---|
| 557 | # grist <e>.
|
|---|
| 558 | #
|
|---|
| 559 | # First, that means that "bjam hello.o" will build all
|
|---|
| 560 | # known hello.o targets.
|
|---|
| 561 | # Second, the <e> grist makes sure this target won't be confused
|
|---|
| 562 | # with other targets, for example, if we have subdir 'test'
|
|---|
| 563 | # with target 'test' in it that includes 'test.o' file,
|
|---|
| 564 | # then the target for directory will be just 'test' the target
|
|---|
| 565 | # for test.o will be <ptest/bin/gcc/debug>test.o and the target
|
|---|
| 566 | # we create below will be <e>test.o
|
|---|
| 567 | DEPENDS $(target:G=e) : $(target) ;
|
|---|
| 568 | }
|
|---|
| 569 | else
|
|---|
| 570 | {
|
|---|
| 571 | SEARCH on $(target) = [ path.native $(self.path) ] ;
|
|---|
| 572 | }
|
|---|
| 573 | }
|
|---|
| 574 |
|
|---|
| 575 | # Returns the directory for this target
|
|---|
| 576 | rule path ( )
|
|---|
| 577 | {
|
|---|
| 578 | if ! $(self.path)
|
|---|
| 579 | {
|
|---|
| 580 | if $(self.action)
|
|---|
| 581 | {
|
|---|
| 582 | local p = [ $(self.action).properties ] ;
|
|---|
| 583 | local path = [ $(p).target-path ] ;
|
|---|
| 584 |
|
|---|
| 585 | if $(path[2]) = true
|
|---|
| 586 | {
|
|---|
| 587 | # Indicates that the path is relative to
|
|---|
| 588 | # build dir.
|
|---|
| 589 | path = [ path.join [ $(self.project).build-dir ]
|
|---|
| 590 | $(path[1]) ] ;
|
|---|
| 591 | }
|
|---|
| 592 |
|
|---|
| 593 | # Store the computed path, so that it's not recomputed
|
|---|
| 594 | # any more
|
|---|
| 595 | self.path = [ path.native $(path) ] ;
|
|---|
| 596 | }
|
|---|
| 597 | }
|
|---|
| 598 | return $(self.path) ;
|
|---|
| 599 | }
|
|---|
| 600 |
|
|---|
| 601 | }
|
|---|
| 602 |
|
|---|
| 603 | class notfile-target : abstract-file-target
|
|---|
| 604 | {
|
|---|
| 605 | rule __init__ ( name : project : action ? )
|
|---|
| 606 | {
|
|---|
| 607 | abstract-file-target.__init__ $(name) : : $(project) : $(action) ;
|
|---|
| 608 | }
|
|---|
| 609 |
|
|---|
| 610 | # Returns nothing, to indicate that target path is not known.
|
|---|
| 611 | rule path ( )
|
|---|
| 612 | {
|
|---|
| 613 | return ;
|
|---|
| 614 | }
|
|---|
| 615 |
|
|---|
| 616 | rule actualize-location ( target )
|
|---|
| 617 | {
|
|---|
| 618 | NOTFILE $(target) ;
|
|---|
| 619 | ALWAYS $(target) ;
|
|---|
| 620 | }
|
|---|
| 621 | }
|
|---|
| 622 |
|
|---|
| 623 | # Class which represents an action.
|
|---|
| 624 | # Both 'targets' and 'sources' should list instances of 'virtual-target'.
|
|---|
| 625 | # Action name should name a rule with this prototype
|
|---|
| 626 | # rule action-name ( targets + : sources * : properties * )
|
|---|
| 627 | # Targets and sources are passed as actual jam targets. The rule may
|
|---|
| 628 | # not establish dependency relationship, but should do everything else.
|
|---|
| 629 | class action
|
|---|
| 630 | {
|
|---|
| 631 | import type toolset property-set indirect class path assert errors ;
|
|---|
| 632 |
|
|---|
| 633 | rule __init__ ( sources * : action-name + : property-set ? )
|
|---|
| 634 | {
|
|---|
| 635 | self.sources = $(sources) ;
|
|---|
| 636 |
|
|---|
| 637 | self.action-name = [ indirect.make-qualified $(action-name) ] ;
|
|---|
| 638 |
|
|---|
| 639 | if ! $(property-set)
|
|---|
| 640 | {
|
|---|
| 641 | property-set = [ property-set.empty ] ;
|
|---|
| 642 | }
|
|---|
| 643 |
|
|---|
| 644 | if ! [ class.is-instance $(property-set) ]
|
|---|
| 645 | {
|
|---|
| 646 | errors.error "Property set instance required" ;
|
|---|
| 647 | }
|
|---|
| 648 |
|
|---|
| 649 | self.properties = $(property-set) ;
|
|---|
| 650 | }
|
|---|
| 651 |
|
|---|
| 652 | rule add-targets ( targets * )
|
|---|
| 653 | {
|
|---|
| 654 | self.targets += $(targets) ;
|
|---|
| 655 | }
|
|---|
| 656 |
|
|---|
| 657 | rule targets ( )
|
|---|
| 658 | {
|
|---|
| 659 | return $(self.targets) ;
|
|---|
| 660 | }
|
|---|
| 661 |
|
|---|
| 662 | rule sources ( )
|
|---|
| 663 | {
|
|---|
| 664 | return $(self.sources) ;
|
|---|
| 665 | }
|
|---|
| 666 |
|
|---|
| 667 | rule action-name ( )
|
|---|
| 668 | {
|
|---|
| 669 | return $(self.action-name) ;
|
|---|
| 670 | }
|
|---|
| 671 |
|
|---|
| 672 | rule properties ( )
|
|---|
| 673 | {
|
|---|
| 674 | return $(self.properties) ;
|
|---|
| 675 | }
|
|---|
| 676 |
|
|---|
| 677 | # Generates actual build instructions.
|
|---|
| 678 | rule actualize ( )
|
|---|
| 679 | {
|
|---|
| 680 | if ! $(self.actualized)
|
|---|
| 681 | {
|
|---|
| 682 | self.actualized = true ;
|
|---|
| 683 |
|
|---|
| 684 | local ps = [ properties ] ;
|
|---|
| 685 | local properties = [ adjust-properties $(ps) ] ;
|
|---|
| 686 |
|
|---|
| 687 | local actual-targets ;
|
|---|
| 688 | for local i in [ targets ]
|
|---|
| 689 | {
|
|---|
| 690 | actual-targets += [ $(i).actualize ] ;
|
|---|
| 691 | }
|
|---|
| 692 |
|
|---|
| 693 | actualize-sources [ sources ] : $(properties) ;
|
|---|
| 694 |
|
|---|
| 695 | DEPENDS $(actual-targets) : $(self.actual-sources) $(self.dependency-only-sources) ;
|
|---|
| 696 |
|
|---|
| 697 | # Action name can include additional argument to rule, which should not
|
|---|
| 698 | # be passed to 'set-target-variables'
|
|---|
| 699 | toolset.set-target-variables
|
|---|
| 700 | [ indirect.get-rule $(self.action-name[1]) ] $(actual-targets)
|
|---|
| 701 | : $(properties) ;
|
|---|
| 702 |
|
|---|
| 703 | indirect.call $(self.action-name)
|
|---|
| 704 | $(actual-targets) : $(self.actual-sources) : [ $(properties).raw ]
|
|---|
| 705 | ;
|
|---|
| 706 |
|
|---|
| 707 | # Since we set up creating action here, we also set up
|
|---|
| 708 | # action for cleaning up
|
|---|
| 709 | common.Clean clean : $(actual-targets) ;
|
|---|
| 710 | }
|
|---|
| 711 | }
|
|---|
| 712 |
|
|---|
| 713 | # Helper for 'actualize-sources'.
|
|---|
| 714 | # For each passed source, actualizes it with the appropriate scanner.
|
|---|
| 715 | # Returns the actualized virtual targets.
|
|---|
| 716 | rule actualize-source-type ( sources * : property-set )
|
|---|
| 717 | {
|
|---|
| 718 | local result = ;
|
|---|
| 719 | for local i in $(sources)
|
|---|
| 720 | {
|
|---|
| 721 | local scanner ;
|
|---|
| 722 | if [ $(i).type ]
|
|---|
| 723 | {
|
|---|
| 724 | scanner =
|
|---|
| 725 | [ type.get-scanner [ $(i).type ] : $(property-set) ] ;
|
|---|
| 726 | }
|
|---|
| 727 | result += [ $(i).actualize $(scanner) ] ;
|
|---|
| 728 | }
|
|---|
| 729 |
|
|---|
| 730 | return $(result) ;
|
|---|
| 731 | }
|
|---|
| 732 |
|
|---|
| 733 | # Creates actual jam targets for sources. Initialized two member
|
|---|
| 734 | # variables:.
|
|---|
| 735 | # 'self.actual-sources' -- sources which are passed to updating action
|
|---|
| 736 | # 'self.dependency-only-sources' -- sources which are made dependencies, but
|
|---|
| 737 | # are not used otherwise.
|
|---|
| 738 | #
|
|---|
| 739 | # New values will be *appended* to the variables. They may be non-empty,
|
|---|
| 740 | # if caller wants it.
|
|---|
| 741 | rule actualize-sources ( sources * : property-set )
|
|---|
| 742 | {
|
|---|
| 743 | local dependencies = [ $(self.properties).get <dependency> ] ;
|
|---|
| 744 |
|
|---|
| 745 | self.dependency-only-sources += [
|
|---|
| 746 | actualize-source-type $(dependencies) : $(property-set) ] ;
|
|---|
| 747 | self.actual-sources += [
|
|---|
| 748 | actualize-source-type $(sources) : $(property-set) ] ;
|
|---|
| 749 | }
|
|---|
| 750 |
|
|---|
| 751 | # Determined real properties when trying building with 'properties'.
|
|---|
| 752 | # This is last chance to fix properties, for example to adjust includes
|
|---|
| 753 | # to get generated headers correctly. Default implementation returns
|
|---|
| 754 | # its argument.
|
|---|
| 755 | rule adjust-properties ( property-set )
|
|---|
| 756 | {
|
|---|
| 757 | return $(property-set) ;
|
|---|
| 758 | }
|
|---|
| 759 | }
|
|---|
| 760 |
|
|---|
| 761 | # Action class which does nothing --- it produces the targets with
|
|---|
| 762 | # specific properties out of nowhere. It's needed to distinguish virtual
|
|---|
| 763 | # targets with different properties that are known to exist, and have no
|
|---|
| 764 | # actions which create them.
|
|---|
| 765 | class null-action : action
|
|---|
| 766 | {
|
|---|
| 767 | rule __init__ ( property-set ? )
|
|---|
| 768 | {
|
|---|
| 769 | action.__init__ : .no-action : $(property-set) ;
|
|---|
| 770 | }
|
|---|
| 771 |
|
|---|
| 772 | rule actualize ( )
|
|---|
| 773 | {
|
|---|
| 774 | if ! $(self.actualized)
|
|---|
| 775 | {
|
|---|
| 776 | self.actualized = true ;
|
|---|
| 777 |
|
|---|
| 778 | for local i in [ targets ]
|
|---|
| 779 | {
|
|---|
| 780 | $(i).actualize ;
|
|---|
| 781 | }
|
|---|
| 782 | }
|
|---|
| 783 | }
|
|---|
| 784 | }
|
|---|
| 785 |
|
|---|
| 786 | # Class which acts exactly like 'action', except that the sources
|
|---|
| 787 | # are not scanned for dependencies.
|
|---|
| 788 | class non-scanning-action : action
|
|---|
| 789 | {
|
|---|
| 790 | rule __init__ ( sources * : action-name + : property-set ? )
|
|---|
| 791 | {
|
|---|
| 792 | action.__init__ $(sources) : $(action-name) : $(property-set) ;
|
|---|
| 793 | }
|
|---|
| 794 | rule actualize-source-type ( sources * : property-set )
|
|---|
| 795 | {
|
|---|
| 796 | local result ;
|
|---|
| 797 | for local i in $(sources)
|
|---|
| 798 | {
|
|---|
| 799 | result += [ $(i).actualize ] ;
|
|---|
| 800 | }
|
|---|
| 801 | return $(result) ;
|
|---|
| 802 | }
|
|---|
| 803 | }
|
|---|
| 804 |
|
|---|
| 805 |
|
|---|
| 806 | # Creates a virtual target with approariate name and type from 'file'.
|
|---|
| 807 | # If a target with that name in that project was already created, returns that already
|
|---|
| 808 | # created target.
|
|---|
| 809 | # FIXME: more correct way would be to compute path to the file, based on name and source location
|
|---|
| 810 | # for the project, and use that path to determine if the target was already created.
|
|---|
| 811 | # TODO: passing project with all virtual targets starts to be annoying.
|
|---|
| 812 | rule from-file ( file : file-loc : project )
|
|---|
| 813 | {
|
|---|
| 814 | import type ; # had to do this here to break a circular dependency
|
|---|
| 815 |
|
|---|
| 816 | # Check if we've created a target corresponding to this file.
|
|---|
| 817 | local path = [ path.root [ path.root $(file) $(file-loc) ]
|
|---|
| 818 | [ path.pwd ] ] ;
|
|---|
| 819 |
|
|---|
| 820 | if $(.files.$(path))
|
|---|
| 821 | {
|
|---|
| 822 | return $(.files.$(path)) ;
|
|---|
| 823 | }
|
|---|
| 824 | else
|
|---|
| 825 | {
|
|---|
| 826 | local name = [ path.make $(file) ] ;
|
|---|
| 827 | local type = [ type.type $(file) ] ;
|
|---|
| 828 | local result ;
|
|---|
| 829 |
|
|---|
| 830 | result = [ new file-target $(file)
|
|---|
| 831 | : $(type)
|
|---|
| 832 | : $(project)
|
|---|
| 833 | : #action
|
|---|
| 834 | : $(file-loc) ] ;
|
|---|
| 835 |
|
|---|
| 836 | .files.$(path) = $(result) ;
|
|---|
| 837 | return $(result) ;
|
|---|
| 838 | }
|
|---|
| 839 | }
|
|---|
| 840 |
|
|---|
| 841 | # Registers a new virtual target. Checks if there's already registered target, with the same
|
|---|
| 842 | # name, type, project and subvariant properties, and also with the same sources
|
|---|
| 843 | # and equal action. If such target is found it is retured and 'target' is not registers.
|
|---|
| 844 | # Otherwise, 'target' is registered and returned.
|
|---|
| 845 | rule register ( target )
|
|---|
| 846 | {
|
|---|
| 847 | local signature = [ sequence.join
|
|---|
| 848 | [ $(target).path ] [ $(target).name ] : - ] ;
|
|---|
| 849 |
|
|---|
| 850 |
|
|---|
| 851 | local result ;
|
|---|
| 852 | for local t in $(.cache.$(signature))
|
|---|
| 853 | {
|
|---|
| 854 | local a1 = [ $(t).action ] ;
|
|---|
| 855 | local a2 = [ $(target).action ] ;
|
|---|
| 856 |
|
|---|
| 857 | if ! $(result)
|
|---|
| 858 | {
|
|---|
| 859 | if ! $(a1) && ! $(a2)
|
|---|
| 860 | {
|
|---|
| 861 | result = $(t) ;
|
|---|
| 862 | }
|
|---|
| 863 | else
|
|---|
| 864 | {
|
|---|
| 865 | if $(a1) && $(a2) && [ $(a1).action-name ] = [ $(a2).action-name ] &&
|
|---|
| 866 | [ $(a1).sources ] = [ $(a2).sources ]
|
|---|
| 867 | {
|
|---|
| 868 | local ps1 = [ $(a1).properties ] ;
|
|---|
| 869 | local ps2 = [ $(a2).properties ] ;
|
|---|
| 870 | local p1 = [ $(ps1).base ] [ $(ps1).free ] [ $(ps1).dependency ] ;
|
|---|
| 871 | local p2 = [ $(ps2).base ] [ $(ps2).free ] [ $(ps2).dependency ] ;
|
|---|
| 872 | if $(p1) = $(p2)
|
|---|
| 873 | {
|
|---|
| 874 | result = $(t) ;
|
|---|
| 875 | }
|
|---|
| 876 | }
|
|---|
| 877 | }
|
|---|
| 878 | }
|
|---|
| 879 | }
|
|---|
| 880 |
|
|---|
| 881 | if ! $(result)
|
|---|
| 882 | {
|
|---|
| 883 | .cache.$(signature) += $(target) ;
|
|---|
| 884 | result = $(target) ;
|
|---|
| 885 | }
|
|---|
| 886 |
|
|---|
| 887 | .recent-targets += $(result) ;
|
|---|
| 888 |
|
|---|
| 889 | return $(result) ;
|
|---|
| 890 | }
|
|---|
| 891 |
|
|---|
| 892 |
|
|---|
| 893 | # Each target returned by 'register' is added to a list of
|
|---|
| 894 | # 'recent-target', returned by this function. So, this allows
|
|---|
| 895 | # us to find all targets created when building a given main
|
|---|
| 896 | # target, even if the target
|
|---|
| 897 | rule recent-targets ( )
|
|---|
| 898 | {
|
|---|
| 899 | return $(.recent-targets) ;
|
|---|
| 900 | }
|
|---|
| 901 |
|
|---|
| 902 | rule clear-recent-targets ( )
|
|---|
| 903 | {
|
|---|
| 904 | .recent-targets = ;
|
|---|
| 905 | }
|
|---|
| 906 |
|
|---|
| 907 |
|
|---|
| 908 |
|
|---|
| 909 |
|
|---|
| 910 | rule register-actual-name ( actual-name : virtual-target )
|
|---|
| 911 | {
|
|---|
| 912 | if $(.actual.$(actual-name))
|
|---|
| 913 | {
|
|---|
| 914 | local cs1 = [ $(.actual.$(actual-name)).creating-subvariant ] ;
|
|---|
| 915 | local cs2 = [ $(virtual-target).creating-subvariant ] ;
|
|---|
| 916 | local cmt1 = [ $(cs1).main-target ] ;
|
|---|
| 917 | local cmt2 = [ $(cs2).main-target ] ;
|
|---|
| 918 |
|
|---|
| 919 |
|
|---|
| 920 | local action1 = [ $(.actual.$(actual-name)).action ] ;
|
|---|
| 921 | local action2 = [ $(virtual-target).action ] ;
|
|---|
| 922 | local properties-added ;
|
|---|
| 923 | local properties-removed ;
|
|---|
| 924 | if $(action1) && $(action2)
|
|---|
| 925 | {
|
|---|
| 926 | local p1 = [ $(action1).properties ] ;
|
|---|
| 927 | p1 = [ $(p1).raw ] ;
|
|---|
| 928 | local p2 = [ $(action2).properties ] ;
|
|---|
| 929 | p2 = [ $(p2).raw ] ;
|
|---|
| 930 | properties-removed = [ set.difference $(p1) : $(p2) ] ;
|
|---|
| 931 | properties-removed ?= "none" ;
|
|---|
| 932 | properties-added = [ set.difference $(p2) : $(p1) ] ;
|
|---|
| 933 | properties-added ?= "none" ;
|
|---|
| 934 | }
|
|---|
| 935 | errors.error "Duplicate name of actual target:" $(actual-name)
|
|---|
| 936 | : "previous virtual target" [ $(.actual.$(actual-name)).str ]
|
|---|
| 937 | : "created from" [ $(cmt1).full-name ]
|
|---|
| 938 | : "another virtual target" [ $(virtual-target).str ]
|
|---|
| 939 | : "created from" [ $(cmt2).full-name ]
|
|---|
| 940 | : "added properties: " $(properties-added)
|
|---|
| 941 | : "removed properties: " $(properties-removed) ;
|
|---|
| 942 | }
|
|---|
| 943 | else
|
|---|
| 944 | {
|
|---|
| 945 | .actual.$(actual-name) = $(virtual-target) ;
|
|---|
| 946 | }
|
|---|
| 947 | }
|
|---|
| 948 |
|
|---|
| 949 |
|
|---|
| 950 | # Traverses the dependency graph of 'target' and return all targets that will
|
|---|
| 951 | # be created before this one is created. If root of some dependency graph is
|
|---|
| 952 | # found during traversal, it's either included or not, dependencing of the
|
|---|
| 953 | # value of 'include-roots'. In either case, sources of root are not traversed.
|
|---|
| 954 | rule traverse ( target : include-roots ? : include-sources ? )
|
|---|
| 955 | {
|
|---|
| 956 | local result ;
|
|---|
| 957 | if [ $(target).action ]
|
|---|
| 958 | {
|
|---|
| 959 | local action = [ $(target).action ] ;
|
|---|
| 960 | # This includes 'target' as well
|
|---|
| 961 | result += [ $(action).targets ] ;
|
|---|
| 962 |
|
|---|
| 963 | for local t in [ $(action).sources ]
|
|---|
| 964 | {
|
|---|
| 965 | if ! [ $(t).root ]
|
|---|
| 966 | {
|
|---|
| 967 | result += [ traverse $(t) : $(include-roots) : $(include-sources) ] ;
|
|---|
| 968 | }
|
|---|
| 969 | else if $(include-roots)
|
|---|
| 970 | {
|
|---|
| 971 | result += $(t) ;
|
|---|
| 972 | }
|
|---|
| 973 | }
|
|---|
| 974 | }
|
|---|
| 975 | else if $(include-sources)
|
|---|
| 976 | {
|
|---|
| 977 | result = $(target) ;
|
|---|
| 978 | }
|
|---|
| 979 | return $(result) ;
|
|---|
| 980 | }
|
|---|
| 981 |
|
|---|
| 982 | # Takes an 'action' instances and creates new instance of it
|
|---|
| 983 | # and all produced target. The rule-name and properties are set
|
|---|
| 984 | # to 'new-rule-name' and 'new-properties', if those are specified.
|
|---|
| 985 | # Returns the cloned action.
|
|---|
| 986 | rule clone-action ( action : new-project : new-action-name ? : new-properties ? )
|
|---|
| 987 | {
|
|---|
| 988 | if ! $(new-action-name)
|
|---|
| 989 | {
|
|---|
| 990 | new-action-name = [ $(action).action-name ] ;
|
|---|
| 991 | }
|
|---|
| 992 | if ! $(new-properties)
|
|---|
| 993 | {
|
|---|
| 994 | new-properties = [ $(action).properties ] ;
|
|---|
| 995 | }
|
|---|
| 996 |
|
|---|
| 997 | local action-class = [ modules.peek $(action) : __class__ ] ;
|
|---|
| 998 | local cloned-action = [ class.new $(action-class)
|
|---|
| 999 | [ $(action).sources ] : $(new-action-name) : $(new-properties) ] ;
|
|---|
| 1000 |
|
|---|
| 1001 | local cloned-targets ;
|
|---|
| 1002 | for local target in [ $(action).targets ]
|
|---|
| 1003 | {
|
|---|
| 1004 | local n = [ $(target).name ] ;
|
|---|
| 1005 | # Don't modify the name of the produced targets.Strip the directory f
|
|---|
| 1006 | local cloned-target = [ class.new file-target $(n) exact : [ $(target).type ]
|
|---|
| 1007 | : $(new-project) : $(cloned-action) ] ;
|
|---|
| 1008 | local d = [ $(target).dependencies ] ;
|
|---|
| 1009 | if $(d)
|
|---|
| 1010 | {
|
|---|
| 1011 | $(cloned-target).depends $(d) ;
|
|---|
| 1012 | }
|
|---|
| 1013 | $(cloned-target).root [ $(target).root ] ;
|
|---|
| 1014 | $(cloned-target).creating-subvariant [ $(target).creating-subvariant ] ;
|
|---|
| 1015 |
|
|---|
| 1016 | cloned-targets += $(cloned-target) ;
|
|---|
| 1017 | }
|
|---|
| 1018 |
|
|---|
| 1019 | return $(cloned-action) ;
|
|---|
| 1020 | }
|
|---|
| 1021 |
|
|---|
| 1022 | class subvariant
|
|---|
| 1023 | {
|
|---|
| 1024 | import sequence ;
|
|---|
| 1025 | import type ;
|
|---|
| 1026 |
|
|---|
| 1027 | rule __init__ ( main-target # The instance of main-target class
|
|---|
| 1028 | : property-set # Properties requested for this target
|
|---|
| 1029 | : sources *
|
|---|
| 1030 | : build-properties # Actually used properties
|
|---|
| 1031 | : sources-usage-requirements # Properties propagated from sources
|
|---|
| 1032 | : created-targets * ) # Top-level created targets
|
|---|
| 1033 | {
|
|---|
| 1034 | self.main-target = $(main-target) ;
|
|---|
| 1035 | self.properties = $(property-set) ;
|
|---|
| 1036 | self.sources = $(sources) ;
|
|---|
| 1037 | self.build-properties = $(build-properties) ;
|
|---|
| 1038 | self.sources-usage-requirements = $(sources-usage-requirements) ;
|
|---|
| 1039 | self.created-targets = $(created-targets) ;
|
|---|
| 1040 |
|
|---|
| 1041 | # Pre-compose the list of other dependency graphs, on which this one
|
|---|
| 1042 | # depends
|
|---|
| 1043 | local deps = [ $(build-properties).get <implicit-dependency> ] ;
|
|---|
| 1044 | for local d in $(deps)
|
|---|
| 1045 | {
|
|---|
| 1046 | self.other-dg += [ $(d:G=).creating-subvariant ] ;
|
|---|
| 1047 | }
|
|---|
| 1048 |
|
|---|
| 1049 | self.other-dg = [ sequence.unique $(self.other-dg) ] ;
|
|---|
| 1050 | }
|
|---|
| 1051 |
|
|---|
| 1052 |
|
|---|
| 1053 | rule main-target ( )
|
|---|
| 1054 | {
|
|---|
| 1055 | return $(self.main-target) ;
|
|---|
| 1056 | }
|
|---|
| 1057 |
|
|---|
| 1058 | rule created-targets ( )
|
|---|
| 1059 | {
|
|---|
| 1060 | return $(self.created-targets) ;
|
|---|
| 1061 | }
|
|---|
| 1062 |
|
|---|
| 1063 | rule requested-properties ( )
|
|---|
| 1064 | {
|
|---|
| 1065 | return $(self.properties) ;
|
|---|
| 1066 | }
|
|---|
| 1067 |
|
|---|
| 1068 | rule build-properties ( )
|
|---|
| 1069 | {
|
|---|
| 1070 | return $(self.build-properties) ;
|
|---|
| 1071 | }
|
|---|
| 1072 |
|
|---|
| 1073 | rule sources-usage-requirements ( )
|
|---|
| 1074 | {
|
|---|
| 1075 | return $(self.sources-usage-requirements) ;
|
|---|
| 1076 | }
|
|---|
| 1077 |
|
|---|
| 1078 | rule set-usage-requirements ( usage-requirements )
|
|---|
| 1079 | {
|
|---|
| 1080 | self.usage-requirements = $(usage-requirements) ;
|
|---|
| 1081 | }
|
|---|
| 1082 |
|
|---|
| 1083 | rule usage-requirements ( )
|
|---|
| 1084 | {
|
|---|
| 1085 | return $(self.usage-requirements) ;
|
|---|
| 1086 | }
|
|---|
| 1087 |
|
|---|
| 1088 | # Returns all targets referenced by this subvariant,
|
|---|
| 1089 | # either directly or indirectly, and
|
|---|
| 1090 | # either as sources, or as dependency properties.
|
|---|
| 1091 | # Targets referred with dependency property are returned a properties,
|
|---|
| 1092 | # not targets.
|
|---|
| 1093 | rule all-referenced-targets ( )
|
|---|
| 1094 | {
|
|---|
| 1095 | # Find directly referenced targets.
|
|---|
| 1096 | local deps = [ $(self.build-properties).dependency ] ;
|
|---|
| 1097 | local all-targets = $(self.sources) $(deps) ;
|
|---|
| 1098 |
|
|---|
| 1099 | # Find other subvariants.
|
|---|
| 1100 | local r ;
|
|---|
| 1101 | for local t in $(all-targets)
|
|---|
| 1102 | {
|
|---|
| 1103 | r += [ $(t:G=).creating-subvariant ] ;
|
|---|
| 1104 | }
|
|---|
| 1105 | r = [ sequence.unique $(r) ] ;
|
|---|
| 1106 | for local s in $(r)
|
|---|
| 1107 | {
|
|---|
| 1108 | if $(s) != $(__name__)
|
|---|
| 1109 | {
|
|---|
| 1110 | all-targets += [ $(s).all-referenced-targets ] ;
|
|---|
| 1111 | }
|
|---|
| 1112 | }
|
|---|
| 1113 | return $(all-targets) ;
|
|---|
| 1114 | }
|
|---|
| 1115 |
|
|---|
| 1116 | # Returns the properties which specify implicit include paths to
|
|---|
| 1117 | # generated headers. This traverses all targets in this subvariant,
|
|---|
| 1118 | # and subvariants referred by <implcit-dependecy>properties.
|
|---|
| 1119 | # For all targets which are of type 'target-type' (or for all targets,
|
|---|
| 1120 | # if 'target-type' is not specified), the result will contain
|
|---|
| 1121 | # <$(feature)>path-to-that-target.
|
|---|
| 1122 | rule implicit-includes ( feature : target-type ? )
|
|---|
| 1123 | {
|
|---|
| 1124 | local key = ii$(feature)-$(target-type:E="") ;
|
|---|
| 1125 | if ! $($(key))-is-nonempty
|
|---|
| 1126 | {
|
|---|
| 1127 | local target-paths = [ all-target-directories $(target-type) ] ;
|
|---|
| 1128 | target-paths = [ sequence.unique $(target-paths) ] ;
|
|---|
| 1129 | local result = $(target-paths:G=$(feature)) ;
|
|---|
| 1130 | if ! $(result)
|
|---|
| 1131 | {
|
|---|
| 1132 | result = "" ;
|
|---|
| 1133 | }
|
|---|
| 1134 | $(key) = $(result) ;
|
|---|
| 1135 | }
|
|---|
| 1136 | if $($(key)) = ""
|
|---|
| 1137 | {
|
|---|
| 1138 | return ;
|
|---|
| 1139 | }
|
|---|
| 1140 | else
|
|---|
| 1141 | {
|
|---|
| 1142 | return $($(key)) ;
|
|---|
| 1143 | }
|
|---|
| 1144 | }
|
|---|
| 1145 |
|
|---|
| 1146 | rule all-target-directories ( target-type ? )
|
|---|
| 1147 | {
|
|---|
| 1148 | if ! $(self.target-directories)
|
|---|
| 1149 | {
|
|---|
| 1150 | compute-target-directories $(target-type) ;
|
|---|
| 1151 | }
|
|---|
| 1152 | return $(self.target-directories) ;
|
|---|
| 1153 | }
|
|---|
| 1154 |
|
|---|
| 1155 | rule compute-target-directories ( target-type ? )
|
|---|
| 1156 | {
|
|---|
| 1157 | local result ;
|
|---|
| 1158 | for local t in $(self.created-targets)
|
|---|
| 1159 | {
|
|---|
| 1160 | if $(target-type) && ! [ type.is-derived [ $(t).type ] $(target-type) ]
|
|---|
| 1161 | {
|
|---|
| 1162 | # Skip target which is of wrong type.
|
|---|
| 1163 | }
|
|---|
| 1164 | else
|
|---|
| 1165 | {
|
|---|
| 1166 | result = [ sequence.merge $(result) : [ $(t).path ] ] ;
|
|---|
| 1167 | }
|
|---|
| 1168 | }
|
|---|
| 1169 | for local d in $(self.other-dg)
|
|---|
| 1170 | {
|
|---|
| 1171 | result += [ $(d).all-target-directories $(target-type) ] ;
|
|---|
| 1172 | }
|
|---|
| 1173 | self.target-directories = $(result) ;
|
|---|
| 1174 | }
|
|---|
| 1175 | }
|
|---|
| 1176 |
|
|---|