1# Copyright (c) 2005 Vladimir Prus. 2# Copyright 2006 Rene Rivera. 3# 4# Use, modification and distribution is subject to the Boost Software 5# License Version 1.0. (See accompanying file LICENSE_1_0.txt or 6# http://www.boost.org/LICENSE_1_0.txt) 7 8# Provides mechanism for installing whole packages into a specific directory 9# structure. This is opposed to the 'install' rule, that installs a number of 10# targets to a single directory, and does not care about directory structure at 11# all. 12 13# Example usage: 14# 15# package.install boost : <properties> 16# : <binaries> 17# : <libraries> 18# : <headers> 19# ; 20# 21# This will install binaries, libraries and headers to the 'proper' location, 22# given by command line options --prefix, --exec-prefix, --bindir, --libdir and 23# --includedir. 24# 25# The rule is just a convenient wrapper, avoiding the need to define several 26# 'install' targets. 27# 28# The only install-related feature is <install-source-root>. It will apply to 29# headers only and if present, paths of headers relatively to source root will 30# be retained after installing. If it is not specified, then "." is assumed, so 31# relative paths in headers are always preserved. 32 33import "class" : new ; 34import option ; 35import project ; 36import feature ; 37import path ; 38import property ; 39import stage ; 40import targets ; 41import modules ; 42import os ; 43 44feature.feature install-default-prefix : : free incidental ; 45 46class package-paths 47{ 48 import feature ; 49 import modules ; 50 import option ; 51 import os ; 52 import path ; 53 rule __init__ ( default-prefix ) 54 { 55 local explicit-options = [ MATCH --(prefix|bindir|libdir|includedir|datarootdir)=.* 56 : [ modules.peek : ARGV ] ] ; 57 self.has-$(explicit-options) = true ; 58 if prefix in $(explicit-options) 59 { 60 # If --prefix is explicitly specified on the command line, 61 # then we need wipe away any settings of libdir/includir that 62 # is specified via options in config files. 63 option.set bindir : ; 64 option.set libdir : ; 65 option.set includedir : ; 66 option.set datarootdir : ; 67 } 68 69 handle-path prefix : $(default-prefix) ; 70 handle-path libdir : $(self.prefix)/lib ; 71 handle-path bindir : $(self.prefix)/bin ; 72 handle-path includedir : $(self.prefix)/include ; 73 handle-path datarootdir : $(self.prefix)/share ; 74 } 75 76 local rule handle-path ( option : default-value ) 77 { 78 local opt = [ option.get $(option) ] ; 79 if $(opt) 80 { 81 opt = [ path.root [ path.make $(opt) ] [ path.pwd ] ] ; 82 } 83 else 84 { 85 opt = $(default-value) ; 86 } 87 self.$(option) = $(opt) ; 88 } 89 90 rule prefix ( ) 91 { 92 return $(self.prefix) ; 93 } 94 95 rule libdir ( ) 96 { 97 return $(self.libdir) ; 98 } 99 100 rule bindir ( ) 101 { 102 return $(self.bindir) ; 103 } 104 105 rule includedir ( ) 106 { 107 return $(self.includedir) ; 108 } 109 110 rule datarootdir ( ) 111 { 112 return $(self.datarootdir) ; 113 } 114 115 rule get ( option ) 116 { 117 if ! $(self.$(option)) 118 { 119 local info = [ modules.peek package : .options.$(option) ] ; 120 local default-value = $(info[1]) ; 121 local relative-to = $(info[2]) ; 122 if $(self.has-$(relative-to)) 123 { 124 option.set $(option) ; 125 self.has-$(option) = true ; 126 } 127 if [ MATCH --$(option)=(.*) : [ modules.peek : ARGV ] ] 128 { 129 self.has-$(option) = true ; 130 } 131 local adjusted-default = 132 [ path.join [ get $(relative-to) ] $(default-value) ] ; 133 handle-path $(option) : $(adjusted-default) ; 134 } 135 return $(self.$(option)) ; 136 } 137} 138 139# Registers an additional path option. The option name 140# can then be used with a package-paths object. 141# 142# default-path is the default path that will be used if 143# the option is not set explicitly. It will be interpreted 144# relative to another option. This allows options to be 145# defined hierarchically with --prefix as the root. 146# 147# relative-to should be the name of another option. It defaults 148# to prefix. 149# 150# Example:: 151# 152# package.add-path-option cmakedir : cmake : libdir ; 153# cmakedir = [ $(mypaths).get cmakedir ] ; # defaults to /usr/local/lib/cmake 154# 155rule add-path-option ( name : default-path : relative-to ? ) 156{ 157 local value = $(default-path) $(relative-to:E=prefix) ; 158 if $(.options.$(name)) && $(.options.$(name)) != $(value) 159 { 160 import errors ; 161 errors.error Duplicate definition of $(name) ; 162 } 163 .options.$(name) = $(value) ; 164} 165 166 167# Returns a package-paths object that can be used 168# to find the various install paths. If requirements 169# contains <install-default-prefix> then that will be used 170# as the default prefix, otherwise a platform specific 171# default prefix will be used. All other properties 172# in requirements are ignored. 173# 174rule paths ( package-name : requirements * ) 175{ 176 local default-prefix = [ feature.get-values <install-default-prefix> : $(requirements) ] ; 177 # Or some likely defaults if neither is given. 178 if ! $(default-prefix) 179 { 180 if [ os.name ] = NT { default-prefix = C:\\$(package-name) ; } 181 else { default-prefix = /usr/local ; } 182 } 183 default-prefix = [ path.make $(default-prefix) ] ; 184 if ! $(.package-paths.$(default-prefix)) 185 { 186 .package-paths.$(default-prefix) = [ new package-paths $(default-prefix) ] ; 187 } 188 return $(.package-paths.$(default-prefix)) ; 189} 190 191rule install ( name package-name ? : requirements * : binaries * : libraries * : headers * ) 192{ 193 package-name ?= $(name) ; 194 195 # If <install-source-root> is not specified, all headers are installed to 196 # prefix/include, no matter what their relative path is. Sometimes that is 197 # what is needed. 198 local install-source-root = [ property.select <install-source-root> : 199 $(requirements) ] ; 200 install-source-root = $(install-source-root:G=) ; 201 requirements = [ property.change $(requirements) : <install-source-root> ] ; 202 203 local install-header-subdir = [ property.select <install-header-subdir> : 204 $(requirements) ] ; 205 install-header-subdir = /$(install-header-subdir:G=) ; 206 install-header-subdir ?= "" ; 207 requirements = [ property.change $(requirements) : <install-header-subdir> ] 208 ; 209 210 # First, figure out all locations. Use the default if no prefix option 211 # given. 212 local paths = [ paths $(package-name) : $(requirements) ] ; 213 214 # Binaries. 215 local bin-locate = [ $(paths).bindir ] ; 216 217 # Object code libraries. 218 local lib-locate = [ $(paths).libdir ] ; 219 220 # Source header files. 221 local include-locate = [ $(paths).includedir ] ; 222 223 stage.install $(name)-bin : $(binaries) : $(requirements) 224 <location>$(bin-locate) ; 225 alias $(name)-lib : $(name)-lib-shared $(name)-lib-static ; 226 227 # Since the install location of shared libraries differs on universe 228 # and cygwin, use target alternatives to make different targets. 229 # We should have used indirection conditioanl requirements, but it's 230 # awkward to pass bin-locate and lib-locate from there to another rule. 231 alias $(name)-lib-shared : $(name)-lib-shared-universe ; 232 alias $(name)-lib-shared : $(name)-lib-shared-cygwin : <target-os>cygwin ; 233 234 # For shared libraries, we install both explicitly specified one and the 235 # shared libraries that the installed executables depend on. 236 stage.install $(name)-lib-shared-universe : $(binaries) $(libraries) : $(requirements) 237 <location>$(lib-locate) <install-dependencies>on <install-type>SHARED_LIB ; 238 stage.install $(name)-lib-shared-cygwin : $(binaries) $(libraries) : $(requirements) 239 <location>$(bin-locate) <install-dependencies>on <install-type>SHARED_LIB ; 240 241 # For static libraries, we do not care about executable dependencies, since 242 # static libraries are already incorporated into them. 243 stage.install $(name)-lib-static : $(libraries) : $(requirements) 244 <location>$(lib-locate) <install-dependencies>on <install-type>STATIC_LIB ; 245 stage.install $(name)-headers : $(headers) : $(requirements) 246 <location>$(include-locate)$(install-header-subdir) 247 <install-source-root>$(install-source-root) ; 248 alias $(name) : $(name)-bin $(name)-lib $(name)-headers ; 249 250 local c = [ project.current ] ; 251 modules.call-in [ $(c).project-module ] : explicit $(name) $(name)-bin 252 $(name)-lib $(name)-headers $(name)-lib-shared $(name)-lib-static 253 $(name)-lib-shared-universe $(name)-lib-shared-cygwin ; 254} 255 256rule install-data ( target-name : package-name : data * : requirements * ) 257{ 258 package-name ?= target-name ; 259 260 local paths = [ paths $(package-name) : $(requirements) ] ; 261 local datadir = [ $(paths).datarootdir ] ; 262 263 stage.install $(target-name) 264 : $(data) 265 : $(requirements) <location>$(datadir)/$(package-name) 266 ; 267 268 local c = [ project.current ] ; 269 local project-module = [ $(c).project-module ] ; 270 module $(project-module) 271 { 272 explicit $(1) ; 273 } 274} 275