1# Copyright (c) 2010 Vladimir Prus. 2# Copyright (c) 2013 Steven Watanabe 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 8import property-set ; 9import path ; 10import modules ; 11import "class" ; 12import errors ; 13import configure ; 14import project ; 15import virtual-target ; 16import generators ; 17import property ; 18import print ; 19 20project.initialize $(__name__) ; 21.project = [ project.current ] ; 22project ac ; 23 24rule generate-include ( target : sources * : properties * ) 25{ 26 local header = [ property.select <include> : $(properties) ] ; 27 print.output $(target) ; 28 print.text "#include <$(header:G=)>" : true ; 29} 30 31rule generate-main ( target : sources * : properties * ) 32{ 33 print.output $(target) ; 34 print.text "int main() {}" : true ; 35} 36 37rule find-include-path ( properties : header : provided-path ? ) 38{ 39 if $(provided-path) && [ path.exists [ path.root $(header) $(provided-path) ] ] 40 { 41 return $(provided-path) ; 42 } 43 else 44 { 45 local a = [ class.new action : ac.generate-include : [ property-set.create <include>$(header) ] ] ; 46 local cpp = [ class.new file-target $(header).cpp exact : CPP : $(.project) : $(a) ] ; 47 cpp = [ virtual-target.register $(cpp) ] ; 48 local result = [ generators.construct $(.project) $(header) : OBJ : $(properties) : $(cpp) : true ] ; 49 local jam-targets ; 50 for t in $(result[2-]) 51 { 52 jam-targets += [ $(t).actualize ] ; 53 } 54 if [ UPDATE_NOW $(jam-targets) : [ modules.peek configure : .log-fd ] 55 : ignore-minus-n : ignore-minus-q ] 56 { 57 return %default ; 58 } 59 } 60} 61 62rule construct-library ( name : property-set : provided-path ? ) 63{ 64 property-set = [ $(property-set).refine [ property-set.create $(link-opt) ] ] ; 65 local lib-props = [ $(property-set).add-raw <name>$(name) <search>$(provided-path) ] ; 66 return [ generators.construct $(.project) lib-$(name) 67 : SEARCHED_LIB : $(lib-props) : : true ] ; 68} 69 70 71rule find-library ( properties : names + : provided-path ? ) 72{ 73 local result ; 74 if ! $(.main.cpp) 75 { 76 local a = [ class.new action : ac.generate-main : 77 [ property-set.empty ] ] ; 78 .main.cpp = [ virtual-target.register 79 [ class.new file-target main.cpp exact 80 : CPP : $(.project) : $(a) ] ] ; 81 } 82 if [ $(properties).get <link> ] = shared 83 { 84 link-opts = <link>shared <link>static ; 85 } 86 else 87 { 88 link-opts = <link>static <link>shared ; 89 } 90 while $(link-opts) 91 { 92 local names-iter = $(names) ; 93 properties = [ $(properties).refine [ property-set.create $(link-opts[1]) ] ] ; 94 while $(names-iter) 95 { 96 local name = $(names-iter[1]) ; 97 local lib = [ construct-library $(name) : $(properties) : $(provided-path) ] ; 98 local test = [ generators.construct $(.project) $(name) : EXE 99 : [ $(properties).add $(lib[1]) ] : $(.main.cpp) $(lib[2-]) 100 : true ] ; 101 local jam-targets ; 102 for t in $(test[2-]) 103 { 104 jam-targets += [ $(t).actualize ] ; 105 } 106 if [ UPDATE_NOW $(jam-targets) : [ modules.peek configure : .log-fd ] 107 : ignore-minus-n : ignore-minus-q ] 108 { 109 result = $(name) $(link-opts[1]) ; 110 names-iter = ; link-opts = ; # break 111 } 112 names-iter = $(names-iter[2-]) ; 113 } 114 link-opts = $(link-opts[2-]) ; 115 } 116 return $(result) ; 117} 118 119class ac-library : basic-target 120{ 121 import errors ; 122 import indirect ; 123 import virtual-target ; 124 import ac ; 125 import configure ; 126 import config-cache ; 127 128 rule __init__ ( name : project : requirements * : include-path ? : library-path ? : library-name ? ) 129 { 130 basic-target.__init__ $(name) : $(project) : : $(requirements) ; 131 132 reconfigure $(include-path) : $(library-path) : $(library-name) ; 133 } 134 135 rule set-header ( header ) 136 { 137 self.header = $(header) ; 138 } 139 140 rule set-default-names ( names + ) 141 { 142 self.default-names = $(names) ; 143 } 144 145 rule reconfigure ( include-path ? : library-path ? : library-name ? ) 146 { 147 if $(include-path) || $(library-path) || $(library-name) 148 { 149 check-not-configured ; 150 151 self.include-path = $(include-path) ; 152 self.library-path = $(library-path) ; 153 self.library-name = $(library-name) ; 154 } 155 } 156 157 rule set-target ( target ) 158 { 159 check-not-configured ; 160 self.target = $(target) ; 161 } 162 163 rule check-not-configured ( ) 164 { 165 if $(self.include-path) || $(self.library-path) || $(self.library-name) || $(self.target) 166 { 167 errors.user-error [ name ] "is already configured" ; 168 } 169 } 170 171 rule construct ( name : sources * : property-set ) 172 { 173 if $(self.target) 174 { 175 return [ $(self.target).generate $(property-set) ] ; 176 } 177 else 178 { 179 local use-environment ; 180 if ! $(self.library-name) && ! $(self.include-path) && ! $(self.library-path) 181 { 182 use-environment = true ; 183 } 184 local libnames = $(self.library-name) ; 185 if ! $(libnames) && $(use-environment) 186 { 187 libnames = [ modules.peek : $(name:U)_NAME ] ; 188 # Backward compatibility only. 189 libnames ?= [ modules.peek : $(name:U)_BINARY ] ; 190 } 191 libnames ?= $(self.default-names) ; 192 193 local include-path = $(self.include-path) ; 194 if ! $(include-path) && $(use-environment) 195 { 196 include-path = [ modules.peek : $(name:U)_INCLUDE ] ; 197 } 198 199 local library-path = $(self.library-path) ; 200 if ! $(library-path) && $(use-environment) 201 { 202 library-path = [ modules.peek : $(name:U)_LIBRARY_PATH ] ; 203 # Backwards compatibility only 204 library-path ?= [ modules.peek : $(name:U)_LIBPATH ] ; 205 } 206 207 local toolset = [ $(property-set).get <toolset> ] ; 208 local toolset-version-property = "<toolset-$(toolset):version>" ; 209 local relevant = [ property.select <target-os> <toolset> 210 $(toolset-version-property) <link> <address-model> <architecture> : 211 [ $(property-set).raw ] ] ; 212 213 local key = ac-library-$(name)-$(relevant:J=-) ; 214 local lookup = [ config-cache.get $(key) ] ; 215 216 if $(lookup) 217 { 218 if $(lookup) = missing 219 { 220 configure.log-library-search-result $(name) : "no (cached)" ; 221 return [ property-set.empty ] ; 222 } 223 else 224 { 225 local includes = $(lookup[1]) ; 226 if $(includes) = %default 227 { 228 includes = ; 229 } 230 local library = [ ac.construct-library $(lookup[2]) : 231 [ $(property-set).refine [ property-set.create $(lookup[3]) ] ] : $(library-path) ] ; 232 configure.log-library-search-result $(name) : "yes (cached)" ; 233 return [ $(library[1]).add-raw <include>$(includes) ] $(library[2-]) ; 234 } 235 } 236 else 237 { 238 local includes = [ ac.find-include-path $(property-set) : $(self.header) : $(include-path) ] ; 239 local library = [ ac.find-library $(property-set) : $(libnames) : $(library-path) ] ; 240 if $(includes) && $(library) 241 { 242 config-cache.set $(key) : $(includes) $(library) ; 243 if $(includes) = %default 244 { 245 includes = ; 246 } 247 library = [ ac.construct-library $(library[1]) : 248 [ $(property-set).refine [ property-set.create $(library[2]) ] ] : $(library-path) ] ; 249 configure.log-library-search-result $(name) : "yes" ; 250 return [ $(library[1]).add-raw <include>$(includes) ] $(library[2-]) ; 251 } 252 else 253 { 254 config-cache.set $(key) : missing ; 255 configure.log-library-search-result $(name) : "no" ; 256 return [ property-set.empty ] ; 257 } 258 } 259 } 260 } 261} 262 263class check-library-worker 264{ 265 import property-set ; 266 import targets ; 267 import property ; 268 269 rule __init__ ( target : true-properties * : false-properties * ) 270 { 271 self.target = $(target) ; 272 self.true-properties = $(true-properties) ; 273 self.false-properties = $(false-properties) ; 274 } 275 276 rule check ( properties * ) 277 { 278 local choosen ; 279 local t = [ targets.current ] ; 280 local p = [ $(t).project ] ; 281 local ps = [ property-set.create $(properties) ] ; 282 ps = [ $(ps).propagated ] ; 283 local generated = 284 [ targets.generate-from-reference $(self.target) : $(p) : $(ps) ] ; 285 if $(generated[2]) 286 { 287 choosen = $(self.true-properties) ; 288 } 289 else 290 { 291 choosen = $(self.false-properties) ; 292 } 293 return [ property.evaluate-conditionals-in-context $(choosen) : 294 $(properties) ] ; 295 } 296} 297 298rule check-library ( target : true-properties * : false-properties * ) 299{ 300 local instance = [ class.new check-library-worker $(target) : 301 $(true-properties) : $(false-properties) ] ; 302 return <conditional>@$(instance).check ; 303} 304