]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | # Copyright 2003 Dave Abrahams |
2 | # Copyright 2002, 2003, 2004, 2005 Vladimir Prus | |
3 | # Distributed under the Boost Software License, Version 1.0. | |
1e59de90 TL |
4 | # (See accompanying file LICENSE.txt or copy at |
5 | # https://www.bfgroup.xyz/b2/LICENSE.txt) | |
7c673cae FG |
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 | ||
27 | import "class" : new ; | |
28 | import property ; | |
29 | import property-set ; | |
30 | import virtual-target ; | |
31 | ||
32 | # Base scanner class. | |
33 | # | |
34 | class 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 ; | |
92f5a8d4 | 45 | errors.error "method must be overridden" ; |
7c673cae FG |
46 | } |
47 | ||
48 | # Establish necessary relationship between targets, given an actual target | |
92f5a8d4 | 49 | # being scanned and a list of pattern matches in that file. |
7c673cae FG |
50 | # |
51 | rule process ( target : matches * ) | |
52 | { | |
53 | import errors : error : errors.error ; | |
92f5a8d4 | 54 | errors.error "method must be overridden" ; |
7c673cae FG |
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 | # | |
63 | rule 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 | # | |
73 | class 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 | # | |
100 | rule get ( scanner-class : property-set ) | |
101 | { | |
102 | if ! $(scanner-class) in $(.registered) | |
103 | { | |
104 | import errors ; | |
92f5a8d4 | 105 | errors.error "attempt to get an unregistered scanner" ; |
7c673cae FG |
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 | # | |
128 | rule 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 | # | |
144 | rule 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 | ||
153 | rule 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 | # | |
163 | IMPORT scanner : hdrrule : : scanner.hdrrule ; |