summaryrefslogtreecommitdiffstats
path: root/src/boost/tools/build/test/TestToolset.py
blob: 7fef16b02af4e8a519790aedda10de19905e2538 (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
#!/usr/bin/python
#
# Copyright 2017 Steven Watanabe
#
# Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE.txt or copy at
# https://www.bfgroup.xyz/b2/LICENSE.txt)

# validates a toolset using a mock of the compiler

import BoostBuild
import os
import re
import sys

renames = {"debug": "variant=debug", "release": "variant=release"}

def set_default_target_os(os):
    global removed
    global default_target_os
    default_target_os = os
    removed = set()
    removed.add("target-os=" + default_target_os)

def adjust_property(property):
    global renames
    if property in renames:
        return renames[property]
    else:
        return property

def adjust_properties(properties):
    global removed
    return [adjust_property(p) for p in properties if p not in removed]

def has_property(name, properties):
    return name in [re.sub("=.*", "", p) for p in properties]

def get_property(name, properties):
    for m in [re.match("(.*)=(.*)", p) for p in properties]:
        if m and m.group(1) == name:
            return m.group(2)

def get_target_os(properties):
    return get_property("target-os", properties) or default_target_os

def expand_properties(properties, toolset):
    result = properties[:]
    if not has_property("variant", properties):
        result += ["variant=debug"]
    if not has_property("threading", properties):
        result += ["threading=single"]
    if not has_property("exception-handling", properties):
        result += ["exception-handling=on"]
    if not has_property("link", properties):
        result += ["link=shared"]
    if not has_property("rtti", properties):
        result += ["rtti=on"]
    if not has_property("runtime-link", properties):
        result += ["runtime-link=shared"]
    if toolset == "msvc" and "runtime-link=shared" in result:
        result.remove("threading=" + get_property("threading", result))
        result += ["threading=multi"]
    if not has_property("strip", properties):
        result += ["strip=off"]
    if not has_property("target-os", properties):
        result += ["target-os=" + default_target_os]
    if not has_property("windows-api", properties):
        result += ["windows-api=desktop"]
    return result

def compute_path(properties, target_type):
    path = ""
    if "variant=release" in properties:
        path += "/release"
    else:
        path += "/debug"
    if has_property("address-model", properties):
        path += "/address-model-" + get_property("address-model", properties)
    if has_property("architecture", properties):
        path += "/architecture-" + get_property("architecture", properties)
    if "cxxstd=latest" in properties:
        path += "/cxxstd-latest-iso"
    if "exception-handling=off" in properties:
        path += "/exception-handling-off"
    if "link=static" in properties:
        path += "/link-static"
    if "rtti=off" in properties:
        path += "/rtti-off"
    if "runtime-link=static" in properties: # and target_type in ["exe"]:
        path += "/runtime-link-static"
    if "strip=on" in properties and target_type in ["dll", "exe", "obj2"]:
        path += "/strip-on"
    if get_target_os(properties) != default_target_os:
        path += "/target-os-" + get_target_os(properties)
    if "threading=multi" in properties:
      if "runtime-link=static" not in properties: # TODO: I don't think this it's intended to work this way though
        path += "/threading-multi"
    if not "windows-api=desktop" in properties:
        path += "/windows-api-" + get_property("windows-api", properties)
    return path

def test_toolset(toolset, version, property_sets):
    t = BoostBuild.Tester()

    t.set_tree("toolset-mock")

    # Build necessary tools
    t.run_build_system(["-sPYTHON_CMD=%s" % sys.executable], subdir="src")
    set_default_target_os(t.read("src/bin/target-os.txt").strip())

    for properties in property_sets:
        t.set_toolset(toolset + "-" + version, get_target_os(properties))
        properties = adjust_properties(properties)
        expanded_properties = expand_properties(properties, toolset)
        def path(t):
            return toolset.split("-")[0] + "-*" + version + compute_path(expanded_properties, t)
        os.environ["B2_PROPERTIES"] = " ".join(expanded_properties)
        t.run_build_system(["--user-config=", "-sPYTHON_CMD=%s" % sys.executable] + properties)
        t.expect_addition("bin/%s/lib.obj" % (path("obj")))
        if "link=static" not in properties:
            if get_target_os(properties) in ["cygwin", "windows"] and toolset != "clang-linux":
                t.expect_addition("bin/%s/l1.implib" % (path("dll")))
            t.expect_addition("bin/%s/l1.dll" % (path("dll")))
            t.ignore_addition("bin/%s/*l1.*.rsp" % (path("dll")))
        else:
            t.expect_addition("bin/%s/l1.lib" % (path("lib")))
        t.expect_addition("bin/%s/main.obj" % (path("obj2")))
        t.expect_addition("bin/%s/test.exe" % (path("exe")))
        t.ignore_addition("bin/%s/test.rsp" % (path("exe")))
        t.expect_nothing_more()
        t.rm("bin")

    t.cleanup()