]>
Commit | Line | Data |
---|---|---|
7c673cae | 1 | # Copyright (c) 2010 Vladimir Prus. |
b32b8144 | 2 | # Copyright 2017 Rene Rivera. |
7c673cae FG |
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 | # This module defines function to help with two main tasks: | |
9 | # | |
10 | # - Discovering build-time configuration for the purposes of adjusting the build | |
11 | # process. | |
12 | # - Reporting what is built, and how it is configured. | |
13 | ||
14 | import "class" : new ; | |
15 | import common ; | |
92f5a8d4 | 16 | import indirect ; |
7c673cae | 17 | import path ; |
92f5a8d4 | 18 | import project ; |
7c673cae FG |
19 | import property ; |
20 | import property-set ; | |
21 | import targets ; | |
22 | import config-cache ; | |
b32b8144 FG |
23 | import feature ; |
24 | import modules ; | |
11fdf7f2 | 25 | import sequence ; |
b32b8144 | 26 | import utility ; |
11fdf7f2 | 27 | import virtual-target ; |
b32b8144 FG |
28 | |
29 | ||
30 | # The configure feature allows external definition of what features are | |
31 | # relevant for doing configuration builds. One can add additional relevant | |
32 | # features by using: | |
33 | # | |
34 | # import feature ; | |
35 | # import configure ; | |
36 | # feature.compose <configure> : <threading> ; | |
37 | # | |
38 | feature.feature configure : : composite optional ; | |
39 | ||
40 | # This is the initial set of relevant features. Note that subfeature of all | |
41 | # relevant features are also considered relevant. | |
42 | # | |
43 | feature.compose <configure> : | |
44 | <target-os> <toolset> <address-model> <architecture> <cxxstd> ; | |
7c673cae FG |
45 | |
46 | ||
47 | rule log-summary ( ) | |
48 | { | |
49 | } | |
50 | ||
51 | ||
52 | .width = 30 ; | |
53 | ||
54 | rule set-width ( width ) | |
55 | { | |
56 | .width = $(width) ; | |
57 | } | |
58 | ||
59 | ||
60 | # Declare that the components specified by the parameter exist. | |
61 | # | |
62 | rule register-components ( components * ) | |
63 | { | |
64 | .components += $(components) ; | |
65 | } | |
66 | ||
67 | ||
68 | # Declare that the components specified by the parameters will be built. | |
69 | # | |
70 | rule components-building ( components * ) | |
71 | { | |
72 | .built-components += $(components) ; | |
73 | } | |
74 | ||
75 | ||
76 | # Report something about component configuration that the user should better | |
77 | # know. | |
78 | # | |
79 | rule log-component-configuration ( component : message ) | |
80 | { | |
81 | # FIXME: Implement per-property-set logs. | |
82 | .component-logs.$(component) += $(message) ; | |
83 | } | |
84 | ||
85 | ||
86 | rule log-check-result ( result ) | |
87 | { | |
88 | if ! $(.announced-checks) | |
89 | { | |
90 | ECHO "Performing configuration checks\n" ; | |
91 | .announced-checks = 1 ; | |
92 | } | |
93 | ||
94 | ECHO $(result) ; | |
95 | # FIXME: Unfinished code. Nothing seems to set .check-results at the moment. | |
96 | #.check-results += $(result) ; | |
97 | } | |
98 | ||
99 | ||
100 | rule log-library-search-result ( library : result ) | |
101 | { | |
102 | local x = [ PAD " - $(library)" : $(.width) ] ; | |
103 | log-check-result "$(x) : $(result)" ; | |
104 | } | |
105 | ||
106 | ||
107 | rule print-component-configuration ( ) | |
108 | { | |
109 | # FIXME: See what was intended with this initial assignment. | |
110 | # local c = [ sequence.unique $(.components) ] ; | |
111 | ||
112 | ECHO "\nComponent configuration:\n" ; | |
113 | local c ; | |
114 | for c in $(.components) | |
115 | { | |
116 | local s ; | |
117 | if $(c) in $(.built-components) | |
118 | { | |
119 | s = "building" ; | |
120 | } | |
121 | else | |
122 | { | |
123 | s = "not building" ; | |
124 | } | |
125 | ECHO [ PAD " - $(c)" : $(.width) ] ": $(s)" ; | |
126 | for local m in $(.component-logs.$(c)) | |
127 | { | |
128 | ECHO " -" $(m) ; | |
129 | } | |
130 | } | |
131 | ECHO ; | |
132 | } | |
133 | ||
134 | ||
135 | rule print-configure-checks-summary ( ) | |
136 | { | |
137 | # FIXME: The problem with this approach is that the user sees the checks | |
138 | # summary when all checks are done, and has no progress reporting while the | |
139 | # checks are being executed. | |
140 | if $(.check-results) | |
141 | { | |
142 | ECHO "Configuration checks summary\n" ; | |
143 | for local r in $(.check-results) | |
144 | { | |
145 | ECHO $(r) ; | |
146 | } | |
147 | ECHO ; | |
148 | } | |
149 | } | |
150 | ||
11fdf7f2 TL |
151 | if --reconfigure in [ modules.peek : ARGV ] |
152 | { | |
153 | .reconfigure = true ; | |
154 | } | |
155 | ||
156 | # Handle the --reconfigure option | |
157 | rule maybe-force-rebuild ( targets * ) | |
158 | { | |
159 | if $(.reconfigure) | |
160 | { | |
161 | local all-targets ; | |
162 | for local t in $(targets) | |
163 | { | |
164 | all-targets += [ virtual-target.traverse $(t) ] ; | |
165 | } | |
166 | for local t in [ sequence.unique $(all-targets) ] | |
167 | { | |
168 | $(t).always ; | |
169 | } | |
170 | } | |
171 | } | |
172 | ||
7c673cae FG |
173 | # Attempts to build a set of virtual targets |
174 | rule try-build ( targets * : ps : what : retry ? ) | |
175 | { | |
176 | local cache-name = $(what) [ $(ps).raw ] ; | |
177 | cache-name = $(cache-name:J=-) ; | |
178 | local value = [ config-cache.get $(cache-name) ] ; | |
179 | ||
180 | local result ; | |
181 | local jam-targets ; | |
182 | ||
11fdf7f2 TL |
183 | maybe-force-rebuild $(targets) ; |
184 | ||
7c673cae FG |
185 | for local t in $(targets) |
186 | { | |
187 | jam-targets += [ $(t).actualize ] ; | |
188 | } | |
189 | ||
190 | if $(value) | |
191 | { | |
192 | local x = [ PAD " - $(what)" : $(.width) ] ; | |
193 | if $(value) = true | |
194 | { | |
195 | .$(what)-supported.$(ps) = yes ; | |
196 | result = true ; | |
197 | log-check-result "$(x) : yes (cached)" ; | |
198 | } | |
199 | else | |
200 | { | |
201 | log-check-result "$(x) : no (cached)" ; | |
202 | } | |
203 | } | |
204 | else if ! UPDATE_NOW in [ RULENAMES ] | |
205 | { | |
92f5a8d4 | 206 | # Cannot determine. Assume existence. |
7c673cae FG |
207 | } |
208 | else | |
209 | { | |
210 | local x = [ PAD " - $(what)" : $(.width) ] ; | |
211 | if [ UPDATE_NOW $(jam-targets) : | |
212 | $(.log-fd) : ignore-minus-n : ignore-minus-q ] | |
213 | { | |
214 | .$(what)-supported.$(ps) = yes ; | |
215 | result = true ; | |
216 | log-check-result "$(x) : yes" ; | |
217 | } | |
218 | else | |
219 | { | |
220 | log-check-result "$(x) : no" ; | |
221 | } | |
222 | } | |
223 | if ! $(value) | |
224 | { | |
225 | if $(result) | |
226 | { | |
227 | config-cache.set $(cache-name) : true ; | |
228 | } | |
229 | else | |
230 | { | |
231 | config-cache.set $(cache-name) : false ; | |
232 | } | |
233 | } | |
234 | return $(result) ; | |
235 | } | |
236 | ||
11fdf7f2 TL |
237 | # Attempts to build several sets of virtual targets. Returns the |
238 | # the index of the first set that builds. | |
239 | rule try-find-build ( ps : what : * ) | |
240 | { | |
241 | local args = 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ; | |
242 | # The outer layer only needs to check $(what), but we | |
243 | # also need to check the individual elements, in case | |
244 | # the set of targets has changed since the last build. | |
245 | local cache-name = $(what) $($(args)[1]) [ $(ps).raw ] ; | |
246 | cache-name = $(cache-name:J=-) ; | |
247 | local value = [ config-cache.get $(cache-name) ] ; | |
248 | ||
249 | local result ; | |
250 | local jam-targets ; | |
251 | ||
252 | maybe-force-rebuild $($(args)[2-]) ; | |
253 | ||
254 | # Make sure that the targets are always actualized, | |
255 | # even if the result is cached. This is needed to | |
256 | # allow clean-all to find them and also to avoid | |
257 | # unintentional behavior changes. | |
258 | for local t in $($(args)[2-]) | |
259 | { | |
260 | $(t).actualize ; | |
261 | } | |
262 | ||
263 | if $(value) | |
264 | { | |
265 | local none = none ; # What to show when the argument | |
266 | local name = $(value) ; | |
267 | if $(name) != none | |
268 | { | |
269 | name = [ CALC $(name) + 2 ] ; | |
270 | } | |
271 | local x = [ PAD " - $(what)" : $(.width) ] ; | |
272 | local y = [ PAD $($(name)[1]) : 3 ] ; | |
273 | result = $(value) ; | |
274 | log-check-result "$(x) : $(y) (cached)" ; | |
275 | } | |
276 | else | |
277 | { | |
278 | local x = [ PAD " - $(what)" : $(.width) ] ; | |
279 | for local i in $(args) | |
280 | { | |
281 | if ! $($(i)[1]) | |
282 | { | |
283 | break ; | |
284 | } | |
285 | local jam-targets ; | |
286 | for local t in $($(i)[2-]) | |
287 | { | |
288 | jam-targets += [ $(t).actualize ] ; | |
289 | } | |
290 | if [ UPDATE_NOW $(jam-targets) : | |
291 | $(.log-fd) : ignore-minus-n : ignore-minus-q ] | |
292 | { | |
293 | result = [ CALC $(i) - 2 ] ; | |
294 | log-check-result "$(x) : $($(i)[1])" ; | |
295 | break ; | |
296 | } | |
297 | } | |
298 | if ! $(result) | |
299 | { | |
300 | log-check-result "$(x) : none" ; | |
301 | result = none ; | |
302 | } | |
303 | } | |
304 | if ! $(value) | |
305 | { | |
306 | if $(result) | |
307 | { | |
308 | config-cache.set $(cache-name) : $(result) ; | |
309 | } | |
310 | else | |
311 | { | |
312 | config-cache.set $(cache-name) : $(result) ; | |
313 | } | |
314 | } | |
315 | if $(result) != none | |
316 | { | |
317 | return $(result) ; | |
318 | } | |
319 | } | |
320 | ||
7c673cae FG |
321 | # Attempt to build a metatarget named by 'metatarget-reference' |
322 | # in context of 'project' with properties 'ps'. | |
323 | # Returns non-empty value if build is OK. | |
324 | rule builds-raw ( metatarget-reference : project : ps : what : retry ? ) | |
325 | { | |
326 | local result ; | |
327 | ||
328 | if ! $(retry) && ! $(.$(what)-tested.$(ps)) | |
329 | { | |
330 | .$(what)-tested.$(ps) = true ; | |
331 | ||
332 | local targets = [ targets.generate-from-reference | |
333 | $(metatarget-reference) : $(project) : $(ps) ] ; | |
334 | ||
335 | result = [ try-build $(targets[2-]) : $(ps) : $(what) : $(retry) ] ; | |
336 | .$(what)-supported.$(ps) = $(result) ; | |
337 | ||
338 | return $(result) ; | |
339 | ||
340 | } | |
341 | else | |
342 | { | |
343 | return $(.$(what)-supported.$(ps)) ; | |
344 | } | |
345 | } | |
346 | ||
11fdf7f2 TL |
347 | # Attempt to build a metatarget named by 'metatarget-reference' |
348 | # in context of 'project' with properties 'ps'. | |
349 | # Returns the 1-based index of the first target | |
350 | # that builds. | |
351 | rule find-builds-raw ( project : ps : what : * ) | |
352 | { | |
353 | local result ; | |
354 | local args = 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ; | |
355 | ||
356 | if ! $(.$(what)-tested.$(ps)) | |
357 | { | |
358 | .$(what)-tested.$(ps) = true ; | |
359 | local targets.$(i) what.$(i) ; | |
360 | for local i in $(args) | |
361 | { | |
362 | if ! $($(i)) | |
363 | { | |
364 | break ; | |
365 | } | |
366 | targets.$(i) = [ targets.generate-from-reference | |
367 | $($(i)[1]) : $(project) : $(ps) ] ; | |
368 | # ignore usage requirements | |
369 | targets.$(i) = $(targets.$(i)[2-]) ; | |
370 | if $($(i)[2]) | |
371 | { | |
372 | what.$(i) = $($(i)[2]) ; | |
373 | } | |
374 | else | |
375 | { | |
376 | local t = [ targets.resolve-reference | |
377 | $($(i)[1]) : $(project) ] ; | |
378 | what.$(i) = [ $(t[1]).name ] ; | |
379 | } | |
380 | } | |
381 | ||
382 | result = [ try-find-build $(ps) : $(what) | |
383 | : $(what.4) $(targets.4) | |
384 | : $(what.5) $(targets.5) | |
385 | : $(what.6) $(targets.6) | |
386 | : $(what.7) $(targets.7) | |
387 | : $(what.8) $(targets.8) | |
388 | : $(what.9) $(targets.9) | |
389 | : $(what.10) $(targets.10) | |
390 | : $(what.11) $(targets.11) | |
391 | : $(what.12) $(targets.12) | |
392 | : $(what.13) $(targets.13) | |
393 | : $(what.14) $(targets.14) | |
394 | : $(what.15) $(targets.15) | |
395 | : $(what.16) $(targets.16) | |
396 | : $(what.17) $(targets.17) | |
397 | : $(what.18) $(targets.18) | |
398 | : $(what.19) $(targets.19) ] ; | |
399 | .$(what)-result.$(ps) = $(result) ; | |
400 | ||
401 | return $(result) ; | |
402 | } | |
403 | else | |
404 | { | |
405 | return $(.$(what)-result.$(ps)) ; | |
406 | } | |
407 | } | |
408 | ||
409 | rule get-relevant-features ( ) | |
b32b8144 FG |
410 | { |
411 | local relevant = [ feature.expand <configure> ] ; | |
412 | local result = ; | |
413 | for local f in $(relevant) | |
414 | { | |
415 | if $(f) != <configure> | |
416 | { | |
417 | local sub = [ modules.peek feature : $(f).subfeatures ] ; | |
418 | local name = [ utility.ungrist $(f) ] ; | |
419 | result += $(f) <$(name)-$(sub)> ; | |
420 | } | |
421 | } | |
422 | return $(result) ; | |
423 | } | |
424 | ||
7c673cae FG |
425 | rule builds ( metatarget-reference : properties * : what ? : retry ? ) |
426 | { | |
b32b8144 FG |
427 | local toolset-subfeatures = [ modules.peek feature : <toolset>.subfeatures ] ; |
428 | toolset-subfeatures = <toolset-$(toolset-subfeatures)> ; | |
7c673cae FG |
429 | # FIXME: This should not be hardcoded. Other checks might want to consider a |
430 | # different set of features as relevant. | |
b32b8144 | 431 | local relevant = [ property.select [ get-relevant-features ] : $(properties) ] ; |
7c673cae FG |
432 | local ps = [ property-set.create $(relevant) ] ; |
433 | local t = [ targets.current ] ; | |
434 | local p = [ $(t).project ] ; | |
435 | ||
436 | if ! $(what) | |
437 | { | |
438 | local resolved = [ targets.resolve-reference $(metatarget-reference) : $(p) ] ; | |
439 | local name = [ $(resolved[1]).name ] ; | |
440 | what = "$(name) builds" ; | |
441 | } | |
442 | ||
443 | return [ builds-raw $(metatarget-reference) : $(p) : $(ps) : $(what) : | |
444 | $(retry) ] ; | |
445 | } | |
446 | ||
11fdf7f2 TL |
447 | rule find-builds ( what : properties * : * ) |
448 | { | |
449 | local relevant = [ property.select [ get-relevant-features ] : $(properties) ] ; | |
450 | local ps = [ property-set.create $(relevant) ] ; | |
451 | local t = [ targets.current ] ; | |
452 | local p = [ $(t).project ] ; | |
453 | ||
454 | return [ find-builds-raw $(p) : $(ps) : $(what) : | |
455 | $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) : | |
456 | $(10) : $(11) : $(12) : $(13) : $(14) : $(15) : | |
457 | $(16) : $(17) : $(18) : $(19) ] ; | |
458 | } | |
459 | ||
7c673cae FG |
460 | |
461 | # Called by Boost.Build startup code to specify the file to receive the | |
462 | # configuration check results. Should never be called by user code. | |
463 | # | |
464 | rule set-log-file ( log-file ) | |
465 | { | |
466 | path.makedirs [ path.parent $(log-file) ] ; | |
11fdf7f2 TL |
467 | .log-fd = [ FILE_OPEN [ path.native $(log-file) ] : "w" ] ; |
468 | if ! $(.log-fd) | |
469 | { | |
470 | ECHO "warning:" failed to open log file $(log-file) for writing ; | |
471 | } | |
7c673cae FG |
472 | } |
473 | ||
474 | ||
475 | # Frontend rules | |
476 | ||
477 | class check-target-builds-worker | |
478 | { | |
479 | import configure ; | |
480 | import property-set ; | |
481 | import targets ; | |
92f5a8d4 | 482 | import project ; |
7c673cae FG |
483 | import property ; |
484 | ||
485 | rule __init__ ( target message ? : true-properties * : false-properties * ) | |
486 | { | |
92f5a8d4 | 487 | local project = [ project.current ] ; |
7c673cae FG |
488 | self.target = $(target) ; |
489 | self.message = $(message) ; | |
92f5a8d4 TL |
490 | self.true-properties = |
491 | [ configure.translate-properties $(true-properties) : $(project) ] ; | |
492 | self.false-properties = | |
493 | [ configure.translate-properties $(false-properties) : $(project) ] ; | |
7c673cae FG |
494 | } |
495 | ||
496 | rule check ( properties * ) | |
497 | { | |
498 | local choosen ; | |
499 | if [ configure.builds $(self.target) : $(properties) : $(self.message) ] | |
500 | { | |
501 | choosen = $(self.true-properties) ; | |
502 | } | |
503 | else | |
504 | { | |
505 | choosen = $(self.false-properties) ; | |
506 | } | |
507 | return [ property.evaluate-conditionals-in-context $(choosen) : | |
508 | $(properties) ] ; | |
509 | } | |
510 | } | |
511 | ||
11fdf7f2 TL |
512 | class configure-choose-worker |
513 | { | |
514 | import configure ; | |
515 | import property ; | |
92f5a8d4 | 516 | import project ; |
11fdf7f2 TL |
517 | rule __init__ ( message : * ) |
518 | { | |
92f5a8d4 | 519 | local project = [ project.current ] ; |
11fdf7f2 TL |
520 | self.message = $(message) ; |
521 | for i in 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | |
522 | { | |
523 | local name = [ CALC $(i) - 1 ] ; | |
524 | self.targets.$(name) = $($(i)[1]) ; | |
525 | if ! $($(i)[2]:G) # Check whether the second argument is a property | |
526 | { | |
527 | self.what.$(name) = $($(i)[2]) ; | |
528 | self.props.$(name) = $($(i)[3-]) ; | |
529 | } | |
530 | else | |
531 | { | |
532 | self.props.$(name) = $($(i)[2-]) ; | |
533 | } | |
92f5a8d4 TL |
534 | self.props.$(name) = [ configure.translate-properties |
535 | $(self.props.$(name)) : $(project) ] ; | |
11fdf7f2 TL |
536 | } |
537 | } | |
538 | rule all-properties ( ) | |
539 | { | |
540 | local i = 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ; | |
541 | return $(self.props.$(i)) ; | |
542 | } | |
543 | rule check ( properties * ) | |
544 | { | |
545 | local i = [ configure.find-builds $(self.message) : $(properties) | |
546 | : $(self.targets.1) $(self.what.1) | |
547 | : $(self.targets.2) $(self.what.2) | |
548 | : $(self.targets.3) $(self.what.3) | |
549 | : $(self.targets.4) $(self.what.4) | |
550 | : $(self.targets.5) $(self.what.5) | |
551 | : $(self.targets.6) $(self.what.6) | |
552 | : $(self.targets.7) $(self.what.7) | |
553 | : $(self.targets.8) $(self.what.8) | |
554 | : $(self.targets.9) $(self.what.9) | |
555 | : $(self.targets.10) $(self.what.10) | |
556 | : $(self.targets.11) $(self.what.11) | |
557 | : $(self.targets.12) $(self.what.12) | |
558 | : $(self.targets.13) $(self.what.13) | |
559 | : $(self.targets.14) $(self.what.14) | |
560 | : $(self.targets.15) $(self.what.15) | |
561 | : $(self.targets.16) $(self.what.16) | |
562 | : $(self.targets.17) $(self.what.17) | |
563 | : $(self.targets.18) $(self.what.18) | |
564 | : $(self.targets.19) $(self.what.19) ] ; | |
565 | if $(self.props.$(i)) | |
566 | { | |
567 | return [ property.evaluate-conditionals-in-context $(self.props.$(i)) : $(properties) ] ; | |
568 | } | |
569 | } | |
570 | } | |
571 | ||
92f5a8d4 TL |
572 | rule translate-properties ( properties * : project ? ) |
573 | { | |
574 | if $(project) && [ $(project).location ] | |
575 | { | |
576 | local location = [ $(project).location ] ; | |
577 | local m = [ $(project).project-module ] ; | |
578 | local project-id = [ project.attribute $(m) id ] ; | |
579 | project-id ?= [ path.root $(location) [ path.pwd ] ] ; | |
580 | return [ property.translate $(properties) | |
581 | : $(project-id) : $(location) : $(m) ] ; | |
582 | } | |
583 | else | |
584 | { | |
585 | return $(properties) ; | |
586 | } | |
587 | } | |
7c673cae FG |
588 | |
589 | rule check-target-builds ( target message ? : true-properties * : | |
590 | false-properties * ) | |
591 | { | |
592 | local instance = [ new check-target-builds-worker $(target) $(message) : | |
593 | $(true-properties) : $(false-properties) ] ; | |
92f5a8d4 TL |
594 | local rulename = [ indirect.make check : $(instance) ] ; |
595 | return <conditional>@$(rulename) | |
11fdf7f2 TL |
596 | [ property.evaluate-conditional-relevance |
597 | $(true-properties) $(false-properties) | |
598 | : [ configure.get-relevant-features ] ] ; | |
599 | } | |
600 | ||
601 | # Usage: | |
602 | # [ configure.choose "architecture" | |
603 | # : /config//x86 x86 <architecture>x86 | |
604 | # : /config//mips mips <architecture>mips | |
605 | # ] | |
606 | rule choose ( message : * ) | |
607 | { | |
608 | local instance = [ new configure-choose-worker $(message) | |
609 | : $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) | |
610 | : $(10) : $(11) : $(12) : $(13) : $(14) : $(15) : $(16) | |
611 | : $(17) : $(18) : $(19) ] ; | |
92f5a8d4 TL |
612 | local rulename = [ indirect.make check : $(instance) ] ; |
613 | return <conditional>@$(rulename) | |
11fdf7f2 TL |
614 | [ property.evaluate-conditional-relevance |
615 | [ $(instance).all-properties ] | |
616 | : [ configure.get-relevant-features ] ] ; | |
7c673cae FG |
617 | } |
618 | ||
619 | ||
620 | IMPORT $(__name__) : check-target-builds : : check-target-builds ; |