| # Copyright 2003 Dave Abrahams |
| # Copyright 2005, 2006 Rene Rivera |
| # Copyright 2002, 2003, 2004, 2005, 2006 Vladimir Prus |
| # Distributed under the Boost Software License, Version 1.0. |
| # (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) |
| |
| # This module defines the 'install' rule, used to copy a set of targets to a |
| # single location. |
| |
| import targets ; |
| import "class" : new ; |
| import errors ; |
| import type ; |
| import generators ; |
| import feature ; |
| import project ; |
| import virtual-target ; |
| import path ; |
| import types/register ; |
| |
| |
| feature.feature <install-dependencies> : off on : incidental ; |
| feature.feature <install-type> : : free incidental ; |
| feature.feature <install-source-root> : : free path ; |
| feature.feature <so-version> : : free incidental ; |
| |
| # If 'on', version symlinks for shared libraries will not be created. Affects |
| # Unix builds only. |
| feature.feature <install-no-version-symlinks> : on : optional incidental ; |
| |
| |
| class install-target-class : basic-target |
| { |
| import feature ; |
| import project ; |
| import type ; |
| import errors ; |
| import generators ; |
| import path ; |
| import stage ; |
| import "class" : new ; |
| import property ; |
| import property-set ; |
| |
| rule __init__ ( name-and-dir : project : sources * : requirements * : default-build * ) |
| { |
| basic-target.__init__ $(name-and-dir) : $(project) : $(sources) : |
| $(requirements) : $(default-build) ; |
| } |
| |
| # If <location> is not set, sets it based on the project data. |
| # |
| rule update-location ( property-set ) |
| { |
| local loc = [ $(property-set).get <location> ] ; |
| if ! $(loc) |
| { |
| loc = [ path.root $(self.name) [ $(self.project).get location ] ] ; |
| property-set = [ $(property-set).add-raw $(loc:G=<location>) ] ; |
| } |
| |
| return $(property-set) ; |
| } |
| |
| # Takes a target that is installed and a property set which is used when |
| # installing. |
| # |
| rule adjust-properties ( target : build-property-set ) |
| { |
| local ps-raw ; |
| local a = [ $(target).action ] ; |
| if $(a) |
| { |
| local ps = [ $(a).properties ] ; |
| ps-raw = [ $(ps).raw ] ; |
| |
| # Unless <hardcode-dll-paths>true is in properties, which can happen |
| # only if the user has explicitly requested it, nuke all <dll-path> |
| # properties. |
| if [ $(build-property-set).get <hardcode-dll-paths> ] != true |
| { |
| ps-raw = [ property.change $(ps-raw) : <dll-path> ] ; |
| } |
| |
| # If any <dll-path> properties were specified for installing, add |
| # them. |
| local l = [ $(build-property-set).get <dll-path> ] ; |
| ps-raw += $(l:G=<dll-path>) ; |
| |
| # Also copy <linkflags> feature from current build set, to be used |
| # for relinking. |
| local l = [ $(build-property-set).get <linkflags> ] ; |
| ps-raw += $(l:G=<linkflags>) ; |
| |
| # Remove the <tag> feature on original targets. |
| ps-raw = [ property.change $(ps-raw) : <tag> ] ; |
| |
| # And <location>. If stage target has another stage target in |
| # sources, then we shall get virtual targets with the <location> |
| # property set. |
| ps-raw = [ property.change $(ps-raw) : <location> ] ; |
| } |
| |
| local d = [ $(build-property-set).get <dependency> ] ; |
| ps-raw += $(d:G=<dependency>) ; |
| |
| local d = [ $(build-property-set).get <location> ] ; |
| ps-raw += $(d:G=<location>) ; |
| |
| local ns = [ $(build-property-set).get <install-no-version-symlinks> ] ; |
| ps-raw += $(ns:G=<install-no-version-symlinks>) ; |
| |
| local d = [ $(build-property-set).get <install-source-root> ] ; |
| # Make the path absolute: we shall use it to compute relative paths and |
| # making the path absolute will help. |
| if $(d) |
| { |
| d = [ path.root $(d) [ path.pwd ] ] ; |
| ps-raw += $(d:G=<install-source-root>) ; |
| } |
| |
| if $(ps-raw) |
| { |
| return [ property-set.create $(ps-raw) ] ; |
| } |
| else |
| { |
| return [ property-set.empty ] ; |
| } |
| } |
| |
| rule construct ( name : source-targets * : property-set ) |
| { |
| source-targets = [ targets-to-stage $(source-targets) : |
| $(property-set) ] ; |
| |
| property-set = [ update-location $(property-set) ] ; |
| |
| local ename = [ $(property-set).get <name> ] ; |
| |
| if $(ename) && $(source-targets[2]) |
| { |
| errors.error "When <name> property is used in 'install', only one" |
| "source is allowed" ; |
| } |
| |
| local result ; |
| for local i in $(source-targets) |
| { |
| local staged-targets ; |
| |
| local new-properties = [ adjust-properties $(i) : |
| $(property-set) ] ; |
| |
| # See if something special should be done when staging this type. It |
| # is indicated by the presence of a special "INSTALLED_" type. |
| local t = [ $(i).type ] ; |
| if $(t) && [ type.registered INSTALLED_$(t) ] |
| { |
| if $(ename) |
| { |
| errors.error "In 'install': <name> property specified with target that requires relinking." ; |
| } |
| else |
| { |
| local targets = [ generators.construct $(self.project) |
| $(name) : INSTALLED_$(t) : $(new-properties) : $(i) ] ; |
| staged-targets += $(targets[2-]) ; |
| } |
| } |
| else |
| { |
| staged-targets = [ stage.copy-file $(self.project) $(ename) : |
| $(i) : $(new-properties) ] ; |
| } |
| |
| if ! $(staged-targets) |
| { |
| errors.error "Unable to generate staged version of " [ $(source).str ] ; |
| } |
| |
| for t in $(staged-targets) |
| { |
| result += [ virtual-target.register $(t) ] ; |
| } |
| } |
| |
| return [ property-set.empty ] $(result) ; |
| } |
| |
| # Given the list of source targets explicitly passed to 'stage', returns the |
| # list of targets which must be staged. |
| # |
| rule targets-to-stage ( source-targets * : property-set ) |
| { |
| local result ; |
| |
| # Traverse the dependencies, if needed. |
| if [ $(property-set).get <install-dependencies> ] = "on" |
| { |
| source-targets = [ collect-targets $(source-targets) ] ; |
| } |
| |
| # Filter the target types, if needed. |
| local included-types = [ $(property-set).get <install-type> ] ; |
| for local r in $(source-targets) |
| { |
| local ty = [ $(r).type ] ; |
| if $(ty) |
| { |
| # Do not stage searched libs. |
| if $(ty) != SEARCHED_LIB |
| { |
| if $(included-types) |
| { |
| if [ include-type $(ty) : $(included-types) ] |
| { |
| result += $(r) ; |
| } |
| } |
| else |
| { |
| result += $(r) ; |
| } |
| } |
| } |
| else if ! $(included-types) |
| { |
| # Don't install typeless target if there is an explicit list of |
| # allowed types. |
| result += $(r) ; |
| } |
| } |
| |
| return $(result) ; |
| } |
| |
| # CONSIDER: figure out why we can not use virtual-target.traverse here. |
| # |
| rule collect-targets ( targets * ) |
| { |
| # Find subvariants |
| local s ; |
| for local t in $(targets) |
| { |
| s += [ $(t).creating-subvariant ] ; |
| } |
| s = [ sequence.unique $(s) ] ; |
| |
| local result = [ new set ] ; |
| $(result).add $(targets) ; |
| |
| for local i in $(s) |
| { |
| $(i).all-referenced-targets $(result) ; |
| } |
| local result2 ; |
| for local r in [ $(result).list ] |
| { |
| if $(r:G) != <use> |
| { |
| result2 += $(r:G=) ; |
| } |
| } |
| DELETE_MODULE $(result) ; |
| result = [ sequence.unique $(result2) ] ; |
| } |
| |
| # Returns true iff 'type' is subtype of some element of 'types-to-include'. |
| # |
| local rule include-type ( type : types-to-include * ) |
| { |
| local found ; |
| while $(types-to-include) && ! $(found) |
| { |
| if [ type.is-subtype $(type) $(types-to-include[1]) ] |
| { |
| found = true ; |
| } |
| types-to-include = $(types-to-include[2-]) ; |
| } |
| |
| return $(found) ; |
| } |
| } |
| |
| |
| # Creates a copy of target 'source'. The 'properties' object should have a |
| # <location> property which specifies where the target must be placed. |
| # |
| rule copy-file ( project name ? : source : properties ) |
| { |
| name ?= [ $(source).name ] ; |
| local relative ; |
| |
| local new-a = [ new non-scanning-action $(source) : common.copy : |
| $(properties) ] ; |
| local source-root = [ $(properties).get <install-source-root> ] ; |
| if $(source-root) |
| { |
| # Get the real path of the target. We probably need to strip relative |
| # path from the target name at construction. |
| local path = [ $(source).path ] ; |
| path = [ path.root $(name:D) $(path) ] ; |
| # Make the path absolute. Otherwise, it would be hard to compute the |
| # relative path. The 'source-root' is already absolute, see the |
| # 'adjust-properties' method above. |
| path = [ path.root $(path) [ path.pwd ] ] ; |
| |
| relative = [ path.relative-to $(source-root) $(path) ] ; |
| } |
| |
| # Note: Using $(name:D=$(relative)) might be faster here, but then we would |
| # need to explicitly check that relative is not ".", otherwise we might get |
| # paths like '<prefix>/boost/.', try to create it and mkdir would obviously |
| # fail. |
| name = [ path.join $(relative) $(name:D=) ] ; |
| |
| return [ new file-target $(name) exact : [ $(source).type ] : $(project) : |
| $(new-a) ] ; |
| } |
| |
| |
| rule symlink ( name : project : source : properties ) |
| { |
| local a = [ new action $(source) : symlink.ln : $(properties) ] ; |
| return [ new file-target $(name) exact : [ $(source).type ] : $(project) : |
| $(a) ] ; |
| } |
| |
| |
| rule relink-file ( project : source : property-set ) |
| { |
| local action = [ $(source).action ] ; |
| local cloned-action = [ virtual-target.clone-action $(action) : $(project) : |
| "" : $(property-set) ] ; |
| return [ $(cloned-action).targets ] ; |
| } |
| |
| |
| # Declare installed version of the EXE type. Generator for this type will cause |
| # relinking to the new location. |
| type.register INSTALLED_EXE : : EXE ; |
| |
| |
| class installed-exe-generator : generator |
| { |
| import type ; |
| import property-set ; |
| import modules ; |
| import stage ; |
| |
| rule __init__ ( ) |
| { |
| generator.__init__ install-exe : EXE : INSTALLED_EXE ; |
| } |
| |
| rule run ( project name ? : property-set : source : multiple ? ) |
| { |
| local need-relink ; |
| |
| if [ $(property-set).get <os> ] in NT CYGWIN || |
| [ $(property-set).get <target-os> ] in windows cygwin |
| { |
| } |
| else |
| { |
| # See if the dll-path properties are not changed during |
| # install. If so, copy, don't relink. |
| local a = [ $(source).action ] ; |
| local p = [ $(a).properties ] ; |
| local original = [ $(p).get <dll-path> ] ; |
| local current = [ $(property-set).get <dll-path> ] ; |
| |
| if $(current) != $(original) |
| { |
| need-relink = true ; |
| } |
| } |
| |
| |
| if $(need-relink) |
| { |
| return [ stage.relink-file $(project) |
| : $(source) : $(property-set) ] ; |
| } |
| else |
| { |
| return [ stage.copy-file $(project) |
| : $(source) : $(property-set) ] ; |
| } |
| } |
| } |
| |
| |
| generators.register [ new installed-exe-generator ] ; |
| |
| |
| # Installing a shared link on Unix might cause a creation of versioned symbolic |
| # links. |
| type.register INSTALLED_SHARED_LIB : : SHARED_LIB ; |
| |
| |
| class installed-shared-lib-generator : generator |
| { |
| import type ; |
| import property-set ; |
| import modules ; |
| import stage ; |
| |
| rule __init__ ( ) |
| { |
| generator.__init__ install-shared-lib : SHARED_LIB |
| : INSTALLED_SHARED_LIB ; |
| } |
| |
| rule run ( project name ? : property-set : source : multiple ? ) |
| { |
| if [ $(property-set).get <os> ] in NT CYGWIN || |
| [ $(property-set).get <target-os> ] in windows cygwin |
| { |
| local copied = [ stage.copy-file $(project) : $(source) : |
| $(property-set) ] ; |
| return [ virtual-target.register $(copied) ] ; |
| } |
| else |
| { |
| local a = [ $(source).action ] ; |
| local copied ; |
| if ! $(a) |
| { |
| # Non-derived file, just copy. |
| copied = [ stage.copy-file $(project) : $(source) : |
| $(property-set) ] ; |
| } |
| else |
| { |
| local cp = [ $(a).properties ] ; |
| local current-dll-path = [ $(cp).get <dll-path> ] ; |
| local new-dll-path = [ $(property-set).get <dll-path> ] ; |
| |
| if $(current-dll-path) != $(new-dll-path) |
| { |
| # Rpath changed, need to relink. |
| copied = [ stage.relink-file $(project) : $(source) : |
| $(property-set) ] ; |
| } |
| else |
| { |
| copied = [ stage.copy-file $(project) : $(source) : |
| $(property-set) ] ; |
| } |
| } |
| |
| copied = [ virtual-target.register $(copied) ] ; |
| |
| local result = $(copied) ; |
| # If the name is in the form NNN.XXX.YYY.ZZZ, where all 'X', 'Y' and |
| # 'Z' are numbers, we need to create NNN.XXX and NNN.XXX.YYY |
| # symbolic links. |
| local m = [ MATCH (.*)\\.([0123456789]+)\\.([0123456789]+)\\.([0123456789]+)$ |
| : [ $(copied).name ] ] ; |
| if $(m) |
| { |
| # Symlink without version at all is used to make |
| # -lsome_library work. |
| result += [ stage.symlink $(m[1]) : $(project) : $(copied) : |
| $(property-set) ] ; |
| |
| # Symlinks of some libfoo.N and libfoo.N.M are used so that |
| # library can found at runtime, if libfoo.N.M.X has soname of |
| # libfoo.N. That happens when the library makes some binary |
| # compatibility guarantees. If not, it is possible to skip those |
| # symlinks. |
| local suppress = |
| [ $(property-set).get <install-no-version-symlinks> ] ; |
| |
| if $(suppress) != "on" |
| { |
| result += [ stage.symlink $(m[1]).$(m[2]) : $(project) |
| : $(copied) : $(property-set) ] ; |
| result += [ stage.symlink $(m[1]).$(m[2]).$(m[3]) : $(project) |
| : $(copied) : $(property-set) ] ; |
| } |
| } |
| |
| return $(result) ; |
| } |
| } |
| } |
| |
| generators.register [ new installed-shared-lib-generator ] ; |
| |
| |
| # Main target rule for 'install'. |
| # |
| rule install ( name : sources * : requirements * : default-build * ) |
| { |
| local project = [ project.current ] ; |
| |
| # Unless the user has explicitly asked us to hardcode dll paths, add |
| # <hardcode-dll-paths>false in requirements, to override default value. |
| if ! <hardcode-dll-paths>true in $(requirements) |
| { |
| requirements += <hardcode-dll-paths>false ; |
| } |
| |
| if <tag> in $(requirements:G) |
| { |
| errors.user-error |
| "The <tag> property is not allowed for the 'install' rule" ; |
| } |
| |
| targets.main-target-alternative |
| [ new install-target-class $(name) : $(project) |
| : [ targets.main-target-sources $(sources) : $(name) ] |
| : [ targets.main-target-requirements $(requirements) : $(project) ] |
| : [ targets.main-target-default-build $(default-build) : $(project) ] |
| ] ; |
| } |
| |
| |
| IMPORT $(__name__) : install : : install ; |
| IMPORT $(__name__) : install : : stage ; |