From 21ae1bf6e5d487a155dafbee65dd2dc3b5d3300e Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Sat, 5 Aug 2023 11:35:56 +0100 Subject: [PATCH 1/4] tests: Pass a mock C compiler to detect_cpu(), detect_cpu_family() In some cases the desired result can be different if there are no compilers at all. The expectations here are based on there being at least one compiler, so reflect that by providing one; a later test enhancement can cover the case where there are no compilers provided. As a result of the mock any_compiler_has_define(), all that matters will be the distinction between an empty or non-empty dict: the compiler object itself is unused. Signed-off-by: Simon McVittie --- unittests/internaltests.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/unittests/internaltests.py b/unittests/internaltests.py index 672a5a069bc6..ea4231a7c0a0 100644 --- a/unittests/internaltests.py +++ b/unittests/internaltests.py @@ -1596,16 +1596,18 @@ def mock_trial(value: str) -> T.Iterable[None]: ('aarch64_be', 'aarch64'), ] + cc = ClangCCompiler([], [], 'fake', MachineChoice.HOST, False, mock.Mock()) + with mock.patch('mesonbuild.environment.any_compiler_has_define', mock.Mock(return_value=False)): for test, expected in cases: with self.subTest(test, has_define=False), mock_trial(test): - actual = mesonbuild.environment.detect_cpu_family({}) + actual = mesonbuild.environment.detect_cpu_family({'c': cc}) self.assertEqual(actual, expected) with mock.patch('mesonbuild.environment.any_compiler_has_define', mock.Mock(return_value=True)): for test, expected in [('x86_64', 'x86'), ('aarch64', 'arm'), ('ppc', 'ppc64'), ('mips64', 'mips64')]: with self.subTest(test, has_define=True), mock_trial(test): - actual = mesonbuild.environment.detect_cpu_family({}) + actual = mesonbuild.environment.detect_cpu_family({'c': cc}) self.assertEqual(actual, expected) def test_detect_cpu(self) -> None: @@ -1633,16 +1635,18 @@ def mock_trial(value: str) -> T.Iterable[None]: ('aarch64_be', 'aarch64'), ] + cc = ClangCCompiler([], [], 'fake', MachineChoice.HOST, False, mock.Mock()) + with mock.patch('mesonbuild.environment.any_compiler_has_define', mock.Mock(return_value=False)): for test, expected in cases: with self.subTest(test, has_define=False), mock_trial(test): - actual = mesonbuild.environment.detect_cpu({}) + actual = mesonbuild.environment.detect_cpu({'c': cc}) self.assertEqual(actual, expected) with mock.patch('mesonbuild.environment.any_compiler_has_define', mock.Mock(return_value=True)): for test, expected in [('x86_64', 'i686'), ('aarch64', 'arm'), ('ppc', 'ppc64'), ('mips64', 'mips64')]: with self.subTest(test, has_define=True), mock_trial(test): - actual = mesonbuild.environment.detect_cpu({}) + actual = mesonbuild.environment.detect_cpu({'c': cc}) self.assertEqual(actual, expected) def test_interpreter_unpicklable(self) -> None: From 40966374e133a785a90556131435aec771e3916a Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Sat, 5 Aug 2023 11:13:53 +0100 Subject: [PATCH 2/4] environment: Assume that mips64 can run 32-bit mips binaries The relationship between mips64 and mips is similar to the relationship between x86_64 and x86. Representing it here is necessary so that we will not require an exe_wrapper when cross-compiling for 32-bit mips on mips64, or when a complete 32-bit mips user-space runs on a 64-bit kernel without using linux32 to alter uname(2) to pretend to be 32-bit. Signed-off-by: Simon McVittie --- mesonbuild/environment.py | 1 + 1 file changed, 1 insertion(+) diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py index ce7c9f1e6c02..9e8176575aa7 100644 --- a/mesonbuild/environment.py +++ b/mesonbuild/environment.py @@ -469,6 +469,7 @@ def machine_info_can_run(machine_info: MachineInfo): return \ (machine_info.cpu_family == true_build_cpu_family) or \ ((true_build_cpu_family == 'x86_64') and (machine_info.cpu_family == 'x86')) or \ + ((true_build_cpu_family == 'mips64') and (machine_info.cpu_family == 'mips')) or \ ((true_build_cpu_family == 'aarch64') and (machine_info.cpu_family == 'arm')) class Environment: From b64a0937a57e072913bc891ca22f73281f4c4a46 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Sat, 5 Aug 2023 11:34:29 +0100 Subject: [PATCH 3/4] environment: Don't override mips64 to mips if no compilers are available If we have a build- or host-architecture compiler, we can detect mips64 vs. mips by the fact that mips64 compilers define __mips64. However, machine_info_can_run() doesn't provide any compilers, because it is interested in the architecture of the underlying kernel. If we don't return mips64 when running on a mips64 kernel, machine_info_can_run() will wrongly say that we can't run mips64 binaries. If we're running a complete 32-bit mips user-space on a mips64 kernel, it's OK to return mips64 in the absence of any compilers, as a result of the previous commit "environment: Assume that mips64 can run 32-bit mips binaries". Resolves: https://github.com/mesonbuild/meson/issues/12017 Bug-Debian: https://bugs.debian.org/1041499 Fixes: 6def03c7 "detect_cpu: Fix mips32 detection on mips64" Signed-off-by: Simon McVittie --- mesonbuild/environment.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py index 9e8176575aa7..d22fc2904710 100644 --- a/mesonbuild/environment.py +++ b/mesonbuild/environment.py @@ -343,7 +343,7 @@ def detect_cpu_family(compilers: CompilersDict) -> str: # MIPS64 is able to run MIPS32 code natively, so there is a chance that # such mixture mentioned above exists. elif trial == 'mips64': - if not any_compiler_has_define(compilers, '__mips64'): + if compilers and not any_compiler_has_define(compilers, '__mips64'): trial = 'mips' if trial not in known_cpu_families: @@ -383,7 +383,7 @@ def detect_cpu(compilers: CompilersDict) -> str: if '64' not in trial: trial = 'mips' else: - if not any_compiler_has_define(compilers, '__mips64'): + if compilers and not any_compiler_has_define(compilers, '__mips64'): trial = 'mips' else: trial = 'mips64' From 9569d68118191419017dceeccaefbf20ca19a9b7 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Sat, 5 Aug 2023 11:40:04 +0100 Subject: [PATCH 4/4] tests: Assert that mips64 kernel is detected as mips64 with no compilers Reproduces: https://github.com/mesonbuild/meson/issues/12017 Signed-off-by: Simon McVittie --- unittests/internaltests.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/unittests/internaltests.py b/unittests/internaltests.py index ea4231a7c0a0..b4d090dd29c3 100644 --- a/unittests/internaltests.py +++ b/unittests/internaltests.py @@ -1610,6 +1610,16 @@ def mock_trial(value: str) -> T.Iterable[None]: actual = mesonbuild.environment.detect_cpu_family({'c': cc}) self.assertEqual(actual, expected) + # machine_info_can_run calls detect_cpu_family with no compilers at all + with mock.patch( + 'mesonbuild.environment.any_compiler_has_define', + mock.Mock(side_effect=AssertionError('Should not be called')), + ): + for test, expected in [('mips64', 'mips64')]: + with self.subTest(test, has_compiler=False), mock_trial(test): + actual = mesonbuild.environment.detect_cpu_family({}) + self.assertEqual(actual, expected) + def test_detect_cpu(self) -> None: @contextlib.contextmanager @@ -1649,6 +1659,15 @@ def mock_trial(value: str) -> T.Iterable[None]: actual = mesonbuild.environment.detect_cpu({'c': cc}) self.assertEqual(actual, expected) + with mock.patch( + 'mesonbuild.environment.any_compiler_has_define', + mock.Mock(side_effect=AssertionError('Should not be called')), + ): + for test, expected in [('mips64', 'mips64')]: + with self.subTest(test, has_compiler=False), mock_trial(test): + actual = mesonbuild.environment.detect_cpu({}) + self.assertEqual(actual, expected) + def test_interpreter_unpicklable(self) -> None: build = mock.Mock() build.environment = mock.Mock()