diff mbox series

[4/4] oeqa/selftest: add new test for toolchain switching

Message ID 20250617171332.3162295-4-ross.burton@arm.com
State New
Headers show
Series [1/4] oeqa/utils/command: fast-path get_bb_var() | expand

Commit Message

Ross Burton June 17, 2025, 5:13 p.m. UTC
Add a basic test for the toolchain switching code: set the
toolchain to GCC by default but Clang for a specific recipe, and verify
that two recipes are built with the expected compiler.

This works because before we strip the installed binaries there is a
.comment segment that contains the list of toolchains used.

Signed-off-by: Ross Burton <ross.burton@arm.com>
---
 meta/lib/oeqa/selftest/cases/toolchain.py | 71 +++++++++++++++++++++++
 1 file changed, 71 insertions(+)
 create mode 100644 meta/lib/oeqa/selftest/cases/toolchain.py
diff mbox series

Patch

diff --git a/meta/lib/oeqa/selftest/cases/toolchain.py b/meta/lib/oeqa/selftest/cases/toolchain.py
new file mode 100644
index 00000000000..b4b280d0375
--- /dev/null
+++ b/meta/lib/oeqa/selftest/cases/toolchain.py
@@ -0,0 +1,71 @@ 
+#
+# Copyright OpenEmbedded Contributors
+#
+# SPDX-License-Identifier: MIT
+#
+
+import shutil
+import subprocess
+import tempfile
+from types import SimpleNamespace
+
+import oe.path
+from oeqa.selftest.case import OESelftestTestCase
+from oeqa.utils.commands import bitbake, get_bb_var, get_bb_vars
+
+class ToolchainTests(OESelftestTestCase):
+
+    def test_toolchain_switching(self):
+        """
+        Test that a configuration that uses GCC by default but clang for one
+        specific recipe does infact do that.
+        """
+
+        def extract_comment(objcopy, filename):
+            """
+            Using the specified `objcopy`, return the .comment segment from
+            `filename` as a bytes().
+            """
+            with tempfile.NamedTemporaryFile(prefix="comment-") as f:
+                cmd = [objcopy, "--dump-section", ".comment=" + f.name, filename]
+                subprocess.run(cmd, check=True)
+                # clang's objcopy writes to a temporary file and renames, so we need to re-open.
+                with open(f.name, "rb") as f2:
+                    return f2.read()
+
+        def check_recipe(recipe, filename, override, comment_present, comment_absent=None):
+            """
+            Check that `filename` in `recipe`'s bindir contains `comment`, and
+            the overrides contain `override`.
+            """
+            d = SimpleNamespace(**get_bb_vars(("D", "bindir", "OBJCOPY", "OVERRIDES", "PATH"), target=recipe))
+
+            self.assertIn(override, d.OVERRIDES)
+
+            binary = oe.path.join(d.D, d.bindir, filename)
+
+            objcopy = shutil.which(d.OBJCOPY, path=d.PATH)
+            self.assertIsNotNone(objcopy)
+
+            comment = extract_comment(objcopy, binary)
+            self.assertIn(comment_present, comment)
+            if comment_absent:
+                self.assertNotIn(comment_absent, comment)
+
+
+        # GCC by default, clang for selftest-hello.
+        self.write_config("""
+TOOLCHAIN = "gcc"
+TOOLCHAIN:pn-selftest-hello = "clang"
+        """)
+
+        # Force these recipes to re-install so we can extract the .comments from
+        # the install directory, as they're stripped out of the final packages.
+        bitbake("m4 selftest-hello -C install")
+
+        # m4 should be built with GCC and only GCC
+        check_recipe("m4", "m4", "toolchain-gcc", b"GCC: (GNU)", b"clang")
+
+        # helloworld should be built with clang. We can't assert that GCC is not
+        # present as it will be linked against glibc which is built with GCC.
+        check_recipe("selftest-hello", "helloworld", "toolchain-clang", b"clang version")