1# Copyright Rene Rivera 2015 2# Distributed under the Boost Software License, Version 1.0. 3# (See accompanying file LICENSE_1_0.txt or copy at 4# http://www.boost.org/LICENSE_1_0.txt) 5 6import path ; 7import project ; 8import modules ; 9import regex ; 10import type ; 11 12# Add a location, i.e. directory, where to search for libraries. 13# The optional 'prefix' indicates which rooted-prefixes the new 14# search dir applies to. The prefix defaults to '/'. 15rule add-location ( dir prefix ? : base-dir ? ) 16{ 17 process-args ; 18 19 prefix ?= "/" ; 20 21 # Dir path of caller to base paths from. 22 caller-module ?= [ CALLER_MODULE ] ; 23 local caller-dir = [ modules.peek $(caller-module) : __file__ ] ; 24 caller-dir = $(caller-dir:D) ; 25 26 base-dir ?= $(caller-dir) ; 27 28 .search-path-prefix += $(prefix) ; 29 .search-path.$(prefix) += [ path.root [ path.root $(dir) $(base-dir) ] [ path.pwd ] ] ; 30} 31 32# Declares additional definitions of a modular library target external 33# to the modular library build itself. This makes it possible to externally 34# define modular libraries without modifying the library. The passed in 35# values are added on demand when the named library is first declared. 36rule external ( 37 name : sources * : requirements * : default-build * : 38 usage-requirements * ) 39{ 40 .external.($(name)).sources = $(sources) ; 41 .external.($(name)).requirements = $(requirements) ; 42 .external.($(name)).default-build = $(default-build) ; 43 .external.($(name)).usage-requirements = $(usage-requirements) ; 44} 45 46# Find, and declare, any modular libraries referenced in the target-refs. 47# This will both load the modular libraries, and declare/manufacture 48# the modular libraries as needed. 49rule find ( target-refs + ) 50{ 51 process-args ; 52 53 local caller-mod = [ CALLER_MODULE ] ; 54 local caller-dir = [ modules.peek $(caller-mod) : __file__ ] ; 55 caller-dir = $(caller-dir:D) ; 56 caller-dir = [ path.root $(caller-dir) [ path.pwd ] ] ; 57 58 local result-refs ; 59 for local target-ref in $(target-refs) 60 { 61 result-refs += [ resolve-reference $(target-ref) 62 : $(caller-mod) $(caller-dir) ] ; 63 } 64 65 return $(result-refs) ; 66} 67 68############################################################################## 69 70local rule resolve-reference ( target-ref : caller-mod caller-dir ? ) 71{ 72 # ECHO %%% modular.resolve-target-ref $(target-ref) :: $(caller-mod) $(caller-dir) ; 73 if ! $(caller-dir) 74 { 75 caller-dir = [ modules.peek $(caller-mod) : __file__ ] ; 76 caller-dir = $(caller-dir:D) ; 77 caller-dir = [ path.root $(caller-dir) [ path.pwd ] ] ; 78 } 79 local result-ref = $(target-ref) ; 80 local ref = [ MATCH ^(.*)//.* : $(target-ref:G=) ] ; 81 # if ! ( $(ref) in $(.target-refs) ) 82 { 83 # .target-refs += $(ref) ; 84 local search-prefix ; 85 local search-sub ; 86 for local prefix in $(.search-path-prefix) 87 { 88 if ! $(search-prefix) 89 { 90 local search-match = [ MATCH ^($(prefix))/(.*)$ : $(ref) ] ; 91 search-prefix = $(search-match[1]) ; 92 search-sub = $(search-match[2]) ; 93 } 94 } 95 96 if $(search-prefix) 97 { 98 local found = [ path.glob $(.search-path.$(search-prefix)) : $(search-sub) ] ; 99 found = $(found[1]) ; 100 if $(found) 101 { 102 local lib-ref = [ regex.split $(search-sub) / ] ; 103 lib-ref = $(search-prefix)/$(lib-ref[1]) ; 104 local lib-path = [ path.relative-to $(caller-dir) $(found) ] ; 105 define-library $(lib-ref) $(caller-mod) : $(lib-path) ; 106 } 107 } 108 } 109 return $(result-ref) ; 110} 111 112local rule define-library ( name caller-module ? : root ) 113{ 114 # ECHO ~~~ modular.library $(name) $(caller-module) :: $(root) :: $(depends) ; 115 116 process-args ; 117 118 # Dir path of caller to base paths from. 119 caller-module ?= [ CALLER_MODULE ] ; 120 local caller-dir = [ modules.peek $(caller-module) : __file__ ] ; 121 caller-dir = $(caller-dir:D) ; 122 123 # Find the various parts of the library. 124 local lib-dir = [ path.root [ path.root $(root) $(caller-dir) ] [ path.pwd ] ] ; 125 local lib-contents = [ path.glob $(lib-dir) : "include" "build" ] ; 126 lib-contents = $(lib-contents:D=) ; 127 128 # "include" dir for library.. 129 local include-dir ; 130 if "include" in $(lib-contents) 131 { 132 include-dir = $(root)/include ; 133 } 134 135 # If it has a build dir, i.e. it has targets to build, 136 # we root the project at the build dir to make it easy 137 # to refer to the build targets. This mirrors the regular 138 # Boost organization of the project aliases. 139 if "build" in $(lib-contents) 140 { 141 root = $(root)/build ; 142 build-dir = "." ; 143 } 144 145 # Shadow target declarations so that we can alter build targets 146 # to work in the standalone modular structure. 147 local lib-location = [ path.root [ path.make $(root) ] $(caller-dir) ] ; 148 local lib-module-name = [ project.module-name $(lib-location) ] ; 149 local modular-rules = [ RULENAMES modular-rules ] ; 150 IMPORT modular-rules : $(modular-rules) : $(lib-module-name) : $(modular-rules) ; 151 152 # Load/create/declare library project. 153 local lib-module = [ project.find $(root) : $(caller-dir) ] ; 154 if ! $(lib-module) 155 { 156 # If the find was unable to load the project we synthesize it. 157 lib-module = [ project.load $(lib-location) : synthesize ] ; 158 } 159 local lib-target = [ project.target $(lib-module) ] ; 160 if ! [ modules.peek $(lib-module) : __library__ ] 161 { 162 modules.poke $(lib-module) : __library__ : $(name) ; 163 for local type in [ modules.peek type : .types ] 164 { 165 main-rule-name = [ type.type-to-rule-name $(type) ] ; 166 IMPORT modular-rules : main-target-rule : $(lib-module-name) : $(main-rule-name) ; 167 } 168 } 169 170 # Declare project alternate ID. 171 modules.call-in $(caller-module) : use-project $(name) : $(root) ; 172 173 # Create a "library" target that has basic usage info if needed. 174 if ! [ $(lib-target).has-alternative-for-target library ] 175 { 176 include-dir = [ path.relative-to $(root) $(include-dir) ] ; 177 178 project.push-current $(lib-target) ; 179 180 # Declare the library alias. 181 modules.call-in $(lib-module) : library 182 : # Sources 183 : # Requirements 184 : # Default Build 185 : # Usage Requirements 186 <include>$(include-dir) 187 ; 188 189 project.pop-current ; 190 } 191} 192 193local rule process-args ( ) 194{ 195 if ! $(.did-process-args) 196 { 197 .did-process-args = yes ; 198 local argv = [ modules.peek : ARGV ] ; 199 local dirs = [ MATCH ^--modular-search-dir=(.*)$ : $(argv) ] ; 200 for local dir in $(dirs) 201 { 202 add-location $(dir) : [ path.pwd ] ; 203 } 204 } 205} 206 207rule apply-external ( 208 mod : field : values * ) 209{ 210 local result ; 211 local name = [ modules.peek $(mod) : __library__ ] ; 212 values += $(.external.($(name)).$(field)) ; 213 for local value in $(values) 214 { 215 result += [ resolve-reference $(value) : $(mod) ] ; 216 } 217 return $(result) ; 218} 219 220module modular-rules 221{ 222 import type ; 223 import targets ; 224 import builtin ; 225 import alias ; 226 227 # Avoids any form of installation for Boost modules. 228 rule boost-install ( libraries * ) { } 229 230 # Generic typed target rule to pre-process main target 231 # declarations to make them work within the standalone 232 # modular structure. 233 rule main-target-rule ( 234 name : sources * : requirements * : default-build * : 235 usage-requirements * ) 236 { 237 local mod = [ CALLER_MODULE ] ; 238 239 # ECHO @@@ [[$(mod)]] modular-rules.main-target-rule $(name) :: $(sources) :: $(requirements) :: $(default-build) :: $(usage-requirements) ; 240 241 # First discover the required target type based on the exact alias used to 242 # invoke this rule. 243 local bt = [ BACKTRACE 1 ] ; 244 local rulename = $(bt[4]) ; 245 local target-type = [ type.type-from-rule-name $(rulename) ] ; 246 return [ targets.create-typed-target $(target-type) : [ project.current ] : 247 $(name) : $(sources) : $(requirements) : $(default-build) : 248 $(usage-requirements) ] ; 249 } 250 251 rule lib ( names + : sources * : requirements * : default-build * : 252 usage-requirements * ) 253 { 254 local mod = [ CALLER_MODULE ] ; 255 requirements += <use>library ; 256 usage-requirements += <use>library ; 257 258 # ECHO @@@ [[$(mod)]] modular-rules.lib $(names) :: $(sources) :: $(requirements) :: $(default-build) :: $(usage-requirements) ; 259 return [ builtin.lib $(names) : $(sources) : $(requirements) : $(default-build) : $(usage-requirements) ] ; 260 } 261 262 rule alias ( name : sources * : requirements * : default-build * : 263 usage-requirements * ) 264 { 265 local mod = [ CALLER_MODULE ] ; 266 267 # ECHO @@@ [[$(mod)]] modular-rules.alias $(name) :: $(sources) :: $(requirements) :: $(default-build) :: $(usage-requirements) ; 268 return [ alias.alias $(name) : $(sources) : $(requirements) : $(default-build) : $(usage-requirements) ] ; 269 } 270 271 rule library ( name ? : sources * : requirements * : default-build * : 272 usage-requirements * ) 273 { 274 import modular ; 275 276 local mod = [ CALLER_MODULE ] ; 277 sources = [ modular.apply-external $(mod) : sources : $(sources) ] ; 278 requirements = [ modular.apply-external $(mod) : requirements : $(requirements) ] ; 279 default-build = [ modular.apply-external $(mod) : default-build : $(default-build) ] ; 280 usage-requirements = [ modular.apply-external $(mod) : usage-requirements : $(usage-requirements) ] ; 281 282 name ?= library ; 283 284 # ECHO @@@ [[$(mod)]] modular-rules.library $(name) :: $(sources) :: $(requirements) :: $(default-build) :: $(usage-requirements) ; 285 return [ alias.alias $(name) : $(sources) : $(requirements) : $(default-build) : $(usage-requirements) ] ; 286 } 287} 288 289