1#!/usr/local/bin/python3.8
2#
3# Copyright 2017 Steven Watanabe
4#
5# Distributed under the Boost Software License, Version 1.0.
6# (See accompanying file LICENSE_1_0.txt or copy at
7# http://www.boost.org/LICENSE_1_0.txt)
8
9# validates a toolset using a mock of the compiler
10
11import BoostBuild
12import os
13import re
14import sys
15
16renames = {"debug": "variant=debug", "release": "variant=release"}
17
18def set_default_target_os(os):
19    global removed
20    global default_target_os
21    default_target_os = os
22    removed = set()
23    removed.add("target-os=" + default_target_os)
24
25def adjust_property(property):
26    global renames
27    if property in renames:
28        return renames[property]
29    else:
30        return property
31
32def adjust_properties(properties):
33    global removed
34    return [adjust_property(p) for p in properties if p not in removed]
35
36def has_property(name, properties):
37    return name in [re.sub("=.*", "", p) for p in properties]
38
39def get_property(name, properties):
40    for m in [re.match("(.*)=(.*)", p) for p in properties]:
41        if m and m.group(1) == name:
42            return m.group(2)
43
44def get_target_os(properties):
45    return get_property("target-os", properties) or default_target_os
46
47def expand_properties(properties):
48    result = properties[:]
49    if not has_property("variant", properties):
50        result += ["variant=debug"]
51    if not has_property("threading", properties):
52        result += ["threading=single"]
53    if not has_property("exception-handling", properties):
54        result += ["exception-handling=on"]
55    if not has_property("link", properties):
56        result += ["link=shared"]
57    if not has_property("rtti", properties):
58        result += ["rtti=on"]
59    if not has_property("runtime-link", properties):
60        result += ["runtime-link=shared"]
61    if not has_property("strip", properties):
62        result += ["strip=off"]
63    if not has_property("target-os", properties):
64        result += ["target-os=" + default_target_os]
65    return result
66
67def compute_path(properties, target_type):
68    path = ""
69    if "variant=release" in properties:
70        path += "/release"
71    else:
72        path += "/debug"
73    if has_property("address-model", properties):
74        path += "/address-model-" + get_property("address-model", properties)
75    if has_property("architecture", properties):
76        path += "/architecture-" + get_property("architecture", properties)
77    if "cxxstd=latest" in properties:
78        path += "/cxxstd-latest-iso"
79    if "exception-handling=off" in properties:
80        path += "/exception-handling-off"
81    if "link=static" in properties:
82        path += "/link-static"
83    if "rtti=off" in properties:
84        path += "/rtti-off"
85    if "runtime-link=static" in properties and target_type in ["exe"]:
86        path += "/runtime-link-static"
87    if "strip=on" in properties and target_type in ["dll", "exe", "obj2"]:
88        path += "/strip-on"
89    if get_target_os(properties) != default_target_os:
90        path += "/target-os-" + get_target_os(properties)
91    if "threading=multi" in properties:
92        path += "/threading-multi"
93    return path
94
95def test_toolset(toolset, version, property_sets):
96    t = BoostBuild.Tester()
97
98    t.set_tree("toolset-mock")
99
100    # Build necessary tools
101    t.run_build_system(["-sPYTHON_CMD=%s" % sys.executable], subdir="src")
102    set_default_target_os(t.read("src/bin/target-os.txt").strip())
103
104    for properties in property_sets:
105        t.set_toolset(toolset + "-" + version, get_target_os(properties))
106        properties = adjust_properties(properties)
107        def path(t):
108            return toolset.split("-")[0] + "-*" + version + compute_path(properties, t)
109        os.environ["B2_PROPERTIES"] = " ".join(expand_properties(properties))
110        t.run_build_system(["--user-config=", "-sPYTHON_CMD=%s" % sys.executable] + properties)
111        t.expect_addition("bin/%s/lib.obj" % (path("obj")))
112        if "link=static" not in properties:
113            t.expect_addition("bin/%s/l1.dll" % (path("dll")))
114            t.ignore_addition("bin/%s/*l1.*.rsp" % (path("dll")))
115        else:
116            t.expect_addition("bin/%s/l1.lib" % (path("lib")))
117        t.expect_addition("bin/%s/main.obj" % (path("obj2")))
118        t.expect_addition("bin/%s/test.exe" % (path("exe")))
119        t.ignore_addition("bin/%s/test.rsp" % (path("exe")))
120        t.expect_nothing_more()
121        t.rm("bin")
122
123    t.cleanup()
124