]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/tools/build/src/tools/stage.jam
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / boost / tools / build / src / tools / stage.jam
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)
8
9 #| tag::doc[]
10
11 [[bbv2.reference.modules.stage]]
12 = stage
13 This module defines the `install` rule, used to copy a set of targets to a
14 single location.
15
16 |# # end::doc[]
17
18
19 import "class" : new ;
20 import feature ;
21 import generators ;
22 import option ;
23 import path ;
24 import project ;
25 import property ;
26 import targets ;
27 import type ;
28 import types/register ;
29 import virtual-target ;
30
31
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 ;
36
37 # If 'on', version symlinks for shared libraries will not be created. Affects
38 # Unix builds only.
39 feature.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`::
45 Specifies the name of the package to which installed files belong. This is
46 used for default installation prefix on certain platforms.
47
48 |# # end::features-install-package-doc[]
49
50 feature.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 +
58 Defines a named installation directory.
59 +
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`.
64 +
65 Arguments:
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 ----
77 add-install-dir foo : bar : baz : package-suffix ;
78 install (foo) : a : <install-package>xyz ;
79 ----
80 +
81 installs `a` into `(baz)/bar/xyz`.
82
83 |# # end::doc[]
84
85 .dirs = ;
86 rule 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 +
105 Returns names of all registered installation directories.
106
107 |# # end::doc[]
108
109 rule 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>`::
118 Specifies installation prefix for <<bbv2.tasks.installing,`install`>> targets.
119 These 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
146 If 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
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 ;
174
175
176 #| tag::features-staging-prefix-doc[]
177
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`.
181 Example:
182 +
183 [source]
184 ----
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
188 ----
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.
193
194 |# # end::features-staging-prefix-doc[]
195
196 feature.feature staging-prefix : : free path ;
197
198
199 class 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 rule skip-from-usage-requirements ( )
482 {
483 }
484
485 # Returns true iff 'type' is subtype of some element of 'types-to-include'.
486 #
487 local rule include-type ( type : types-to-include * )
488 {
489 local found ;
490 while $(types-to-include) && ! $(found)
491 {
492 if [ type.is-subtype $(type) $(types-to-include[1]) ]
493 {
494 found = true ;
495 }
496 types-to-include = $(types-to-include[2-]) ;
497 }
498
499 return $(found) ;
500 }
501 }
502
503
504 # Creates a copy of target 'source'. The 'properties' object should have a
505 # <location> property which specifies where the target must be placed.
506 #
507 rule copy-file ( project name ? : source : properties )
508 {
509 name ?= [ $(source).name ] ;
510 local relative ;
511
512 local new-a = [ new non-scanning-action $(source) : common.copy :
513 $(properties) ] ;
514 local source-root = [ $(properties).get <install-source-root> ] ;
515 if $(source-root)
516 {
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 ] ] ;
525
526 relative = [ path.relative-to $(source-root) $(path) ] ;
527 }
528
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
532 # fail.
533 name = [ path.join $(relative) $(name:D=) ] ;
534
535 return [ new file-target $(name) exact : [ $(source).type ] : $(project) :
536 $(new-a) ] ;
537 }
538
539
540 rule symlink ( name : project : source : properties )
541 {
542 local a = [ new action $(source) : symlink.ln : $(properties) ] ;
543 local t = [ new file-target $(name) exact : [ $(source).type ] : $(project)
544 : $(a) ] ;
545 return [ virtual-target.register $(t) ] ;
546 }
547
548
549 rule relink-file ( project : source : property-set )
550 {
551 local action = [ $(source).action ] ;
552 local cloned-action = [ virtual-target.clone-action $(action) : $(project) :
553 "" : $(property-set) ] ;
554 return [ $(cloned-action).targets ] ;
555 }
556
557
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 ;
561
562
563 class installed-exe-generator : generator
564 {
565 import type ;
566 import property-set ;
567 import modules ;
568 import stage ;
569
570 rule __init__ ( )
571 {
572 generator.__init__ install-exe : EXE : INSTALLED_EXE ;
573 }
574
575 rule run ( project name ? : property-set : source : multiple ? )
576 {
577 local stage-rule = stage.copy-file ;
578
579 if ! [ $(property-set).get <os> ] in NT CYGWIN &&
580 ! [ $(property-set).get <target-os> ] in windows cygwin
581 {
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> ] ;
588
589 if $(current) != $(original)
590 {
591 stage-rule = stage.relink-file ;
592 }
593 }
594
595 return [ $(stage-rule) $(project) : $(source) : $(property-set) ] ;
596 }
597 }
598
599
600 generators.register [ new installed-exe-generator ] ;
601
602
603 # Installing a shared link on Unix might cause a creation of versioned symbolic
604 # links.
605 type.register INSTALLED_SHARED_LIB : : SHARED_LIB ;
606
607
608 class installed-shared-lib-generator : generator
609 {
610 import type ;
611 import property-set ;
612 import modules ;
613 import stage ;
614
615 rule __init__ ( )
616 {
617 generator.__init__ install-shared-lib : SHARED_LIB :
618 INSTALLED_SHARED_LIB ;
619 }
620
621 rule run ( project name ? : property-set : source : multiple ? )
622 {
623 if [ $(property-set).get <os> ] in NT CYGWIN ||
624 [ $(property-set).get <target-os> ] in windows cygwin
625 {
626 local copied = [ stage.copy-file $(project) : $(source) :
627 $(property-set) ] ;
628 return [ virtual-target.register $(copied) ] ;
629 }
630 else
631 {
632 local a = [ $(source).action ] ;
633 local copied ;
634 if ! $(a)
635 {
636 # Non-derived file, just copy.
637 copied = [ stage.copy-file $(project) : $(source) :
638 $(property-set) ] ;
639 }
640 else
641 {
642 local cp = [ $(a).properties ] ;
643 local current-dll-path = [ $(cp).get <dll-path> ] ;
644 local new-dll-path = [ $(property-set).get <dll-path> ] ;
645
646 if $(current-dll-path) != $(new-dll-path)
647 {
648 # Rpath changed, need to relink.
649 copied = [ stage.relink-file $(project) : $(source) :
650 $(property-set) ] ;
651 }
652 else
653 {
654 copied = [ stage.copy-file $(project) : $(source) :
655 $(property-set) ] ;
656 }
657 }
658
659 copied = [ virtual-target.register $(copied) ] ;
660
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
664 # symbolic links.
665 local m = [ MATCH
666 "(.*)\\.([0123456789]+)\\.([0123456789]+)\\.([0123456789]+)$" :
667 [ $(copied).name ] ] ;
668 if $(m)
669 {
670 # Symlink without version at all is used to make
671 # -lsome_library work.
672 result += [ stage.symlink $(m[1]) : $(project) : $(copied) :
673 $(property-set) ] ;
674
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
679 # symlinks.
680 local suppress = [ $(property-set).get
681 <install-no-version-symlinks> ] ;
682
683 if $(suppress) != "on"
684 {
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) ] ;
689 }
690 }
691
692 return $(result) ;
693 }
694 }
695 }
696
697 generators.register [ new installed-shared-lib-generator ] ;
698
699
700 #| tag::doc[]
701
702 . `rule get-dir ( name : property-set : package-name : flags * )`
703 +
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:
709 +
710 [source]
711 ----
712 stage.add-install-dir foo : bar : baz ;
713
714 local ps = [ property-set.create <install-foo>x/y/z ] ;
715 echo [ stage.get-dir foo : $(ps) : $(__name__) ] ; # outputs x/y/z
716
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
719 ----
720 +
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.
724 +
725 Available `flags`:
726 +
727 * `staged`: take <<bbv2.builtin.features.staging-prefix,`staging-prefix`>> into
728 account.
729 * `relative`: return the path to `name` relative to its base directory.
730
731 |# # end::doc[]
732
733 rule get-dir ( name : property-set : package-name : flags * )
734 {
735 local result ;
736
737 # We treat the 'prefix' directory in a special way, because it's default
738 # is based on the value of <target-os> property.
739 if $(name) = prefix
740 {
741 result = [ get-install-prefix $(property-set) : $(package-name)
742 : $(flags) ] ;
743 }
744 else
745 {
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
750 # relative path.
751 result ?= $(info[1]) ;
752 if $(result)
753 {
754 result = [ path.make $(result) ] ;
755 }
756
757 # If there is a base directory, we may need to modify result further.
758 if $(info[2])
759 {
760 local base = [ get-dir $(info[2]) : $(property-set)
761 : $(package-name) : $(flags) ] ;
762 if relative in $(flags)
763 {
764 local rel = [ path.relative $(result) $(base) : no-error ] ;
765 if not-a-child != $(rel)
766 {
767 result = $(rel) ;
768 }
769 }
770 else
771 {
772 result = [ path.root $(result) $(base) ] ;
773 }
774 }
775 }
776
777 return $(result) ;
778 }
779
780
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]) ;
784 if ! x$(path)
785 {
786 import errors ;
787 errors.error $(name) is not an installation directory name. ;
788 }
789
790 if package-suffix in $(.dir.$(name).options)
791 {
792 path = [ path.join $(path) $(package-name) ] ;
793 }
794
795 return $(path) $(.dir.$(name)[2]) ;
796 }
797
798
799 local rule get-install-prefix ( property-set : package-name : flags * )
800 {
801 local prefix ;
802 if staged in $(flags)
803 {
804 prefix = [ $(property-set).get <staging-prefix> ] ;
805 }
806 prefix ?= [ $(property-set).get <install-prefix> ] ;
807 prefix = $(prefix[0]) ;
808 prefix ?= [ option.get prefix ] ;
809 if ! $(prefix)
810 {
811 if windows = [ $(property-set).get <target-os> ]
812 {
813 prefix = C:\\$(package-name) ;
814 }
815 else
816 {
817 prefix = /usr/local ;
818 }
819 }
820 return [ path.make $(prefix) ] ;
821 }
822
823
824 #| tag::doc[]
825
826 . `rule get-package-name ( property-set : project-module ? )`
827 +
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).
837
838 |# # end::doc[]
839
840 rule get-package-name ( property-set : project-module ? )
841 {
842 local package = [ $(property-set).get <install-package> ] ;
843 if ! $(package)
844 {
845 project-module ?= [ CALLER_MODULE 1 ] ;
846
847 local m = $(project-module) ;
848 package = [ project.attribute $(m) id ] ;
849 while ! $(package)
850 {
851 m = [ project.attribute $(m) parent-module ] ;
852 if ! $(m) { break ; }
853
854 package = [ project.attribute $(m) id ] ;
855 }
856
857 if ! $(package)
858 {
859 local root = [ project.attribute $(project-module) project-root ] ;
860 package = [ path.root $(root) [ path.pwd ] ] ;
861 }
862
863 package = $(package:B) ;
864 }
865 return $(package) ;
866 }
867
868
869 rule stage-translate-path ( feature value : properties * : project-id : project-location )
870 {
871 if $(feature) = <location> && [ MATCH "^\\((.+)\\)(/(.*))?$" : $(value) ]
872 {
873 return $(value) ;
874 }
875 }
876
877
878 # Main target rule for 'install'.
879 #
880 rule install ( name : sources * : requirements * : default-build * )
881 {
882 local project = [ project.current ] ;
883
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)
887 {
888 requirements += <hardcode-dll-paths>false ;
889 }
890
891 if <tag> in $(requirements:G)
892 {
893 import errors ;
894 errors.user-error The <tag> property is not allowed for the 'install'
895 rule. ;
896 }
897
898 targets.create-metatarget install-target-class : $(project) : $(name) :
899 $(sources) : $(requirements) <translate-path>@stage-translate-path : $(default-build) ;
900 }
901
902
903 IMPORT $(__name__) : install : : install ;
904 IMPORT $(__name__) : install : : stage ;
905 IMPORT $(__name__) : stage-translate-path : : stage-translate-path ;