diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/build/ErrorBuildConfiguration.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/build/ErrorBuildConfiguration.java new file mode 100644 index 00000000000..fa83980f92e --- /dev/null +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/build/ErrorBuildConfiguration.java @@ -0,0 +1,149 @@ +/******************************************************************************* + * Copyright (c) 2019 QNX Software Systems 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.core.build; + +import java.io.IOException; +import java.net.URI; +import java.util.Map; + +import org.eclipse.cdt.core.CCorePlugin; +import org.eclipse.cdt.core.envvar.IEnvironmentVariable; +import org.eclipse.cdt.core.parser.IScannerInfo; +import org.eclipse.cdt.core.parser.IScannerInfoChangeListener; +import org.eclipse.cdt.core.resources.IConsole; +import org.eclipse.cdt.internal.core.build.Messages; +import org.eclipse.core.resources.IBuildConfiguration; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.PlatformObject; + +/** + * A Build configuration that simply spits out an error message on the console at build and clean time. + * Used to signify that we're not sure how to build this project in it's current state. + * + * TODO leaving most of the implementation as default. I don't think any of these methods get called when + * we're in this error state but we'll keep an eye open for NPE's and bad behavior. + */ +public class ErrorBuildConfiguration extends PlatformObject implements ICBuildConfiguration, ICBuildConfiguration2 { + + private final IBuildConfiguration config; + private String errorMessage; + + public static final String NAME = "!"; //$NON-NLS-1$ + + private static class Provider implements ICBuildConfigurationProvider { + @Override + public String getId() { + return "buildError"; //$NON-NLS-1$ + } + + @Override + public ICBuildConfiguration getCBuildConfiguration(IBuildConfiguration config, String name) + throws CoreException { + return new ErrorBuildConfiguration(config, Messages.ErrorBuildConfiguration_What); + } + } + + public static final Provider PROVIDER = new Provider(); + + public ErrorBuildConfiguration(IBuildConfiguration config, String errorMessage) { + this.errorMessage = errorMessage; + this.config = config; + } + + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } + + @Override + public IProject[] build(int kind, Map args, IConsole console, IProgressMonitor monitor) + throws CoreException { + try { + console.getErrorStream().write(errorMessage); + } catch (IOException e) { + throw new CoreException( + CCorePlugin.createStatus(Messages.ErrorBuildConfiguration_ErrorWritingToConsole, e)); + } + return null; + } + + @Override + public void clean(IConsole console, IProgressMonitor monitor) throws CoreException { + try { + console.getErrorStream().write(errorMessage); + } catch (IOException e) { + throw new CoreException( + CCorePlugin.createStatus(Messages.ErrorBuildConfiguration_ErrorWritingToConsole, e)); + } + } + + @Override + public IScannerInfo getScannerInformation(IResource resource) { + // TODO Auto-generated method stub + return null; + } + + @Override + public void subscribe(IResource resource, IScannerInfoChangeListener listener) { + // TODO Auto-generated method stub + + } + + @Override + public void unsubscribe(IResource resource, IScannerInfoChangeListener listener) { + // TODO Auto-generated method stub + + } + + @Override + public void setActive() { + // TODO Auto-generated method stub + + } + + @Override + public URI getBuildDirectoryURI() throws CoreException { + // TODO Auto-generated method stub + return null; + } + + @Override + public IBuildConfiguration getBuildConfiguration() throws CoreException { + return config; + } + + @Override + public IToolChain getToolChain() throws CoreException { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getBinaryParserId() throws CoreException { + // TODO Auto-generated method stub + return null; + } + + @Override + public IEnvironmentVariable getVariable(String name) throws CoreException { + // TODO Auto-generated method stub + return null; + } + + @Override + public IEnvironmentVariable[] getVariables() throws CoreException { + // TODO Auto-generated method stub + return null; + } + +} diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/build/IToolChain.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/build/IToolChain.java index a4caf4a7b68..163fd89d0ad 100644 --- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/build/IToolChain.java +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/build/IToolChain.java @@ -263,11 +263,18 @@ public interface IToolChain extends IAdaptable { } /** + * Determine if this toolchain supports targets with the given set of properties. + * + * @param properties the set of properties to test against + * @return does this toolchain support these properties + * * @since 6.1 */ default boolean matches(Map properties) { for (Map.Entry property : properties.entrySet()) { - if (!property.getValue().equals(getProperty(property.getKey()))) { + String tcValue = getProperty(property.getKey()); + // If toolchain doesn't have this property, it doesn't care + if (tcValue != null && !property.getValue().equals(tcValue)) { return false; } } diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/build/CBuildConfigurationManager.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/build/CBuildConfigurationManager.java index 572324f91cf..ee279adc33f 100644 --- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/build/CBuildConfigurationManager.java +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/build/CBuildConfigurationManager.java @@ -308,9 +308,11 @@ public class CBuildConfigurationManager // First see if we have one for (IBuildConfiguration config : project.getBuildConfigs()) { ICBuildConfiguration cconfig = getBuildConfiguration(config); - if (cconfig != null && cconfig.getToolChain().equals(toolChain) - && launchMode.equals(cconfig.getLaunchMode())) { - return cconfig; + if (cconfig != null) { + IToolChain tc = cconfig.getToolChain(); + if (tc != null && tc.equals(toolChain) && launchMode.equals(cconfig.getLaunchMode())) { + return cconfig; + } } } diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/build/Messages.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/build/Messages.java index 4176fe34302..5378540f548 100644 --- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/build/Messages.java +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/build/Messages.java @@ -24,6 +24,8 @@ public class Messages extends NLS { public static String CBuilder_NotConfiguredCorrectly2; public static String CBuildConfiguration_CommandNotFound; public static String CBuildConfiguration_BuildComplete; + public static String ErrorBuildConfiguration_What; + public static String ErrorBuildConfiguration_ErrorWritingToConsole; public static String StandardBuildConfiguration_0; public static String StandardBuildConfiguration_1; public static String StandardBuildConfiguration_Failure; diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/build/ToolChainManager.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/build/ToolChainManager.java index c13682b6a30..45fb3edd663 100644 --- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/build/ToolChainManager.java +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/build/ToolChainManager.java @@ -192,17 +192,7 @@ public class ToolChainManager implements IToolChainManager { List tcs = new ArrayList<>(); if (orderedToolChains != null) { for (IToolChain toolChain : orderedToolChains.toArray(new IToolChain[0])) { - boolean matches = true; - for (Map.Entry property : properties.entrySet()) { - String tcProperty = toolChain.getProperty(property.getKey()); - if (tcProperty != null) { - if (!property.getValue().equals(tcProperty)) { - matches = false; - break; - } - } - } - if (matches) { + if (toolChain.matches(properties)) { tcs.add(toolChain); } } diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/build/messages.properties b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/build/messages.properties index 87e2672b232..6473f66a22a 100644 --- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/build/messages.properties +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/build/messages.properties @@ -21,3 +21,5 @@ CBuildConfiguration_CreateJob=Create Build Folder CBuildConfiguration_Location=line %d, external location: %s CBuildConfiguration_ToolchainMissing=Toolchain is missing for build configuration CBuildConfiguration_RunningScannerInfo=Calculating scanner info for %s +ErrorBuildConfiguration_What=Unknown initialization error +ErrorBuildConfiguration_ErrorWritingToConsole=Error writing to console diff --git a/debug/org.eclipse.cdt.debug.core/META-INF/MANIFEST.MF b/debug/org.eclipse.cdt.debug.core/META-INF/MANIFEST.MF index aecca6c71af..3f3072594b3 100644 --- a/debug/org.eclipse.cdt.debug.core/META-INF/MANIFEST.MF +++ b/debug/org.eclipse.cdt.debug.core/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %pluginName Bundle-SymbolicName: org.eclipse.cdt.debug.core; singleton:=true -Bundle-Version: 8.3.200.qualifier +Bundle-Version: 8.3.300.qualifier Bundle-Activator: org.eclipse.cdt.debug.core.CDebugCorePlugin Bundle-Vendor: %providerName Bundle-Localization: plugin diff --git a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/launch/CoreBuildLaunchBarTracker.java b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/launch/CoreBuildLaunchBarTracker.java index f6c98da3799..43906d4790b 100644 --- a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/launch/CoreBuildLaunchBarTracker.java +++ b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/launch/CoreBuildLaunchBarTracker.java @@ -16,6 +16,7 @@ import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; +import org.eclipse.cdt.core.build.ErrorBuildConfiguration; import org.eclipse.cdt.core.build.ICBuildConfiguration; import org.eclipse.cdt.core.build.ICBuildConfiguration2; import org.eclipse.cdt.core.build.ICBuildConfigurationManager; @@ -41,6 +42,9 @@ import org.eclipse.launchbar.core.ILaunchBarListener; import org.eclipse.launchbar.core.ILaunchBarManager; import org.eclipse.launchbar.core.ILaunchDescriptor; import org.eclipse.launchbar.core.target.ILaunchTarget; +import org.eclipse.launchbar.core.target.ILaunchTargetListener; +import org.eclipse.launchbar.core.target.ILaunchTargetManager; +import org.eclipse.launchbar.core.target.TargetStatus; /** * A launchbar listener that attempts to set the active core build configuration @@ -48,17 +52,26 @@ import org.eclipse.launchbar.core.target.ILaunchTarget; * * @since 8.3 */ -public class CoreBuildLaunchBarTracker implements ILaunchBarListener { +public class CoreBuildLaunchBarTracker implements ILaunchBarListener, ILaunchTargetListener { private final ILaunchBarManager launchBarManager = CDebugCorePlugin.getService(ILaunchBarManager.class); private final ICBuildConfigurationManager configManager = CDebugCorePlugin .getService(ICBuildConfigurationManager.class); private final IToolChainManager toolChainManager = CDebugCorePlugin.getService(IToolChainManager.class); + private final ILaunchTargetManager targetManager = CDebugCorePlugin.getService(ILaunchTargetManager.class); private ILaunchMode lastMode; private ILaunchDescriptor lastDescriptor; private ILaunchTarget lastTarget; + public CoreBuildLaunchBarTracker() { + targetManager.addListener(this); + } + + public void dispose() { + targetManager.removeListener(this); + } + private void setActiveBuildConfig(ILaunchMode mode, ILaunchDescriptor descriptor, ILaunchTarget target) throws CoreException { IProject project = descriptor.getAdapter(IProject.class); @@ -102,14 +115,13 @@ public class CoreBuildLaunchBarTracker implements ILaunchBarListener { Map properties = new HashMap<>(); properties.putAll(lastTarget.getAttributes()); Collection tcs = toolChainManager.getToolChainsMatching(properties); + ICBuildConfiguration buildConfig = null; if (!tcs.isEmpty()) { - ICBuildConfiguration buildConfig = null; - - // First, see if any existing non default build configs match + // First, see if any existing non default build configs match the target properties configs: for (IBuildConfiguration config : finalProject.getBuildConfigs()) { if (!config.getName().equals(IBuildConfiguration.DEFAULT_CONFIG_NAME)) { ICBuildConfiguration testConfig = configManager.getBuildConfiguration(config); - if (testConfig != null) { + if (testConfig != null && !(testConfig instanceof ErrorBuildConfiguration)) { for (IToolChain tc : tcs) { if (testConfig.getToolChain().equals(tc)) { buildConfig = testConfig; @@ -129,32 +141,62 @@ public class CoreBuildLaunchBarTracker implements ILaunchBarListener { } } } - - if (buildConfig != null - && !buildConfig.getBuildConfiguration().equals(finalProject.getActiveBuildConfig())) { - CoreModel m = CoreModel.getDefault(); - synchronized (m) { - // set it as active - IProjectDescription desc = finalProject.getDescription(); - IBuildConfiguration[] configs = finalProject.getBuildConfigs(); - Set names = new LinkedHashSet<>(); - for (IBuildConfiguration config : configs) { - names.add(config.getName()); - } - // must add default config name as it may not be in build config list - names.add(IBuildConfiguration.DEFAULT_CONFIG_NAME); - // ensure active config is last in list so clean build will clean - // active config last and this will be left in build console for user to see - names.remove(buildConfig.getBuildConfiguration().getName()); - names.add(buildConfig.getBuildConfiguration().getName()); - - desc.setBuildConfigs(names.toArray(new String[0])); - desc.setActiveBuildConfig(buildConfig.getBuildConfiguration().getName()); - finalProject.setDescription(desc, monitor); - } - // notify the active build config that it is active - ((ICBuildConfiguration2) buildConfig).setActive(); + } else { + // No toolchain, set to error builder since we can't do much in this situation + // TODO check if it's already an error builder and just set the message + String error = String.format( + InternalDebugCoreMessages.CoreBuildLaunchBarTracker_NoToolchainForTarget, + target.getId()); + if (!targetManager.getStatus(target).equals(TargetStatus.OK_STATUS)) { + error += '\n' + InternalDebugCoreMessages.CoreBuildLaunchBarTracker_TargetNotAvailable; } + + // Do we already have an error build config? + for (IBuildConfiguration config : finalProject.getBuildConfigs()) { + if (!config.getName().equals(IBuildConfiguration.DEFAULT_CONFIG_NAME)) { + ICBuildConfiguration testConfig = configManager.getBuildConfiguration(config); + if (testConfig instanceof ErrorBuildConfiguration) { + ((ErrorBuildConfiguration) testConfig).setErrorMessage(error); + buildConfig = testConfig; + break; + } + } + } + + // Nope, create one + if (buildConfig == null) { + IBuildConfiguration config = configManager.createBuildConfiguration( + ErrorBuildConfiguration.PROVIDER, finalProject, ErrorBuildConfiguration.NAME, + monitor); + buildConfig = new ErrorBuildConfiguration(config, error); + configManager.addBuildConfiguration(config, buildConfig); + } + } + + if (buildConfig != null + && !buildConfig.getBuildConfiguration().equals(finalProject.getActiveBuildConfig())) { + CoreModel m = CoreModel.getDefault(); + synchronized (m) { + // set it as active + IProjectDescription desc = finalProject.getDescription(); + IBuildConfiguration[] configs = finalProject.getBuildConfigs(); + Set names = new LinkedHashSet<>(); + for (IBuildConfiguration config : configs) { + names.add(config.getName()); + } + // must add default config name as it may not be in build config list + names.add(IBuildConfiguration.DEFAULT_CONFIG_NAME); + // ensure active config is last in list so clean build will clean + // active config last and this will be left in build console for user to see + names.remove(buildConfig.getBuildConfiguration().getName()); + names.add(buildConfig.getBuildConfiguration().getName()); + + desc.setBuildConfigs(names.toArray(new String[0])); + desc.setActiveBuildConfig(buildConfig.getBuildConfiguration().getName()); + finalProject.setDescription(desc, monitor); + } + // notify the active build config that it is active + ((ICBuildConfiguration2) buildConfig).setActive(); } return Status.OK_STATUS; @@ -186,6 +228,24 @@ public class CoreBuildLaunchBarTracker implements ILaunchBarListener { } } + @Override + public void launchTargetStatusChanged(ILaunchTarget target) { + try { + if (targetManager.getStatus(target).equals(TargetStatus.OK_STATUS)) { + // Now that we have access to the target, it may change what the build config + ILaunchMode mode = launchBarManager.getActiveLaunchMode(); + if (mode == null) { + return; + } + + ILaunchDescriptor descriptor = launchBarManager.getActiveLaunchDescriptor(); + setActiveBuildConfig(mode, descriptor, target); + } + } catch (CoreException e) { + CDebugCorePlugin.log(e.getStatus()); + } + } + @Override public void activeLaunchDescriptorChanged(ILaunchDescriptor descriptor) { try { diff --git a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/InternalDebugCoreMessages.java b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/InternalDebugCoreMessages.java index af47d8b4e8d..9c204f489b8 100644 --- a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/InternalDebugCoreMessages.java +++ b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/InternalDebugCoreMessages.java @@ -30,6 +30,8 @@ public class InternalDebugCoreMessages extends NLS { public static String CDebugAdapter_1; public static String CDebugAdapter_Program_file_not_specified; public static String CoreBuildLaunchBarTracker_Job; + public static String CoreBuildLaunchBarTracker_NoToolchainForTarget; + public static String CoreBuildLaunchBarTracker_TargetNotAvailable; public static String CoreBuildLaunchConfigDelegate_noBinaries; public static String CoreBuildLocalRunLaunchDelegate_ErrorLaunching; public static String CRegisterManager_0; diff --git a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/InternalDebugCoreMessages.properties b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/InternalDebugCoreMessages.properties index 8f411cee22b..0942b459a99 100644 --- a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/InternalDebugCoreMessages.properties +++ b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/InternalDebugCoreMessages.properties @@ -25,6 +25,8 @@ CDebugAdapter_0=This debugger does not support debugging external files CDebugAdapter_1=Debugger Process CDebugAdapter_Program_file_not_specified=Program file not specified CoreBuildLaunchBarTracker_Job=Change Build Configurations +CoreBuildLaunchBarTracker_NoToolchainForTarget=No Toolchain found for Target %s +CoreBuildLaunchBarTracker_TargetNotAvailable=Target is not available CoreBuildLaunchConfigDelegate_noBinaries=No binaries CoreBuildLocalRunLaunchDelegate_ErrorLaunching=Error launching CRegisterManager_0=Unable to restore register groups - invalid memento.