summaryrefslogtreecommitdiff
path: root/tools/build/v2/tools/rc.jam
blob: 9964d339bafc5b48ca2db10dc5ea6ec3bc04be97 (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
154
155
156
#  Copyright (C) Andre Hentz 2003. Permission to copy, use, modify, sell and
#  distribute this software is granted provided this copyright notice appears in
#  all copies. This software is provided "as is" without express or implied
#  warranty, and with no claim as to its suitability for any purpose.
#  
#  Copyright (c) 2006 Rene Rivera.
#
#  Use, modification and distribution is subject to the Boost Software
#  License Version 1.0. (See accompanying file LICENSE_1_0.txt or
#  http://www.boost.org/LICENSE_1_0.txt)

import type ;
import generators ;
import feature ;
import errors ;
import scanner ;
import toolset : flags ;

if [ MATCH (--debug-configuration) : [ modules.peek : ARGV ] ]
{
    .debug-configuration = true ;
}

type.register RC : rc ;

rule init ( )
{
}

# Configures a new resource compilation command specific to a condition,
# usually a toolset selection condition. The possible options are:
#
#     * <rc-type>(rc|windres) - Indicates the type of options the command
#       accepts.
#
# Even though the arguments are all optional, only when a command, condition,
# and at minimum the rc-type option are given will the command be configured.
# This is so that callers don't have to check auto-configuration values
# before calling this. And still get the functionality of build failures when
# the resource compiler can't be found.
#
rule configure ( command ? : condition ? : options * )
{
    local rc-type = [ feature.get-values <rc-type> : $(options) ] ;

    if $(command) && $(condition) && $(rc-type)
    {
        flags rc.compile.resource .RC $(condition) : $(command) ;
        flags rc.compile.resource .RC_TYPE $(condition) : $(rc-type:L) ;
        flags rc.compile.resource DEFINES <define> ;
        flags rc.compile.resource INCLUDES <include> ;
        if $(.debug-configuration)
        {
            ECHO notice: using rc compiler :: $(condition) :: $(command) ;
        }
    }
}

rule compile.resource ( target : sources * : properties * )
{
    local rc-type = [ on $(target) return $(.RC_TYPE) ] ;
    rc-type ?= null ;
    compile.resource.$(rc-type) $(target) : $(sources[1]) ;
}

actions compile.resource.rc
{
    "$(.RC)" -l 0x409 "-U$(UNDEFS)" "-D$(DEFINES)" -I"$(>:D)" -I"$(<:D)" -I"$(INCLUDES)" -fo "$(<)" "$(>)"
}

actions compile.resource.windres
{
    "$(.RC)" "-U$(UNDEFS)" "-D$(DEFINES)" -I"$(>:D)" -I"$(<:D)" -I"$(INCLUDES)" -o "$(<)" -i "$(>)"
}

actions quietly compile.resource.null
{
    as /dev/null -o "$(<)"
}

# Since it's a common practice to write
# exe hello : hello.cpp hello.rc
# we change the name of object created from RC file, to
# avoid conflict with hello.cpp.
# The reason we generate OBJ and not RES, is that gcc does not
# seem to like RES files, but works OK with OBJ.
# See http://article.gmane.org/gmane.comp.lib.boost.build/5643/
#
# Using 'register-c-compiler' adds the build directory to INCLUDES
generators.register-c-compiler rc.compile.resource : RC : OBJ(%_res) ;

# Register scanner for resources
class res-scanner : scanner 
{
    import regex virtual-target path scanner ;    
    
    rule __init__ ( includes * )
    {
        scanner.__init__ ;
    
        self.includes = $(includes) ;
    }    

    rule pattern ( )
    {
        return "(([^ ]+[ ]+(BITMAP|CURSOR|FONT|ICON|MESSAGETABLE|RT_MANIFEST)[ ]+([^ \"]+|\"[^\"]+\"))|(#include[ ]*(<[^<]+>|\"[^\"]+\")))" ;
    }

    rule process ( target : matches * : binding )
    {
        local angle = [ regex.transform $(matches) : "#include[ ]*<([^<]+)>" ] ;
        local quoted = [ regex.transform $(matches) : "#include[ ]*\"([^\"]+)\"" ] ;
        local res = [ regex.transform $(matches) : "[^ ]+[ ]+(BITMAP|CURSOR|FONT|ICON|MESSAGETABLE|RT_MANIFEST)[ ]+(([^ \"]+)|\"([^\"]+)\")" : 3 4 ] ;

        # Icons and other includes may referenced as 
        #
        # IDR_MAINFRAME ICON "res\\icon.ico"
        #
        # so we have to replace double backslashes to single ones.
        res = [ regex.replace-list $(res) : "\\\\\\\\" : "/" ] ;

        # CONSIDER: the new scoping rule seem to defeat "on target" variables.
        local g = [ on $(target) return $(HDRGRIST) ] ;  
        local b = [ NORMALIZE_PATH $(binding:D) ] ;

        # Attach binding of including file to included targets.
        # When target is directly created from virtual target
        # this extra information is unnecessary. But in other
        # cases, it allows to distinguish between two headers of the 
        # same name included from different places.      
        # We don't need this extra information for angle includes,
        # since they should not depend on including file (we can't
        # get literal "." in include path).
        local g2 = $(g)"#"$(b) ;
       
        angle = $(angle:G=$(g)) ;
        quoted = $(quoted:G=$(g2)) ;
        res = $(res:G=$(g2)) ;
        
        local all = $(angle) $(quoted) ;

        INCLUDES $(target) : $(all) ;
        DEPENDS $(target) : $(res) ;
        NOCARE $(all) $(res) ;
        SEARCH on $(angle) = $(self.includes:G=) ;
        SEARCH on $(quoted) = $(b) $(self.includes:G=) ;
        SEARCH on $(res) = $(b) $(self.includes:G=) ;
        
        # Just propagate current scanner to includes, in a hope
        # that includes do not change scanners. 
        scanner.propagate $(__name__) : $(angle) $(quoted) : $(target) ;
    }        
}

scanner.register res-scanner : include ;
type.set-scanner RC : res-scanner ;