summaryrefslogtreecommitdiff
path: root/jam-files/boost-build/build/scanner.jam
blob: d6042ea2c78dff3105a9cd8bdfdf84c5dc6de69f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
# 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 ;