1# Status: ported. 2# Base revison: 64488 3# 4# Copyright (c) 2010 Vladimir Prus. 5# 6# Use, modification and distribution is subject to the Boost Software 7# License Version 1.0. (See accompanying file LICENSE_1_0.txt or 8# http://www.boost.org/LICENSE_1_0.txt) 9 10# This module defines function to help with two main tasks: 11# 12# - Discovering build-time configuration for the purposes of adjusting 13# build process. 14# - Reporting what is built, and how it is configured. 15 16import b2.build.property as property 17import b2.build.property_set as property_set 18 19import b2.build.targets 20 21from b2.manager import get_manager 22from b2.util.sequence import unique 23from b2.util import bjam_signature, value_to_jam 24 25import bjam 26import os 27 28__width = 30 29 30def set_width(width): 31 global __width 32 __width = 30 33 34__components = [] 35__built_components = [] 36__component_logs = {} 37__announced_checks = False 38 39__log_file = None 40__log_fd = -1 41 42def register_components(components): 43 """Declare that the components specified by the parameter exist.""" 44 __components.extend(components) 45 46def components_building(components): 47 """Declare that the components specified by the parameters will be build.""" 48 __built_components.extend(components) 49 50def log_component_configuration(component, message): 51 """Report something about component configuration that the user should better know.""" 52 __component_logs.setdefault(component, []).append(message) 53 54def log_check_result(result): 55 global __announced_checks 56 if not __announced_checks: 57 print "Performing configuration checks" 58 __announced_checks = True 59 60 print result 61 62def log_library_search_result(library, result): 63 log_check_result((" - %(library)s : %(result)s" % locals()).rjust(width)) 64 65 66def print_component_configuration(): 67 68 print "\nComponent configuration:" 69 for c in __components: 70 if c in __built_components: 71 s = "building" 72 else: 73 s = "not building" 74 message = " - %s)" % c 75 message = message.rjust(__width) 76 message += " : " + s 77 for m in __component_logs.get(c, []): 78 print " -" + m 79 print "" 80 81__builds_cache = {} 82 83def builds(metatarget_reference, project, ps, what): 84 # Attempt to build a metatarget named by 'metatarget-reference' 85 # in context of 'project' with properties 'ps'. 86 # Returns non-empty value if build is OK. 87 88 result = [] 89 90 existing = __builds_cache.get((what, ps), None) 91 if existing is None: 92 93 result = False 94 __builds_cache[(what, ps)] = False 95 96 targets = b2.build.targets.generate_from_reference( 97 metatarget_reference, project, ps).targets() 98 jam_targets = [] 99 for t in targets: 100 jam_targets.append(t.actualize()) 101 102 x = (" - %s" % what).rjust(__width) 103 if bjam.call("UPDATE_NOW", jam_targets, str(__log_fd), "ignore-minus-n"): 104 __builds_cache[(what, ps)] = True 105 result = True 106 log_check_result("%s: yes" % x) 107 else: 108 log_check_result("%s: no" % x) 109 110 return result 111 else: 112 return existing 113 114def set_log_file(log_file_name): 115 # Called by Boost.Build startup code to specify name of a file 116 # that will receive results of configure checks. This 117 # should never be called by users. 118 global __log_file, __log_fd 119 dirname = os.path.dirname(log_file_name) 120 if not os.path.exists(dirname): 121 os.makedirs(dirname) 122 # Make sure to keep the file around, so that it's not 123 # garbage-collected and closed 124 __log_file = open(log_file_name, "w") 125 __log_fd = __log_file.fileno() 126 127# Frontend rules 128 129class CheckTargetBuildsWorker: 130 131 def __init__(self, target, true_properties, false_properties): 132 self.target = target 133 self.true_properties = property.create_from_strings(true_properties, True) 134 self.false_properties = property.create_from_strings(false_properties, True) 135 136 def check(self, ps): 137 138 # FIXME: this should not be hardcoded. Other checks might 139 # want to consider different set of features as relevant. 140 toolset = ps.get('toolset')[0] 141 toolset_version_property = "<toolset-" + toolset + ":version>" ; 142 relevant = ps.get_properties('target-os') + \ 143 ps.get_properties("toolset") + \ 144 ps.get_properties(toolset_version_property) + \ 145 ps.get_properties("address-model") + \ 146 ps.get_properties("architecture") 147 rps = property_set.create(relevant) 148 t = get_manager().targets().current() 149 p = t.project() 150 if builds(self.target, p, rps, "%s builds" % self.target): 151 choosen = self.true_properties 152 else: 153 choosen = self.false_properties 154 return property.evaluate_conditionals_in_context(choosen, ps) 155 156@bjam_signature((["target"], ["true_properties", "*"], ["false_properties", "*"])) 157def check_target_builds(target, true_properties, false_properties): 158 worker = CheckTargetBuildsWorker(target, true_properties, false_properties) 159 value = value_to_jam(worker.check) 160 return "<conditional>" + value 161 162get_manager().projects().add_rule("check-target-builds", check_target_builds) 163 164 165