diff --git a/docs/runtimes.md b/docs/runtimes.md index b2262ad..991cae5 100644 --- a/docs/runtimes.md +++ b/docs/runtimes.md @@ -16,9 +16,14 @@ The following runtimes are available: ## null -The default runtime. Assumes you have any necessary toolchain installed on your -system. If you request a build that requires a (cross) toolchain you don't have -installed locally, the build will just fail. +The default runtime. Uses toolchains installed on your system. You need to +install any required (cross) compilers yourself. For example, to cross-compile +for arm64 on Debian you would need to install `gcc-aarch64-linux-gnu`. + +If a required compiler is not installed, the build will fail. + +The support matrix (`tuxmake -p`) checks which compilers are available in your +`$PATH` and only reports combinations as supported when the compiler is found. ## docker diff --git a/test/conftest.py b/test/conftest.py index a9cc2c4..d8c4342 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -63,6 +63,8 @@ def fake_cross_compilers(tmpdir_factory): binary = arch.makevars["CROSS_COMPILE"] + tool if not shutil.which(binary): missing[binary] = tool + if not shutil.which("clang"): + missing["clang"] = "true" if missing: testbin = tmpdir_factory.mktemp("bin") for p, real in missing.items(): diff --git a/test/integration/fakelinux b/test/integration/fakelinux index b0680ae..1ed16b4 100755 --- a/test/integration/fakelinux +++ b/test/integration/fakelinux @@ -132,6 +132,7 @@ test_dtbs() { } test_dtbs_armv5() { + skip_if not program_installed arm-linux-gnueabi-gcc run tuxmake --target-arch=armv5 dtbs assertTrue "build dtbs on armv5" "grep 'dtbs: PASS' stderr" } diff --git a/test/test_build.py b/test/test_build.py index 6ac4e05..3fa2be4 100644 --- a/test/test_build.py +++ b/test/test_build.py @@ -889,7 +889,7 @@ def test_errors(self, build): class TestUnsupportedToolchainArchitectureCombination: def test_exception(self, linux, mocker): - mocker.patch("tuxmake.runtime.Runtime.is_supported", return_value=False) + mocker.patch("tuxmake.runtime.NullRuntime.is_supported", return_value=False) with pytest.raises( tuxmake.exceptions.UnsupportedArchitectureToolchainCombination ): diff --git a/test/test_runtime.py b/test/test_runtime.py index 73491a9..3b73929 100644 --- a/test/test_runtime.py +++ b/test/test_runtime.py @@ -2,6 +2,7 @@ import subprocess import pytest +from tuxmake.arch import Architecture from tuxmake.build import Build from tuxmake.exceptions import InvalidRuntimeError from tuxmake.exceptions import RuntimePreparationFailed @@ -13,6 +14,7 @@ from tuxmake.runtime import PodmanRuntime from tuxmake.runtime import PodmanLocalRuntime from tuxmake.runtime import Terminated +from tuxmake.toolchain import Toolchain @pytest.fixture @@ -81,6 +83,14 @@ def test_create_output_directory_on_prepare_already_exists(self, tmp_path): assert runtime.output_dir.exists() +class TestRuntimeIsSupported: + def test_base_class_returns_true(self): + runtime = Runtime.get("docker") + arch = Architecture("x86_64") + toolchain = Toolchain("gcc") + assert Runtime.is_supported(runtime, arch, toolchain) is True + + class TestNullRuntime: def test_get_command_line(self, build): assert NullRuntime().get_command_line( @@ -91,6 +101,20 @@ def test_toolchains(self): runtime = NullRuntime() assert "gcc" in runtime.toolchains + def test_is_supported_compiler_found(self, mocker): + mocker.patch("shutil.which", return_value="/usr/bin/gcc") + runtime = NullRuntime() + arch = Architecture("x86_64") + toolchain = Toolchain("gcc") + assert runtime.is_supported(arch, toolchain) is True + + def test_is_supported_compiler_not_found(self, mocker): + mocker.patch("shutil.which", return_value=None) + runtime = NullRuntime() + arch = Architecture("x86_64") + toolchain = Toolchain("gcc") + assert runtime.is_supported(arch, toolchain) is False + @pytest.fixture def container_id(): diff --git a/tuxmake/runtime.py b/tuxmake/runtime.py index 3520e13..bbea49c 100644 --- a/tuxmake/runtime.py +++ b/tuxmake/runtime.py @@ -2,6 +2,7 @@ import re import json import shlex +import shutil import subprocess import sys import time @@ -361,6 +362,10 @@ def run_cmd( class NullRuntime(Runtime): name = "null" + def is_supported(self, arch, toolchain): + compiler = toolchain.compiler(arch) + return shutil.which(compiler) is not None + class Image: def __init__(