| 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 | # Deals with target type declaration and defines target class which supports
|
|---|
| 7 | # typed targets.
|
|---|
| 8 |
|
|---|
| 9 | import feature ;
|
|---|
| 10 | import generators : * ;
|
|---|
| 11 | import "class" : new ;
|
|---|
| 12 | import errors ;
|
|---|
| 13 | import property ;
|
|---|
| 14 | import scanner ;
|
|---|
| 15 | import project ;
|
|---|
| 16 |
|
|---|
| 17 | # This creates a circular dependency
|
|---|
| 18 | # project-test1 -> project -> project-root -> builtin -> type -> targets -> project
|
|---|
| 19 | # import targets ;
|
|---|
| 20 |
|
|---|
| 21 | # The feature is optional so that it never implicitly added.
|
|---|
| 22 | # It's used only for internal purposes, and in all cases we
|
|---|
| 23 | # want to explicitly use it.
|
|---|
| 24 | feature.feature target-type : : composite optional ;
|
|---|
| 25 |
|
|---|
| 26 | # feature.feature base-target-type : : composite optional ;
|
|---|
| 27 | feature.feature main-target-type : : optional incidental ;
|
|---|
| 28 | feature.feature base-target-type : : composite optional free ;
|
|---|
| 29 | # feature.feature main-target-type : : composite optional incidental ;
|
|---|
| 30 |
|
|---|
| 31 | # Store suffixes for generated targets
|
|---|
| 32 | .suffixes = [ new property-map ] ;
|
|---|
| 33 |
|
|---|
| 34 | # Registers a target type, possible derived from a 'base-type'.
|
|---|
| 35 | # If 'suffixes' are provided, they given all the suffixes that mean a file is of 'type'.
|
|---|
| 36 | # Also, the first element gives the suffix to be used when constructing and object of
|
|---|
| 37 | # 'type'.
|
|---|
| 38 | rule register ( type : suffixes * : base-type ? )
|
|---|
| 39 | {
|
|---|
| 40 | # Type names cannot contain hyphens, because when used as
|
|---|
| 41 | # feature-values they will be interpreted as composite features
|
|---|
| 42 | # which need to be decomposed.
|
|---|
| 43 | switch $(type)
|
|---|
| 44 | {
|
|---|
| 45 | case *-* : errors.error "type name \"$(type)\" contains a hyphen" ;
|
|---|
| 46 | }
|
|---|
| 47 |
|
|---|
| 48 | if $(type) in $(.types)
|
|---|
| 49 | {
|
|---|
| 50 | errors.error "Type $(type) is already registered." ;
|
|---|
| 51 | }
|
|---|
| 52 | else
|
|---|
| 53 | {
|
|---|
| 54 | .types += $(type) ;
|
|---|
| 55 | .bases.$(type) = $(base-type) ;
|
|---|
| 56 | .derived.$(base-type) += $(type) ;
|
|---|
| 57 |
|
|---|
| 58 | if $(suffixes)-not-empty
|
|---|
| 59 | {
|
|---|
| 60 | # Generated targets of 'type' will use the first of 'suffixes'
|
|---|
| 61 | # (this may be overriden)
|
|---|
| 62 | $(.suffixes).insert <target-type>$(type) : $(suffixes[1]) ;
|
|---|
| 63 | # Specify mapping from suffixes to type
|
|---|
| 64 | register-suffixes $(suffixes) : $(type) ;
|
|---|
| 65 | }
|
|---|
| 66 |
|
|---|
| 67 | feature.extend target-type : $(type) ;
|
|---|
| 68 | feature.extend main-target-type : $(type) ;
|
|---|
| 69 |
|
|---|
| 70 | feature.compose <target-type>$(type) : $(base-type:G=<base-target-type>) ;
|
|---|
| 71 | feature.extend base-target-type : $(type) ;
|
|---|
| 72 | # feature.compose <target-type>$(type) : <base-target-type>$(type) ;
|
|---|
| 73 | feature.compose <base-target-type>$(type) : <base-target-type>$(base-type) ;
|
|---|
| 74 |
|
|---|
| 75 | # We used to declare main target rule only when 'main' parameter
|
|---|
| 76 | # is specified. However, it's hard to decide that a type *never*
|
|---|
| 77 | # will need a main target rule and so from time to time we needed
|
|---|
| 78 | # to make yet another type 'main'. So, now main target rule is defined
|
|---|
| 79 | # for each type.
|
|---|
| 80 | main-rule-name = [ type-to-rule-name $(type) ] ;
|
|---|
| 81 | .main-target-type.$(main-rule-name) = $(type) ;
|
|---|
| 82 |
|
|---|
| 83 | IMPORT $(__name__) : main-target-rule : : $(main-rule-name) ;
|
|---|
| 84 | }
|
|---|
| 85 | }
|
|---|
| 86 |
|
|---|
| 87 | # Given type, returns name of main target rule which creates
|
|---|
| 88 | # targets of that type.
|
|---|
| 89 | rule type-to-rule-name ( type )
|
|---|
| 90 | {
|
|---|
| 91 | # Lowercase everything. Convert underscores to dashes.ame.
|
|---|
| 92 | import regex ;
|
|---|
| 93 | local n = [ regex.split $(type:L) "_" ] ;
|
|---|
| 94 | n = $(n:J=-) ;
|
|---|
| 95 | return $(n) ;
|
|---|
| 96 | }
|
|---|
| 97 |
|
|---|
| 98 | # Returns a type, given the name of a main rule.
|
|---|
| 99 | rule type-from-rule-name ( main-target-name )
|
|---|
| 100 | {
|
|---|
| 101 | return $(.main-target-type.$(main-target-name)) ;
|
|---|
| 102 | }
|
|---|
| 103 |
|
|---|
| 104 |
|
|---|
| 105 |
|
|---|
| 106 | # Specifies that targets with suffix from 'suffixes' has the type 'type'.
|
|---|
| 107 | # If different type is already specified for any of syffixes,
|
|---|
| 108 | # issues an error.
|
|---|
| 109 | rule register-suffixes ( suffixes + : type )
|
|---|
| 110 | {
|
|---|
| 111 | for local s in $(suffixes)
|
|---|
| 112 | {
|
|---|
| 113 | if ! $(.type.$(s))
|
|---|
| 114 | {
|
|---|
| 115 | .type.$(s) = $(type) ;
|
|---|
| 116 | }
|
|---|
| 117 | else if $(.type.$(s)) != type
|
|---|
| 118 | {
|
|---|
| 119 | errors.error Attempting to specify type for suffix \"$(s)\"
|
|---|
| 120 | : "Old type $(.type.$(s)), New type $(type)" ;
|
|---|
| 121 | }
|
|---|
| 122 | }
|
|---|
| 123 | }
|
|---|
| 124 |
|
|---|
| 125 |
|
|---|
| 126 | # Returns true iff type has been registered.
|
|---|
| 127 | rule registered ( type )
|
|---|
| 128 | {
|
|---|
| 129 | if $(type) in $(.types)
|
|---|
| 130 | {
|
|---|
| 131 | return true ;
|
|---|
| 132 | }
|
|---|
| 133 | }
|
|---|
| 134 |
|
|---|
| 135 | # Issues an error if 'type' is unknown.
|
|---|
| 136 | rule validate ( type )
|
|---|
| 137 | {
|
|---|
| 138 | if ! $(type) in $(.types)
|
|---|
| 139 | {
|
|---|
| 140 | errors.error "Unknown target type $(type)" ;
|
|---|
| 141 | }
|
|---|
| 142 | }
|
|---|
| 143 |
|
|---|
| 144 |
|
|---|
| 145 | # Sets a scanner class that will be used for this 'type'.
|
|---|
| 146 | rule set-scanner ( type : scanner )
|
|---|
| 147 | {
|
|---|
| 148 | if ! $(type) in $(.types)
|
|---|
| 149 | {
|
|---|
| 150 | error "Type" $(type) "is not declared" ;
|
|---|
| 151 | }
|
|---|
| 152 | .scanner.$(type) = $(scanner) ;
|
|---|
| 153 | }
|
|---|
| 154 |
|
|---|
| 155 | # Returns a scanner instance appropriate to 'type' and 'properties'.
|
|---|
| 156 | rule get-scanner ( type : property-set )
|
|---|
| 157 | {
|
|---|
| 158 | if $(.scanner.$(type)) {
|
|---|
| 159 | return [ scanner.get $(.scanner.$(type)) : $(property-set) ] ;
|
|---|
| 160 | }
|
|---|
| 161 | }
|
|---|
| 162 |
|
|---|
| 163 | # returns type and all of its bases in order of their distance from type.
|
|---|
| 164 | rule all-bases ( type )
|
|---|
| 165 | {
|
|---|
| 166 | local result = $(type) ;
|
|---|
| 167 | while $(type)
|
|---|
| 168 | {
|
|---|
| 169 | type = $(.bases.$(type)) ;
|
|---|
| 170 | result += $(type) ;
|
|---|
| 171 | }
|
|---|
| 172 | return $(result) ;
|
|---|
| 173 | }
|
|---|
| 174 |
|
|---|
| 175 | rule all-derived ( type )
|
|---|
| 176 | {
|
|---|
| 177 | local result = $(type) ;
|
|---|
| 178 | for local d in $(.derived.$(type))
|
|---|
| 179 | {
|
|---|
| 180 | result += [ all-derived $(d) ] ;
|
|---|
| 181 | }
|
|---|
| 182 | return $(result) ;
|
|---|
| 183 | }
|
|---|
| 184 |
|
|---|
| 185 |
|
|---|
| 186 | # Returns true if 'type' has 'base' as its direct or
|
|---|
| 187 | # indirect base.
|
|---|
| 188 | rule is-derived ( type base )
|
|---|
| 189 | {
|
|---|
| 190 | if $(base) in [ all-bases $(type) ]
|
|---|
| 191 | {
|
|---|
| 192 | return true ;
|
|---|
| 193 | }
|
|---|
| 194 | }
|
|---|
| 195 |
|
|---|
| 196 | # Returns true if 'type' is either derived from 'base',
|
|---|
| 197 | # or 'type' is equal to 'base'.
|
|---|
| 198 | rule is-subtype ( type base )
|
|---|
| 199 | {
|
|---|
| 200 | if $(type) = $(base)
|
|---|
| 201 | {
|
|---|
| 202 | return true ;
|
|---|
| 203 | }
|
|---|
| 204 | else
|
|---|
| 205 | {
|
|---|
| 206 | return [ is-derived $(type) $(base) ] ;
|
|---|
| 207 | }
|
|---|
| 208 | }
|
|---|
| 209 |
|
|---|
| 210 |
|
|---|
| 211 | # Sets a target suffix that should be used when generating target
|
|---|
| 212 | # of 'type' with the specified properties. Can be called with
|
|---|
| 213 | # empty properties if no suffix for 'type' was specified yet.
|
|---|
| 214 | # This does not automatically specify that files 'suffix' have
|
|---|
| 215 | # 'type' --- two different types can use the same suffix for
|
|---|
| 216 | # generating, but only one type should be auto-detected for
|
|---|
| 217 | # a file with that suffix. User should explicitly specify which
|
|---|
| 218 | # one.
|
|---|
| 219 | #
|
|---|
| 220 | # The 'suffix' parameter can be empty string ("") to indicate that
|
|---|
| 221 | # no suffix should be used.
|
|---|
| 222 | rule set-generated-target-suffix ( type : properties * : suffix )
|
|---|
| 223 | {
|
|---|
| 224 | set-generated-target-ps $(type) : $(properties) : suffix : $(suffix) ;
|
|---|
| 225 | }
|
|---|
| 226 |
|
|---|
| 227 | # Change the suffix previously registered for this type/properties
|
|---|
| 228 | # combination. If suffix is not yet specified, sets it.
|
|---|
| 229 | rule change-generated-target-suffix ( type : properties * : suffix )
|
|---|
| 230 | {
|
|---|
| 231 | change-generated-target-ps $(type) : $(properties) : suffix : $(suffix) ;
|
|---|
| 232 | }
|
|---|
| 233 |
|
|---|
| 234 |
|
|---|
| 235 | # Returns suffix that should be used when generating target of 'type',
|
|---|
| 236 | # with the specified properties. If not suffix were specified for
|
|---|
| 237 | # 'type', returns suffix for base type, if any.
|
|---|
| 238 | rule generated-target-suffix-real ( type : properties * )
|
|---|
| 239 | {
|
|---|
| 240 | return [ generated-target-ps-real $(type) : $(properties) : suffix ] ;
|
|---|
| 241 | }
|
|---|
| 242 |
|
|---|
| 243 | rule generated-target-suffix ( type : property-set )
|
|---|
| 244 | {
|
|---|
| 245 | return [ generated-target-ps $(type) : $(property-set) : suffix ] ;
|
|---|
| 246 | }
|
|---|
| 247 |
|
|---|
| 248 |
|
|---|
| 249 | # Returns file type given it's name. If there are several dots in filename,
|
|---|
| 250 | # tries each suffix. E.g. for name of "file.so.1.2" suffixes "2", "1", and
|
|---|
| 251 | # "so" will be tried.
|
|---|
| 252 | rule type ( filename )
|
|---|
| 253 | {
|
|---|
| 254 | local type ;
|
|---|
| 255 | while ! $(type) && $(filename:S)
|
|---|
| 256 | {
|
|---|
| 257 | local suffix = $(filename:S) ;
|
|---|
| 258 | type = $(.type$(suffix)) ;
|
|---|
| 259 | filename = $(filename:S=) ;
|
|---|
| 260 | }
|
|---|
| 261 | return $(type) ;
|
|---|
| 262 | }
|
|---|
| 263 |
|
|---|
| 264 |
|
|---|
| 265 |
|
|---|
| 266 | rule main-target-rule ( name : sources * : requirements * : default-build *
|
|---|
| 267 | : usage-requirements * )
|
|---|
| 268 | {
|
|---|
| 269 | # First find required target type, which is equal to the name used
|
|---|
| 270 | # to invoke us.
|
|---|
| 271 | local bt = [ BACKTRACE 1 ] ;
|
|---|
| 272 | local rulename = $(bt[4]) ;
|
|---|
| 273 |
|
|---|
| 274 | # This rule may be only called from Jamfile, and therefore,
|
|---|
| 275 | # CALLER_MODULE is Jamfile module, which is used to denote
|
|---|
| 276 | # a project.
|
|---|
| 277 | local project = [ project.current ] ;
|
|---|
| 278 |
|
|---|
| 279 | # This is a circular module dependency, so it must be imported here
|
|---|
| 280 | import targets ;
|
|---|
| 281 | return [ targets.create-typed-target $(.main-target-type.$(rulename)) : $(project)
|
|---|
| 282 | : $(name) : $(sources) : $(requirements)
|
|---|
| 283 | : $(default-build) : $(usage-requirements) ] ;
|
|---|
| 284 | }
|
|---|
| 285 |
|
|---|
| 286 | # These prefix provisioning rules were derived from suffix provisioning
|
|---|
| 287 | # rules almost by just changing "suffix" to "prefix" in the suffix rules.
|
|---|
| 288 | # Then they were refactored by moving duplicate code into
|
|---|
| 289 | # rules that apply to prefix and suffix provisioning.
|
|---|
| 290 |
|
|---|
| 291 | # Store prefixes for generated targets (e.g. "lib" for library)
|
|---|
| 292 | .prefixes = [ new property-map ] ;
|
|---|
| 293 |
|
|---|
| 294 | # Sets a target prefix that should be used when generating target
|
|---|
| 295 | # of 'type' with the specified properties. Can be called with
|
|---|
| 296 | # empty properties if no prefix for 'type' was specified yet.
|
|---|
| 297 | #
|
|---|
| 298 | # The 'prefix' parameter can be empty string ("") to indicate that
|
|---|
| 299 | # no prefix should be used.
|
|---|
| 300 | #
|
|---|
| 301 | # Example usage is for library names that have to have a "lib"
|
|---|
| 302 | # prefix as in unix.
|
|---|
| 303 | rule set-generated-target-prefix ( type : properties * : prefix )
|
|---|
| 304 | {
|
|---|
| 305 | set-generated-target-ps $(type) : $(properties) : prefix : $(prefix) ;
|
|---|
| 306 | }
|
|---|
| 307 |
|
|---|
| 308 | # Change the prefix previously registered for this type/properties
|
|---|
| 309 | # combination. If prefix is not yet specified, sets it.
|
|---|
| 310 | rule change-generated-target-prefix ( type : properties * : prefix )
|
|---|
| 311 | {
|
|---|
| 312 | change-generated-target-ps $(type) : $(properties) : prefix : $(prefix) ;
|
|---|
| 313 | }
|
|---|
| 314 |
|
|---|
| 315 | # Returns prefix that should be used when generating target of 'type',
|
|---|
| 316 | # with the specified properties. If no prefix is specified for
|
|---|
| 317 | # 'type', returns prefix for base type, if any.
|
|---|
| 318 | rule generated-target-prefix-real ( type : properties * )
|
|---|
| 319 | {
|
|---|
| 320 | return [ generated-target-ps-real $(type) : $(properties) : prefix ] ;
|
|---|
| 321 | }
|
|---|
| 322 |
|
|---|
| 323 | rule generated-target-prefix ( type : property-set )
|
|---|
| 324 | {
|
|---|
| 325 | return [ generated-target-ps $(type) : $(property-set) : prefix ] ;
|
|---|
| 326 | }
|
|---|
| 327 |
|
|---|
| 328 | # Common rules for prefix/suffix provisioning follow
|
|---|
| 329 |
|
|---|
| 330 | rule set-generated-target-ps ( type : properties * : ps : psval )
|
|---|
| 331 | {
|
|---|
| 332 | properties = <target-type>$(type) $(properties) ;
|
|---|
| 333 | $(.$(ps)es).insert $(properties) : $(psval) ;
|
|---|
| 334 | }
|
|---|
| 335 |
|
|---|
| 336 | rule change-generated-target-ps ( type : properties * : ps : psval )
|
|---|
| 337 | {
|
|---|
| 338 | properties = <target-type>$(type) $(properties) ;
|
|---|
| 339 | local prev = [ $(.$(ps)es).find-replace $(properties) : $(psval) ] ;
|
|---|
| 340 | if ! $(prev)
|
|---|
| 341 | {
|
|---|
| 342 | set-generated-target-prefix $(type) : $(properties) : $(psval) ;
|
|---|
| 343 | }
|
|---|
| 344 | }
|
|---|
| 345 |
|
|---|
| 346 | rule generated-target-ps-real ( type : properties * : psn )
|
|---|
| 347 | {
|
|---|
| 348 | local result ;
|
|---|
| 349 | local found ;
|
|---|
| 350 | while $(type) && ! $(found)
|
|---|
| 351 | {
|
|---|
| 352 | result = [ $(.$(ps)es).find <target-type>$(type) $(properties) ] ;
|
|---|
| 353 | # If the property (prefix/suffix) is explicitly set to empty string,
|
|---|
| 354 | # we consider prefix to be found. If we did not compare with "",
|
|---|
| 355 | # there would be no way for user to set empty prefix.
|
|---|
| 356 | if $(result)-is-not-empty
|
|---|
| 357 | {
|
|---|
| 358 | found = true ;
|
|---|
| 359 | }
|
|---|
| 360 | type = $(.bases.$(type)) ;
|
|---|
| 361 | }
|
|---|
| 362 | if $(result) = ""
|
|---|
| 363 | {
|
|---|
| 364 | result = ;
|
|---|
| 365 | }
|
|---|
| 366 | return $(result) ;
|
|---|
| 367 | }
|
|---|
| 368 |
|
|---|
| 369 | rule generated-target-ps ( type : property-set : ps )
|
|---|
| 370 | {
|
|---|
| 371 | local key = .$(ps).$(type).$(property-set) ;
|
|---|
| 372 | local v = $($(key)) ;
|
|---|
| 373 | if ! $(v)
|
|---|
| 374 | {
|
|---|
| 375 | v = [ generated-target-prefix-real $(type)
|
|---|
| 376 | : [ $(property-set).raw ] ] ;
|
|---|
| 377 | if ! $(v)
|
|---|
| 378 | {
|
|---|
| 379 | v = none ;
|
|---|
| 380 | }
|
|---|
| 381 | $(key) = $(v) ;
|
|---|
| 382 | }
|
|---|
| 383 |
|
|---|
| 384 | if $(v) != none
|
|---|
| 385 | {
|
|---|
| 386 | return $(v) ;
|
|---|
| 387 | }
|
|---|
| 388 | }
|
|---|