From patchwork Sun Aug 2 19:53:01 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: AdrianF X-Patchwork-Id: 94252 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 65CC9C55197 for ; Sun, 2 Aug 2026 19:53:55 +0000 (UTC) Received: from mta-64-228.siemens.flowmailer.net (mta-64-228.siemens.flowmailer.net [185.136.64.228]) by mx.groups.io with SMTP id smtpd.msgproc01-g2.29332.1785700422645016214 for ; Sun, 02 Aug 2026 12:53:43 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=adrian.freihofer@siemens.com header.s=fm1 header.b=S+/QlOnx; spf=pass (domain: rts-flowmailer.siemens.com, ip: 185.136.64.228, mailfrom: fm-1329275-202608021953403fb33a7e180002079c-p7svo6@rts-flowmailer.siemens.com) Received: by mta-64-228.siemens.flowmailer.net with ESMTPSA id 202608021953403fb33a7e180002079c for ; Sun, 02 Aug 2026 21:53:41 +0200 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; s=fm1; d=siemens.com; i=adrian.freihofer@siemens.com; h=Date:From:Subject:To:Message-ID:MIME-Version:Content-Type:Content-Transfer-Encoding:Cc:References:In-Reply-To; bh=VlBbab+b47jjuu6VBG+Za41cQO3xmLB1NKGzvLZaJt8=; b=S+/QlOnxUyq27QESFlVu4JKCj4EspA8acTo7jwtM7CD1F9Z7mW5Xgr/zjG1hJe8Er2rB1y y/EOVG4+hTWgSoEGzc8GLI31XF3dM24ygBc4q+7JKow2Oo14NpR9pfk6xqD8DNE7Loe/xnth 5L8JhK4gWZB14A9jObCU6PbkH2qKqAH2iP/Le+GMM4BeNzI8jrzhESvIXxFPc5xJlwywL1wU kcTnfatJx4nAdLN6Es98T6mW2rnd/Dm+EjgHalDAqdNKOpLfKH9bzO6NKuRCfz9+M/paOscJ Od8vsCkrrZGQs5ZJIoiUEa8MgJSWSfajw2R4xSlp/i28ee3VeipC53Ag==; From: AdrianF To: openembedded-core@lists.openembedded.org Cc: Adrian Freihofer Subject: [PATCH 14/14] oe-selftest: devtool ide-sdk: add test for ide=none LLDB/clang support Date: Sun, 2 Aug 2026 21:53:01 +0200 Message-ID: <20260802195324.64533-15-adrian.freihofer@siemens.com> In-Reply-To: <20260802195324.64533-1-adrian.freihofer@siemens.com> References: <20260802195324.64533-1-adrian.freihofer@siemens.com> MIME-Version: 1.0 X-Flowmailer-Platform: Siemens Feedback-ID: 519:519-1329275:519-21489:flowmailer List-Id: X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com [45.33.107.173] by aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Sun, 02 Aug 2026 19:53:55 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/242575 From: Adrian Freihofer Add test_devtool_ide_sdk_none_cmake_clang to DevtoolIdeSdkTests to exercise the new LldbServerConfigNone code path in ide_none.py. The test uses the cmake-example-clang recipe (TOOLCHAIN = "clang") and runs devtool ide-sdk with --ide=none. It verifies: - lldb_server___multi script is generated - lldbinit/lldbinit__ init file is generated - lldb__ wrapper script is generated - No gdbserver_* script is generated for a clang recipe - The install_and_deploy script exists - The oe-scripts symlink inside the source tree is valid - lldb-server can be started on the target via the generated script - The pid file written by the start script references the live process - An lldb --batch session using the generated wrapper reaches main and can evaluate CppExample::test_string at the breakpoint - lldb-server stops cleanly via the generated stop script A new helper _lldb_none_debugging_multi is added alongside the existing _gdb_cross_debugging_multi, following the same structure. Signed-off-by: Adrian Freihofer --- meta/lib/oeqa/selftest/cases/devtool.py | 192 ++++++++++++++++++++++++ 1 file changed, 192 insertions(+) diff --git a/meta/lib/oeqa/selftest/cases/devtool.py b/meta/lib/oeqa/selftest/cases/devtool.py index e9b8f38449..7145755fed 100644 --- a/meta/lib/oeqa/selftest/cases/devtool.py +++ b/meta/lib/oeqa/selftest/cases/devtool.py @@ -4378,6 +4378,198 @@ class DevtoolIdeSdkTests(DevtoolBase): lambda magic_string: self._lldb_server_debugging_once( tempdir, qemu, magic_string)) + def _lldb_none_debugging_multi(self, tempdir, qemu, recipe_name, example_exe, magic_string): + """Verify lldb-server scripts generated by ide=none work end-to-end. + + Mirrors _gdb_cross_debugging_multi but for the LLDB/clang path: + - uses the generated lldb_server_* start/stop script + - uses the generated lldb_* wrapper script with lldb --batch + + Covers the executable, the library and a header-only inline function + (see _lldb_debug_cpp_example_batch_commands), since a single call-site + breakpoint would not exercise (and thus not catch a regression in) the + lldbinit source map / debug-file-search-paths setup for the library's + own debug info specifically. + """ + sshargs = '-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no' + scripts_dir = self._workspace_scripts_dir(recipe_name) + binary_pretty = 'usr-bin-' + example_exe + lldb_server_script = os.path.join( + scripts_dir, 'lldb_server_1234_%s_multi' % binary_pretty) + lldb_script = os.path.join(scripts_dir, 'lldb_1234_%s' % binary_pretty) + + self.assertExists(lldb_server_script) + self.assertExists(lldb_script) + + # Start lldb-server (script exits once the port is ready) + r = runCmd(lldb_server_script, output_log=self._cmd_logger) + self.assertEqual(r.status, 0) + + # Verify lldb-server is running on the target + r = runCmd('ssh %s root@%s ps' % (sshargs, qemu.ip), + output_log=self._cmd_logger) + self.assertEqual(r.status, 0) + self.assertIn('lldb-server', r.output) + + # Verify the pid file points at the running lldb-server process + pid_file = '/tmp/lldb_server_1234_%s_multi/lldb_server.pid' % binary_pretty + test_cmd = "'cat /proc/$(cat %s)/cmdline'" % pid_file + r = runCmd('ssh %s root@%s %s' % (sshargs, qemu.ip, test_cmd), + output_log=self._cmd_logger) + self.assertEqual(r.status, 0) + self.assertIn('lldb-server', r.output) + + # Run an lldb batch session covering the executable, library and + # header breakpoints, then continue to completion + lldb_batch_args = self._lldb_debug_cpp_example_batch_commands(tempdir) + r = runCmd([lldb_script, '--batch'] + lldb_batch_args, + output_log=self._cmd_logger) + self.logger.debug("lldb batch output: %s", r.output) + self.assertEqual(r.status, 0) + self._lldb_debug_cpp_example_check(r.output, magic_string) + + # Stop lldb-server + r = runCmd(lldb_server_script + ' stop', output_log=self._cmd_logger) + self.assertEqual(r.status, 0) + + # Verify lldb-server is no longer running + r = runCmd('ssh %s root@%s ps' % (sshargs, qemu.ip), + output_log=self._cmd_logger) + self.assertEqual(r.status, 0) + self.assertNotIn('lldb-server', r.output) + + @OETestTag("runqemu") + def test_devtool_ide_sdk_none_cmake_clang(self): + """Verify ide=none generates correct LLDB scripts for a clang cmake recipe. + + Uses cmake-example-clang (TOOLCHAIN = "clang") which is built with the + clang toolchain. devtool ide-sdk with --ide=none should produce: + - lldb_server___multi (start/stop script) + - lldbinit/lldbinit__ (platform connect + source maps) + - lldb__ (lldb wrapper) + + The test verifies that lldb-server can be started via the generated + script, and that a basic lldb --batch debugging session reaches main. + """ + recipe_name = 'cmake-example-clang' + example_exe = 'cmake-example-clang' + build_file = 'CMakeLists.txt' + testimage = 'oe-selftest-image' + + self._check_workspace() + self._write_bb_config([recipe_name], extra_packages=['lldb-server']) + self._check_runqemu_prerequisites() + bitbake(testimage) + with runqemu(testimage, runqemuparams='nographic') as qemu: + tempdir = self._devtool_ide_sdk_recipe(recipe_name, build_file, testimage) + bitbake_sdk_cmd = 'devtool ide-sdk %s %s -t root@%s -c --ide=none' % ( + recipe_name, testimage, qemu.ip) + runCmd(bitbake_sdk_cmd, output_log=self._cmd_logger) + + # Verify cmake preset still works (build system unchanged) + compile_cmd = self._verify_cmake_preset(tempdir) + + # Verify install && deploy script exists + # (_verify_install_script_code opens .vscode/tasks.json which is not + # generated for ide=none; check the script path directly instead) + recipe_id, _ = self._get_recipe_ids(recipe_name) + scripts_dir = self._workspace_scripts_dir(recipe_name) + self.assertExists(os.path.join( + scripts_dir, 'install_and_deploy_' + recipe_id)) + + # Verify LLDB scripts were generated (not GDB scripts) + binary_pretty = 'usr-bin-' + example_exe + self.assertExists(os.path.join( + scripts_dir, 'lldb_server_1234_%s_multi' % binary_pretty)) + self.assertExists(os.path.join( + scripts_dir, 'lldbinit', 'lldbinit_1234_%s' % binary_pretty)) + self.assertExists(os.path.join( + scripts_dir, 'lldb_1234_%s' % binary_pretty)) + # No GDB scripts should have been generated for a clang recipe + self.assertFalse(os.path.exists(os.path.join( + scripts_dir, 'gdbserver_1234_%s_multi' % binary_pretty)), + 'gdbserver script should not be generated for clang recipe') + + # Verify the oe-scripts sym-link is valid + self.assertEqual(self._workspace_scripts_dir(recipe_name), + self._sources_scripts_dir(tempdir)) + + # Verify end-to-end lldb debugging, before and after a code + # change/recompile/redeploy cycle (see _lldb_cross_debugging_multi) + self._lldb_cross_debugging_multi( + tempdir, recipe_name, compile_cmd, + lambda magic_string: self._lldb_none_debugging_multi( + tempdir, qemu, recipe_name, example_exe, magic_string)) + + @OETestTag("runqemu") + def test_devtool_ide_sdk_none_meson_clang(self): + """Verify ide=none generates correct LLDB scripts for a clang meson recipe. + + This is the meson/ninja counterpart of test_devtool_ide_sdk_none_cmake_clang. + It is required in addition to the cmake/clang test because meson/ninja + (unlike cmake here) invoke the compiler with source paths relative to + the build directory, which is what previously caused source-level + breakpoints to be left unresolved (pending) for devtool workspaces due + to -fdebug-prefix-map/-ffile-prefix-map underflow; see + _lldb_none_debugging_multi. + + Uses meson-example-clang (TOOLCHAIN = "clang"). + """ + recipe_name = 'meson-example-clang' + example_exe = 'mesonex-clang' + build_file = 'meson.build' + testimage = 'oe-selftest-image' + + self._check_workspace() + self._write_bb_config([recipe_name], extra_packages=['lldb-server']) + self._check_runqemu_prerequisites() + + # Build image with debug settings (lldb-server for clang) before starting QEMU + tempdir = self._devtool_ide_sdk_recipe(recipe_name, build_file, testimage) + runCmd('devtool ide-sdk %s %s -c --ide=none' % (recipe_name, testimage), + output_log=self._cmd_logger) + + with runqemu(testimage, runqemuparams='nographic') as qemu: + # Re-run with actual QEMU IP; image is already built + bitbake_sdk_cmd = 'devtool ide-sdk %s %s -t root@%s -c --skip-bitbake --ide=none' % ( + recipe_name, testimage, qemu.ip) + runCmd(bitbake_sdk_cmd, output_log=self._cmd_logger) + + # Verify the meson build system still works (unchanged by clang/lldb support) + compile_cmd = self._verify_meson_build(tempdir, recipe_name) + + # Verify install && deploy script exists + # (_verify_install_script_code opens .vscode/tasks.json which is not + # generated for ide=none; check the script path directly instead) + recipe_id, _ = self._get_recipe_ids(recipe_name) + scripts_dir = self._workspace_scripts_dir(recipe_name) + self.assertExists(os.path.join( + scripts_dir, 'install_and_deploy_' + recipe_id)) + + # Verify LLDB scripts were generated (not GDB scripts) + binary_pretty = 'usr-bin-' + example_exe + self.assertExists(os.path.join( + scripts_dir, 'lldb_server_1234_%s_multi' % binary_pretty)) + self.assertExists(os.path.join( + scripts_dir, 'lldbinit', 'lldbinit_1234_%s' % binary_pretty)) + self.assertExists(os.path.join( + scripts_dir, 'lldb_1234_%s' % binary_pretty)) + # No GDB scripts should have been generated for a clang recipe + self.assertFalse(os.path.exists(os.path.join( + scripts_dir, 'gdbserver_1234_%s_multi' % binary_pretty)), + 'gdbserver script should not be generated for clang recipe') + + # Verify the oe-scripts sym-link is valid + self.assertEqual(self._workspace_scripts_dir(recipe_name), + self._sources_scripts_dir(tempdir)) + + # Verify end-to-end lldb debugging, before and after a code + # change/recompile/redeploy cycle (see _lldb_cross_debugging_multi) + self._lldb_cross_debugging_multi( + tempdir, recipe_name, compile_cmd, + lambda magic_string: self._lldb_none_debugging_multi( + tempdir, qemu, recipe_name, example_exe, magic_string)) + def test_devtool_ide_sdk_plugins(self): """Test that devtool ide-sdk can use plugins from other layers."""