| # 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 copy at |
| # http://www.boost.org/LICENSE_1_0.txt) |
| |
| # Implements scanners: objects computing implicit dependencies for files, such |
| # as includes in C++. |
| # |
| # A scanner has a regular expression used to find the dependencies, some data |
| # needed to interpret those dependencies (e.g., include paths), and code which |
| # establishing needed relationships between actual jam targets. |
| # |
| # Scanner objects are created by actions when they try to actualize virtual |
| # targets, passed to the virtual-target.actualize() method and are then |
| # associated with actual targets. It is possible to use several scanners for a |
| # single virtual-target. For example, a single source file might be compiled |
| # twice - each time using a different include path. In this case, two separate |
| # actual targets will be created, each having a scanner of its own. |
| # |
| # Typically, scanners are created from target type and the action's properties, |
| # using the rule 'get' in this module. Directly creating scanners is not |
| # recommended, as it might create multiple equvivalent but different instances, |
| # and lead to unnecessary actual target duplication. However, actions can also |
| # create scanners in a special way, instead of relying on just the target type. |
| |
| import "class" : new ; |
| import property ; |
| import property-set ; |
| import virtual-target ; |
| |
| # Base scanner class. |
| # |
| class scanner |
| { |
| rule __init__ ( ) |
| { |
| } |
| |
| # Returns a pattern to use for scanning. |
| # |
| rule pattern ( ) |
| { |
| import errors : error : errors.error ; |
| errors.error "method must be overriden" ; |
| } |
| |
| # Establish necessary relationship between targets, given an actual target |
| # beeing scanned and a list of pattern matches in that file. |
| # |
| rule process ( target : matches * ) |
| { |
| import errors : error : errors.error ; |
| errors.error "method must be overriden" ; |
| } |
| } |
| |
| |
| # Registers a new generator class, specifying a set of properties relevant to |
| # this scanner. Constructor for that class should have one parameter: a list of |
| # properties. |
| # |
| rule register ( scanner-class : relevant-properties * ) |
| { |
| .registered += $(scanner-class) ; |
| .relevant-properties.$(scanner-class) = $(relevant-properties) ; |
| } |
| |
| |
| # Common scanner class, usable when there is 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 a previously registered scanner, with the specified |
| # properties. |
| # |
| rule get ( scanner-class : property-set ) |
| { |
| if ! $(scanner-class) in $(.registered) |
| { |
| import errors ; |
| errors.error "attempt to get an 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=-)) |
| { |
| local s = [ new $(scanner-class) [ $(r).raw ] ] ; |
| scanner.$(scanner-class).$(r:J=-) = $(s) ; |
| } |
| return $(scanner.$(scanner-class).$(r:J=-)) ; |
| } |
| |
| |
| # Installs the specified scanner on the actual target 'target'. |
| # |
| rule install ( scanner : target ) |
| { |
| HDRSCAN on $(target) = [ $(scanner).pattern ] ; |
| SCANNER on $(target) = $(scanner) ; |
| HDRRULE on $(target) = scanner.hdrrule ; |
| |
| # Scanner reflects differences in properties affecting binding of 'target', |
| # which will be known when processing includes for it, and give information |
| # on how to interpret different include types (e.g. quoted vs. those in |
| # angle brackets in C files). |
| HDRGRIST on $(target) = $(scanner) ; |
| } |
| |
| |
| # Propagate scanner settings 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 it can be invoked by header |
| # scanning. |
| # |
| IMPORT scanner : hdrrule : : scanner.hdrrule ; |