1# Copyright 2003 Dave Abrahams 2# Copyright 2005, 2006 Rene Rivera 3# Copyright 2002, 2003, 2004, 2005, 2006 Vladimir Prus 4# Copyright 2020 Dmitry Arkhipov 5# Distributed under the Boost Software License, Version 1.0. 6# (See accompanying file LICENSE_1_0.txt or copy at 7# http://www.boost.org/LICENSE_1_0.txt) 8 9#| tag::doc[] 10 11[[bbv2.reference.modules.stage]] 12= stage 13This module defines the `install` rule, used to copy a set of targets to a 14single location. 15 16|# # end::doc[] 17 18 19import "class" : new ; 20import feature ; 21import generators ; 22import option ; 23import path ; 24import project ; 25import property ; 26import targets ; 27import type ; 28import types/register ; 29import virtual-target ; 30 31 32feature.feature <install-dependencies> : off on : incidental ; 33feature.feature <install-type> : : free incidental ; 34feature.feature <install-source-root> : : free path ; 35feature.feature <so-version> : : free incidental ; 36 37# If 'on', version symlinks for shared libraries will not be created. Affects 38# Unix builds only. 39feature.feature <install-no-version-symlinks> : on : optional incidental ; 40 41 42#| tag::features-install-package-doc[] 43 44[[bbv2.builtin.features.install-package]]`install-package`:: 45Specifies the name of the package to which installed files belong. This is 46used for default installation prefix on certain platforms. 47 48|# # end::features-install-package-doc[] 49 50feature.feature install-package : : free ; 51 52 53#| tag::doc[] 54 55[[bbv2.reference.modules.stage.add-install-dir]] 56. `rule add-install-dir ( name : suffix ? : parent ? : options * )` 57+ 58Defines a named installation directory. 59+ 60For example, `add-install-dir foo : bar : baz ;` creates feature 61<<bbv2.builtin.features.install-prefix,`<install-foo>`>> and adds support for 62named directory `(foo)` to `install` rule. The rule will try to use the value 63of `<install-foo>` property if present, otherwise will fallback to `(baz)/bar`. 64+ 65Arguments: 66+ 67* `name`: the name of the directory. 68* `suffix`: the path suffix appended to the parent named directory. 69* `parent`: the optional name of parent named directory. 70* `options`: special options that modify treatment of the directory. 71 Allowed options: 72+ 73** `package-suffix`: append the package name to the default value. For example: 74+ 75[source] 76---- 77add-install-dir foo : bar : baz : package-suffix ; 78install (foo) : a : <install-package>xyz ; 79---- 80+ 81installs `a` into `(baz)/bar/xyz`. 82 83|# # end::doc[] 84 85.dirs = ; 86rule add-install-dir ( name : suffix ? : parent ? : options * ) 87{ 88 suffix ?= "" ; 89 if $(name) in $(.dirs) 90 { 91 import errors ; 92 errors.error Directory name $(name) is already registered. ; 93 } 94 feature.feature install-$(name) : : free ; 95 .dirs += $(name) ; 96 .dir.$(name) = $(suffix) $(parent) ; 97 .dir.$(name).options = $(options) ; 98} 99 100 101#| tag::doc[] 102 103. `rule install-dir-names ( )` 104+ 105Returns names of all registered installation directories. 106 107|# # end::doc[] 108 109rule install-dir-names ( ) 110{ 111 return $(.dirs) ; 112} 113 114 115#| tag::features-install-prefix-doc[] 116 117[[bbv2.builtin.features.install-prefix]]`install-<name>`:: 118Specifies installation prefix for <<bbv2.tasks.installing,`install`>> targets. 119These named installation prefixes are registered by default: 120+ 121* `prefix`: `C:\<package name>` if `<target-os>windows` is in the property set, 122 `/usr/local` otherwise 123* `exec-prefix`: `(prefix)` 124* `bindir`: `(exec-prefix)/bin` 125* `sbindir`: `(exec-prefix)/sbin` 126* `libexecdir`: `(exec-prefix)/libexec` 127* `libdir`: `(exec-prefix)/lib` 128* `datarootdir`: `(prefix)/share` 129* `datadir`: `(datarootdir)` 130* `sysconfdir`: `(prefix)/etc` 131* `sharedstatedir`: `(prefix)/com` 132* `localstatedir`: `(prefix)/var` 133* `runstatedir`: `(localstatedir)/run` 134* `includedir`: `(prefix)/include` 135* `oldincludedir`: `/usr/include` 136* `docdir`: `(datarootdir)/doc/<package name>` 137* `infodir`: `(datarootdir)/info` 138* `htmldir`: `(docdir)` 139* `dvidir` : `(docdir)` 140* `pdfdir` : `(docdir)` 141* `psdir` : `(docdir)` 142* `lispdir`: `(datarootdir)/emacs/site-lisp` 143* `localedir`: `(datarootdir)/locale` 144* `mandir`: `(datarootdir)/man` 145 146If more are necessary, they could be added with 147<<bbv2.reference.modules.stage.add-install-dir,`stage.add-install-dir`>>. 148 149|# # end::features-install-prefix-doc[] 150 151feature.feature install-prefix : : free path ; 152add-install-dir exec-prefix : "" : prefix ; 153add-install-dir bindir : bin : exec-prefix ; 154add-install-dir sbindir : sbin : exec-prefix ; 155add-install-dir libexecdir : libexec : exec-prefix ; 156add-install-dir libdir : lib : exec-prefix ; 157add-install-dir datarootdir : share : prefix ; 158add-install-dir datadir : "" : datarootdir ; 159add-install-dir sysconfdir : etc : prefix ; 160add-install-dir sharedstatedir : com : prefix ; 161add-install-dir localstatedir : var : prefix ; 162add-install-dir runstatedir : run : localstatedir ; 163add-install-dir includedir : "include" : prefix ; 164add-install-dir oldincludedir : /usr/include ; 165add-install-dir docdir : doc : datarootdir : package-suffix ; 166add-install-dir infodir : info : datarootdir ; 167add-install-dir htmldir : "" : docdir ; 168add-install-dir dvidir : "" : docdir ; 169add-install-dir pdfdir : "" : docdir ; 170add-install-dir psdir : "" : docdir ; 171add-install-dir lispdir : emacs/site-lisp : datarootdir ; 172add-install-dir localedir : locale : datarootdir ; 173add-install-dir mandir : man : datarootdir ; 174 175 176#| tag::features-staging-prefix-doc[] 177 178[[bbv2.builtin.features.staging-prefix]]`staging-prefix`:: 179Specifies staging prefix for <<bbv2.tasks.installing,`install`>> targets. 180If present, it will be used instead of the path to named directory `prefix`. 181Example: 182+ 183[source] 184---- 185project : requirements <install-prefix>x/y/z ; 186install a1 : a : <location>(bindir) ; # installs into x/y/z/bin 187install a2 : a : <location>(bindir) <staging-prefix>q ; # installs into q/bin 188---- 189The feature is useful when you cannot (or don't want to) put build artfiacts 190into their intented locations during the build (such as when cross-compiling), 191but still need to communicate those intended locations to the build system, 192e.g. to generate configuration files. 193 194|# # end::features-staging-prefix-doc[] 195 196feature.feature staging-prefix : : free path ; 197 198 199class install-target-class : basic-target 200{ 201 import "class" : new ; 202 import feature ; 203 import generators ; 204 import path ; 205 import project ; 206 import property ; 207 import property-set ; 208 import stage ; 209 import type ; 210 211 rule __init__ ( name-and-dir : project : sources * : requirements * : 212 default-build * : usage-requirements * ) 213 { 214 # The usage-requirements specified here are ignored but are taken as a 215 # parameter to have this metatarget class have the same standard 216 # instantiation interface as all the other Boost Build metatarget 217 # classes. 218 basic-target.__init__ $(name-and-dir) : $(project) : $(sources) : 219 $(requirements) : $(default-build) ; 220 } 221 222 # If <location> is not set, sets it based on the project data. 223 # Either way, expands installation prefixes. 224 rule update-location ( property-set ) 225 { 226 local location = [ $(property-set).get <location> ] ; 227 local project-location = [ $(self.project).get location ] ; 228 229 local prefix ; 230 local suffix = $(location) ; 231 if $(suffix) 232 { 233 local rel = [ path.relative $(suffix) $(project-location) 234 : no-error ] ; 235 if not-a-child != $(rel) 236 { 237 suffix = $(rel) ; 238 } 239 } 240 suffix ?= $(self.name) ; 241 local matches = [ MATCH "^\\((.+)\\)(/(.*))?$" : $(suffix) ] ; 242 243 # if location can be split into named directory and optional trailing 244 # path, do the split and expand the name into path 245 if $(matches) 246 { 247 suffix = $(matches[3]) ; 248 suffix ?= "" ; 249 local package-name = [ stage.get-package-name $(property-set) 250 : [ $(self.project).project-module ] ] ; 251 prefix = [ stage.get-dir $(matches[1]) : $(property-set) 252 : $(package-name) : staged ] ; 253 } 254 # prefix location with the project's path 255 else if ! $(location) 256 { 257 prefix = $(project-location) ; 258 } 259 260 # only modify location if it's necessary 261 if $(prefix) 262 { 263 suffix = [ path.root $(suffix) $(prefix) ] ; 264 local properties = [ $(property-set).raw ] ; 265 properties = [ property.change $(properties) : <location> ] ; 266 property-set = [ property-set.create $(properties) <location>$(suffix) ] ; 267 } 268 269 return $(property-set) ; 270 } 271 272 # Takes a target that is installed and a property set which is used when 273 # installing. 274 # 275 rule adjust-properties ( target : build-property-set ) 276 { 277 local ps-raw ; 278 local a = [ $(target).action ] ; 279 if $(a) 280 { 281 local ps = [ $(a).properties ] ; 282 ps-raw = [ $(ps).raw ] ; 283 284 # Unless <hardcode-dll-paths>true is in properties, which can happen 285 # only if the user has explicitly requested it, nuke all <dll-path> 286 # properties. 287 if [ $(build-property-set).get <hardcode-dll-paths> ] != true 288 { 289 ps-raw = [ property.change $(ps-raw) : <dll-path> ] ; 290 } 291 292 # If any <dll-path> properties were specified for installing, add 293 # them. 294 local l = [ $(build-property-set).get <dll-path> ] ; 295 ps-raw += $(l:G=<dll-path>) ; 296 297 # Also copy <linkflags> feature from current build set, to be used 298 # for relinking. 299 local l = [ $(build-property-set).get <linkflags> ] ; 300 ps-raw += $(l:G=<linkflags>) ; 301 302 # Remove the <tag> feature on original targets. 303 ps-raw = [ property.change $(ps-raw) : <tag> ] ; 304 305 # And <location>. If stage target has another stage target in 306 # sources, then we shall get virtual targets with the <location> 307 # property set. 308 ps-raw = [ property.change $(ps-raw) : <location> ] ; 309 } 310 311 local d = [ $(build-property-set).get <dependency> ] ; 312 ps-raw += $(d:G=<dependency>) ; 313 314 local d = [ $(build-property-set).get <location> ] ; 315 ps-raw += $(d:G=<location>) ; 316 317 local ns = [ $(build-property-set).get <install-no-version-symlinks> ] ; 318 ps-raw += $(ns:G=<install-no-version-symlinks>) ; 319 320 local d = [ $(build-property-set).get <install-source-root> ] ; 321 # Make the path absolute: we shall use it to compute relative paths and 322 # making the path absolute will help. 323 if $(d) 324 { 325 d = [ path.root $(d) [ path.pwd ] ] ; 326 ps-raw += $(d:G=<install-source-root>) ; 327 } 328 329 if $(ps-raw) 330 { 331 return [ property-set.create $(ps-raw) ] ; 332 } 333 else 334 { 335 return [ property-set.empty ] ; 336 } 337 } 338 339 rule construct ( name : source-targets * : property-set ) 340 { 341 source-targets = [ targets-to-stage $(source-targets) : 342 $(property-set) ] ; 343 344 property-set = [ update-location $(property-set) ] ; 345 346 local ename = [ $(property-set).get <name> ] ; 347 348 if $(ename) && $(source-targets[2]) 349 { 350 import errors : error : $(__name__) : errors.error ; 351 errors.error When <name> property is used "in" 'install', only one 352 source is allowed. ; 353 } 354 355 local result ; 356 for local i in $(source-targets) 357 { 358 local staged-targets ; 359 360 local new-properties = [ adjust-properties $(i) : 361 $(property-set) ] ; 362 363 # See if something special should be done when staging this type. It 364 # is indicated by the presence of a special "INSTALLED_" type. 365 local t = [ $(i).type ] ; 366 if $(t) && [ type.registered INSTALLED_$(t) ] 367 { 368 if $(ename) 369 { 370 import errors : error : $(__name__) : errors.error ; 371 errors.error In "'install':" <name> property specified with 372 target that requires relinking. ; 373 } 374 else 375 { 376 local targets = [ generators.construct $(self.project) 377 $(name) : INSTALLED_$(t) : $(new-properties) : $(i) ] ; 378 staged-targets += $(targets[2-]) ; 379 } 380 } 381 else 382 { 383 staged-targets = [ stage.copy-file $(self.project) $(ename) : 384 $(i) : $(new-properties) ] ; 385 } 386 387 if ! $(staged-targets) 388 { 389 import errors : error : $(__name__) : errors.error ; 390 errors.error Unable to generate staged version of 391 [ $(source).str ] ; 392 } 393 394 for t in $(staged-targets) 395 { 396 result += [ virtual-target.register $(t) ] ; 397 } 398 } 399 400 return [ property-set.empty ] $(result) ; 401 } 402 403 # Given the list of source targets explicitly passed to 'stage', returns the 404 # list of targets which must be staged. 405 # 406 rule targets-to-stage ( source-targets * : property-set ) 407 { 408 local result ; 409 410 # Traverse the dependencies, if needed. 411 if [ $(property-set).get <install-dependencies> ] = "on" 412 { 413 source-targets = [ collect-targets $(source-targets) ] ; 414 } 415 416 # Filter the target types, if needed. 417 local included-types = [ $(property-set).get <install-type> ] ; 418 for local r in $(source-targets) 419 { 420 local ty = [ $(r).type ] ; 421 if $(ty) 422 { 423 # Do not stage searched libs. 424 if $(ty) != SEARCHED_LIB 425 { 426 if $(included-types) 427 { 428 if [ include-type $(ty) : $(included-types) ] 429 { 430 result += $(r) ; 431 } 432 } 433 else 434 { 435 result += $(r) ; 436 } 437 } 438 } 439 else if ! $(included-types) 440 { 441 # Do not install typeless targets if there is an explicit list 442 # of allowed types. 443 result += $(r) ; 444 } 445 } 446 447 return $(result) ; 448 } 449 450 # CONSIDER: figure out why we can not use virtual-target.traverse here. 451 # 452 rule collect-targets ( targets * ) 453 { 454 # Find subvariants 455 local s ; 456 for local t in $(targets) 457 { 458 s += [ $(t).creating-subvariant ] ; 459 } 460 s = [ sequence.unique $(s) ] ; 461 462 local result = [ new set ] ; 463 $(result).add $(targets) ; 464 465 for local i in $(s) 466 { 467 $(i).all-referenced-targets $(result) ; 468 } 469 local result2 ; 470 for local r in [ $(result).list ] 471 { 472 if $(r:G) != <use> 473 { 474 result2 += $(r:G=) ; 475 } 476 } 477 DELETE_MODULE $(result) ; 478 return [ sequence.unique $(result2) ] ; 479 } 480 481 # Returns true iff 'type' is subtype of some element of 'types-to-include'. 482 # 483 local rule include-type ( type : types-to-include * ) 484 { 485 local found ; 486 while $(types-to-include) && ! $(found) 487 { 488 if [ type.is-subtype $(type) $(types-to-include[1]) ] 489 { 490 found = true ; 491 } 492 types-to-include = $(types-to-include[2-]) ; 493 } 494 495 return $(found) ; 496 } 497} 498 499 500# Creates a copy of target 'source'. The 'properties' object should have a 501# <location> property which specifies where the target must be placed. 502# 503rule copy-file ( project name ? : source : properties ) 504{ 505 name ?= [ $(source).name ] ; 506 local relative ; 507 508 local new-a = [ new non-scanning-action $(source) : common.copy : 509 $(properties) ] ; 510 local source-root = [ $(properties).get <install-source-root> ] ; 511 if $(source-root) 512 { 513 # Get the real path of the target. We probably need to strip relative 514 # path from the target name at construction. 515 local path = [ $(source).path ] ; 516 path = [ path.root $(name:D) $(path) ] ; 517 # Make the path absolute. Otherwise, it would be hard to compute the 518 # relative path. The 'source-root' is already absolute, see the 519 # 'adjust-properties' method above. 520 path = [ path.root $(path) [ path.pwd ] ] ; 521 522 relative = [ path.relative-to $(source-root) $(path) ] ; 523 } 524 525 # Note: Using $(name:D=$(relative)) might be faster here, but then we would 526 # need to explicitly check that relative is not ".", otherwise we might get 527 # paths like '<prefix>/boost/.', try to create it and mkdir would obviously 528 # fail. 529 name = [ path.join $(relative) $(name:D=) ] ; 530 531 return [ new file-target $(name) exact : [ $(source).type ] : $(project) : 532 $(new-a) ] ; 533} 534 535 536rule symlink ( name : project : source : properties ) 537{ 538 local a = [ new action $(source) : symlink.ln : $(properties) ] ; 539 local t = [ new file-target $(name) exact : [ $(source).type ] : $(project) 540 : $(a) ] ; 541 return [ virtual-target.register $(t) ] ; 542} 543 544 545rule relink-file ( project : source : property-set ) 546{ 547 local action = [ $(source).action ] ; 548 local cloned-action = [ virtual-target.clone-action $(action) : $(project) : 549 "" : $(property-set) ] ; 550 return [ $(cloned-action).targets ] ; 551} 552 553 554# Declare installed version of the EXE type. Generator for this type will cause 555# relinking to the new location. 556type.register INSTALLED_EXE : : EXE ; 557 558 559class installed-exe-generator : generator 560{ 561 import type ; 562 import property-set ; 563 import modules ; 564 import stage ; 565 566 rule __init__ ( ) 567 { 568 generator.__init__ install-exe : EXE : INSTALLED_EXE ; 569 } 570 571 rule run ( project name ? : property-set : source : multiple ? ) 572 { 573 local stage-rule = stage.copy-file ; 574 575 if ! [ $(property-set).get <os> ] in NT CYGWIN && 576 ! [ $(property-set).get <target-os> ] in windows cygwin 577 { 578 # If dll-path properties have been changed for the stage target, 579 # relink instead of copying. 580 local a = [ $(source).action ] ; 581 local p = [ $(a).properties ] ; 582 local original = [ $(p).get <dll-path> ] ; 583 local current = [ $(property-set).get <dll-path> ] ; 584 585 if $(current) != $(original) 586 { 587 stage-rule = stage.relink-file ; 588 } 589 } 590 591 return [ $(stage-rule) $(project) : $(source) : $(property-set) ] ; 592 } 593} 594 595 596generators.register [ new installed-exe-generator ] ; 597 598 599# Installing a shared link on Unix might cause a creation of versioned symbolic 600# links. 601type.register INSTALLED_SHARED_LIB : : SHARED_LIB ; 602 603 604class installed-shared-lib-generator : generator 605{ 606 import type ; 607 import property-set ; 608 import modules ; 609 import stage ; 610 611 rule __init__ ( ) 612 { 613 generator.__init__ install-shared-lib : SHARED_LIB : 614 INSTALLED_SHARED_LIB ; 615 } 616 617 rule run ( project name ? : property-set : source : multiple ? ) 618 { 619 if [ $(property-set).get <os> ] in NT CYGWIN || 620 [ $(property-set).get <target-os> ] in windows cygwin 621 { 622 local copied = [ stage.copy-file $(project) : $(source) : 623 $(property-set) ] ; 624 return [ virtual-target.register $(copied) ] ; 625 } 626 else 627 { 628 local a = [ $(source).action ] ; 629 local copied ; 630 if ! $(a) 631 { 632 # Non-derived file, just copy. 633 copied = [ stage.copy-file $(project) : $(source) : 634 $(property-set) ] ; 635 } 636 else 637 { 638 local cp = [ $(a).properties ] ; 639 local current-dll-path = [ $(cp).get <dll-path> ] ; 640 local new-dll-path = [ $(property-set).get <dll-path> ] ; 641 642 if $(current-dll-path) != $(new-dll-path) 643 { 644 # Rpath changed, need to relink. 645 copied = [ stage.relink-file $(project) : $(source) : 646 $(property-set) ] ; 647 } 648 else 649 { 650 copied = [ stage.copy-file $(project) : $(source) : 651 $(property-set) ] ; 652 } 653 } 654 655 copied = [ virtual-target.register $(copied) ] ; 656 657 local result = $(copied) ; 658 # If the name is in the form NNN.XXX.YYY.ZZZ, where all 'X', 'Y' and 659 # 'Z' are numbers, we need to create NNN.XXX and NNN.XXX.YYY 660 # symbolic links. 661 local m = [ MATCH 662 "(.*)\\.([0123456789]+)\\.([0123456789]+)\\.([0123456789]+)$" : 663 [ $(copied).name ] ] ; 664 if $(m) 665 { 666 # Symlink without version at all is used to make 667 # -lsome_library work. 668 result += [ stage.symlink $(m[1]) : $(project) : $(copied) : 669 $(property-set) ] ; 670 671 # Symlinks of some libfoo.N and libfoo.N.M are used so that 672 # library can found at runtime, if libfoo.N.M.X has soname of 673 # libfoo.N. That happens when the library makes some binary 674 # compatibility guarantees. If not, it is possible to skip those 675 # symlinks. 676 local suppress = [ $(property-set).get 677 <install-no-version-symlinks> ] ; 678 679 if $(suppress) != "on" 680 { 681 result += [ stage.symlink $(m[1]).$(m[2]) : $(project) : 682 $(copied) : $(property-set) ] ; 683 result += [ stage.symlink $(m[1]).$(m[2]).$(m[3]) : 684 $(project) : $(copied) : $(property-set) ] ; 685 } 686 } 687 688 return $(result) ; 689 } 690 } 691} 692 693generators.register [ new installed-shared-lib-generator ] ; 694 695 696#| tag::doc[] 697 698. `rule get-dir ( name : property-set : package-name : flags * )` 699+ 700Returns the path to a named installation directory. For a given `name=xyz` the 701rule uses the value of `<install-xyz>` property if it is present in 702`property-set`. Otherwise it tries to construct the default value of the path 703recursively getting the path to ``name``'s registered base named directory and 704relative path. For example: 705+ 706[source] 707---- 708stage.add-install-dir foo : bar : baz ; 709 710local ps = [ property-set.create <install-foo>x/y/z ] ; 711echo [ stage.get-dir foo : $(ps) : $(__name__) ] ; # outputs x/y/z 712 713ps = [ property-set.create <install-baz>a/b/c/d ] ; 714echo [ stage.get-dir foo : $(ps) : $(__name__) ] ; # outputs a/b/c/d/bar 715---- 716+ 717The argument `package-name` is used to construct the path for named directories 718that were registered with `package-suffix` option and also to construct 719`install-prefix` when targeting Windows. 720+ 721Available `flags`: 722+ 723* `staged`: take <<bbv2.builtin.features.staging-prefix,`staging-prefix`>> into 724 account. 725* `relative`: return the path to `name` relative to its base directory. 726 727|# # end::doc[] 728 729rule get-dir ( name : property-set : package-name : flags * ) 730{ 731 local result ; 732 733 # We treat the 'prefix' directory in a special way, because it's default 734 # is based on the value of <target-os> property. 735 if $(name) = prefix 736 { 737 result = [ get-install-prefix $(property-set) : $(package-name) 738 : $(flags) ] ; 739 } 740 else 741 { 742 # First, try getting the path for requested directory from properties. 743 result = [ $(property-set).get <install-$(name)> ] ; 744 local info = [ get-dir-info $(name) : $(package-name) ] ; 745 # Otherwise, use the default path. In both cases, it could be a 746 # relative path. 747 result ?= $(info[1]) ; 748 if $(result) 749 { 750 result = [ path.make $(result) ] ; 751 } 752 753 # If there is a base directory, we may need to modify result further. 754 if $(info[2]) 755 { 756 local base = [ get-dir $(info[2]) : $(property-set) 757 : $(package-name) : $(flags) ] ; 758 if relative in $(flags) 759 { 760 local rel = [ path.relative $(result) $(base) : no-error ] ; 761 if not-a-child != $(rel) 762 { 763 result = $(rel) ; 764 } 765 } 766 else 767 { 768 result = [ path.root $(result) $(base) ] ; 769 } 770 } 771 } 772 773 return $(result) ; 774} 775 776 777# For a given named directory returns its parent directory and relative path 778local rule get-dir-info ( name : package-name ) { 779 local path = $(.dir.$(name)[1]) ; 780 if ! x$(path) 781 { 782 import errors ; 783 errors.error $(name) is not an installation directory name. ; 784 } 785 786 if package-suffix in $(.dir.$(name).options) 787 { 788 path = [ path.join $(path) $(package-name) ] ; 789 } 790 791 return $(path) $(.dir.$(name)[2]) ; 792} 793 794 795local rule get-install-prefix ( property-set : package-name : flags * ) 796{ 797 local prefix ; 798 if staged in $(flags) 799 { 800 prefix = [ $(property-set).get <staging-prefix> ] ; 801 } 802 prefix ?= [ $(property-set).get <install-prefix> ] ; 803 prefix = $(prefix[0]) ; 804 prefix ?= [ option.get prefix ] ; 805 if ! $(prefix) 806 { 807 if windows = [ $(property-set).get <target-os> ] 808 { 809 prefix = C:\\$(package-name) ; 810 } 811 else 812 { 813 prefix = /usr/local ; 814 } 815 } 816 return [ path.make $(prefix) ] ; 817} 818 819 820#| tag::doc[] 821 822. `rule get-package-name ( property-set : project-module ? )` 823+ 824Returns the package name that will be used for `install` targets when 825constructing installation location. The rule uses the value of 826<<bbv2.builtin.features.install-package,`<install-package>`>> property if it's 827present in `property-set`. Otherwise it deduces the package name using 828``project-module``'s attributes. It traverses the project hierarchy up to the 829root searching for the first project with an id. If none is found, the base 830name of the root project's location is used. If `project-module` is empty, the 831caller module is used (this allows invoking just `[ get-package-name $(ps) ]` 832in project jam files). 833 834|# # end::doc[] 835 836rule get-package-name ( property-set : project-module ? ) 837{ 838 local package = [ $(property-set).get <install-package> ] ; 839 if ! $(package) 840 { 841 project-module ?= [ CALLER_MODULE 1 ] ; 842 843 local m = $(project-module) ; 844 package = [ project.attribute $(m) id ] ; 845 while ! $(package) 846 { 847 m = [ project.attribute $(m) parent-module ] ; 848 if ! $(m) { break ; } 849 850 package = [ project.attribute $(m) id ] ; 851 } 852 853 if ! $(package) 854 { 855 local root = [ project.attribute $(project-module) project-root ] ; 856 package = [ path.root $(root) [ path.pwd ] ] ; 857 } 858 859 package = $(package:B) ; 860 } 861 return $(package) ; 862} 863 864 865rule stage-translate-path ( feature value : properties * : project-id : project-location ) 866{ 867 if $(feature) = <location> && [ MATCH "^\\((.+)\\)(/(.*))?$" : $(value) ] 868 { 869 return $(value) ; 870 } 871} 872 873 874# Main target rule for 'install'. 875# 876rule install ( name : sources * : requirements * : default-build * ) 877{ 878 local project = [ project.current ] ; 879 880 # Unless the user has explicitly asked us to hardcode dll paths, add 881 # <hardcode-dll-paths>false in requirements, to override default value. 882 if ! <hardcode-dll-paths>true in $(requirements) 883 { 884 requirements += <hardcode-dll-paths>false ; 885 } 886 887 if <tag> in $(requirements:G) 888 { 889 import errors ; 890 errors.user-error The <tag> property is not allowed for the 'install' 891 rule. ; 892 } 893 894 targets.create-metatarget install-target-class : $(project) : $(name) : 895 $(sources) : $(requirements) <translate-path>@stage-translate-path : $(default-build) ; 896} 897 898 899IMPORT $(__name__) : install : : install ; 900IMPORT $(__name__) : install : : stage ; 901IMPORT $(__name__) : stage-translate-path : : stage-translate-path ; 902