1# Status: ported. 2# Base revision: 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 19from b2.build import targets as targets_ 20 21from b2.manager import get_manager 22from b2.util.sequence import unique 23from b2.util import bjam_signature, value_to_jam, is_iterable 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 assert is_iterable(components) 45 __components.extend(components) 46 47def components_building(components): 48 """Declare that the components specified by the parameters will be build.""" 49 assert is_iterable(components) 50 __built_components.extend(components) 51 52def log_component_configuration(component, message): 53 """Report something about component configuration that the user should better know.""" 54 assert isinstance(component, basestring) 55 assert isinstance(message, basestring) 56 __component_logs.setdefault(component, []).append(message) 57 58def log_check_result(result): 59 assert isinstance(result, basestring) 60 global __announced_checks 61 if not __announced_checks: 62 print "Performing configuration checks" 63 __announced_checks = True 64 65 print result 66 67def log_library_search_result(library, result): 68 assert isinstance(library, basestring) 69 assert isinstance(result, basestring) 70 log_check_result((" - %(library)s : %(result)s" % locals()).rjust(__width)) 71 72 73def print_component_configuration(): 74 75 print "\nComponent configuration:" 76 for c in __components: 77 if c in __built_components: 78 s = "building" 79 else: 80 s = "not building" 81 message = " - %s)" % c 82 message = message.rjust(__width) 83 message += " : " + s 84 for m in __component_logs.get(c, []): 85 print " -" + m 86 print "" 87 88__builds_cache = {} 89 90def builds(metatarget_reference, project, ps, what): 91 # Attempt to build a metatarget named by 'metatarget-reference' 92 # in context of 'project' with properties 'ps'. 93 # Returns non-empty value if build is OK. 94 assert isinstance(metatarget_reference, basestring) 95 assert isinstance(project, targets_.ProjectTarget) 96 assert isinstance(ps, property_set.PropertySet) 97 assert isinstance(what, basestring) 98 99 result = [] 100 101 existing = __builds_cache.get((what, ps), None) 102 if existing is None: 103 104 result = False 105 __builds_cache[(what, ps)] = False 106 107 targets = targets_.generate_from_reference( 108 metatarget_reference, project, ps).targets() 109 jam_targets = [] 110 for t in targets: 111 jam_targets.append(t.actualize()) 112 113 x = (" - %s" % what).rjust(__width) 114 if bjam.call("UPDATE_NOW", jam_targets, str(__log_fd), "ignore-minus-n"): 115 __builds_cache[(what, ps)] = True 116 result = True 117 log_check_result("%s: yes" % x) 118 else: 119 log_check_result("%s: no" % x) 120 121 return result 122 else: 123 return existing 124 125def set_log_file(log_file_name): 126 assert isinstance(log_file_name, basestring) 127 # Called by Boost.Build startup code to specify name of a file 128 # that will receive results of configure checks. This 129 # should never be called by users. 130 global __log_file, __log_fd 131 dirname = os.path.dirname(log_file_name) 132 if not os.path.exists(dirname): 133 os.makedirs(dirname) 134 # Make sure to keep the file around, so that it's not 135 # garbage-collected and closed 136 __log_file = open(log_file_name, "w") 137 __log_fd = __log_file.fileno() 138 139# Frontend rules 140 141class CheckTargetBuildsWorker: 142 143 def __init__(self, target, true_properties, false_properties): 144 self.target = target 145 self.true_properties = property.create_from_strings(true_properties, True) 146 self.false_properties = property.create_from_strings(false_properties, True) 147 148 def check(self, ps): 149 assert isinstance(ps, property_set.PropertySet) 150 # FIXME: this should not be hardcoded. Other checks might 151 # want to consider different set of features as relevant. 152 toolset = ps.get('toolset')[0] 153 toolset_version_property = "<toolset-" + toolset + ":version>" ; 154 relevant = ps.get_properties('target-os') + \ 155 ps.get_properties("toolset") + \ 156 ps.get_properties(toolset_version_property) + \ 157 ps.get_properties("address-model") + \ 158 ps.get_properties("architecture") 159 rps = property_set.create(relevant) 160 t = get_manager().targets().current() 161 p = t.project() 162 if builds(self.target, p, rps, "%s builds" % self.target): 163 choosen = self.true_properties 164 else: 165 choosen = self.false_properties 166 return property.evaluate_conditionals_in_context(choosen, ps) 167 168@bjam_signature((["target"], ["true_properties", "*"], ["false_properties", "*"])) 169def check_target_builds(target, true_properties, false_properties): 170 worker = CheckTargetBuildsWorker(target, true_properties, false_properties) 171 value = value_to_jam(worker.check) 172 return "<conditional>" + value 173 174get_manager().projects().add_rule("check-target-builds", check_target_builds) 175 176 177