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.txt or copy at
7 # https://www.bfgroup.xyz/b2/LICENSE.txt)
11 [[bbv2.reference.modules.stage]]
13 This module defines the `install` rule, used to copy a set of targets to a
19 import "class" : new ;
28 import types/register ;
29 import virtual-target ;
32 feature.feature <install-dependencies> : off on : incidental ;
33 feature.feature <install-type> : : free incidental ;
34 feature.feature <install-source-root> : : free path ;
35 feature.feature <so-version> : : free incidental ;
37 # If 'on', version symlinks for shared libraries will not be created. Affects
39 feature.feature <install-no-version-symlinks> : on : optional incidental ;
42 #| tag::features-install-package-doc[]
44 [[bbv2.builtin.features.install-package]]`install-package`::
45 Specifies the name of the package to which installed files belong. This is
46 used for default installation prefix on certain platforms.
48 |# # end::features-install-package-doc[]
50 feature.feature install-package : : free ;
55 [[bbv2.reference.modules.stage.add-install-dir]]
56 . `rule add-install-dir ( name : suffix ? : parent ? : options * )`
58 Defines a named installation directory.
60 For example, `add-install-dir foo : bar : baz ;` creates feature
61 <<bbv2.builtin.features.install-prefix,`<install-foo>`>> and adds support for
62 named directory `(foo)` to `install` rule. The rule will try to use the value
63 of `<install-foo>` property if present, otherwise will fallback to `(baz)/bar`.
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.
73 ** `package-suffix`: append the package name to the default value. For example:
77 add-install-dir foo : bar : baz : package-suffix ;
78 install (foo) : a : <install-package>xyz ;
81 installs `a` into `(baz)/bar/xyz`.
86 rule add-install-dir ( name : suffix ? : parent ? : options * )
89 if $(name) in $(.dirs)
92 errors.error Directory name $(name) is already registered. ;
94 feature.feature install-$(name) : : free ;
96 .dir.$(name) = $(suffix) $(parent) ;
97 .dir.$(name).options = $(options) ;
103 . `rule install-dir-names ( )`
105 Returns names of all registered installation directories.
109 rule install-dir-names ( )
115 #| tag::features-install-prefix-doc[]
117 [[bbv2.builtin.features.install-prefix]]`install-<name>`::
118 Specifies installation prefix for <<bbv2.tasks.installing,`install`>> targets.
119 These named installation prefixes are registered by default:
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`
146 If more are necessary, they could be added with
147 <<bbv2.reference.modules.stage.add-install-dir,`stage.add-install-dir`>>.
149 |# # end::features-install-prefix-doc[]
151 feature.feature install-prefix : : free path ;
152 add-install-dir exec-prefix : "" : prefix ;
153 add-install-dir bindir : bin : exec-prefix ;
154 add-install-dir sbindir : sbin : exec-prefix ;
155 add-install-dir libexecdir : libexec : exec-prefix ;
156 add-install-dir libdir : lib : exec-prefix ;
157 add-install-dir datarootdir : share : prefix ;
158 add-install-dir datadir : "" : datarootdir ;
159 add-install-dir sysconfdir : etc : prefix ;
160 add-install-dir sharedstatedir : com : prefix ;
161 add-install-dir localstatedir : var : prefix ;
162 add-install-dir runstatedir : run : localstatedir ;
163 add-install-dir includedir : "include" : prefix ;
164 add-install-dir oldincludedir : /usr/include ;
165 add-install-dir docdir : doc : datarootdir : package-suffix ;
166 add-install-dir infodir : info : datarootdir ;
167 add-install-dir htmldir : "" : docdir ;
168 add-install-dir dvidir : "" : docdir ;
169 add-install-dir pdfdir : "" : docdir ;
170 add-install-dir psdir : "" : docdir ;
171 add-install-dir lispdir : emacs/site-lisp : datarootdir ;
172 add-install-dir localedir : locale : datarootdir ;
173 add-install-dir mandir : man : datarootdir ;
176 #| tag::features-staging-prefix-doc[]
178 [[bbv2.builtin.features.staging-prefix]]`staging-prefix`::
179 Specifies staging prefix for <<bbv2.tasks.installing,`install`>> targets.
180 If present, it will be used instead of the path to named directory `prefix`.
185 project : requirements <install-prefix>x/y/z ;
186 install a1 : a : <location>(bindir) ; # installs into x/y/z/bin
187 install a2 : a : <location>(bindir) <staging-prefix>q ; # installs into q/bin
189 The feature is useful when you cannot (or don't want to) put build artfiacts
190 into their intented locations during the build (such as when cross-compiling),
191 but still need to communicate those intended locations to the build system,
192 e.g. to generate configuration files.
194 |# # end::features-staging-prefix-doc[]
196 feature.feature staging-prefix : : free path ;
199 class install-target-class : basic-target
201 import "class" : new ;
207 import property-set ;
211 rule __init__ ( name-and-dir : project : sources * : requirements * :
212 default-build * : usage-requirements * )
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
218 basic-target.__init__ $(name-and-dir) : $(project) : $(sources) :
219 $(requirements) : $(default-build) ;
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 )
226 local location = [ $(property-set).get <location> ] ;
227 local project-location = [ $(self.project).get location ] ;
230 local suffix = $(location) ;
233 local rel = [ path.relative $(suffix) $(project-location)
235 if not-a-child != $(rel)
240 suffix ?= $(self.name) ;
241 local matches = [ MATCH "^\\((.+)\\)(/(.*))?$" : $(suffix) ] ;
243 # if location can be split into named directory and optional trailing
244 # path, do the split and expand the name into path
247 suffix = $(matches[3]) ;
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 ] ;
254 # prefix location with the project's path
255 else if ! $(location)
257 prefix = $(project-location) ;
260 # only modify location if it's necessary
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) ] ;
269 return $(property-set) ;
272 # Takes a target that is installed and a property set which is used when
275 rule adjust-properties ( target : build-property-set )
278 local a = [ $(target).action ] ;
281 local ps = [ $(a).properties ] ;
282 ps-raw = [ $(ps).raw ] ;
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>
287 if [ $(build-property-set).get <hardcode-dll-paths> ] != true
289 ps-raw = [ property.change $(ps-raw) : <dll-path> ] ;
292 # If any <dll-path> properties were specified for installing, add
294 local l = [ $(build-property-set).get <dll-path> ] ;
295 ps-raw += $(l:G=<dll-path>) ;
297 # Also copy <linkflags> feature from current build set, to be used
299 local l = [ $(build-property-set).get <linkflags> ] ;
300 ps-raw += $(l:G=<linkflags>) ;
302 # Remove the <tag> feature on original targets.
303 ps-raw = [ property.change $(ps-raw) : <tag> ] ;
305 # And <location>. If stage target has another stage target in
306 # sources, then we shall get virtual targets with the <location>
308 ps-raw = [ property.change $(ps-raw) : <location> ] ;
311 local d = [ $(build-property-set).get <dependency> ] ;
312 ps-raw += $(d:G=<dependency>) ;
314 local d = [ $(build-property-set).get <location> ] ;
315 ps-raw += $(d:G=<location>) ;
317 local ns = [ $(build-property-set).get <install-no-version-symlinks> ] ;
318 ps-raw += $(ns:G=<install-no-version-symlinks>) ;
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.
325 d = [ path.root $(d) [ path.pwd ] ] ;
326 ps-raw += $(d:G=<install-source-root>) ;
331 return [ property-set.create $(ps-raw) ] ;
335 return [ property-set.empty ] ;
339 rule construct ( name : source-targets * : property-set )
341 source-targets = [ targets-to-stage $(source-targets) :
344 property-set = [ update-location $(property-set) ] ;
346 local ename = [ $(property-set).get <name> ] ;
348 if $(ename) && $(source-targets[2])
350 import errors : error : $(__name__) : errors.error ;
351 errors.error When <name> property is used "in" 'install', only one
356 for local i in $(source-targets)
358 local staged-targets ;
360 local new-properties = [ adjust-properties $(i) :
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) ]
370 import errors : error : $(__name__) : errors.error ;
371 errors.error In "'install':" <name> property specified with
372 target that requires relinking. ;
376 local targets = [ generators.construct $(self.project)
377 $(name) : INSTALLED_$(t) : $(new-properties) : $(i) ] ;
378 staged-targets += $(targets[2-]) ;
383 staged-targets = [ stage.copy-file $(self.project) $(ename) :
384 $(i) : $(new-properties) ] ;
387 if ! $(staged-targets)
389 import errors : error : $(__name__) : errors.error ;
390 errors.error Unable to generate staged version of
394 for t in $(staged-targets)
396 result += [ virtual-target.register $(t) ] ;
400 return [ property-set.empty ] $(result) ;
403 # Given the list of source targets explicitly passed to 'stage', returns the
404 # list of targets which must be staged.
406 rule targets-to-stage ( source-targets * : property-set )
410 # Traverse the dependencies, if needed.
411 if [ $(property-set).get <install-dependencies> ] = "on"
413 source-targets = [ collect-targets $(source-targets) ] ;
416 # Filter the target types, if needed.
417 local included-types = [ $(property-set).get <install-type> ] ;
418 for local r in $(source-targets)
420 local ty = [ $(r).type ] ;
423 # Do not stage searched libs.
424 if $(ty) != SEARCHED_LIB
428 if [ include-type $(ty) : $(included-types) ]
439 else if ! $(included-types)
441 # Do not install typeless targets if there is an explicit list
450 # CONSIDER: figure out why we can not use virtual-target.traverse here.
452 rule collect-targets ( targets * )
456 for local t in $(targets)
458 s += [ $(t).creating-subvariant ] ;
460 s = [ sequence.unique $(s) ] ;
462 local result = [ new set ] ;
463 $(result).add $(targets) ;
467 $(i).all-referenced-targets $(result) ;
470 for local r in [ $(result).list ]
477 DELETE_MODULE $(result) ;
478 return [ sequence.unique $(result2) ] ;
481 rule skip-from-usage-requirements ( )
485 # Returns true iff 'type' is subtype of some element of 'types-to-include'.
487 local rule include-type ( type : types-to-include * )
490 while $(types-to-include) && ! $(found)
492 if [ type.is-subtype $(type) $(types-to-include[1]) ]
496 types-to-include = $(types-to-include[2-]) ;
504 # Creates a copy of target 'source'. The 'properties' object should have a
505 # <location> property which specifies where the target must be placed.
507 rule copy-file ( project name ? : source : properties )
509 name ?= [ $(source).name ] ;
512 local new-a = [ new non-scanning-action $(source) : common.copy :
514 local source-root = [ $(properties).get <install-source-root> ] ;
517 # Get the real path of the target. We probably need to strip relative
518 # path from the target name at construction.
519 local path = [ $(source).path ] ;
520 path = [ path.root $(name:D) $(path) ] ;
521 # Make the path absolute. Otherwise, it would be hard to compute the
522 # relative path. The 'source-root' is already absolute, see the
523 # 'adjust-properties' method above.
524 path = [ path.root $(path) [ path.pwd ] ] ;
526 relative = [ path.relative-to $(source-root) $(path) ] ;
529 # Note: Using $(name:D=$(relative)) might be faster here, but then we would
530 # need to explicitly check that relative is not ".", otherwise we might get
531 # paths like '<prefix>/boost/.', try to create it and mkdir would obviously
533 name = [ path.join $(relative) $(name:D=) ] ;
535 return [ new file-target $(name) exact : [ $(source).type ] : $(project) :
540 rule symlink ( name : project : source : properties )
542 local a = [ new action $(source) : symlink.ln : $(properties) ] ;
543 local t = [ new file-target $(name) exact : [ $(source).type ] : $(project)
545 return [ virtual-target.register $(t) ] ;
549 rule relink-file ( project : source : property-set )
551 local action = [ $(source).action ] ;
552 local cloned-action = [ virtual-target.clone-action $(action) : $(project) :
553 "" : $(property-set) ] ;
554 return [ $(cloned-action).targets ] ;
558 # Declare installed version of the EXE type. Generator for this type will cause
559 # relinking to the new location.
560 type.register INSTALLED_EXE : : EXE ;
563 class installed-exe-generator : generator
566 import property-set ;
572 generator.__init__ install-exe : EXE : INSTALLED_EXE ;
575 rule run ( project name ? : property-set : source : multiple ? )
577 local stage-rule = stage.copy-file ;
579 if ! [ $(property-set).get <os> ] in NT CYGWIN &&
580 ! [ $(property-set).get <target-os> ] in windows cygwin
582 # If dll-path properties have been changed for the stage target,
583 # relink instead of copying.
584 local a = [ $(source).action ] ;
585 local p = [ $(a).properties ] ;
586 local original = [ $(p).get <dll-path> ] ;
587 local current = [ $(property-set).get <dll-path> ] ;
589 if $(current) != $(original)
591 stage-rule = stage.relink-file ;
595 return [ $(stage-rule) $(project) : $(source) : $(property-set) ] ;
600 generators.register [ new installed-exe-generator ] ;
603 # Installing a shared link on Unix might cause a creation of versioned symbolic
605 type.register INSTALLED_SHARED_LIB : : SHARED_LIB ;
608 class installed-shared-lib-generator : generator
611 import property-set ;
617 generator.__init__ install-shared-lib : SHARED_LIB :
618 INSTALLED_SHARED_LIB ;
621 rule run ( project name ? : property-set : source : multiple ? )
623 if [ $(property-set).get <os> ] in NT CYGWIN ||
624 [ $(property-set).get <target-os> ] in windows cygwin
626 local copied = [ stage.copy-file $(project) : $(source) :
628 return [ virtual-target.register $(copied) ] ;
632 local a = [ $(source).action ] ;
636 # Non-derived file, just copy.
637 copied = [ stage.copy-file $(project) : $(source) :
642 local cp = [ $(a).properties ] ;
643 local current-dll-path = [ $(cp).get <dll-path> ] ;
644 local new-dll-path = [ $(property-set).get <dll-path> ] ;
646 if $(current-dll-path) != $(new-dll-path)
648 # Rpath changed, need to relink.
649 copied = [ stage.relink-file $(project) : $(source) :
654 copied = [ stage.copy-file $(project) : $(source) :
659 copied = [ virtual-target.register $(copied) ] ;
661 local result = $(copied) ;
662 # If the name is in the form NNN.XXX.YYY.ZZZ, where all 'X', 'Y' and
663 # 'Z' are numbers, we need to create NNN.XXX and NNN.XXX.YYY
666 "(.*)\\.([0123456789]+)\\.([0123456789]+)\\.([0123456789]+)$" :
667 [ $(copied).name ] ] ;
670 # Symlink without version at all is used to make
671 # -lsome_library work.
672 result += [ stage.symlink $(m[1]) : $(project) : $(copied) :
675 # Symlinks of some libfoo.N and libfoo.N.M are used so that
676 # library can found at runtime, if libfoo.N.M.X has soname of
677 # libfoo.N. That happens when the library makes some binary
678 # compatibility guarantees. If not, it is possible to skip those
680 local suppress = [ $(property-set).get
681 <install-no-version-symlinks> ] ;
683 if $(suppress) != "on"
685 result += [ stage.symlink $(m[1]).$(m[2]) : $(project) :
686 $(copied) : $(property-set) ] ;
687 result += [ stage.symlink $(m[1]).$(m[2]).$(m[3]) :
688 $(project) : $(copied) : $(property-set) ] ;
697 generators.register [ new installed-shared-lib-generator ] ;
702 . `rule get-dir ( name : property-set : package-name : flags * )`
704 Returns the path to a named installation directory. For a given `name=xyz` the
705 rule uses the value of `<install-xyz>` property if it is present in
706 `property-set`. Otherwise it tries to construct the default value of the path
707 recursively getting the path to ``name``'s registered base named directory and
708 relative path. For example:
712 stage.add-install-dir foo : bar : baz ;
714 local ps = [ property-set.create <install-foo>x/y/z ] ;
715 echo [ stage.get-dir foo : $(ps) : $(__name__) ] ; # outputs x/y/z
717 ps = [ property-set.create <install-baz>a/b/c/d ] ;
718 echo [ stage.get-dir foo : $(ps) : $(__name__) ] ; # outputs a/b/c/d/bar
721 The argument `package-name` is used to construct the path for named directories
722 that were registered with `package-suffix` option and also to construct
723 `install-prefix` when targeting Windows.
727 * `staged`: take <<bbv2.builtin.features.staging-prefix,`staging-prefix`>> into
729 * `relative`: return the path to `name` relative to its base directory.
733 rule get-dir ( name : property-set : package-name : flags * )
737 # We treat the 'prefix' directory in a special way, because it's default
738 # is based on the value of <target-os> property.
741 result = [ get-install-prefix $(property-set) : $(package-name)
746 # First, try getting the path for requested directory from properties.
747 result = [ $(property-set).get <install-$(name)> ] ;
748 local info = [ get-dir-info $(name) : $(package-name) ] ;
749 # Otherwise, use the default path. In both cases, it could be a
751 result ?= $(info[1]) ;
754 result = [ path.make $(result) ] ;
757 # If there is a base directory, we may need to modify result further.
760 local base = [ get-dir $(info[2]) : $(property-set)
761 : $(package-name) : $(flags) ] ;
762 if relative in $(flags)
764 local rel = [ path.relative $(result) $(base) : no-error ] ;
765 if not-a-child != $(rel)
772 result = [ path.root $(result) $(base) ] ;
781 # For a given named directory returns its parent directory and relative path
782 local rule get-dir-info ( name : package-name ) {
783 local path = $(.dir.$(name)[1]) ;
787 errors.error $(name) is not an installation directory name. ;
790 if package-suffix in $(.dir.$(name).options)
792 path = [ path.join $(path) $(package-name) ] ;
795 return $(path) $(.dir.$(name)[2]) ;
799 local rule get-install-prefix ( property-set : package-name : flags * )
802 if staged in $(flags)
804 prefix = [ $(property-set).get <staging-prefix> ] ;
806 prefix ?= [ $(property-set).get <install-prefix> ] ;
807 prefix = $(prefix[0]) ;
808 prefix ?= [ option.get prefix ] ;
811 if windows = [ $(property-set).get <target-os> ]
813 prefix = C:\\$(package-name) ;
817 prefix = /usr/local ;
820 return [ path.make $(prefix) ] ;
826 . `rule get-package-name ( property-set : project-module ? )`
828 Returns the package name that will be used for `install` targets when
829 constructing installation location. The rule uses the value of
830 <<bbv2.builtin.features.install-package,`<install-package>`>> property if it's
831 present in `property-set`. Otherwise it deduces the package name using
832 ``project-module``'s attributes. It traverses the project hierarchy up to the
833 root searching for the first project with an id. If none is found, the base
834 name of the root project's location is used. If `project-module` is empty, the
835 caller module is used (this allows invoking just `[ get-package-name $(ps) ]`
836 in project jam files).
840 rule get-package-name ( property-set : project-module ? )
842 local package = [ $(property-set).get <install-package> ] ;
845 project-module ?= [ CALLER_MODULE 1 ] ;
847 local m = $(project-module) ;
848 package = [ project.attribute $(m) id ] ;
851 m = [ project.attribute $(m) parent-module ] ;
852 if ! $(m) { break ; }
854 package = [ project.attribute $(m) id ] ;
859 local root = [ project.attribute $(project-module) project-root ] ;
860 package = [ path.root $(root) [ path.pwd ] ] ;
863 package = $(package:B) ;
869 rule stage-translate-path ( feature value : properties * : project-id : project-location )
871 if $(feature) = <location> && [ MATCH "^\\((.+)\\)(/(.*))?$" : $(value) ]
878 # Main target rule for 'install'.
880 rule install ( name : sources * : requirements * : default-build * )
882 local project = [ project.current ] ;
884 # Unless the user has explicitly asked us to hardcode dll paths, add
885 # <hardcode-dll-paths>false in requirements, to override default value.
886 if ! <hardcode-dll-paths>true in $(requirements)
888 requirements += <hardcode-dll-paths>false ;
891 if <tag> in $(requirements:G)
894 errors.user-error The <tag> property is not allowed for the 'install'
898 targets.create-metatarget install-target-class : $(project) : $(name) :
899 $(sources) : $(requirements) <translate-path>@stage-translate-path : $(default-build) ;
903 IMPORT $(__name__) : install : : install ;
904 IMPORT $(__name__) : install : : stage ;
905 IMPORT $(__name__) : stage-translate-path : : stage-translate-path ;