1# Copyright 2003 Dave Abrahams 2# Copyright 2002, 2003, 2004, 2005 Vladimir Prus 3# Distributed under the Boost Software License, Version 1.0. 4# (See accompanying file LICENSE_1_0.txt or copy at 5# http://www.boost.org/LICENSE_1_0.txt) 6 7# Implements scanners: objects computing implicit dependencies for files, such 8# as includes in C++. 9# 10# A scanner has a regular expression used to find the dependencies, some data 11# needed to interpret those dependencies (e.g., include paths), and code which 12# establishing needed relationships between actual jam targets. 13# 14# Scanner objects are created by actions when they try to actualize virtual 15# targets, passed to the virtual-target.actualize() method and are then 16# associated with actual targets. It is possible to use several scanners for a 17# single virtual-target. For example, a single source file might be compiled 18# twice - each time using a different include path. In this case, two separate 19# actual targets will be created, each having a scanner of its own. 20# 21# Typically, scanners are created from target type and the action's properties, 22# using the rule 'get' in this module. Directly creating scanners is not 23# recommended, as it might create multiple equvivalent but different instances, 24# and lead to unnecessary actual target duplication. However, actions can also 25# create scanners in a special way, instead of relying on just the target type. 26 27import "class" : new ; 28import property ; 29import property-set ; 30import virtual-target ; 31 32# Base scanner class. 33# 34class scanner 35{ 36 rule __init__ ( ) 37 { 38 } 39 40 # Returns a pattern to use for scanning. 41 # 42 rule pattern ( ) 43 { 44 import errors : error : errors.error ; 45 errors.error "method must be overriden" ; 46 } 47 48 # Establish necessary relationship between targets, given an actual target 49 # beeing scanned and a list of pattern matches in that file. 50 # 51 rule process ( target : matches * ) 52 { 53 import errors : error : errors.error ; 54 errors.error "method must be overriden" ; 55 } 56} 57 58 59# Registers a new generator class, specifying a set of properties relevant to 60# this scanner. Constructor for that class should have one parameter: a list of 61# properties. 62# 63rule register ( scanner-class : relevant-properties * ) 64{ 65 .registered += $(scanner-class) ; 66 .relevant-properties.$(scanner-class) = $(relevant-properties) ; 67} 68 69 70# Common scanner class, usable when there is only one kind of includes (unlike 71# C, where "" and <> includes have different search paths). 72# 73class common-scanner : scanner 74{ 75 import scanner ; 76 77 rule __init__ ( includes * ) 78 { 79 scanner.__init__ ; 80 self.includes = $(includes) ; 81 } 82 83 rule process ( target : matches * : binding ) 84 { 85 local target_path = [ NORMALIZE_PATH $(binding:D) ] ; 86 87 NOCARE $(matches) ; 88 INCLUDES $(target) : $(matches) ; 89 SEARCH on $(matches) = $(target_path) $(self.includes:G=) ; 90 ISFILE $(matches) ; 91 92 scanner.propagate $(__name__) : $(matches) : $(target) ; 93 } 94} 95 96 97# Returns an instance of a previously registered scanner, with the specified 98# properties. 99# 100rule get ( scanner-class : property-set ) 101{ 102 if ! $(scanner-class) in $(.registered) 103 { 104 import errors ; 105 errors.error "attempt to get an unregisted scanner" ; 106 } 107 108 local r = $(.rv-cache.$(property-set)) ; 109 if ! $(r) 110 { 111 r = [ property-set.create 112 [ property.select $(.relevant-properties.$(scanner-class)) : 113 [ $(property-set).raw ] ] ] ; 114 .rv-cache.$(property-set) = $(r) ; 115 } 116 117 if ! $(scanner.$(scanner-class).$(r:J=-)) 118 { 119 local s = [ new $(scanner-class) [ $(r).raw ] ] ; 120 scanner.$(scanner-class).$(r:J=-) = $(s) ; 121 } 122 return $(scanner.$(scanner-class).$(r:J=-)) ; 123} 124 125 126# Installs the specified scanner on the actual target 'target'. 127# 128rule install ( scanner : target ) 129{ 130 HDRSCAN on $(target) = [ $(scanner).pattern ] ; 131 SCANNER on $(target) = $(scanner) ; 132 HDRRULE on $(target) = scanner.hdrrule ; 133 134 # Scanner reflects differences in properties affecting binding of 'target', 135 # which will be known when processing includes for it, and give information 136 # on how to interpret different include types (e.g. quoted vs. those in 137 # angle brackets in C files). 138 HDRGRIST on $(target) = $(scanner) ; 139} 140 141 142# Propagate scanner settings from 'including-target' to 'targets'. 143# 144rule propagate ( scanner : targets * : including-target ) 145{ 146 HDRSCAN on $(targets) = [ on $(including-target) return $(HDRSCAN) ] ; 147 SCANNER on $(targets) = $(scanner) ; 148 HDRRULE on $(targets) = scanner.hdrrule ; 149 HDRGRIST on $(targets) = [ on $(including-target) return $(HDRGRIST) ] ; 150} 151 152 153rule hdrrule ( target : matches * : binding ) 154{ 155 local scanner = [ on $(target) return $(SCANNER) ] ; 156 $(scanner).process $(target) : $(matches) : $(binding) ; 157} 158 159 160# hdrrule must be available at global scope so it can be invoked by header 161# scanning. 162# 163IMPORT scanner : hdrrule : : scanner.hdrrule ; 164