From 52945113180dcae9a4494af16280b82bd3e16cb7 Mon Sep 17 00:00:00 2001 From: James Blackburn Date: Thu, 26 Aug 2010 15:36:21 +0000 Subject: [PATCH] Bug 317796 - Build before launch should be cleverer about which configuration is built. Add option to LaunchConfig Main Tab to automatically choose a build configuration appropriate to the binary being debugged. --- .../ICDTLaunchConfigurationConstants.java | 8 +++ .../gdb/internal/ui/launching/CMainTab.java | 4 ++ .../META-INF/MANIFEST.MF | 2 +- .../cdt/launch/AbstractCLaunchDelegate.java | 27 ++++++-- .../cdt/launch/AbstractCLaunchDelegate2.java | 20 ++++-- .../org/eclipse/cdt/launch/LaunchUtils.java | 69 +++++++++++++++++++ .../internal/ui/LaunchMessages.properties | 1 + .../cdt/launch/ui/CAbstractMainTab.java | 55 ++++++++++++++- .../org/eclipse/cdt/launch/ui/CMainTab.java | 4 ++ 9 files changed, 176 insertions(+), 14 deletions(-) diff --git a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/ICDTLaunchConfigurationConstants.java b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/ICDTLaunchConfigurationConstants.java index e26776c9b01..3e3e0e84b12 100644 --- a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/ICDTLaunchConfigurationConstants.java +++ b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/ICDTLaunchConfigurationConstants.java @@ -9,6 +9,7 @@ * QNX Software Systems - initial API and implementation * Ken Ryall (Nokia) - bug 118894 * Ken Ryall (Nokia) - bug 178731 + * Alex Collins (Broadcom Corp.) - choose build config automatically *******************************************************************************/ package org.eclipse.cdt.debug.core; @@ -120,6 +121,13 @@ public interface ICDTLaunchConfigurationConstants { */ public static final String ATTR_PROJECT_BUILD_CONFIG_ID = CDT_LAUNCH_ID + ".PROJECT_BUILD_CONFIG_ID_ATTR"; //$NON-NLS-1$ + /** + * Automatically choose build configuration for launch key. The value indicates whether the ID of the build configuration + * to be built before launch should be calculated based on the path to the application being launched. + * @since 7.1 + */ + public static final String ATTR_PROJECT_BUILD_CONFIG_AUTO = CDT_LAUNCH_ID + ".PROJECT_BUILD_CONFIG_AUTO_ATTR"; //$NON-NLS-1$ + /** * Launch configuration attribute key. The value is a string specifying * application a C/C++ launch configuration. diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/launching/CMainTab.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/launching/CMainTab.java index 2253f502ac8..e999027faca 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/launching/CMainTab.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/launching/CMainTab.java @@ -522,6 +522,10 @@ public class CMainTab extends CAbstractMainTab { config.setAttribute(ICDTLaunchConfigurationConstants.ATTR_PROJECT_BUILD_CONFIG_ID, EMPTY_STRING); config.setAttribute(ICDTLaunchConfigurationConstants.ATTR_COREFILE_PATH, EMPTY_STRING); + // Set the auto choose build configuration to true for new configurations. + // Existing configurations created before this setting was introduced will have this disabled. + config.setAttribute(ICDTLaunchConfigurationConstants.ATTR_PROJECT_BUILD_CONFIG_AUTO, true); + ICElement cElement = null; cElement = getContext(config, getPlatform(config)); if (cElement != null) { diff --git a/launch/org.eclipse.cdt.launch/META-INF/MANIFEST.MF b/launch/org.eclipse.cdt.launch/META-INF/MANIFEST.MF index 27325259f81..4d43a1e3c07 100644 --- a/launch/org.eclipse.cdt.launch/META-INF/MANIFEST.MF +++ b/launch/org.eclipse.cdt.launch/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %pluginName Bundle-SymbolicName: org.eclipse.cdt.launch; singleton:=true -Bundle-Version: 6.1.0.qualifier +Bundle-Version: 6.2.0.qualifier Bundle-Activator: org.eclipse.cdt.launch.internal.ui.LaunchUIPlugin Bundle-Vendor: %providerName Bundle-Localization: plugin diff --git a/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/AbstractCLaunchDelegate.java b/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/AbstractCLaunchDelegate.java index 58665c43ebc..a5375d4045b 100644 --- a/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/AbstractCLaunchDelegate.java +++ b/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/AbstractCLaunchDelegate.java @@ -10,6 +10,7 @@ * Andrew Ferguson (andrew.ferguson@arm.com) - bug 123997 * Ken Ryall (Nokia) - bug 178731 * Anton Leherbauer (Wind River Systems) - bug 224187 + * Alex Collins (Broadcom Corp.) - choose build config automatically *******************************************************************************/ package org.eclipse.cdt.launch; @@ -126,6 +127,7 @@ abstract public class AbstractCLaunchDelegate extends LaunchConfigurationDelegat } } + private static final String EMPTY_STR = ""; //$NON-NLS-1$ public AbstractCLaunchDelegate() { super(); @@ -619,18 +621,29 @@ abstract public class AbstractCLaunchDelegate extends LaunchConfigurationDelegat } /** - * Sets up a project for building by making sure the active configuration is the one used - * when the launch was created. - * @param configuration - * @param buildProject + * Sets up a project for building by making sure the active configuration is set to the configuration chosen to + * be built before the launch. + * + * If the configuration to be built before launch was set to be automatically discovered, it is set to the unique + * build configuration for the project that outputs to the directory containing the program to be launched. + * + * @param configuration The launch configuration being launched. + * @param buildProject The project to be build before the launch configuration is launched. */ private void setBuildConfiguration(ILaunchConfiguration configuration, IProject buildProject) { - try { - String buildConfigID = configuration.getAttribute(ICDTLaunchConfigurationConstants.ATTR_PROJECT_BUILD_CONFIG_ID, ""); //$NON-NLS-1$ ICProjectDescription projDes = CDTPropertyManager.getProjectDescription(buildProject); + String buildConfigID = null; + + if (configuration.getAttribute(ICDTLaunchConfigurationConstants.ATTR_PROJECT_BUILD_CONFIG_AUTO, false)) { + String programPath = configuration.getAttribute(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_NAME, EMPTY_STR); + ICConfigurationDescription buildConfig = LaunchUtils.getBuildConfigByProgramPath(buildProject, programPath); + if (buildConfig != null) + buildConfigID = buildConfig.getId(); + } else + buildConfigID = configuration.getAttribute(ICDTLaunchConfigurationConstants.ATTR_PROJECT_BUILD_CONFIG_ID, EMPTY_STR); - if (buildConfigID.length() > 0 && projDes != null) + if (buildConfigID != null && buildConfigID.length() > 0 && projDes != null) { ICConfigurationDescription buildConfiguration = projDes.getConfigurationById(buildConfigID); if (buildConfiguration != null) { diff --git a/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/AbstractCLaunchDelegate2.java b/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/AbstractCLaunchDelegate2.java index 2c7c21fd100..514cb9cf847 100644 --- a/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/AbstractCLaunchDelegate2.java +++ b/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/AbstractCLaunchDelegate2.java @@ -242,11 +242,23 @@ public abstract class AbstractCLaunchDelegate2 extends LaunchConfigurationDelega if (buildBeforeLaunchValue == ICDTLaunchConfigurationConstants.BUILD_BEFORE_LAUNCH_DISABLED) { return false; } - + + String buildConfigID = null; + + // If automatic configuration detection then discover the build config corresponding to the executable + if (configuration.getAttribute(ICDTLaunchConfigurationConstants.ATTR_PROJECT_BUILD_CONFIG_AUTO, false)) { + String programPath = configuration.getAttribute(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_NAME, ""); //$NON-NLS-1$ + ICConfigurationDescription buildConfig = LaunchUtils.getBuildConfigByProgramPath(project, programPath); + if (buildConfig != null) + buildConfigID = buildConfig.getId(); + } + // The attribute value will be "" if 'Use Active' is selected - String buildConfigID = configuration.getAttribute(ICDTLaunchConfigurationConstants.ATTR_PROJECT_BUILD_CONFIG_ID, ""); //$NON-NLS-1$ - if (buildConfigID.length() == 0) { - buildConfigID = null; + if (buildConfigID == null) { + buildConfigID = configuration.getAttribute(ICDTLaunchConfigurationConstants.ATTR_PROJECT_BUILD_CONFIG_ID, ""); //$NON-NLS-1$ + if (buildConfigID.length() == 0) { + buildConfigID = null; + } } // There's no guarantee the ID stored in the launch config is valid. diff --git a/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/LaunchUtils.java b/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/LaunchUtils.java index d5fb53c28aa..3e2bef83449 100644 --- a/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/LaunchUtils.java +++ b/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/LaunchUtils.java @@ -7,6 +7,7 @@ * * Contributors: * QNX Software Systems - Initial API and implementation + * Alex Collins (Broadcom Corp.) - choose build config automatically *******************************************************************************/ package org.eclipse.cdt.launch; @@ -18,8 +19,17 @@ import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.IBinaryParser; import org.eclipse.cdt.core.IBinaryParser.IBinaryObject; import org.eclipse.cdt.core.ICExtensionReference; +import org.eclipse.cdt.core.model.CoreModel; +import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; +import org.eclipse.cdt.core.settings.model.ICOutputEntry; +import org.eclipse.cdt.core.settings.model.ICProjectDescription; +import org.eclipse.cdt.core.settings.model.extension.CBuildData; +import org.eclipse.cdt.core.settings.model.extension.CConfigurationData; +import org.eclipse.cdt.core.settings.model.util.CDataUtil; import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants; +import org.eclipse.cdt.internal.core.resources.ResourceLookup; import org.eclipse.cdt.utils.CommandLineUtil; +import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; @@ -141,4 +151,63 @@ public class LaunchUtils { } + /** + * Get the build configuration that most likely builds the given program path. + * The build configuration is chosen as the one that outputs to a directory that contains + * the given program. + * + * @param projectDesc The description for the project in which to search for the configuration. + * @param programPath The path to the program to search the build configurations for + * @return The build configuration that builds programName; or null if none or more than one were found. + * @since 6.2 + */ + public static ICConfigurationDescription getBuildConfigByProgramPath(IProject project, String programPath) { + if (project == null || programPath == null) + return null; + ICProjectDescription projectDesc = CoreModel.getDefault().getProjectDescription(project, false); + if (projectDesc == null) + return null; + + // If the program path is relative, it must be relative to the projects root + IPath path = new Path(programPath); + if (!path.isAbsolute()) { + IPath projLocation = project.getLocation(); + if (projLocation == null) + return null; + path = projLocation.append(path); + } + + // Get all possible files that the program path could refer to + IFile[] files = ResourceLookup.findFilesForLocation(path); + + // Find the build config whose output directory matches one of the possible files + ICConfigurationDescription buildConfig = null; + findCfg: for (ICConfigurationDescription cfgDes : projectDesc.getConfigurations()) { + CConfigurationData cfgData = cfgDes.getConfigurationData(); + if (cfgData == null) + continue; + CBuildData buildData = cfgData.getBuildData(); + if (buildData == null) + continue; + for (ICOutputEntry dir : buildData.getOutputDirectories()) { + ICOutputEntry absoluteDir = CDataUtil.makeAbsolute(project, dir); + if (absoluteDir == null) + continue; + IPath dirLocation = absoluteDir.getLocation(); + if (dirLocation == null) + continue; + for (IFile file : files) { + if (dirLocation.isPrefixOf(file.getLocation())) { + if (buildConfig != null && buildConfig != cfgDes) { + // Matched more than one, so use the active configuration + buildConfig = null; + break findCfg; + } + buildConfig = cfgDes; + } + } + } + } + return buildConfig; + } } diff --git a/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/internal/ui/LaunchMessages.properties b/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/internal/ui/LaunchMessages.properties index 33c8c6a503c..775d3981a73 100644 --- a/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/internal/ui/LaunchMessages.properties +++ b/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/internal/ui/LaunchMessages.properties @@ -87,6 +87,7 @@ CMainTab.Program_is_not_a_recongnized_executable=Program is not a recognized exe CMainTab.Program_invalid_proj_path=Program specification is not a valid project-relative path. CMainTab.Build_Config=Build configuration: CMainTab.Use_Active=Use Active +CMainTab.Build_Config_Auto=Select configuration using 'C/C++ Application' #For CMainTab.Configuration_name: {0} - project name; {1} - configuration name CMainTab.Configuration_name={0} {1} CMainTab.Build_options=Build (if required) before launching diff --git a/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/ui/CAbstractMainTab.java b/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/ui/CAbstractMainTab.java index 5d9536ba05e..74204b412c5 100644 --- a/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/ui/CAbstractMainTab.java +++ b/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/ui/CAbstractMainTab.java @@ -8,6 +8,7 @@ * Contributors: * Ken Ryall (Nokia) - initial API and implementation * IBM Corporation + * Alex Collins (Broadcom Corp.) - choose build config automatically *******************************************************************************/ package org.eclipse.cdt.launch.ui; @@ -16,8 +17,8 @@ import java.util.HashMap; import java.util.Map; import org.eclipse.cdt.core.CCorePlugin; -import org.eclipse.cdt.core.ICDescriptor; import org.eclipse.cdt.core.IBinaryParser.IBinaryObject; +import org.eclipse.cdt.core.ICDescriptor; import org.eclipse.cdt.core.model.CModelException; import org.eclipse.cdt.core.model.CoreModel; import org.eclipse.cdt.core.model.IBinary; @@ -72,6 +73,12 @@ public abstract class CAbstractMainTab extends CLaunchConfigurationTab { * @since 6.0 */ protected Combo fBuildConfigCombo; + /** @since 6.2 */ + protected Button fBuildConfigAuto; + /** Indicates whether the user has clicked on the build config auto button + * Prevents causing a delta to the underlying launch configuration if the user hasn't touched this setting. + * @since 6.2 */ + protected boolean fBuildConfigAutoChanged; /** @since 6.1 */ protected Button fDisableBuildButton; /** @since 6.1 */ @@ -262,6 +269,7 @@ public abstract class CAbstractMainTab extends CLaunchConfigurationTab { protected void updateBuildConfigCombo(String selectedConfigID) { if (fBuildConfigCombo != null) { + fBuildConfigCombo.setEnabled(!fBuildConfigAuto.getSelection()); fBuildConfigCombo.removeAll(); fBuildConfigCombo.add(LaunchMessages.getString("CMainTab.Use_Active")); //$NON-NLS-1$ fBuildConfigCombo.setData("0", ""); //$NON-NLS-1$ //$NON-NLS-2$ @@ -272,6 +280,14 @@ public abstract class CAbstractMainTab extends CLaunchConfigurationTab { ICProjectDescription projDes = CDTPropertyManager.getProjectDescription(cproject.getProject()); if (projDes != null) { + // Find the config that should be automatically selected + String autoConfigId = null; + if (fBuildConfigAuto.getSelection()) { + ICConfigurationDescription autoConfig = LaunchUtils.getBuildConfigByProgramPath(cproject.getProject(), fProgText.getText()); + if (autoConfig != null) + autoConfigId = autoConfig.getId(); + } + int selIndex = 0; ICConfigurationDescription[] configurations = projDes.getConfigurations(); ICConfigurationDescription selectedConfig = projDes.getConfigurationById(selectedConfigID); @@ -279,8 +295,10 @@ public abstract class CAbstractMainTab extends CLaunchConfigurationTab { String configName = configurations[i].getName(); fBuildConfigCombo.add(configName); fBuildConfigCombo.setData(Integer.toString(i + 1), configurations[i].getId()); - if (selectedConfig != null && selectedConfigID.equals(configurations[i].getId())) + if (selectedConfig != null && selectedConfigID.equals(configurations[i].getId()) || + fBuildConfigAuto.getSelection() && configurations[i].getId().equals(autoConfigId)) { selIndex = i + 1; + } } fBuildConfigCombo.select(selIndex); } @@ -313,6 +331,26 @@ public abstract class CAbstractMainTab extends CLaunchConfigurationTab { updateLaunchConfigurationDialog(); } }); + + new Label(comboComp, SWT.NONE).setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + + fBuildConfigAuto = new Button(comboComp, SWT.CHECK); + fBuildConfigAuto.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + fBuildConfigAuto.setText(LaunchMessages.getString("CMainTab.Build_Config_Auto")); //$NON-NLS-1$ + fBuildConfigAuto.addSelectionListener(new SelectionListener() { + public void widgetSelected(SelectionEvent e) { + fBuildConfigAutoChanged = true; + fBuildConfigCombo.setEnabled(false); + updateBuildConfigCombo(""); //$NON-NLS-1$ + updateLaunchConfigurationDialog(); + } + public void widgetDefaultSelected(SelectionEvent e) { + fBuildConfigAutoChanged = true; + fBuildConfigCombo.setEnabled(true); + updateBuildConfigCombo(""); //$NON-NLS-1$ + updateLaunchConfigurationDialog(); + } + }); } /** @since 6.1 */ @@ -377,13 +415,20 @@ public abstract class CAbstractMainTab extends CLaunchConfigurationTab { /** @since 6.1 */ protected void updateBuildOptionFromConfig(ILaunchConfiguration config) { + boolean configAuto = false; int buildBeforeLaunchValue = ICDTLaunchConfigurationConstants.BUILD_BEFORE_LAUNCH_USE_WORKSPACE_SETTING; try { buildBeforeLaunchValue = config.getAttribute(ICDTLaunchConfigurationConstants.ATTR_BUILD_BEFORE_LAUNCH, buildBeforeLaunchValue); + configAuto = config.getAttribute(ICDTLaunchConfigurationConstants.ATTR_PROJECT_BUILD_CONFIG_AUTO, false); } catch (CoreException e) { LaunchUIPlugin.log(e); } + if (fBuildConfigAuto != null) { + fBuildConfigAuto.setSelection(configAuto); + if (configAuto) + updateBuildConfigCombo(""); //$NON-NLS-1$ + } if (fDisableBuildButton != null) fDisableBuildButton.setSelection(buildBeforeLaunchValue == ICDTLaunchConfigurationConstants.BUILD_BEFORE_LAUNCH_DISABLED); if (fEnableBuildButton != null) @@ -501,6 +546,10 @@ public abstract class CAbstractMainTab extends CLaunchConfigurationTab { config.setAttribute(ICDTLaunchConfigurationConstants.ATTR_PROJECT_BUILD_CONFIG_ID, (String)fBuildConfigCombo.getData(Integer.toString(fBuildConfigCombo.getSelectionIndex()))); } + if (fBuildConfigAutoChanged && fBuildConfigAuto != null) { + config.setAttribute(ICDTLaunchConfigurationConstants.ATTR_PROJECT_BUILD_CONFIG_AUTO, fBuildConfigAuto.getSelection()); + } + if (fDisableBuildButton != null) { int buildBeforeLaunchValue = ICDTLaunchConfigurationConstants.BUILD_BEFORE_LAUNCH_USE_WORKSPACE_SETTING; if (fDisableBuildButton.getSelection()) { @@ -545,6 +594,8 @@ public abstract class CAbstractMainTab extends CLaunchConfigurationTab { */ @Override protected void updateLaunchConfigurationDialog() { + if (fBuildConfigAuto.getSelection()) + updateBuildConfigCombo(""); //$NON-NLS-1$ super.updateLaunchConfigurationDialog(); } diff --git a/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/ui/CMainTab.java b/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/ui/CMainTab.java index c3465704eca..c9609842869 100644 --- a/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/ui/CMainTab.java +++ b/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/ui/CMainTab.java @@ -535,6 +535,10 @@ public class CMainTab extends CAbstractMainTab { config.setAttribute(ICDTLaunchConfigurationConstants.ATTR_PROJECT_BUILD_CONFIG_ID, EMPTY_STRING); config.setAttribute(ICDTLaunchConfigurationConstants.ATTR_COREFILE_PATH, EMPTY_STRING); + // Set the auto choose build configuration to true for new configurations. + // Existing configurations created before this setting was introduced will have this disabled. + config.setAttribute(ICDTLaunchConfigurationConstants.ATTR_PROJECT_BUILD_CONFIG_AUTO, true); + ICElement cElement = null; cElement = getContext(config, getPlatform(config)); if (cElement != null) {