1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-07-19 23:15:24 +02:00

Bug 548980 - Track launch target connects and add error builds

We need a way to alert the user that we are unable to find a toolchain
that maps to the current target. An ErrorBuildConfiguration is created
that simply prints out an error message at build time to handle this.
We then set one of these as the active build config in the tracker
with the appropriate message.

We also add a target listener so that when a target becomes OK_STATUS,
we run the tracker again to see if we have the right active build
config for that target. Some targets can only determine some of their
attributes when connected.

Hook up the IToolChain matches so we're using it in the toolchain
manager. This allows toolchains to do more complicated matching of
the properties.

Change-Id: Icaff85117e8147cd2793f2915fa75ce33673ab52
This commit is contained in:
Doug Schaefer 2019-07-04 10:55:42 -04:00
parent b1702ff753
commit b953649c09
10 changed files with 262 additions and 46 deletions

View file

@ -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<String, String> 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;
}
}

View file

@ -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 * @since 6.1
*/ */
default boolean matches(Map<String, String> properties) { default boolean matches(Map<String, String> properties) {
for (Map.Entry<String, String> property : properties.entrySet()) { for (Map.Entry<String, String> 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; return false;
} }
} }

View file

@ -308,9 +308,11 @@ public class CBuildConfigurationManager
// First see if we have one // First see if we have one
for (IBuildConfiguration config : project.getBuildConfigs()) { for (IBuildConfiguration config : project.getBuildConfigs()) {
ICBuildConfiguration cconfig = getBuildConfiguration(config); ICBuildConfiguration cconfig = getBuildConfiguration(config);
if (cconfig != null && cconfig.getToolChain().equals(toolChain) if (cconfig != null) {
&& launchMode.equals(cconfig.getLaunchMode())) { IToolChain tc = cconfig.getToolChain();
return cconfig; if (tc != null && tc.equals(toolChain) && launchMode.equals(cconfig.getLaunchMode())) {
return cconfig;
}
} }
} }

View file

@ -24,6 +24,8 @@ public class Messages extends NLS {
public static String CBuilder_NotConfiguredCorrectly2; public static String CBuilder_NotConfiguredCorrectly2;
public static String CBuildConfiguration_CommandNotFound; public static String CBuildConfiguration_CommandNotFound;
public static String CBuildConfiguration_BuildComplete; public static String CBuildConfiguration_BuildComplete;
public static String ErrorBuildConfiguration_What;
public static String ErrorBuildConfiguration_ErrorWritingToConsole;
public static String StandardBuildConfiguration_0; public static String StandardBuildConfiguration_0;
public static String StandardBuildConfiguration_1; public static String StandardBuildConfiguration_1;
public static String StandardBuildConfiguration_Failure; public static String StandardBuildConfiguration_Failure;

View file

@ -192,17 +192,7 @@ public class ToolChainManager implements IToolChainManager {
List<IToolChain> tcs = new ArrayList<>(); List<IToolChain> tcs = new ArrayList<>();
if (orderedToolChains != null) { if (orderedToolChains != null) {
for (IToolChain toolChain : orderedToolChains.toArray(new IToolChain[0])) { for (IToolChain toolChain : orderedToolChains.toArray(new IToolChain[0])) {
boolean matches = true; if (toolChain.matches(properties)) {
for (Map.Entry<String, String> property : properties.entrySet()) {
String tcProperty = toolChain.getProperty(property.getKey());
if (tcProperty != null) {
if (!property.getValue().equals(tcProperty)) {
matches = false;
break;
}
}
}
if (matches) {
tcs.add(toolChain); tcs.add(toolChain);
} }
} }

View file

@ -21,3 +21,5 @@ CBuildConfiguration_CreateJob=Create Build Folder
CBuildConfiguration_Location=line %d, external location: %s CBuildConfiguration_Location=line %d, external location: %s
CBuildConfiguration_ToolchainMissing=Toolchain is missing for build configuration CBuildConfiguration_ToolchainMissing=Toolchain is missing for build configuration
CBuildConfiguration_RunningScannerInfo=Calculating scanner info for %s CBuildConfiguration_RunningScannerInfo=Calculating scanner info for %s
ErrorBuildConfiguration_What=Unknown initialization error
ErrorBuildConfiguration_ErrorWritingToConsole=Error writing to console

View file

@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2 Bundle-ManifestVersion: 2
Bundle-Name: %pluginName Bundle-Name: %pluginName
Bundle-SymbolicName: org.eclipse.cdt.debug.core; singleton:=true 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-Activator: org.eclipse.cdt.debug.core.CDebugCorePlugin
Bundle-Vendor: %providerName Bundle-Vendor: %providerName
Bundle-Localization: plugin Bundle-Localization: plugin

View file

@ -16,6 +16,7 @@ import java.util.LinkedHashSet;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import org.eclipse.cdt.core.build.ErrorBuildConfiguration;
import org.eclipse.cdt.core.build.ICBuildConfiguration; import org.eclipse.cdt.core.build.ICBuildConfiguration;
import org.eclipse.cdt.core.build.ICBuildConfiguration2; import org.eclipse.cdt.core.build.ICBuildConfiguration2;
import org.eclipse.cdt.core.build.ICBuildConfigurationManager; 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.ILaunchBarManager;
import org.eclipse.launchbar.core.ILaunchDescriptor; import org.eclipse.launchbar.core.ILaunchDescriptor;
import org.eclipse.launchbar.core.target.ILaunchTarget; 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 * 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 * @since 8.3
*/ */
public class CoreBuildLaunchBarTracker implements ILaunchBarListener { public class CoreBuildLaunchBarTracker implements ILaunchBarListener, ILaunchTargetListener {
private final ILaunchBarManager launchBarManager = CDebugCorePlugin.getService(ILaunchBarManager.class); private final ILaunchBarManager launchBarManager = CDebugCorePlugin.getService(ILaunchBarManager.class);
private final ICBuildConfigurationManager configManager = CDebugCorePlugin private final ICBuildConfigurationManager configManager = CDebugCorePlugin
.getService(ICBuildConfigurationManager.class); .getService(ICBuildConfigurationManager.class);
private final IToolChainManager toolChainManager = CDebugCorePlugin.getService(IToolChainManager.class); private final IToolChainManager toolChainManager = CDebugCorePlugin.getService(IToolChainManager.class);
private final ILaunchTargetManager targetManager = CDebugCorePlugin.getService(ILaunchTargetManager.class);
private ILaunchMode lastMode; private ILaunchMode lastMode;
private ILaunchDescriptor lastDescriptor; private ILaunchDescriptor lastDescriptor;
private ILaunchTarget lastTarget; private ILaunchTarget lastTarget;
public CoreBuildLaunchBarTracker() {
targetManager.addListener(this);
}
public void dispose() {
targetManager.removeListener(this);
}
private void setActiveBuildConfig(ILaunchMode mode, ILaunchDescriptor descriptor, ILaunchTarget target) private void setActiveBuildConfig(ILaunchMode mode, ILaunchDescriptor descriptor, ILaunchTarget target)
throws CoreException { throws CoreException {
IProject project = descriptor.getAdapter(IProject.class); IProject project = descriptor.getAdapter(IProject.class);
@ -102,14 +115,13 @@ public class CoreBuildLaunchBarTracker implements ILaunchBarListener {
Map<String, String> properties = new HashMap<>(); Map<String, String> properties = new HashMap<>();
properties.putAll(lastTarget.getAttributes()); properties.putAll(lastTarget.getAttributes());
Collection<IToolChain> tcs = toolChainManager.getToolChainsMatching(properties); Collection<IToolChain> tcs = toolChainManager.getToolChainsMatching(properties);
ICBuildConfiguration buildConfig = null;
if (!tcs.isEmpty()) { if (!tcs.isEmpty()) {
ICBuildConfiguration buildConfig = null; // First, see if any existing non default build configs match the target properties
// First, see if any existing non default build configs match
configs: for (IBuildConfiguration config : finalProject.getBuildConfigs()) { configs: for (IBuildConfiguration config : finalProject.getBuildConfigs()) {
if (!config.getName().equals(IBuildConfiguration.DEFAULT_CONFIG_NAME)) { if (!config.getName().equals(IBuildConfiguration.DEFAULT_CONFIG_NAME)) {
ICBuildConfiguration testConfig = configManager.getBuildConfiguration(config); ICBuildConfiguration testConfig = configManager.getBuildConfiguration(config);
if (testConfig != null) { if (testConfig != null && !(testConfig instanceof ErrorBuildConfiguration)) {
for (IToolChain tc : tcs) { for (IToolChain tc : tcs) {
if (testConfig.getToolChain().equals(tc)) { if (testConfig.getToolChain().equals(tc)) {
buildConfig = testConfig; buildConfig = testConfig;
@ -129,32 +141,62 @@ public class CoreBuildLaunchBarTracker implements ILaunchBarListener {
} }
} }
} }
} else {
if (buildConfig != null // No toolchain, set to error builder since we can't do much in this situation
&& !buildConfig.getBuildConfiguration().equals(finalProject.getActiveBuildConfig())) { // TODO check if it's already an error builder and just set the message
CoreModel m = CoreModel.getDefault(); String error = String.format(
synchronized (m) { InternalDebugCoreMessages.CoreBuildLaunchBarTracker_NoToolchainForTarget,
// set it as active target.getId());
IProjectDescription desc = finalProject.getDescription(); if (!targetManager.getStatus(target).equals(TargetStatus.OK_STATUS)) {
IBuildConfiguration[] configs = finalProject.getBuildConfigs(); error += '\n' + InternalDebugCoreMessages.CoreBuildLaunchBarTracker_TargetNotAvailable;
Set<String> 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();
} }
// 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<String> 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; 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 @Override
public void activeLaunchDescriptorChanged(ILaunchDescriptor descriptor) { public void activeLaunchDescriptorChanged(ILaunchDescriptor descriptor) {
try { try {

View file

@ -30,6 +30,8 @@ public class InternalDebugCoreMessages extends NLS {
public static String CDebugAdapter_1; public static String CDebugAdapter_1;
public static String CDebugAdapter_Program_file_not_specified; public static String CDebugAdapter_Program_file_not_specified;
public static String CoreBuildLaunchBarTracker_Job; public static String CoreBuildLaunchBarTracker_Job;
public static String CoreBuildLaunchBarTracker_NoToolchainForTarget;
public static String CoreBuildLaunchBarTracker_TargetNotAvailable;
public static String CoreBuildLaunchConfigDelegate_noBinaries; public static String CoreBuildLaunchConfigDelegate_noBinaries;
public static String CoreBuildLocalRunLaunchDelegate_ErrorLaunching; public static String CoreBuildLocalRunLaunchDelegate_ErrorLaunching;
public static String CRegisterManager_0; public static String CRegisterManager_0;

View file

@ -25,6 +25,8 @@ CDebugAdapter_0=This debugger does not support debugging external files
CDebugAdapter_1=Debugger Process CDebugAdapter_1=Debugger Process
CDebugAdapter_Program_file_not_specified=Program file not specified CDebugAdapter_Program_file_not_specified=Program file not specified
CoreBuildLaunchBarTracker_Job=Change Build Configurations CoreBuildLaunchBarTracker_Job=Change Build Configurations
CoreBuildLaunchBarTracker_NoToolchainForTarget=No Toolchain found for Target %s
CoreBuildLaunchBarTracker_TargetNotAvailable=Target is not available
CoreBuildLaunchConfigDelegate_noBinaries=No binaries CoreBuildLaunchConfigDelegate_noBinaries=No binaries
CoreBuildLocalRunLaunchDelegate_ErrorLaunching=Error launching CoreBuildLocalRunLaunchDelegate_ErrorLaunching=Error launching
CRegisterManager_0=Unable to restore register groups - invalid memento. CRegisterManager_0=Unable to restore register groups - invalid memento.