summaryrefslogtreecommitdiff
path: root/zephyr/zmake/zmake/toolchains.py
blob: a92baf2a3e07005a877ccb68c31a5c519fd83991 (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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
# Copyright 2020 The ChromiumOS Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

"""Definitions of toolchain variables."""

import os
import pathlib

import zmake.build_config as build_config


class GenericToolchain:
    """Default toolchain if not known to zmake.

    Simply pass ZEPHYR_TOOLCHAIN_VARIANT=name to the build, with
    nothing extra.
    """

    def __init__(self, name, modules=None):
        self.name = name
        self.modules = modules or {}

    @staticmethod
    def probe():
        """Probe if the toolchain is available on the system."""
        # Since the toolchain is not known to zmake, we have no way to
        # know if it's installed.  Simply return False to indicate not
        # installed.  An unknown toolchain would only be used if -t
        # was manually passed to zmake, and is not valid to put in a
        # BUILD.py file.
        return False

    def get_build_config(self):
        """Get the build configuration for the toolchain.

        Returns:
            A build_config.BuildConfig to be applied to the build.
        """
        return build_config.BuildConfig(
            cmake_defs={
                "ZEPHYR_TOOLCHAIN_VARIANT": self.name,
            },
        )


class CorebootSdkToolchain(GenericToolchain):
    """Coreboot SDK toolchain installed in default location."""

    @staticmethod
    def _find_coreboot_sdk():
        """Find coreboot-sdk, if available.

        Returns:
            The path to coreboot-sdk, or None if unavailable.
        """
        path = pathlib.Path(
            os.environ.get("COREBOOT_SDK_ROOT", "/opt/coreboot-sdk")
        ).resolve()
        if path.is_dir():
            return path
        return None

    def probe(self):
        return bool(self._find_coreboot_sdk())

    def get_build_config(self):
        return (
            build_config.BuildConfig(
                cmake_defs={
                    "TOOLCHAIN_ROOT": str(self.modules["ec"] / "zephyr"),
                    "COREBOOT_SDK_ROOT": str(self._find_coreboot_sdk()),
                },
            )
            | super().get_build_config()
        )


class ZephyrToolchain(GenericToolchain):
    """Zephyr SDK toolchain.

    Either set the environment var ZEPHYR_SDK_INSTALL_DIR, or install
    the SDK in one of the common known locations.
    """

    def __init__(self, *args, **kwargs):
        self.zephyr_sdk_install_dir = self._find_zephyr_sdk()
        super().__init__(*args, **kwargs)

    @staticmethod
    def _find_zephyr_sdk():
        """Find the Zephyr SDK, if it's installed.

        Returns:
            The path to the Zephyr SDK, using the search rules defined by
            https://docs.zephyrproject.org/latest/getting_started/installation_linux.html,
            or None, if one cannot be found on the system.
        """
        from_env = os.getenv("ZEPHYR_SDK_INSTALL_DIR")
        if from_env:
            return pathlib.Path(from_env)

        def _gen_sdk_paths():
            for prefix in (
                "~",
                "~/.local",
                "~/.local/opt",
                "~/bin",
                "/opt",
                "/usr",
                "/usr/local",
            ):
                prefix = pathlib.Path(os.path.expanduser(prefix))
                yield prefix / "zephyr-sdk"
                yield from prefix.glob("zephyr-sdk-*")

        for path in _gen_sdk_paths():
            if (path / "sdk_version").is_file():
                return path

        return None

    def probe(self):
        return bool(self.zephyr_sdk_install_dir)

    def get_build_config(self):
        if not self.zephyr_sdk_install_dir:
            raise RuntimeError(
                "No installed Zephyr SDK was found"
                " (see docs/zephyr/zephyr_build.md for documentation)"
            )
        tc_vars = {
            "ZEPHYR_SDK_INSTALL_DIR": str(self.zephyr_sdk_install_dir),
        }
        return (
            build_config.BuildConfig(cmake_defs=tc_vars)
            | super().get_build_config()
        )


class LlvmToolchain(GenericToolchain):
    """LLVM toolchain as used in the chroot."""

    def probe(self):
        # TODO: differentiate chroot llvm path vs. something more
        # generic?
        return pathlib.Path("/usr/bin/x86_64-pc-linux-gnu-clang").exists()

    def get_build_config(self):
        # TODO: this contains custom settings for the chroot.  Plumb a
        # toolchain for "generic-llvm" for external uses?
        return (
            build_config.BuildConfig(
                cmake_defs={
                    "TOOLCHAIN_ROOT": str(self.modules["ec"] / "zephyr"),
                },
            )
            | super().get_build_config()
        )


class HostToolchain(GenericToolchain):
    """GCC toolchain found in the PATH."""

    def probe(self):
        # "host" toolchain for Zephyr means GCC.
        for search_path in os.getenv("PATH", "/usr/bin").split(":"):
            if (pathlib.Path(search_path) / "gcc").exists():
                return True
        return False


# Mapping of toolchain names -> support class
support_classes = {
    "coreboot-sdk": CorebootSdkToolchain,
    "host": HostToolchain,
    "llvm": LlvmToolchain,
    "zephyr": ZephyrToolchain,
}