1#!/usr/local/bin/python3.8
2
3# Copyright 2012 Jurko Gospodnetic
4# Distributed under the Boost Software License, Version 1.0.
5# (See accompanying file LICENSE_1_0.txt or copy at
6# http://www.boost.org/LICENSE_1_0.txt)
7
8# Tests rc toolset behaviour.
9
10import BoostBuild
11
12
13def included_resource_newer_than_rc_script():
14    """
15      When a .rc script file includes another resource file - the resource file
16    being newer than the .rc script file should not cause the .rc script file
17    to be considered old and force all of its dependents to rebuild.
18
19    """
20    toolsetName = "__myDummyResourceCompilerToolset__"
21
22    # Used options rationale:
23    #
24    # -d4 & --debug-configuration
25    #     Display additional information in case of test failure. In the past
26    #   we have had testing system issues  causing this test to fail
27    #   sporadically for which -d+3 output had been instrumental in getting to
28    #   the root cause (a touched file's timestamp was not as new as it should
29    #   have been).
30    #
31    # --ignore-site-config --user-config=
32    #     Disable reading any external Boost Build configuration. This test is
33    #   self sufficient so these options protect it from being adversly
34    #   affected by any local (mis)configuration..
35    t = BoostBuild.Tester(["-d4", "--debug-configuration",
36        "--ignore-site-config", "--user-config=", "toolset=%s" % toolsetName],
37        pass_toolset=False, use_test_config=False,
38        translate_suffixes=False)
39
40    # Prepare a dummy toolset so we do not get errors in case the default one
41    # is not found and that we can test rc.jam functionality without having to
42    # depend on the externally specified toolset actually supporting it exactly
43    # the way it is required for this test, e.g. gcc toolset, under some
44    # circumstances, uses a quiet action for generating its null RC targets.
45    t.write(toolsetName + ".jam", """\
46import feature ;
47import rc ;
48import type ;
49local toolset-name = "%s" ;
50feature.extend toolset : $(toolset-name) ;
51rule init ( ) { }
52rc.configure dummy-rc-command : <toolset>$(toolset-name) : <rc-type>dummy ;
53module rc
54{
55    rule compile.resource.dummy ( targets * : sources * : properties * )
56    {
57        import common ;
58        .TOUCH on $(targets) = [ common.file-touch-command ] ;
59    }
60    actions compile.resource.dummy { $(.TOUCH) "$(<)" }
61}
62# Make OBJ files generated by our toolset use the "obj" suffix on all
63# platforms. We need to do this explicitly for <target-os> windows & cygwin to
64# override the default OBJ type configuration (otherwise we would get
65# 'ambiguous key' errors on those platforms).
66local rule set-generated-obj-suffix ( target-os ? )
67{
68    type.set-generated-target-suffix OBJ : <toolset>$(toolset-name)
69        <target-os>$(target-os) : obj ;
70}
71set-generated-obj-suffix ;
72set-generated-obj-suffix windows ;
73set-generated-obj-suffix cygwin ;
74""" % toolsetName)
75
76    t.write(
77        toolsetName + '.py',
78"""
79from b2.build import feature, type as type_
80from b2.manager import get_manager
81from b2.tools import rc, common
82
83MANAGER = get_manager()
84ENGINE = MANAGER.engine()
85
86toolset_name = "{0}"
87
88feature.extend('toolset', [toolset_name])
89
90def init(*args):
91    pass
92
93rc.configure(['dummy-rc-command'], ['<toolset>' + toolset_name], ['<rc-type>dummy'])
94
95ENGINE.register_action(
96    'rc.compile.resource.dummy',
97    '''
98    %s "$(<)"
99    ''' % common.file_creation_command()
100)
101
102def set_generated_obj_suffix(target_os=''):
103    requirements = ['<toolset>' + toolset_name]
104    if target_os:
105        requirements.append('<target-os>' + target_os)
106    type_.set_generated_target_suffix('OBJ', requirements, 'obj')
107
108set_generated_obj_suffix()
109set_generated_obj_suffix('windows')
110set_generated_obj_suffix('cygwin')
111""".format(toolsetName)
112    )
113
114    # Prepare project source files.
115    t.write("jamroot.jam", """\
116ECHO "{{{" [ modules.peek : XXX ] [ modules.peek : NOEXEC ] "}}}" ;
117obj xxx : xxx.rc ;
118""")
119    t.write("xxx.rc", '1 MESSAGETABLE "xxx.bin"\n')
120    t.write("xxx.bin", "foo")
121
122    def test1(n, expect, noexec=False):
123        params = ["-sXXX=%d" % n]
124        if noexec:
125            params.append("-n")
126            params.append("-sNOEXEC=NOEXEC")
127        t.run_build_system(params)
128        t.expect_output_lines("*NOEXEC*", noexec)
129        obj_file = "xxx_res.obj"
130        t.expect_output_lines("compile.resource.dummy *%s" % obj_file, expect)
131        if expect and not noexec:
132            expect("bin/%s/debug/%s" % (toolsetName, obj_file))
133        t.expect_nothing_more()
134
135    def test(n, expect):
136        test1(n, expect, noexec=True)
137        test1(n, expect)
138
139    test(1, t.expect_addition)
140    test(2, None)
141    t.touch("xxx.bin")
142    test(3, t.expect_touch)
143    test(4, None)
144
145    t.cleanup()
146
147
148included_resource_newer_than_rc_script()
149