diff --git a/cmake/org.eclipse.cdt.cmake.core/META-INF/MANIFEST.MF b/cmake/org.eclipse.cdt.cmake.core/META-INF/MANIFEST.MF index 8878a08b9b4..3f9600e1d94 100644 --- a/cmake/org.eclipse.cdt.cmake.core/META-INF/MANIFEST.MF +++ b/cmake/org.eclipse.cdt.cmake.core/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %pluginName Bundle-SymbolicName: org.eclipse.cdt.cmake.core;singleton:=true -Bundle-Version: 2.0.200.qualifier +Bundle-Version: 2.1.0.qualifier Bundle-Activator: org.eclipse.cdt.cmake.core.internal.Activator Bundle-Vendor: %providerName Require-Bundle: org.eclipse.core.runtime;bundle-version="[3.34.0,4.0.0)", diff --git a/cmake/org.eclipse.cdt.cmake.core/src/org/eclipse/cdt/cmake/core/CMakeBuildConfiguration.java b/cmake/org.eclipse.cdt.cmake.core/src/org/eclipse/cdt/cmake/core/CMakeBuildConfiguration.java index 1dc38a215d2..3460aae70ee 100644 --- a/cmake/org.eclipse.cdt.cmake.core/src/org/eclipse/cdt/cmake/core/CMakeBuildConfiguration.java +++ b/cmake/org.eclipse.cdt.cmake.core/src/org/eclipse/cdt/cmake/core/CMakeBuildConfiguration.java @@ -31,6 +31,7 @@ import org.eclipse.cdt.cmake.core.properties.CMakePropertiesFactory; import org.eclipse.cdt.cmake.core.properties.ICMakeGenerator; import org.eclipse.cdt.cmake.core.properties.ICMakeProperties; +import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.CommandLauncherManager; import org.eclipse.cdt.core.ConsoleOutputStream; import org.eclipse.cdt.core.ErrorParserManager; @@ -60,8 +61,11 @@ import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.SubMonitor; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.debug.core.ILaunchManager; import org.eclipse.launchbar.core.target.ILaunchTarget; @@ -195,50 +199,14 @@ public IProject[] build(int kind, Map args, IConsole console, IP } CommandDescriptorBuilder cmdBuilder = new CommandDescriptorBuilder(cmakeProperties); if (runCMake) { - CMakeBuildConfiguration.deleteCMakeErrorMarkers(project); - - infoStream.write(String.format(Messages.CMakeBuildConfiguration_Configuring, buildDir)); - CommandDescriptor command = cmdBuilder - .makeCMakeCommandline(toolChainFile != null ? toolChainFile.getPath() : null); - // tell cmake where its script is located.. - IContainer srcFolder = project; - command.getArguments().add(new File(srcFolder.getLocationURI()).getAbsolutePath()); - - infoStream.write(String.join(" ", command.getArguments()) + '\n'); //$NON-NLS-1$ - - org.eclipse.core.runtime.Path workingDir = new org.eclipse.core.runtime.Path( - getBuildDirectory().toString()); - // hook in cmake error parsing - try (CMakeErrorParser errorParser = new CMakeErrorParser(new CMakeExecutionMarkerFactory(srcFolder))) { - ParsingConsoleOutputStream errStream = new ParsingConsoleOutputStream(console.getErrorStream(), - errorParser); - IConsole errConsole = new CMakeConsoleWrapper(console, errStream); - Process p = startBuildProcess(command.getArguments(), new IEnvironmentVariable[0], workingDir, - errConsole, monitor); - String arg0 = command.getArguments().get(0); - if (p == null) { - // process start failed - String msg = String.format(Messages.CMakeBuildConfiguration_Failure, ""); //$NON-NLS-1$ - addMarker(new ProblemMarkerInfo(srcFolder.getProject(), -1, msg, - IMarkerGenerator.SEVERITY_ERROR_BUILD, null, new org.eclipse.core.runtime.Path(arg0))); - return null; - } - - // check cmake exit status - final int exitValue = watchProcess(errConsole, monitor); - if (exitValue != 0) { - // cmake had errors... - String msg = String.format(Messages.CMakeBuildConfiguration_ExitFailure, arg0, exitValue); - addMarker(srcFolder.getProject(), -1, msg, IMarkerGenerator.SEVERITY_ERROR_BUILD, null); - return null; - } + IStatus result = configureCMakeBuildFiles(cmdBuilder, console, infoStream, monitor); + if (!result.isOK()) { + return null; } - cmakeListsModified = false; } // parse compile_commands.json file - getCompileCommandsFile().refreshLocal(IResource.DEPTH_ZERO, monitor); - processCompileCommandsFile(console, monitor); + refreshAndProcessCompileCommandsFile(console, monitor); infoStream.write(String.format(Messages.CMakeBuildConfiguration_BuildingIn, buildDir.toString())); // run the build tool... @@ -296,6 +264,89 @@ public IProject[] build(int kind, Map args, IConsole console, IP } } + /** + * Runs the CMake configure step for this build configuration without invoking + * the build target. On success, refreshes and processes compile_commands.json + * so scanner information is updated. + *

+ * This method writes to the CDT build console, deletes stale CMake execution + * markers, may create new CMake execution markers, and updates scanner + * information for this build configuration. + *

+ * Callers should run this from a background workspace operation, not directly + * from the UI thread. + * + * @param monitor progress monitor, or {@code null} + * @return {@link Status#OK_STATUS} if CMake completed successfully; otherwise + * an error status if the CMake process could not be started or exited + * non-zero + * @throws CoreException if workspace refresh, marker handling, or scanner-info + * processing fails + * @throws IOException if console/process I/O fails + * @since 2.1 + */ + public IStatus configureCMakeBuildFiles(IProgressMonitor monitor) throws CoreException, IOException { + // Setup console + IConsole console = CCorePlugin.getDefault().getConsole(); + console.start(getProject()); + ICMakeProperties cmakeProperties = getCMakeProperties(); + CommandDescriptorBuilder cmdBuilder = new CommandDescriptorBuilder(cmakeProperties); + SubMonitor subMonitor = SubMonitor.convert(monitor, 2); + IStatus result = configureCMakeBuildFiles(cmdBuilder, console, console.getInfoStream(), subMonitor.split(1)); + refreshAndProcessCompileCommandsFile(console, subMonitor.split(1)); + return result; + } + + private IStatus configureCMakeBuildFiles(CommandDescriptorBuilder cmdBuilder, IConsole console, + ConsoleOutputStream infoStream, IProgressMonitor monitor) throws CoreException, IOException { + SubMonitor subMonitor = SubMonitor.convert(monitor, 4); + CMakeBuildConfiguration.deleteCMakeErrorMarkers(getProject()); + infoStream.write(String.format(Messages.CMakeBuildConfiguration_Configuring, getBuildDirectory())); + CommandDescriptor command = cmdBuilder + .makeCMakeCommandline(toolChainFile != null ? toolChainFile.getPath() : null); + // tell cmake where its script is located.. + IContainer srcFolder = getProject(); + command.getArguments().add(new File(srcFolder.getLocationURI()).getAbsolutePath()); + + infoStream.write(String.join(" ", command.getArguments()) + '\n'); //$NON-NLS-1$ + + org.eclipse.core.runtime.Path workingDir = new org.eclipse.core.runtime.Path(getBuildDirectory().toString()); + // hook in cmake error parsing + try (CMakeErrorParser errorParser = new CMakeErrorParser(new CMakeExecutionMarkerFactory(srcFolder))) { + ParsingConsoleOutputStream errStream = new ParsingConsoleOutputStream(console.getErrorStream(), + errorParser); + IConsole errConsole = new CMakeConsoleWrapper(console, errStream); + Process p = startBuildProcess(command.getArguments(), new IEnvironmentVariable[0], workingDir, errConsole, + subMonitor.split(1)); + String arg0 = command.getArguments().get(0); + if (p == null) { + // process start failed + String msg = String.format(Messages.CMakeBuildConfiguration_Failure, "Process failed to start"); //$NON-NLS-1$ + addMarker(new ProblemMarkerInfo(srcFolder.getProject(), -1, msg, IMarkerGenerator.SEVERITY_ERROR_BUILD, + null, new org.eclipse.core.runtime.Path(arg0))); + return Status.error(msg); + } + // check cmake exit status + final int exitValue = watchProcess(errConsole, subMonitor.split(1)); + if (exitValue != 0) { + // cmake had errors... + String msg = String.format(Messages.CMakeBuildConfiguration_ExitFailure, arg0, exitValue); + addMarker(srcFolder.getProject(), -1, msg, IMarkerGenerator.SEVERITY_ERROR_BUILD, null); + return Status.error(msg); + } + } + cmakeListsModified = false; + return Status.OK_STATUS; + } + + /** + * Parse compile_commands.json file + */ + private void refreshAndProcessCompileCommandsFile(IConsole console, IProgressMonitor monitor) throws CoreException { + getCompileCommandsFile().refreshLocal(IResource.DEPTH_ZERO, monitor); + processCompileCommandsFile(console, monitor); + } + @Override public void clean(IConsole console, IProgressMonitor monitor) throws CoreException { IProject project = getProject(); diff --git a/cmake/org.eclipse.cdt.cmake.example/META-INF/MANIFEST.MF b/cmake/org.eclipse.cdt.cmake.example/META-INF/MANIFEST.MF index 8a8d68496a1..c1b0621d3f9 100644 --- a/cmake/org.eclipse.cdt.cmake.example/META-INF/MANIFEST.MF +++ b/cmake/org.eclipse.cdt.cmake.example/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %pluginName Bundle-SymbolicName: org.eclipse.cdt.cmake.example;singleton:=true -Bundle-Version: 1.0.0.qualifier +Bundle-Version: 1.0.100.qualifier Export-Package: org.eclipse.cdt.cmake.example;x-internal:=true Bundle-Vendor: %providerName Bundle-RequiredExecutionEnvironment: JavaSE-17 @@ -17,7 +17,10 @@ Require-Bundle: org.eclipse.cdt.cmake.core, org.eclipse.tools.templates.freemarker, org.eclipse.ui, org.eclipse.ui.ide, - org.eclipse.launchbar.core;bundle-version="[3.0.0,4.0.0)" + org.eclipse.launchbar.core;bundle-version="[3.0.0,4.0.0)", + org.eclipse.cdt.debug.core;bundle-version="[9.0.0,10.0.0)", + org.eclipse.debug.core;bundle-version="[3.24.0,4.0.0)", + org.eclipse.cdt.launch;bundle-version="[11.0.0,12.0.0)" Import-Package: freemarker.template;version="[2.3.22,3.0.0)" Automatic-Module-Name: org.eclipse.cdt.cmake.example Bundle-Localization: plugin diff --git a/cmake/org.eclipse.cdt.cmake.example/plugin.xml b/cmake/org.eclipse.cdt.cmake.example/plugin.xml index 31d4d8b78b0..175b5be1d7c 100644 --- a/cmake/org.eclipse.cdt.cmake.example/plugin.xml +++ b/cmake/org.eclipse.cdt.cmake.example/plugin.xml @@ -52,4 +52,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cmake/org.eclipse.cdt.cmake.example/src/org/eclipse/cdt/cmake/example/Messages.java b/cmake/org.eclipse.cdt.cmake.example/src/org/eclipse/cdt/cmake/example/Messages.java index 587e70fd19a..c29884f7e00 100644 --- a/cmake/org.eclipse.cdt.cmake.example/src/org/eclipse/cdt/cmake/example/Messages.java +++ b/cmake/org.eclipse.cdt.cmake.example/src/org/eclipse/cdt/cmake/example/Messages.java @@ -17,6 +17,8 @@ public class Messages extends NLS { public static String NewExtendedCMakeProjectWizard_PageTitle; public static String NewExtendedCMakeProjectWizard_WindowTitle; + public static String ConfigureCMakeProjectHandler_ConfigError; + static { // initialize resource bundle NLS.initializeMessages("org.eclipse.cdt.cmake.example.messages", Messages.class); //$NON-NLS-1$ diff --git a/cmake/org.eclipse.cdt.cmake.example/src/org/eclipse/cdt/cmake/example/handler/ConfigureCMakeProjectHandler.java b/cmake/org.eclipse.cdt.cmake.example/src/org/eclipse/cdt/cmake/example/handler/ConfigureCMakeProjectHandler.java new file mode 100644 index 00000000000..1940fa570c6 --- /dev/null +++ b/cmake/org.eclipse.cdt.cmake.example/src/org/eclipse/cdt/cmake/example/handler/ConfigureCMakeProjectHandler.java @@ -0,0 +1,67 @@ +/******************************************************************************* + * Copyright (c) 2026 Renesas Electronics Europe and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + *******************************************************************************/ +package org.eclipse.cdt.cmake.example.handler; + +import java.io.IOException; +import java.text.MessageFormat; + +import org.eclipse.cdt.cmake.core.CMakeBuildConfiguration; +import org.eclipse.cdt.cmake.example.Messages; +import org.eclipse.cdt.core.build.ICBuildConfiguration; +import org.eclipse.cdt.core.build.ICBuildConfigurationManager; +import org.eclipse.cdt.debug.core.CDebugCorePlugin; +import org.eclipse.cdt.launch.LaunchUtils; +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.WorkspaceJob; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.ILog; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.debug.core.ILaunchConfiguration; +import org.eclipse.launchbar.core.ILaunchBarManager; + +public class ConfigureCMakeProjectHandler extends AbstractHandler { + + @Override + public Object execute(ExecutionEvent event) throws ExecutionException { + ICBuildConfigurationManager configManager = CDebugCorePlugin.getService(ICBuildConfigurationManager.class); + ILaunchBarManager launchBarManager = CDebugCorePlugin.getService(ILaunchBarManager.class); + try { + ILaunchConfiguration activeLaunchConfiguration; + activeLaunchConfiguration = launchBarManager.getActiveLaunchConfiguration(); + IProject project = LaunchUtils.getProject(activeLaunchConfiguration); + ICBuildConfiguration buildConfig = configManager.getBuildConfiguration(project.getActiveBuildConfig()); + if (buildConfig instanceof CMakeBuildConfiguration cbc) { + WorkspaceJob job = new WorkspaceJob("Configuring CMake Project...") { //$NON-NLS-1$ + @Override + public IStatus runInWorkspace(IProgressMonitor monitor) throws CoreException { + try { + return cbc.configureCMakeBuildFiles(monitor); + } catch (CoreException | IOException e) { + return Status.error(MessageFormat.format(Messages.ConfigureCMakeProjectHandler_ConfigError, + project.getName()), e); + } + } + }; + job.setRule(project); + job.schedule(); + } + } catch (CoreException e) { + ILog.of(getClass()).error("Error getting CBuildConfiguration", e); //$NON-NLS-1$ + } + return null; + } + +} diff --git a/cmake/org.eclipse.cdt.cmake.example/src/org/eclipse/cdt/cmake/example/messages.properties b/cmake/org.eclipse.cdt.cmake.example/src/org/eclipse/cdt/cmake/example/messages.properties index 09ebf197424..b0fb92e8743 100644 --- a/cmake/org.eclipse.cdt.cmake.example/src/org/eclipse/cdt/cmake/example/messages.properties +++ b/cmake/org.eclipse.cdt.cmake.example/src/org/eclipse/cdt/cmake/example/messages.properties @@ -1,3 +1,4 @@ NewExtendedCMakeProjectWizard_WindowTitle=New CMake Project NewExtendedCMakeProjectWizard_PageTitle=New CMake Project NewExtendedCMakeProjectWizard_Description=Specify properties of new CMake project. +ConfigureCMakeProjectHandler_ConfigError=Failed to perform CMake configuration for project {0} diff --git a/cmake/org.eclipse.cdt.cmake.ui.tests/manualTests/README.md b/cmake/org.eclipse.cdt.cmake.ui.tests/manualTests/README.md index 3445b09b5ec..fef28b9fb9b 100644 --- a/cmake/org.eclipse.cdt.cmake.ui.tests/manualTests/README.md +++ b/cmake/org.eclipse.cdt.cmake.ui.tests/manualTests/README.md @@ -41,6 +41,16 @@ Note, the Build Settings tab settings are stored separately for Run mode and Deb #### 8.1) Perform build, clean and open build settings Expected: Settings are persisted +### 9) CMake configuration + +Verifies that the API for configuring CMake can be invoked independently. +Note: this API can only be tested in a CDT development environment that includes the **org.eclipse.cdt.cmake.example** plug-in. + + 1. Remove any existing **/build/** folder. + 2. Right-click the project and select Configure CMake Project. + +Expected: The CMake configuration process starts using the active launch settings. + ## Setup & prerequisites ### Setup Host Note, these instructions do not require the following tools to be added to the system path environment variable in the OS before starting Eclipse. This allows a clean environment to be maintained.