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)
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 # Returns true iff 'type' is subtype of some element of 'types-to-include'.
483 local rule include-type ( type : types-to-include * )
486 while $(types-to-include) && ! $(found)
488 if [ type.is-subtype $(type) $(types-to-include[1]) ]
492 types-to-include = $(types-to-include[2-]) ;
500 # Creates a copy of target 'source'. The 'properties' object should have a
501 # <location> property which specifies where the target must be placed.
503 rule copy-file ( project name ? : source : properties )
505 name ?= [ $(source).name ] ;
508 local new-a = [ new non-scanning-action $(source) : common.copy :
510 local source-root = [ $(properties).get <install-source-root> ] ;
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 ] ] ;
522 relative = [ path.relative-to $(source-root) $(path) ] ;
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
529 name = [ path.join $(relative) $(name:D=) ] ;
531 return [ new file-target $(name) exact : [ $(source).type ] : $(project) :
536 rule symlink ( name : project : source : properties )
538 local a = [ new action $(source) : symlink.ln : $(properties) ] ;
539 local t = [ new file-target $(name) exact : [ $(source).type ] : $(project)
541 return [ virtual-target.register $(t) ] ;
545 rule relink-file ( project : source : property-set )
547 local action = [ $(source).action ] ;
548 local cloned-action = [ virtual-target.clone-action $(action) : $(project) :
549 "" : $(property-set) ] ;
550 return [ $(cloned-action).targets ] ;
554 # Declare installed version of the EXE type. Generator for this type will cause
555 # relinking to the new location.
556 type.register INSTALLED_EXE : : EXE ;
559 class installed-exe-generator : generator
562 import property-set ;
568 generator.__init__ install-exe : EXE : INSTALLED_EXE ;
571 rule run ( project name ? : property-set : source : multiple ? )
573 local stage-rule = stage.copy-file ;
575 if ! [ $(property-set).get <os> ] in NT CYGWIN &&
576 ! [ $(property-set).get <target-os> ] in windows cygwin
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> ] ;
585 if $(current) != $(original)
587 stage-rule = stage.relink-file ;
591 return [ $(stage-rule) $(project) : $(source) : $(property-set) ] ;
596 generators.register [ new installed-exe-generator ] ;
599 # Installing a shared link on Unix might cause a creation of versioned symbolic
601 type.register INSTALLED_SHARED_LIB : : SHARED_LIB ;
604 class installed-shared-lib-generator : generator
607 import property-set ;
613 generator.__init__ install-shared-lib : SHARED_LIB :
614 INSTALLED_SHARED_LIB ;
617 rule run ( project name ? : property-set : source : multiple ? )
619 if [ $(property-set).get <os> ] in NT CYGWIN ||
620 [ $(property-set).get <target-os> ] in windows cygwin
622 local copied = [ stage.copy-file $(project) : $(source) :
624 return [ virtual-target.register $(copied) ] ;
628 local a = [ $(source).action ] ;
632 # Non-derived file, just copy.
633 copied = [ stage.copy-file $(project) : $(source) :
638 local cp = [ $(a).properties ] ;
639 local current-dll-path = [ $(cp).get <dll-path> ] ;
640 local new-dll-path = [ $(property-set).get <dll-path> ] ;
642 if $(current-dll-path) != $(new-dll-path)
644 # Rpath changed, need to relink.
645 copied = [ stage.relink-file $(project) : $(source) :
650 copied = [ stage.copy-file $(project) : $(source) :
655 copied = [ virtual-target.register $(copied) ] ;
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
662 "(.*)\\.([0123456789]+)\\.([0123456789]+)\\.([0123456789]+)$" :
663 [ $(copied).name ] ] ;
666 # Symlink without version at all is used to make
667 # -lsome_library work.
668 result += [ stage.symlink $(m[1]) : $(project) : $(copied) :
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
676 local suppress = [ $(property-set).get
677 <install-no-version-symlinks> ] ;
679 if $(suppress) != "on"
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) ] ;
693 generators.register [ new installed-shared-lib-generator ] ;
698 . `rule get-dir ( name : property-set : package-name : flags * )`
700 Returns the path to a named installation directory. For a given `name=xyz` the
701 rule 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
703 recursively getting the path to ``name``'s registered base named directory and
704 relative path. For example:
708 stage.add-install-dir foo : bar : baz ;
710 local ps = [ property-set.create <install-foo>x/y/z ] ;
711 echo [ stage.get-dir foo : $(ps) : $(__name__) ] ; # outputs x/y/z
713 ps = [ property-set.create <install-baz>a/b/c/d ] ;
714 echo [ stage.get-dir foo : $(ps) : $(__name__) ] ; # outputs a/b/c/d/bar
717 The argument `package-name` is used to construct the path for named directories
718 that were registered with `package-suffix` option and also to construct
719 `install-prefix` when targeting Windows.
723 * `staged`: take <<bbv2.builtin.features.staging-prefix,`staging-prefix`>> into
725 * `relative`: return the path to `name` relative to its base directory.
729 rule get-dir ( name : property-set : package-name : flags * )
733 # We treat the 'prefix' directory in a special way, because it's default
734 # is based on the value of <target-os> property.
737 result = [ get-install-prefix $(property-set) : $(package-name)
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
747 result ?= $(info[1]) ;
750 result = [ path.make $(result) ] ;
753 # If there is a base directory, we may need to modify result further.
756 local base = [ get-dir $(info[2]) : $(property-set)
757 : $(package-name) : $(flags) ] ;
758 if relative in $(flags)
760 local rel = [ path.relative $(result) $(base) : no-error ] ;
761 if not-a-child != $(rel)
768 result = [ path.root $(result) $(base) ] ;
777 # For a given named directory returns its parent directory and relative path
778 local rule get-dir-info ( name : package-name ) {
779 local path = $(.dir.$(name)[1]) ;
783 errors.error $(name) is not an installation directory name. ;
786 if package-suffix in $(.dir.$(name).options)
788 path = [ path.join $(path) $(package-name) ] ;
791 return $(path) $(.dir.$(name)[2]) ;
795 local rule get-install-prefix ( property-set : package-name : flags * )
798 if staged in $(flags)
800 prefix = [ $(property-set).get <staging-prefix> ] ;
802 prefix ?= [ $(property-set).get <install-prefix> ] ;
803 prefix = $(prefix[0]) ;
804 prefix ?= [ option.get prefix ] ;
807 if windows = [ $(property-set).get <target-os> ]
809 prefix = C:\\$(package-name) ;
813 prefix = /usr/local ;
816 return [ path.make $(prefix) ] ;
822 . `rule get-package-name ( property-set : project-module ? )`
824 Returns the package name that will be used for `install` targets when
825 constructing installation location. The rule uses the value of
826 <<bbv2.builtin.features.install-package,`<install-package>`>> property if it's
827 present in `property-set`. Otherwise it deduces the package name using
828 ``project-module``'s attributes. It traverses the project hierarchy up to the
829 root searching for the first project with an id. If none is found, the base
830 name of the root project's location is used. If `project-module` is empty, the
831 caller module is used (this allows invoking just `[ get-package-name $(ps) ]`
832 in project jam files).
836 rule get-package-name ( property-set : project-module ? )
838 local package = [ $(property-set).get <install-package> ] ;
841 project-module ?= [ CALLER_MODULE 1 ] ;
843 local m = $(project-module) ;
844 package = [ project.attribute $(m) id ] ;
847 m = [ project.attribute $(m) parent-module ] ;
848 if ! $(m) { break ; }
850 package = [ project.attribute $(m) id ] ;
855 local root = [ project.attribute $(project-module) project-root ] ;
856 package = [ path.root $(root) [ path.pwd ] ] ;
859 package = $(package:B) ;
865 rule stage-translate-path ( feature value : properties * : project-id : project-location )
867 if $(feature) = <location> && [ MATCH "^\\((.+)\\)(/(.*))?$" : $(value) ]
874 # Main target rule for 'install'.
876 rule install ( name : sources * : requirements * : default-build * )
878 local project = [ project.current ] ;
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)
884 requirements += <hardcode-dll-paths>false ;
887 if <tag> in $(requirements:G)
890 errors.user-error The <tag> property is not allowed for the 'install'
894 targets.create-metatarget install-target-class : $(project) : $(name) :
895 $(sources) : $(requirements) <translate-path>@stage-translate-path : $(default-build) ;
899 IMPORT $(__name__) : install : : install ;
900 IMPORT $(__name__) : install : : stage ;
901 IMPORT $(__name__) : stage-translate-path : : stage-translate-path ;