]> git.proxmox.com Git - ceph.git/blame - 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
CommitLineData
7c673cae
FG
1# Copyright 2003 Dave Abrahams
2# Copyright 2005, 2006 Rene Rivera
3# Copyright 2002, 2003, 2004, 2005, 2006 Vladimir Prus
20effc67 4# Copyright 2020 Dmitry Arkhipov
7c673cae 5# Distributed under the Boost Software License, Version 1.0.
1e59de90
TL
6# (See accompanying file LICENSE.txt or copy at
7# https://www.bfgroup.xyz/b2/LICENSE.txt)
7c673cae 8
20effc67
TL
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
7c673cae
FG
18
19import "class" : new ;
20import feature ;
21import generators ;
20effc67 22import option ;
7c673cae
FG
23import path ;
24import project ;
20effc67 25import property ;
7c673cae
FG
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
20effc67
TL
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
7c673cae
FG
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.
20effc67 223 # Either way, expands installation prefixes.
7c673cae
FG
224 rule update-location ( property-set )
225 {
20effc67
TL
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)
7c673cae 256 {
20effc67
TL
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) ] ;
7c673cae
FG
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 ;
11fdf7f2 371 errors.error In "'install':" <name> property specified with
7c673cae
FG
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
1e59de90
TL
481 rule skip-from-usage-requirements ( )
482 {
483 }
484
7c673cae
FG
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#
507rule 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
540rule 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
549rule 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.
560type.register INSTALLED_EXE : : EXE ;
561
562
563class 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
600generators.register [ new installed-exe-generator ] ;
601
602
603# Installing a shared link on Unix might cause a creation of versioned symbolic
604# links.
605type.register INSTALLED_SHARED_LIB : : SHARED_LIB ;
606
607
608class 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
11fdf7f2 666 "(.*)\\.([0123456789]+)\\.([0123456789]+)\\.([0123456789]+)$" :
7c673cae
FG
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
697generators.register [ new installed-shared-lib-generator ] ;
698
699
20effc67
TL
700#| tag::doc[]
701
702. `rule get-dir ( name : property-set : package-name : flags * )`
703+
704Returns the path to a named installation directory. For a given `name=xyz` the
705rule 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
707recursively getting the path to ``name``'s registered base named directory and
708relative path. For example:
709+
710[source]
711----
712stage.add-install-dir foo : bar : baz ;
713
714local ps = [ property-set.create <install-foo>x/y/z ] ;
715echo [ stage.get-dir foo : $(ps) : $(__name__) ] ; # outputs x/y/z
716
717ps = [ property-set.create <install-baz>a/b/c/d ] ;
718echo [ stage.get-dir foo : $(ps) : $(__name__) ] ; # outputs a/b/c/d/bar
719----
720+
721The argument `package-name` is used to construct the path for named directories
722that were registered with `package-suffix` option and also to construct
723`install-prefix` when targeting Windows.
724+
725Available `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
733rule 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
782local 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
799local 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+
828Returns the package name that will be used for `install` targets when
829constructing installation location. The rule uses the value of
830<<bbv2.builtin.features.install-package,`<install-package>`>> property if it's
831present in `property-set`. Otherwise it deduces the package name using
832``project-module``'s attributes. It traverses the project hierarchy up to the
833root searching for the first project with an id. If none is found, the base
834name of the root project's location is used. If `project-module` is empty, the
835caller module is used (this allows invoking just `[ get-package-name $(ps) ]`
836in project jam files).
837
838|# # end::doc[]
839
840rule 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
869rule 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
7c673cae
FG
878# Main target rule for 'install'.
879#
880rule 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) :
20effc67 899 $(sources) : $(requirements) <translate-path>@stage-translate-path : $(default-build) ;
7c673cae
FG
900}
901
902
903IMPORT $(__name__) : install : : install ;
904IMPORT $(__name__) : install : : stage ;
20effc67 905IMPORT $(__name__) : stage-translate-path : : stage-translate-path ;