| # Copyright 2003 Dave Abrahams |
| # Copyright 2002, 2003, 2004, 2005 Vladimir Prus |
| # Distributed under the Boost Software License, Version 1.0. |
| # (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) |
| |
| # Implements scanners: objects that compute implicit dependencies for |
| # files, such as includes in C++. |
| # |
| # Scanner has a regular expression used to find dependencies, some |
| # data needed to interpret those dependencies (for example, include |
| # paths), and a code which actually established needed relationship |
| # between actual jam targets. |
| # |
| # Scanner objects are created by actions, when they try to actualize |
| # virtual targets, passed to 'virtual-target.actualize' method and are |
| # then associated with actual targets. It is possible to use |
| # several scanners for a virtual-target. For example, a single source |
| # might be used by to compile actions, with different include paths. |
| # In this case, two different actual targets will be created, each |
| # having scanner of its own. |
| # |
| # Typically, scanners are created from target type and action's |
| # properties, using the rule 'get' in this module. Directly creating |
| # scanners is not recommended, because it might create many equvivalent |
| # but different instances, and lead in unneeded duplication of |
| # actual targets. However, actions can also create scanners in a special |
| # way, instead of relying on just target type. |
| |
| import "class" : new ; |
| import property virtual-target property-set ; |
| import errors : error ; |
| |
| # Base scanner class. |
| class scanner |
| { |
| rule __init__ ( ) |
| { |
| } |
| |
| # Returns a pattern to use for scanning |
| rule pattern ( ) |
| { |
| error "method must be overriden" ; |
| } |
| |
| # Establish necessary relationship between targets, |
| # given actual target beeing scanned, and a list of |
| # pattern matches in that file. |
| rule process ( target : matches * ) |
| { |
| error "method must be overriden" ; |
| } |
| } |
| |
| # Registers a new generator class, specifying a set of |
| # properties relevant to this scanner. Ctor for that class |
| # should have one parameter: list of properties. |
| rule register ( scanner-class : relevant-properties * ) |
| { |
| .registered += $(scanner-class) ; |
| .relevant-properties.$(scanner-class) = $(relevant-properties) ; |
| } |
| |
| # Common scanner class, which can be used when there's only one |
| # kind of includes (unlike C, where "" and <> includes have different |
| # search paths). |
| class common-scanner : scanner |
| { |
| import scanner ; |
| rule __init__ ( includes * ) |
| { |
| scanner.__init__ ; |
| self.includes = $(includes) ; |
| } |
| |
| rule process ( target : matches * : binding ) |
| { |
| local target_path = [ NORMALIZE_PATH $(binding:D) ] ; |
| |
| NOCARE $(matches) ; |
| INCLUDES $(target) : $(matches) ; |
| SEARCH on $(matches) = $(target_path) $(self.includes:G=) ; |
| ISFILE $(matches) ; |
| |
| scanner.propagate $(__name__) : $(matches) : $(target) ; |
| } |
| } |
| |
| |
| # Returns an instance of previously registered scanner, |
| # with the specified properties. |
| rule get ( scanner-class : property-set ) |
| { |
| if ! $(scanner-class) in $(.registered) |
| { |
| error "attempt to get unregisted scanner" ; |
| } |
| |
| local r = $(.rv-cache.$(property-set)) ; |
| if ! $(r) |
| { |
| r = [ property-set.create |
| [ property.select $(.relevant-properties.$(scanner-class)) : |
| [ $(property-set).raw ] ] ] ; |
| .rv-cache.$(property-set) = $(r) ; |
| } |
| |
| if ! $(scanner.$(scanner-class).$(r:J=-)) |
| { |
| scanner.$(scanner-class).$(r:J=-) = [ new $(scanner-class) [ $(r).raw ] ] ; |
| } |
| return $(scanner.$(scanner-class).$(r:J=-)) ; |
| } |
| |
| |
| # Installs the specified scanner on actual target 'target'. |
| rule install ( scanner : target |
| vtarget # virtual target from which 'target' was actualized |
| ) |
| { |
| HDRSCAN on $(target) = [ $(scanner).pattern ] ; |
| SCANNER on $(target) = $(scanner) ; |
| HDRRULE on $(target) = scanner.hdrrule ; |
| |
| # scanner reflects difference in properties affecting |
| # binding of 'target', which will be known when processing |
| # includes for it, will give information on how to |
| # interpret quoted includes. |
| HDRGRIST on $(target) = $(scanner) ; |
| } |
| |
| # Propagate scanner setting from 'including-target' to 'targets'. |
| rule propagate ( scanner : targets * : including-target ) |
| { |
| HDRSCAN on $(targets) = [ on $(including-target) return $(HDRSCAN) ] ; |
| SCANNER on $(targets) = $(scanner) ; |
| HDRRULE on $(targets) = scanner.hdrrule ; |
| HDRGRIST on $(targets) = [ on $(including-target) return $(HDRGRIST) ] ; |
| } |
| |
| |
| rule hdrrule ( target : matches * : binding ) |
| { |
| local scanner = [ on $(target) return $(SCANNER) ] ; |
| $(scanner).process $(target) : $(matches) : $(binding) ; |
| } |
| # hdrrule must be available at global scope so that it can be invoked |
| # by header scanning |
| IMPORT scanner : hdrrule : : scanner.hdrrule ; |
| |
| |
| |
| |