diff options
author | Jack Rosenthal <jrosenth@chromium.org> | 2021-08-31 18:44:15 -0600 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2021-09-01 22:57:37 +0000 |
commit | 4259d21065b281d8acc58e041d92d64c4db24205 (patch) | |
tree | 4aef746387316e6ad61d488ededf5a173335a5cd /zephyr | |
parent | 3010ab154cb84277e81e906bc05ae360d263993c (diff) | |
download | chrome-ec-4259d21065b281d8acc58e041d92d64c4db24205.tar.gz |
zephyr: zmake: implement multiple toolchain support/probing
Our GitLab builder uses different toolchains than the supported ones
we use for development. At present, this means that the GitLab CI
needs to call -t for each build with the desired toolchain, preventing
us from using the more general commands "zmake coverage" or "zmake
testall".
Extend the idea of toolchain in our config files to be "supported
toolchains" instead (i.e., multiple toolchains can be supported
instead of one. We do this by refactoring our toolchain support code
to consist of two related methods:
- "probe" returns True if the toolchain is detected on the system, or
False otherwise
- "get_toolchain_config" returns the BuildConfig associated with the
toolchain for the system, mirroring the functionality previously
implemented in lambda functions.
Also dropped support for arm-none-eabi, as I believe this was only
used early on during scarlet development, and am not aware of any
current users.
BUG=b:178731498
BRANCH=none
TEST=./run_tests.sh
TEST=zmake testall
Signed-off-by: Jack Rosenthal <jrosenth@chromium.org>
Change-Id: I9b2ad508ae6703f0c3b56518fc32606c0ff1777c
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3134668
Commit-Queue: Jeremy Bettis <jbettis@chromium.org>
Reviewed-by: Jeremy Bettis <jbettis@chromium.org>
Diffstat (limited to 'zephyr')
30 files changed, 398 insertions, 128 deletions
diff --git a/zephyr/projects/asurada/hayato/zmake.yaml b/zephyr/projects/asurada/hayato/zmake.yaml index c1ec732c43..f4e821d582 100644 --- a/zephyr/projects/asurada/hayato/zmake.yaml +++ b/zephyr/projects/asurada/hayato/zmake.yaml @@ -8,7 +8,9 @@ dts-overlays: - gpio.dts - motionsense.dts - pwm.dts +supported-toolchains: + - coreboot-sdk + - zephyr supported-zephyr-versions: - v2.6 -toolchain: coreboot-sdk output-type: binman diff --git a/zephyr/projects/brya/brya/zmake.yaml b/zephyr/projects/brya/brya/zmake.yaml index 9340bdec53..71687e0f3e 100644 --- a/zephyr/projects/brya/brya/zmake.yaml +++ b/zephyr/projects/brya/brya/zmake.yaml @@ -5,7 +5,9 @@ board: brya dts-overlays: - gpio.dts +supported-toolchains: + - coreboot-sdk + - zephyr supported-zephyr-versions: - v2.6 -toolchain: coreboot-sdk output-type: npcx diff --git a/zephyr/projects/herobrine/herobrine_npcx9/zmake.yaml b/zephyr/projects/herobrine/herobrine_npcx9/zmake.yaml index 530278c5e7..775ab65ead 100644 --- a/zephyr/projects/herobrine/herobrine_npcx9/zmake.yaml +++ b/zephyr/projects/herobrine/herobrine_npcx9/zmake.yaml @@ -9,7 +9,9 @@ dts-overlays: - i2c.dts - motionsense.dts - switchcap.dts +supported-toolchains: + - coreboot-sdk + - zephyr supported-zephyr-versions: - v2.6 -toolchain: coreboot-sdk output-type: npcx diff --git a/zephyr/projects/it8xxx2_evb/zmake.yaml b/zephyr/projects/it8xxx2_evb/zmake.yaml index ba536537a5..d05a938500 100644 --- a/zephyr/projects/it8xxx2_evb/zmake.yaml +++ b/zephyr/projects/it8xxx2_evb/zmake.yaml @@ -3,7 +3,9 @@ # found in the LICENSE file. board: it8xxx2_evb +supported-toolchains: + - coreboot-sdk + - zephyr supported-zephyr-versions: - v2.6 -toolchain: coreboot-sdk output-type: raw diff --git a/zephyr/projects/kohaku/zmake.yaml b/zephyr/projects/kohaku/zmake.yaml index cf55fc5e13..99e4f135fb 100644 --- a/zephyr/projects/kohaku/zmake.yaml +++ b/zephyr/projects/kohaku/zmake.yaml @@ -3,7 +3,9 @@ # found in the LICENSE file. board: kohaku +supported-toolchains: + - coreboot-sdk + - zephyr supported-zephyr-versions: - v2.6 -toolchain: coreboot-sdk output-type: npcx diff --git a/zephyr/projects/npcx_evb/npcx7/zmake.yaml b/zephyr/projects/npcx_evb/npcx7/zmake.yaml index 79faa50656..e846e582e7 100644 --- a/zephyr/projects/npcx_evb/npcx7/zmake.yaml +++ b/zephyr/projects/npcx_evb/npcx7/zmake.yaml @@ -8,7 +8,9 @@ dts-overlays: - pwm.dts - fan.dts - keyboard.dts +supported-toolchains: + - coreboot-sdk + - zephyr supported-zephyr-versions: - v2.6 -toolchain: coreboot-sdk output-type: npcx diff --git a/zephyr/projects/npcx_evb/npcx9/zmake.yaml b/zephyr/projects/npcx_evb/npcx9/zmake.yaml index 95a2d3adf7..1d750cc813 100644 --- a/zephyr/projects/npcx_evb/npcx9/zmake.yaml +++ b/zephyr/projects/npcx_evb/npcx9/zmake.yaml @@ -8,7 +8,9 @@ dts-overlays: - pwm.dts - fan.dts - keyboard.dts +supported-toolchains: + - coreboot-sdk + - zephyr supported-zephyr-versions: - v2.6 -toolchain: coreboot-sdk output-type: npcx diff --git a/zephyr/projects/posix-ec/zmake.yaml b/zephyr/projects/posix-ec/zmake.yaml index 1001ea87ac..e06fd99183 100644 --- a/zephyr/projects/posix-ec/zmake.yaml +++ b/zephyr/projects/posix-ec/zmake.yaml @@ -1,5 +1,7 @@ board: native_posix +supported-toolchains: + - llvm + - host supported-zephyr-versions: - v2.6 output-type: elf -toolchain: llvm diff --git a/zephyr/projects/trogdor/herobrine_npcx7/zmake.yaml b/zephyr/projects/trogdor/herobrine_npcx7/zmake.yaml index 03ab9036aa..ef0e8a178e 100644 --- a/zephyr/projects/trogdor/herobrine_npcx7/zmake.yaml +++ b/zephyr/projects/trogdor/herobrine_npcx7/zmake.yaml @@ -7,7 +7,9 @@ dts-overlays: - gpio.dts - battery.dts - motionsense.dts +supported-toolchains: + - coreboot-sdk + - zephyr supported-zephyr-versions: - v2.6 -toolchain: coreboot-sdk output-type: npcx diff --git a/zephyr/projects/trogdor/lazor/zmake.yaml b/zephyr/projects/trogdor/lazor/zmake.yaml index 234d7dd416..c1c14d07d5 100644 --- a/zephyr/projects/trogdor/lazor/zmake.yaml +++ b/zephyr/projects/trogdor/lazor/zmake.yaml @@ -8,7 +8,9 @@ dts-overlays: - gpio.dts - keyboard.dts - motionsense.dts +supported-toolchains: + - coreboot-sdk + - zephyr supported-zephyr-versions: - v2.6 -toolchain: coreboot-sdk output-type: npcx diff --git a/zephyr/projects/trogdor/trogdor/zmake.yaml b/zephyr/projects/trogdor/trogdor/zmake.yaml index 03ab9036aa..ef0e8a178e 100644 --- a/zephyr/projects/trogdor/trogdor/zmake.yaml +++ b/zephyr/projects/trogdor/trogdor/zmake.yaml @@ -7,7 +7,9 @@ dts-overlays: - gpio.dts - battery.dts - motionsense.dts +supported-toolchains: + - coreboot-sdk + - zephyr supported-zephyr-versions: - v2.6 -toolchain: coreboot-sdk output-type: npcx diff --git a/zephyr/projects/volteer/delbin/zmake.yaml b/zephyr/projects/volteer/delbin/zmake.yaml index 92b19417ef..dc5217e042 100644 --- a/zephyr/projects/volteer/delbin/zmake.yaml +++ b/zephyr/projects/volteer/delbin/zmake.yaml @@ -6,7 +6,9 @@ board: volteer dts-overlays: - gpio.dts - motionsense.dts +supported-toolchains: + - coreboot-sdk + - zephyr supported-zephyr-versions: - v2.6 -toolchain: coreboot-sdk output-type: npcx diff --git a/zephyr/projects/volteer/volteer/zmake.yaml b/zephyr/projects/volteer/volteer/zmake.yaml index ef149f29b4..3f291ce671 100644 --- a/zephyr/projects/volteer/volteer/zmake.yaml +++ b/zephyr/projects/volteer/volteer/zmake.yaml @@ -11,7 +11,9 @@ dts-overlays: - keyboard.dts - motionsense.dts - pwm.dts +supported-toolchains: + - coreboot-sdk + - zephyr supported-zephyr-versions: - v2.6 -toolchain: coreboot-sdk output-type: npcx diff --git a/zephyr/test/accel_cal/zmake.yaml b/zephyr/test/accel_cal/zmake.yaml index 5bcd0d054c..decc749ae1 100644 --- a/zephyr/test/accel_cal/zmake.yaml +++ b/zephyr/test/accel_cal/zmake.yaml @@ -5,6 +5,8 @@ board: native_posix supported-zephyr-versions: - v2.6 -toolchain: llvm +supported-toolchains: + - llvm + - host output-type: elf is-test: true diff --git a/zephyr/test/base32/zmake.yaml b/zephyr/test/base32/zmake.yaml index 9158a292d7..6aa10c2661 100644 --- a/zephyr/test/base32/zmake.yaml +++ b/zephyr/test/base32/zmake.yaml @@ -5,6 +5,8 @@ board: native_posix supported-zephyr-versions: - v2.6 -toolchain: llvm +supported-toolchains: + - llvm + - host output-type: elf is-test: true diff --git a/zephyr/test/crc/zmake.yaml b/zephyr/test/crc/zmake.yaml index 9158a292d7..6aa10c2661 100644 --- a/zephyr/test/crc/zmake.yaml +++ b/zephyr/test/crc/zmake.yaml @@ -5,6 +5,8 @@ board: native_posix supported-zephyr-versions: - v2.6 -toolchain: llvm +supported-toolchains: + - llvm + - host output-type: elf is-test: true diff --git a/zephyr/test/drivers/zmake.yaml b/zephyr/test/drivers/zmake.yaml index 789ce8175d..31d8523e8e 100644 --- a/zephyr/test/drivers/zmake.yaml +++ b/zephyr/test/drivers/zmake.yaml @@ -5,7 +5,9 @@ board: native_posix supported-zephyr-versions: - v2.6 -toolchain: llvm +supported-toolchains: + - llvm + - host output-type: elf is-test: true dts-overlays: diff --git a/zephyr/test/ec_app/zmake.yaml b/zephyr/test/ec_app/zmake.yaml index 5bcd0d054c..decc749ae1 100644 --- a/zephyr/test/ec_app/zmake.yaml +++ b/zephyr/test/ec_app/zmake.yaml @@ -5,6 +5,8 @@ board: native_posix supported-zephyr-versions: - v2.6 -toolchain: llvm +supported-toolchains: + - llvm + - host output-type: elf is-test: true diff --git a/zephyr/test/hooks/zmake.yaml b/zephyr/test/hooks/zmake.yaml index 9158a292d7..6aa10c2661 100644 --- a/zephyr/test/hooks/zmake.yaml +++ b/zephyr/test/hooks/zmake.yaml @@ -5,6 +5,8 @@ board: native_posix supported-zephyr-versions: - v2.6 -toolchain: llvm +supported-toolchains: + - llvm + - host output-type: elf is-test: true diff --git a/zephyr/test/i2c/zmake.yaml b/zephyr/test/i2c/zmake.yaml index 81ded15ffc..f5e794c0f8 100644 --- a/zephyr/test/i2c/zmake.yaml +++ b/zephyr/test/i2c/zmake.yaml @@ -5,7 +5,9 @@ board: native_posix supported-zephyr-versions: - v2.6 -toolchain: llvm +supported-toolchains: + - llvm + - host output-type: elf is-test: true dts-overlays: diff --git a/zephyr/test/i2c_dts/zmake.yaml b/zephyr/test/i2c_dts/zmake.yaml index 5d6d9482f9..c3fca2272e 100644 --- a/zephyr/test/i2c_dts/zmake.yaml +++ b/zephyr/test/i2c_dts/zmake.yaml @@ -6,7 +6,9 @@ board: native_posix supported-zephyr-versions: - v2.6 output-type: elf -toolchain: llvm +supported-toolchains: + - llvm + - host is-test: true dts-overlays: - overlay.dts diff --git a/zephyr/test/system/zmake.yaml b/zephyr/test/system/zmake.yaml index 5d6d9482f9..c3fca2272e 100644 --- a/zephyr/test/system/zmake.yaml +++ b/zephyr/test/system/zmake.yaml @@ -6,7 +6,9 @@ board: native_posix supported-zephyr-versions: - v2.6 output-type: elf -toolchain: llvm +supported-toolchains: + - llvm + - host is-test: true dts-overlays: - overlay.dts diff --git a/zephyr/test/tasks/zmake.yaml b/zephyr/test/tasks/zmake.yaml index 9158a292d7..6aa10c2661 100644 --- a/zephyr/test/tasks/zmake.yaml +++ b/zephyr/test/tasks/zmake.yaml @@ -5,6 +5,8 @@ board: native_posix supported-zephyr-versions: - v2.6 -toolchain: llvm +supported-toolchains: + - llvm + - host output-type: elf is-test: true diff --git a/zephyr/zmake/tests/test_project.py b/zephyr/zmake/tests/test_project.py index dd57a5c9c9..2442ceedf6 100644 --- a/zephyr/zmake/tests/test_project.py +++ b/zephyr/zmake/tests/test_project.py @@ -70,8 +70,8 @@ def test_find_dts_overlays(modules): with TemporaryProject( { "board": board, - "toolchain": "foo", "output-type": "elf", + "supported-toolchains": ["llvm"], "supported-zephyr-versions": ["v2.6"], } ) as project: @@ -104,8 +104,8 @@ def test_prune_modules(modules): with TemporaryProject( { "board": "native_posix", - "toolchain": "coreboot-sdk", "output-type": "elf", + "supported-toolchains": ["coreboot-sdk"], "supported-zephyr-versions": ["v2.6"], "modules": modules, } @@ -125,8 +125,8 @@ def test_prune_modules_unavailable(): with TemporaryProject( { "board": "native_posix", - "toolchain": "coreboot-sdk", "output-type": "elf", + "supported-toolchains": ["coreboot-sdk"], "supported-zephyr-versions": ["v2.6"], "modules": ["hal_stm32", "cmsis"], } @@ -144,7 +144,8 @@ def test_find_projects_empty(tmp_path): YAML_FILE = """ supported-zephyr-versions: - v2.6 -toolchain: coreboot-sdk +supported-toolchains: + - coreboot-sdk output-type: npcx """ diff --git a/zephyr/zmake/tests/test_toolchains.py b/zephyr/zmake/tests/test_toolchains.py index 266013b0e0..515f54a112 100644 --- a/zephyr/zmake/tests/test_toolchains.py +++ b/zephyr/zmake/tests/test_toolchains.py @@ -2,34 +2,154 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import os import pathlib -import mock +import pytest +import zmake.project as project import zmake.toolchains as toolchains -def test_coreboot_sdk(): - config = toolchains.get_toolchain("coreboot-sdk", {"ec": pathlib.Path("/")}) - assert config.cmake_defs["ZEPHYR_TOOLCHAIN_VARIANT"] == "coreboot-sdk" - assert config.cmake_defs["TOOLCHAIN_ROOT"] == "/zephyr" +@pytest.fixture +def mockfs(monkeypatch, tmp_path): + """Setup a fake fs root for pathlib objects at tmp_path/mockfs.""" + mockfs_dir = pathlib.PosixPath(tmp_path / "mockfs") + mockfs_dir.mkdir() + class FakePath(pathlib.Path): + def __new__(cls, *args, **kwargs): + parts = pathlib.PosixPath(*args).relative_to("/").parts + # Make sure we don't double up our mocked directory. + mock_dir_parts = mockfs_dir.relative_to("/").parts + if parts[: len(mock_dir_parts)] == mock_dir_parts: + return pathlib.PosixPath(*args) + return pathlib.PosixPath("/", *mock_dir_parts, *parts) -def test_llvm(): - config = toolchains.get_toolchain("llvm", {"ec": pathlib.Path("/")}) - assert config.cmake_defs["ZEPHYR_TOOLCHAIN_VARIANT"] == "llvm" - assert config.cmake_defs["TOOLCHAIN_ROOT"] == "/zephyr" + monkeypatch.setattr(pathlib, "Path", FakePath) + return mockfs_dir -@mock.patch("zmake.toolchains.find_zephyr_sdk", return_value="/opt/zephyr-sdk") -def test_zephyr(find_zephyr_sdk): - config = toolchains.get_toolchain("zephyr", {}) - assert config.cmake_defs["ZEPHYR_TOOLCHAIN_VARIANT"] == "zephyr" - assert config.cmake_defs["ZEPHYR_SDK_INSTALL_DIR"] == "/opt/zephyr-sdk" - assert config.environ_defs["ZEPHYR_SDK_INSTALL_DIR"] == "/opt/zephyr-sdk" +@pytest.fixture +def coreboot_sdk_exists(mockfs): + coreboot_sdk_dir = mockfs / "opt" / "coreboot-sdk" + coreboot_sdk_dir.mkdir(parents=True) -def test_arm_none_eabi(): - config = toolchains.get_toolchain("arm-none-eabi", {}) - assert config.cmake_defs["ZEPHYR_TOOLCHAIN_VARIANT"] == "cross-compile" - assert config.cmake_defs["CROSS_COMPILE"] == "/usr/bin/arm-none-eabi-" +@pytest.fixture +def llvm_exists(mockfs): + llvm_file = mockfs / "usr" / "bin" / "x86_64-pc-linux-gnu-clang" + llvm_file.parent.mkdir(parents=True) + llvm_file.write_text("") + + +@pytest.fixture +def host_toolchain_exists(mockfs, monkeypatch): + monkeypatch.setattr(os, "environ", {}) + + gcc_file = mockfs / "usr" / "bin" / "gcc" + gcc_file.parent.mkdir(parents=True) + gcc_file.write_text("") + + +@pytest.fixture +def zephyr_exists(mockfs): + zephyr_sdk_version_file = mockfs / "opt" / "zephyr-sdk" / "sdk_version" + zephyr_sdk_version_file.parent.mkdir(parents=True) + zephyr_sdk_version_file.write_text("") + + +@pytest.fixture +def fake_project(tmp_path): + return project.Project( + tmp_path, + config_dict={ + "board": "foo", + "supported-zephyr-versions": ["v2.6"], + "supported-toolchains": [ + "coreboot-sdk", + "host", + "llvm", + "zephyr", + ], + "output-type": "raw", + }, + ) + + +module_paths = { + "ec": pathlib.Path("/mnt/host/source/src/platform/ec"), +} + + +def test_coreboot_sdk(fake_project, coreboot_sdk_exists): + tc = fake_project.get_toolchain(module_paths) + assert isinstance(tc, toolchains.CorebootSdkToolchain) + + config = tc.get_build_config() + assert config.cmake_defs == { + "ZEPHYR_TOOLCHAIN_VARIANT": "coreboot-sdk", + "TOOLCHAIN_ROOT": "/mnt/host/source/src/platform/ec/zephyr", + } + + +def test_llvm(fake_project, llvm_exists): + tc = fake_project.get_toolchain(module_paths) + assert isinstance(tc, toolchains.LlvmToolchain) + + config = tc.get_build_config() + assert config.cmake_defs == { + "ZEPHYR_TOOLCHAIN_VARIANT": "llvm", + "TOOLCHAIN_ROOT": "/mnt/host/source/src/platform/ec/zephyr", + } + + +def test_zephyr(fake_project, zephyr_exists): + tc = fake_project.get_toolchain(module_paths) + assert isinstance(tc, toolchains.ZephyrToolchain) + + config = tc.get_build_config() + assert config.cmake_defs == { + "ZEPHYR_TOOLCHAIN_VARIANT": "zephyr", + "ZEPHYR_SDK_INSTALL_DIR": str(pathlib.Path("/opt/zephyr-sdk")), + } + assert config.environ_defs == { + "ZEPHYR_SDK_INSTALL_DIR": str(pathlib.Path("/opt/zephyr-sdk")), + } + + +def test_zephyr_from_env(mockfs, monkeypatch, fake_project): + zephyr_sdk_path = mockfs / "zsdk" + zephyr_sdk_path.mkdir() + + environ = {"ZEPHYR_SDK_INSTALL_DIR": str(zephyr_sdk_path)} + monkeypatch.setattr(os, "environ", environ) + + tc = fake_project.get_toolchain(module_paths) + assert isinstance(tc, toolchains.ZephyrToolchain) + + config = tc.get_build_config() + assert config.cmake_defs == { + "ZEPHYR_TOOLCHAIN_VARIANT": "zephyr", + "ZEPHYR_SDK_INSTALL_DIR": str(zephyr_sdk_path), + } + assert config.environ_defs == { + "ZEPHYR_SDK_INSTALL_DIR": str(zephyr_sdk_path), + } + + +def test_host_toolchain(fake_project, host_toolchain_exists): + tc = fake_project.get_toolchain(module_paths) + assert isinstance(tc, toolchains.HostToolchain) + + config = tc.get_build_config() + assert config.cmake_defs == { + "ZEPHYR_TOOLCHAIN_VARIANT": "host", + } + + +def test_toolchain_override(mockfs, fake_project): + tc = fake_project.get_toolchain(module_paths, override="foo") + config = tc.get_build_config() + assert isinstance(tc, toolchains.GenericToolchain) + assert config.cmake_defs == {"ZEPHYR_TOOLCHAIN_VARIANT": "foo"} diff --git a/zephyr/zmake/tests/test_version.py b/zephyr/zmake/tests/test_version.py index 8fb4a09435..44997f94da 100644 --- a/zephyr/zmake/tests/test_version.py +++ b/zephyr/zmake/tests/test_version.py @@ -54,8 +54,8 @@ def _setup_example_repos(tmp_path): project_path, config_dict={ "board": "foo", - "toolchain": "bar", "output-type": "raw", + "supported-toolchains": ["coreboot-sdk"], "supported-zephyr-versions": ["v2.6"], }, ) diff --git a/zephyr/zmake/tests/test_zmake.py b/zephyr/zmake/tests/test_zmake.py index f7978764f8..641f9f3db9 100644 --- a/zephyr/zmake/tests/test_zmake.py +++ b/zephyr/zmake/tests/test_zmake.py @@ -19,6 +19,7 @@ import zmake.build_config import zmake.jobserver import zmake.multiproc as multiproc import zmake.project +import zmake.toolchains import zmake.zmake as zm OUR_PATH = os.path.dirname(os.path.realpath(__file__)) @@ -49,6 +50,12 @@ class FakeProject: def find_dts_overlays(self, module_paths): return zmake.build_config.BuildConfig() + def get_toolchain(self, module_paths, override=None): + return zmake.toolchains.GenericToolchain( + override or "foo", + modules=module_paths, + ) + class FakeJobserver(zmake.jobserver.GNUMakeJobServer): """A fake jobserver which just runs 'cat' on the provided files""" diff --git a/zephyr/zmake/zmake/project.py b/zephyr/zmake/zmake/project.py index 956971a52a..84151a90b3 100644 --- a/zephyr/zmake/zmake/project.py +++ b/zephyr/zmake/zmake/project.py @@ -12,6 +12,7 @@ import yaml import zmake.build_config as build_config import zmake.modules as modules import zmake.output_packers as packers +import zmake.toolchains as toolchains import zmake.util as util # The version of jsonschema in the chroot has a bunch of @@ -55,7 +56,12 @@ class ProjectConfig: validator = jsonschema.Draft7Validator schema = { "type": "object", - "required": ["supported-zephyr-versions", "board", "output-type", "toolchain"], + "required": [ + "board", + "output-type", + "supported-toolchains", + "supported-zephyr-versions", + ], "properties": { "supported-zephyr-versions": { "type": "array", @@ -80,8 +86,12 @@ class ProjectConfig: "type": "string", "enum": list(packers.packer_registry), }, - "toolchain": { - "type": "string", + "supported-toolchains": { + "type": "array", + "items": { + "type": "string", + "enum": list(toolchains.support_classes), + }, }, "is-test": { "type": "boolean", @@ -120,8 +130,8 @@ class ProjectConfig: return packers.packer_registry[self.config_dict["output-type"]] @property - def toolchain(self): - return self.config_dict["toolchain"] + def supported_toolchains(self): + return self.config_dict["supported-toolchains"] @property def is_test(self): @@ -211,3 +221,28 @@ class Project: "available.".format(module, self.project_dir) ) from e return result + + def get_toolchain(self, module_paths, override=None): + if override: + if override not in self.config.supported_toolchains: + logging.warning( + "Toolchain %r isn't supported by this project. You're on your own.", + override, + ) + support_class = toolchains.support_classes.get( + override, toolchains.GenericToolchain + ) + return support_class(name=override, modules=module_paths) + else: + for name in self.config.supported_toolchains: + support_class = toolchains.support_classes[name] + toolchain = support_class(name=name, modules=module_paths) + if toolchain.probe(): + logging.info("Toolchain %r selected by probe function.", toolchain) + return toolchain + raise OSError( + "No supported toolchains could be found on your system. If you see " + "this message in the chroot, it indicates a bug. Otherwise, you'll " + "either want to setup your system with a supported toolchain, or " + "manually select an unsupported toolchain with the -t flag." + ) diff --git a/zephyr/zmake/zmake/toolchains.py b/zephyr/zmake/zmake/toolchains.py index b07a2080d6..924448aec5 100644 --- a/zephyr/zmake/zmake/toolchains.py +++ b/zephyr/zmake/zmake/toolchains.py @@ -3,88 +3,152 @@ # found in the LICENSE file. """Definitions of toolchain variables.""" -import glob import os import pathlib import zmake.build_config as build_config -def find_zephyr_sdk(): - """Find the Zephyr SDK, if it's installed. +class GenericToolchain: + """Default toolchain if not known to zmake. - Returns: - The path to the Zephyr SDK, using the search rules defined by - https://docs.zephyrproject.org/latest/getting_started/installation_linux.html + Simply pass ZEPHYR_TOOLCHAIN_VARIANT=name to the build, with + nothing extra. """ - def _gen_sdk_paths(): - yield os.getenv("ZEPHYR_SDK_INSTALL_DIR") - - for searchpath in ( - "~/zephyr-sdk", - "~/.local/zephyr-sdk", - "~/.local/opt/zephyr-sdk", - "~/bin/zephyr-sdk", - "/opt/zephyr-sdk", - "/usr/zephyr-sdk", - "/usr/local/zephyr-sdk", - ): - for suffix in ("", "-*"): - yield from glob.glob(os.path.expanduser(searchpath + suffix)) - - for path in _gen_sdk_paths(): - if not path: - continue - path = pathlib.Path(path) - if (path / "sdk_version").is_file(): - return path - - raise OSError("Unable to find the Zephyr SDK") - - -# Mapping of toolchain names -> (λ (module-paths) build-config) -toolchains = { - "coreboot-sdk": lambda modules: build_config.BuildConfig( - cmake_defs={ - "TOOLCHAIN_ROOT": str(modules["ec"] / "zephyr"), - "ZEPHYR_TOOLCHAIN_VARIANT": "coreboot-sdk", - } - ), - "llvm": lambda modules: build_config.BuildConfig( - cmake_defs={ - "TOOLCHAIN_ROOT": str(modules["ec"] / "zephyr"), - "ZEPHYR_TOOLCHAIN_VARIANT": "llvm", - } - ), - "zephyr": lambda _: build_config.BuildConfig( - cmake_defs={ - "ZEPHYR_TOOLCHAIN_VARIANT": "zephyr", - "ZEPHYR_SDK_INSTALL_DIR": str(find_zephyr_sdk()), - }, - environ_defs={"ZEPHYR_SDK_INSTALL_DIR": str(find_zephyr_sdk())}, - ), - "arm-none-eabi": lambda _: build_config.BuildConfig( - cmake_defs={ - "ZEPHYR_TOOLCHAIN_VARIANT": "cross-compile", - "CROSS_COMPILE": "/usr/bin/arm-none-eabi-", + def __init__(self, name, modules=None): + self.name = name + self.modules = modules or {} + + def probe(self): + """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 + # zmake.yaml 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): + def probe(self): + # For now, we always assume it's at /opt/coreboot-sdk, since + # that's where it's installed in the chroot. We may want to + # consider adding support for a coreboot-sdk built in the + # user's home directory, for example, which happens if a + # "make crossgcc" is done from the coreboot repository. + return pathlib.Path("/opt/coreboot-sdk").is_dir() + + def get_build_config(self): + return ( + build_config.BuildConfig( + cmake_defs={ + "TOOLCHAIN_ROOT": str(self.modules["ec"] / "zephyr"), + }, + ) + | super().get_build_config() + ) + + +class ZephyrToolchain(GenericToolchain): + 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): + assert self.zephyr_sdk_install_dir + tc_vars = { + "ZEPHYR_SDK_INSTALL_DIR": str(self.zephyr_sdk_install_dir), } - ), -} + return ( + build_config.BuildConfig( + environ_defs=tc_vars, + cmake_defs=tc_vars, + ) + | super().get_build_config() + ) -def get_toolchain(name, module_paths): - """Get a toolchain by name. +class LlvmToolchain(GenericToolchain): + def probe(self): + # TODO: differentiate chroot llvm path vs. something more + # generic? + return pathlib.Path("/usr/bin/x86_64-pc-linux-gnu-clang").exists() - Args: - name: The name of the toolchain. - module_paths: Dictionary mapping module names to paths. + 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() + ) - Returns: - The corresponding BuildConfig from the defined toolchains, if - one exists, otherwise a simple BuildConfig which sets - ZEPHYR_TOOLCHAIN_VARIANT to the corresponding name. - """ - if name in toolchains: - return toolchains[name](module_paths) - return build_config.BuildConfig(cmake_defs={"ZEPHYR_TOOLCHAIN_VARIANT": name}) + +class HostToolchain(GenericToolchain): + 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, +} diff --git a/zephyr/zmake/zmake/zmake.py b/zephyr/zmake/zmake/zmake.py index 58afdbfec0..2559a16c45 100644 --- a/zephyr/zmake/zmake/zmake.py +++ b/zephyr/zmake/zmake/zmake.py @@ -16,7 +16,6 @@ import zmake.jobserver import zmake.modules import zmake.multiproc import zmake.project -import zmake.toolchains as toolchains import zmake.util as util import zmake.version @@ -260,10 +259,8 @@ class Zmake: dts_overlay_config = project.find_dts_overlays(module_paths) - if not toolchain: - toolchain = project.config.toolchain - - toolchain_config = toolchains.get_toolchain(toolchain, module_paths) + toolchain_support = project.get_toolchain(module_paths, override=toolchain) + toolchain_config = toolchain_support.get_build_config() if bringup: base_config |= zmake.build_config.BuildConfig( |