Blame tools/build/src/tools/rc.py

Packit 58578d
# Status: being ported by Steven Watanabe
Packit 58578d
# Base revision: 47077
Packit 58578d
#
Packit 58578d
#  Copyright (C) Andre Hentz 2003. Permission to copy, use, modify, sell and
Packit 58578d
#  distribute this software is granted provided this copyright notice appears in
Packit 58578d
#  all copies. This software is provided "as is" without express or implied
Packit 58578d
#  warranty, and with no claim as to its suitability for any purpose.
Packit 58578d
#
Packit 58578d
#  Copyright (c) 2006 Rene Rivera.
Packit 58578d
#
Packit 58578d
#  Copyright (c) 2008 Steven Watanabe
Packit 58578d
#
Packit 58578d
#  Use, modification and distribution is subject to the Boost Software
Packit 58578d
#  License Version 1.0. (See accompanying file LICENSE_1_0.txt or
Packit 58578d
#  http://www.boost.org/LICENSE_1_0.txt)
Packit 58578d
Packit 58578d
##import type ;
Packit 58578d
##import generators ;
Packit 58578d
##import feature ;
Packit 58578d
##import errors ;
Packit 58578d
##import scanner ;
Packit 58578d
##import toolset : flags ;
Packit 58578d
Packit 58578d
import os.path
Packit 58578d
import re
Packit 58578d
Packit 58578d
import bjam
Packit 58578d
Packit 58578d
from b2.build import type, toolset, generators, scanner, feature
Packit 58578d
from b2.exceptions import AlreadyDefined
Packit 58578d
from b2.tools import builtin
Packit 58578d
from b2.util import regex
Packit 58578d
from b2.build.toolset import flags
Packit 58578d
from b2.manager import get_manager
Packit 58578d
from b2.util import utility
Packit 58578d
Packit 58578d
__debug = None
Packit 58578d
Packit 58578d
def debug():
Packit 58578d
    global __debug
Packit 58578d
    if __debug is None:
Packit 58578d
        __debug = "--debug-configuration" in bjam.variable("ARGV")
Packit 58578d
    return __debug
Packit 58578d
Packit 58578d
type.register('RC', ['rc'])
Packit 58578d
Packit 58578d
def init():
Packit 58578d
    pass
Packit 58578d
Packit 58578d
def configure (command = None, condition = None, options = None):
Packit 58578d
    """
Packit 58578d
        Configures a new resource compilation command specific to a condition,
Packit 58578d
        usually a toolset selection condition. The possible options are:
Packit 58578d
Packit 58578d
            * <rc-type>(rc|windres) - Indicates the type of options the command
Packit 58578d
              accepts.
Packit 58578d
Packit 58578d
        Even though the arguments are all optional, only when a command, condition,
Packit 58578d
        and at minimum the rc-type option are given will the command be configured.
Packit 58578d
        This is so that callers don't have to check auto-configuration values
Packit 58578d
        before calling this. And still get the functionality of build failures when
Packit 58578d
        the resource compiler can't be found.
Packit 58578d
    """
Packit 58578d
    rc_type = feature.get_values('<rc-type>', options)
Packit 58578d
    if rc_type:
Packit 58578d
        assert(len(rc_type) == 1)
Packit 58578d
        rc_type = rc_type[0]
Packit 58578d
Packit 58578d
    if command and condition and rc_type:
Packit 58578d
        flags('rc.compile.resource', '.RC', condition, command)
Packit 58578d
        flags('rc.compile.resource', '.RC_TYPE', condition, [rc_type.lower()])
Packit 58578d
        flags('rc.compile.resource', 'DEFINES', [], ['<define>'])
Packit 58578d
        flags('rc.compile.resource', 'INCLUDES', [], ['<include>'])
Packit 58578d
        if debug():
Packit 58578d
            print 'notice: using rc compiler ::', condition, '::', command
Packit 58578d
Packit 58578d
engine = get_manager().engine()
Packit 58578d
Packit 58578d
class RCAction:
Packit 58578d
    """Class representing bjam action defined from Python.
Packit 58578d
    The function must register the action to execute."""
Packit 58578d
Packit 58578d
    def __init__(self, action_name, function):
Packit 58578d
        self.action_name = action_name
Packit 58578d
        self.function = function
Packit 58578d
Packit 58578d
    def __call__(self, targets, sources, property_set):
Packit 58578d
        if self.function:
Packit 58578d
            self.function(targets, sources, property_set)
Packit 58578d
Packit 58578d
# FIXME: What is the proper way to dispatch actions?
Packit 58578d
def rc_register_action(action_name, function = None):
Packit 58578d
    global engine
Packit 58578d
    if action_name in engine.actions:
Packit 58578d
        raise AlreadyDefined("Bjam action %s is already defined" % action_name)
Packit 58578d
    engine.actions[action_name] = RCAction(action_name, function)
Packit 58578d
Packit 58578d
def rc_compile_resource(targets, sources, properties):
Packit 58578d
    rc_type = bjam.call('get-target-variable', targets, '.RC_TYPE')
Packit 58578d
    rc_type = rc_type[0] if rc_type else ''
Packit 58578d
    global engine
Packit 58578d
    engine.set_update_action('rc.compile.resource.' + rc_type, targets, sources, properties)
Packit 58578d
Packit 58578d
rc_register_action('rc.compile.resource', rc_compile_resource)
Packit 58578d
Packit 58578d
Packit 58578d
engine.register_action(
Packit 58578d
    'rc.compile.resource.rc',
Packit 58578d
    '"$(.RC)" -l 0x409 "-U$(UNDEFS)" "-D$(DEFINES)" -I"$(>:D)" -I"$(<:D)" -I"$(INCLUDES)" -fo "$(<)" "$(>)"')
Packit 58578d
Packit 58578d
engine.register_action(
Packit 58578d
    'rc.compile.resource.windres',
Packit 58578d
    '"$(.RC)" "-U$(UNDEFS)" "-D$(DEFINES)" -I"$(>:D)" -I"$(<:D)" -I"$(INCLUDES)" -o "$(<)" -i "$(>)"')
Packit 58578d
Packit 58578d
# FIXME: this was originally declared quietly
Packit 58578d
engine.register_action(
Packit 58578d
    'compile.resource.null',
Packit 58578d
    'as /dev/null -o "$(<)"')
Packit 58578d
Packit 58578d
# Since it's a common practice to write
Packit 58578d
# exe hello : hello.cpp hello.rc
Packit 58578d
# we change the name of object created from RC file, to
Packit 58578d
# avoid conflict with hello.cpp.
Packit 58578d
# The reason we generate OBJ and not RES, is that gcc does not
Packit 58578d
# seem to like RES files, but works OK with OBJ.
Packit 58578d
# See http://article.gmane.org/gmane.comp.lib.boost.build/5643/
Packit 58578d
#
Packit 58578d
# Using 'register-c-compiler' adds the build directory to INCLUDES
Packit 58578d
# FIXME: switch to generators
Packit 58578d
builtin.register_c_compiler('rc.compile.resource', ['RC'], ['OBJ(%_res)'], [])
Packit 58578d
Packit 58578d
__angle_include_re = "#include[ ]*<([^<]+)>"
Packit 58578d
Packit 58578d
# Register scanner for resources
Packit 58578d
class ResScanner(scanner.Scanner):
Packit 58578d
Packit 58578d
    def __init__(self, includes):
Packit 58578d
        scanner.__init__ ;
Packit 58578d
        self.includes = includes
Packit 58578d
Packit 58578d
    def pattern(self):
Packit 58578d
        return "(([^ ]+[ ]+(BITMAP|CURSOR|FONT|ICON|MESSAGETABLE|RT_MANIFEST)" +\
Packit 58578d
               "[ ]+([^ \"]+|\"[^\"]+\"))|(#include[ ]*(<[^<]+>|\"[^\"]+\")))" ;
Packit 58578d
Packit 58578d
    def process(self, target, matches, binding):
Packit 58578d
        binding = binding[0]
Packit 58578d
        angle = regex.transform(matches, "#include[ ]*<([^<]+)>")
Packit 58578d
        quoted = regex.transform(matches, "#include[ ]*\"([^\"]+)\"")
Packit 58578d
        res = regex.transform(matches,
Packit 58578d
                              "[^ ]+[ ]+(BITMAP|CURSOR|FONT|ICON|MESSAGETABLE|RT_MANIFEST)" +\
Packit 58578d
                              "[ ]+(([^ \"]+)|\"([^\"]+)\")", [3, 4])
Packit 58578d
Packit 58578d
        # Icons and other includes may referenced as
Packit 58578d
        #
Packit 58578d
        # IDR_MAINFRAME ICON "res\\icon.ico"
Packit 58578d
        #
Packit 58578d
        # so we have to replace double backslashes to single ones.
Packit 58578d
        res = [ re.sub(r'\\\\', '/', match) for match in res if match is not None ]
Packit 58578d
Packit 58578d
        # CONSIDER: the new scoping rule seem to defeat "on target" variables.
Packit 58578d
        g = bjam.call('get-target-variable', target, 'HDRGRIST')[0]
Packit 58578d
        b = os.path.normpath(os.path.dirname(binding))
Packit 58578d
Packit 58578d
        # Attach binding of including file to included targets.
Packit 58578d
        # When target is directly created from virtual target
Packit 58578d
        # this extra information is unnecessary. But in other
Packit 58578d
        # cases, it allows to distinguish between two headers of the
Packit 58578d
        # same name included from different places.
Packit 58578d
        # We don't need this extra information for angle includes,
Packit 58578d
        # since they should not depend on including file (we can't
Packit 58578d
        # get literal "." in include path).
Packit 58578d
        g2 = g + "#" + b
Packit 58578d
Packit 58578d
        g = "<" + g + ">"
Packit 58578d
        g2 = "<" + g2 + ">"
Packit 58578d
        angle = [g + x for x in angle]
Packit 58578d
        quoted = [g2 + x for x in quoted]
Packit 58578d
        res = [g2 + x for x in res]
Packit 58578d
Packit 58578d
        all = angle + quoted
Packit 58578d
Packit 58578d
        bjam.call('mark-included', target, all)
Packit 58578d
Packit 58578d
        engine = get_manager().engine()
Packit 58578d
Packit 58578d
        engine.add_dependency(target, res)
Packit 58578d
        bjam.call('NOCARE', all + res)
Packit 58578d
        engine.set_target_variable(angle, 'SEARCH', [utility.get_value(inc) for inc in self.includes])
Packit 58578d
        engine.set_target_variable(quoted, 'SEARCH', [b + utility.get_value(inc) for inc in self.includes])
Packit 58578d
        engine.set_target_variable(res, 'SEARCH', [b + utility.get_value(inc) for inc in self.includes])
Packit 58578d
Packit 58578d
        # Just propagate current scanner to includes, in a hope
Packit 58578d
        # that includes do not change scanners.
Packit 58578d
        get_manager().scanners().propagate(self, angle + quoted)
Packit 58578d
Packit 58578d
scanner.register(ResScanner, 'include')
Packit 58578d
type.set_scanner('RC', ResScanner)