]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/tools/build/src/build/scanner.py
import new upstream nautilus stable release 14.2.8
[ceph.git] / ceph / src / boost / tools / build / src / build / scanner.py
CommitLineData
7c673cae
FG
1# Status: ported.
2# Base revision: 45462
3#
4# Copyright 2003 Dave Abrahams
5# Copyright 2002, 2003, 2004, 2005 Vladimir Prus
6# Distributed under the Boost Software License, Version 1.0.
7# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
8
9# Implements scanners: objects that compute implicit dependencies for
10# files, such as includes in C++.
11#
12# Scanner has a regular expression used to find dependencies, some
13# data needed to interpret those dependencies (for example, include
14# paths), and a code which actually established needed relationship
15# between actual jam targets.
16#
17# Scanner objects are created by actions, when they try to actualize
18# virtual targets, passed to 'virtual-target.actualize' method and are
19# then associated with actual targets. It is possible to use
20# several scanners for a virtual-target. For example, a single source
21# might be used by to compile actions, with different include paths.
22# In this case, two different actual targets will be created, each
23# having scanner of its own.
24#
25# Typically, scanners are created from target type and action's
26# properties, using the rule 'get' in this module. Directly creating
27# scanners is not recommended, because it might create many equvivalent
28# but different instances, and lead in unneeded duplication of
29# actual targets. However, actions can also create scanners in a special
30# way, instead of relying on just target type.
31import property
32import bjam
33import os
34from b2.manager import get_manager
35from b2.util import is_iterable_typed
36
37
38def reset ():
39 """ Clear the module state. This is mainly for testing purposes.
40 """
41 global __scanners, __rv_cache, __scanner_cache
42
43 # Maps registered scanner classes to relevant properties
44 __scanners = {}
45
46 # A cache of scanners.
47 # The key is: class_name.properties_tag, where properties_tag is the concatenation
48 # of all relevant properties, separated by '-'
49 __scanner_cache = {}
50
51reset ()
52
53
54def register(scanner_class, relevant_properties):
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 """
59 assert issubclass(scanner_class, Scanner)
60 assert isinstance(relevant_properties, basestring)
61 __scanners[str(scanner_class)] = relevant_properties
62
63def registered(scanner_class):
64 """ Returns true iff a scanner of that class is registered
65 """
66 return str(scanner_class) in __scanners
67
68def get(scanner_class, properties):
69 """ Returns an instance of previously registered scanner
70 with the specified properties.
71 """
72 assert issubclass(scanner_class, Scanner)
73 assert is_iterable_typed(properties, basestring)
74 scanner_name = str(scanner_class)
75
76 if not registered(scanner_name):
92f5a8d4 77 raise BaseException ("attempt to get unregistered scanner: %s" % scanner_name)
7c673cae
FG
78
79 relevant_properties = __scanners[scanner_name]
80 r = property.select(relevant_properties, properties)
81
82 scanner_id = scanner_name + '.' + '-'.join(r)
83
84 if scanner_id not in __scanner_cache:
85 __scanner_cache[scanner_id] = scanner_class(r)
86
87 return __scanner_cache[scanner_id]
88
89class Scanner:
90 """ Base scanner class.
91 """
92 def __init__ (self):
93 pass
94
95 def pattern (self):
96 """ Returns a pattern to use for scanning.
97 """
92f5a8d4 98 raise BaseException ("method must be overridden")
7c673cae
FG
99
100 def process (self, target, matches, binding):
101 """ Establish necessary relationship between targets,
92f5a8d4 102 given actual target being scanned, and a list of
7c673cae
FG
103 pattern matches in that file.
104 """
92f5a8d4 105 raise BaseException ("method must be overridden")
7c673cae
FG
106
107
108# Common scanner class, which can be used when there's only one
109# kind of includes (unlike C, where "" and <> includes have different
110# search paths).
111class CommonScanner(Scanner):
112
113 def __init__ (self, includes):
114 Scanner.__init__(self)
115 self.includes = includes
116
117 def process(self, target, matches, binding):
118
119 target_path = os.path.normpath(os.path.dirname(binding[0]))
120 bjam.call("mark-included", target, matches)
121
122 get_manager().engine().set_target_variable(matches, "SEARCH",
123 [target_path] + self.includes)
124 get_manager().scanners().propagate(self, matches)
125
126class ScannerRegistry:
127
128 def __init__ (self, manager):
129 self.manager_ = manager
130 self.count_ = 0
131 self.exported_scanners_ = {}
132
133 def install (self, scanner, target, vtarget):
134 """ Installs the specified scanner on actual target 'target'.
135 vtarget: virtual target from which 'target' was actualized.
136 """
137 assert isinstance(scanner, Scanner)
138 assert isinstance(target, basestring)
139 assert isinstance(vtarget, basestring)
140 engine = self.manager_.engine()
141 engine.set_target_variable(target, "HDRSCAN", scanner.pattern())
142 if scanner not in self.exported_scanners_:
143 exported_name = "scanner_" + str(self.count_)
144 self.count_ = self.count_ + 1
145 self.exported_scanners_[scanner] = exported_name
146 bjam.import_rule("", exported_name, scanner.process)
147 else:
148 exported_name = self.exported_scanners_[scanner]
149
150 engine.set_target_variable(target, "HDRRULE", exported_name)
151
152 # scanner reflects difference in properties affecting
153 # binding of 'target', which will be known when processing
154 # includes for it, will give information on how to
155 # interpret quoted includes.
156 engine.set_target_variable(target, "HDRGRIST", str(id(scanner)))
157 pass
158
159 def propagate(self, scanner, targets):
160 assert isinstance(scanner, Scanner)
161 assert is_iterable_typed(targets, basestring) or isinstance(targets, basestring)
162 engine = self.manager_.engine()
163 engine.set_target_variable(targets, "HDRSCAN", scanner.pattern())
164 engine.set_target_variable(targets, "HDRRULE",
165 self.exported_scanners_[scanner])
166 engine.set_target_variable(targets, "HDRGRIST", str(id(scanner)))
167