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 http://www.boost.org/LICENSE_1_0.txt)
6 # Implements scanners: objects that compute implicit dependencies for
7 # files, such as includes in C++.
9 # Scanner has a regular expression used to find dependencies, some
10 # data needed to interpret those dependencies (for example, include
11 # paths), and a code which actually established needed relationship
12 # between actual jam targets.
14 # Scanner objects are created by actions, when they try to actualize
15 # virtual targets, passed to 'virtual-target.actualize' method and are
16 # then associated with actual targets. It is possible to use
17 # several scanners for a virtual-target. For example, a single source
18 # might be used by to compile actions, with different include paths.
19 # In this case, two different actual targets will be created, each
20 # having scanner of its own.
22 # Typically, scanners are created from target type and action's
23 # properties, using the rule 'get' in this module. Directly creating
24 # scanners is not recommended, because it might create many equvivalent
25 # but different instances, and lead in unneeded duplication of
26 # actual targets. However, actions can also create scanners in a special
27 # way, instead of relying on just target type.
29 import "class" : new ;
30 import property virtual-target property-set ;
31 import errors : error ;
40 # Returns a pattern to use for scanning
43 error "method must be overriden" ;
46 # Establish necessary relationship between targets,
47 # given actual target beeing scanned, and a list of
48 # pattern matches in that file.
49 rule process ( target : matches * )
51 error "method must be overriden" ;
55 # Registers a new generator class, specifying a set of
56 # properties relevant to this scanner. Ctor for that class
57 # should have one parameter: list of properties.
58 rule register ( scanner-class : relevant-properties * )
60 .registered += $(scanner-class) ;
61 .relevant-properties.$(scanner-class) = $(relevant-properties) ;
64 # Common scanner class, which can be used when there's only one
65 # kind of includes (unlike C, where "" and <> includes have different
67 class common-scanner : scanner
70 rule __init__ ( includes * )
73 self.includes = $(includes) ;
76 rule process ( target : matches * : binding )
78 local target_path = [ NORMALIZE_PATH $(binding:D) ] ;
81 INCLUDES $(target) : $(matches) ;
82 SEARCH on $(matches) = $(target_path) $(self.includes:G=) ;
85 scanner.propagate $(__name__) : $(matches) : $(target) ;
90 # Returns an instance of previously registered scanner,
91 # with the specified properties.
92 rule get ( scanner-class : property-set )
94 if ! $(scanner-class) in $(.registered)
96 error "attempt to get unregisted scanner" ;
99 local r = $(.rv-cache.$(property-set)) ;
102 r = [ property-set.create
103 [ property.select $(.relevant-properties.$(scanner-class)) :
104 [ $(property-set).raw ] ] ] ;
105 .rv-cache.$(property-set) = $(r) ;
108 if ! $(scanner.$(scanner-class).$(r:J=-))
110 scanner.$(scanner-class).$(r:J=-) = [ new $(scanner-class) [ $(r).raw ] ] ;
112 return $(scanner.$(scanner-class).$(r:J=-)) ;
116 # Installs the specified scanner on actual target 'target'.
117 rule install ( scanner : target
118 vtarget # virtual target from which 'target' was actualized
121 HDRSCAN on $(target) = [ $(scanner).pattern ] ;
122 SCANNER on $(target) = $(scanner) ;
123 HDRRULE on $(target) = scanner.hdrrule ;
125 # scanner reflects difference in properties affecting
126 # binding of 'target', which will be known when processing
127 # includes for it, will give information on how to
128 # interpret quoted includes.
129 HDRGRIST on $(target) = $(scanner) ;
132 # Propagate scanner setting from 'including-target' to 'targets'.
133 rule propagate ( scanner : targets * : including-target )
135 HDRSCAN on $(targets) = [ on $(including-target) return $(HDRSCAN) ] ;
136 SCANNER on $(targets) = $(scanner) ;
137 HDRRULE on $(targets) = scanner.hdrrule ;
138 HDRGRIST on $(targets) = [ on $(including-target) return $(HDRGRIST) ] ;
142 rule hdrrule ( target : matches * : binding )
144 local scanner = [ on $(target) return $(SCANNER) ] ;
145 $(scanner).process $(target) : $(matches) : $(binding) ;
147 # hdrrule must be available at global scope so that it can be invoked
149 IMPORT scanner : hdrrule : : scanner.hdrrule ;