| /******************************************************************************* |
| * Copyright (c) 2005, 2016 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 |
| * |
| * Contributors: |
| * QNX Software Systems - initial API and implementation |
| * 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 |
| * James Blackburn (Broadcom Corp.) |
| * Philip Langer (EclipseSource Services GmbH) - bug 506843 |
| *******************************************************************************/ |
| package org.eclipse.cdt.launch; |
| |
| import java.io.File; |
| import java.io.FileNotFoundException; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Date; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Map.Entry; |
| import java.util.Properties; |
| import java.util.concurrent.atomic.AtomicBoolean; |
| |
| import org.eclipse.cdt.core.IBinaryParser.IBinaryObject; |
| import org.eclipse.cdt.core.model.ICModelMarker; |
| import org.eclipse.cdt.core.model.ICProject; |
| import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; |
| import org.eclipse.cdt.core.settings.model.ICProjectDescription; |
| import org.eclipse.cdt.debug.core.CDebugUtils; |
| import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants; |
| import org.eclipse.cdt.debug.ui.CDebugUIPlugin; |
| import org.eclipse.cdt.launch.internal.ui.LaunchMessages; |
| import org.eclipse.cdt.launch.internal.ui.LaunchUIPlugin; |
| import org.eclipse.cdt.ui.newui.CDTPropertyManager; |
| import org.eclipse.core.resources.IContainer; |
| import org.eclipse.core.resources.IFile; |
| import org.eclipse.core.resources.IMarker; |
| import org.eclipse.core.resources.IProject; |
| import org.eclipse.core.resources.IResource; |
| import org.eclipse.core.resources.IWorkspace; |
| import org.eclipse.core.resources.IncrementalProjectBuilder; |
| import org.eclipse.core.resources.ResourcesPlugin; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IPath; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.MultiStatus; |
| import org.eclipse.core.runtime.NullProgressMonitor; |
| import org.eclipse.core.runtime.Path; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.core.runtime.SubProgressMonitor; |
| import org.eclipse.core.runtime.jobs.Job; |
| import org.eclipse.core.variables.VariablesPlugin; |
| import org.eclipse.debug.core.DebugPlugin; |
| import org.eclipse.debug.core.ILaunch; |
| import org.eclipse.debug.core.ILaunchConfiguration; |
| import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; |
| import org.eclipse.debug.core.ILaunchManager; |
| import org.eclipse.debug.core.IStatusHandler; |
| import org.eclipse.debug.core.Launch; |
| import org.eclipse.debug.core.model.IPersistableSourceLocator; |
| import org.eclipse.debug.core.model.IProcess; |
| import org.eclipse.debug.core.model.ISourceLocator; |
| import org.eclipse.debug.core.model.LaunchConfigurationDelegate; |
| import org.eclipse.debug.ui.RefreshTab; |
| import org.eclipse.osgi.util.NLS; |
| |
| import com.ibm.icu.text.DateFormat; |
| import com.ibm.icu.text.MessageFormat; |
| |
| /** |
| * AbstractCLaunchDelegate is the launch delegate used by most CDI based debuggers. |
| * It has been superseded by AbstractCLaunchDelegate2 which is used by most DSF based |
| * debuggers. AbstractCLaunchDelegate has been left unmodified because it is commonly |
| * used by CDT clients and contains lots of obscure code created long ago to handle |
| * issues whose relevance is unclear today. |
| * |
| */ |
| abstract public class AbstractCLaunchDelegate extends LaunchConfigurationDelegate { |
| |
| /** |
| * @since 6.0 |
| */ |
| public class CLaunch extends Launch { |
| |
| private final AtomicBoolean fRefreshDone; |
| |
| public CLaunch(ILaunchConfiguration launchConfiguration, String mode, ISourceLocator locator) { |
| super(launchConfiguration, mode, locator); |
| fRefreshDone = new AtomicBoolean(false); |
| } |
| |
| public void refresh() { |
| if (fRefreshDone.compareAndSet(false, true)) { |
| final ILaunchConfiguration config = getLaunchConfiguration(); |
| try { |
| if (RefreshTab.getRefreshScope(config) != null) { |
| Job refreshJob = new Job(LaunchMessages.AbstractCLaunchDelegate_Refresh) { |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor) |
| */ |
| @Override |
| protected IStatus run(IProgressMonitor monitor) { |
| try { |
| RefreshTab.refreshResources(config, monitor); |
| } catch (CoreException e) { |
| return new Status(IStatus.ERROR, LaunchUIPlugin.PLUGIN_ID, 1, |
| e.getLocalizedMessage(), e); |
| } |
| return Status.OK_STATUS; |
| } |
| }; |
| refreshJob.setSystem(true); |
| refreshJob.schedule(); |
| } |
| } catch (CoreException e) { |
| LaunchUIPlugin.log(e.getStatus()); |
| } |
| } |
| } |
| } |
| |
| private static final String EMPTY_STR = ""; //$NON-NLS-1$ |
| |
| public AbstractCLaunchDelegate() { |
| super(); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.debug.core.model.LaunchConfigurationDelegate#getLaunch(org.eclipse.debug.core.ILaunchConfiguration, java.lang.String) |
| */ |
| @Override |
| public ILaunch getLaunch(ILaunchConfiguration configuration, String mode) throws CoreException { |
| return new CLaunch(configuration, mode, null); |
| } |
| |
| /** |
| * The project containing the programs file being launched |
| */ |
| private IProject project; |
| /** |
| * A list of prequisite projects ordered by their build order. |
| */ |
| private List orderedProjects; |
| private String preLaunchBuildConfiguration; |
| |
| /** |
| * Used in conjunction with build before launch settings in the main tab. |
| */ |
| private boolean workspaceBuildBeforeLaunch; |
| /** Flag set to true if build before launch failed, or was cancelled. */ |
| private boolean buildFailed; |
| |
| @Override |
| abstract public void launch(ILaunchConfiguration configuration, String mode, ILaunch launch, |
| IProgressMonitor monitor) throws CoreException; |
| |
| /** |
| * Returns the working directory specified by the given launch |
| * configuration, or <code>null</code> if none. |
| * |
| * @deprecated Should use getWorkingDirectory() |
| * @param configuration |
| * launch configuration |
| * @return the working directory specified by the given launch |
| * configuration, or <code>null</code> if none |
| * @exception CoreException |
| * if unable to retrieve the attribute |
| */ |
| @Deprecated |
| public File getWorkingDir(ILaunchConfiguration configuration) throws CoreException { |
| return getWorkingDirectory(configuration); |
| } |
| |
| /** |
| * Returns the working directory specified by the given launch |
| * configuration, or <code>null</code> if none. |
| * |
| * @param configuration |
| * launch configuration |
| * @return the working directory specified by the given launch |
| * configuration, or <code>null</code> if none |
| * @exception CoreException |
| * if unable to retrieve the attribute |
| */ |
| public File getWorkingDirectory(ILaunchConfiguration configuration) throws CoreException { |
| return verifyWorkingDirectory(configuration); |
| } |
| |
| /** |
| * Expands and returns the working directory attribute of the given launch |
| * configuration. Returns <code>null</code> if a working directory is not |
| * specified. If specified, the working is verified to point to an existing |
| * directory in the local file system. |
| * |
| * @param configuration launch configuration |
| * @return an absolute path to a directory in the local file system, or |
| * <code>null</code> if unspecified |
| * @throws CoreException if unable to retrieve the associated launch |
| * configuration attribute, if unable to resolve any variables, or if the |
| * resolved location does not point to an existing directory in the local |
| * file system |
| */ |
| protected IPath getWorkingDirectoryPath(ILaunchConfiguration config) throws CoreException { |
| String location = config.getAttribute(ICDTLaunchConfigurationConstants.ATTR_WORKING_DIRECTORY, (String) null); |
| if (location != null) { |
| String expandedLocation = LaunchUtils.getStringVariableManager().performStringSubstitution(location); |
| if (expandedLocation.length() > 0) { |
| return new Path(expandedLocation); |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Throws a core exception with an error status object built from the given |
| * message, lower level exception, and error code. |
| * |
| * @param message |
| * the status message |
| * @param exception |
| * lower level exception associated with the error, or |
| * <code>null</code> if none |
| * @param code |
| * error code |
| */ |
| protected void abort(String message, Throwable exception, int code) throws CoreException { |
| IStatus status; |
| if (exception != null) { |
| MultiStatus multiStatus = new MultiStatus(getPluginID(), code, message, exception); |
| multiStatus.add(new Status(IStatus.ERROR, getPluginID(), code, exception.getLocalizedMessage(), exception)); |
| status = multiStatus; |
| } else { |
| status = new Status(IStatus.ERROR, getPluginID(), code, message, null); |
| } |
| throw new CoreException(status); |
| } |
| |
| protected void cancel(String message, int code) throws CoreException { |
| throw new CoreException(new Status(IStatus.OK, getPluginID(), code, message, null)); |
| } |
| |
| /** |
| * @return the ID of the plugin hosting the launch delegate. It's used to |
| * create {@link IStatus} objects. |
| */ |
| abstract protected String getPluginID(); |
| |
| /** |
| * @deprecated Use {@link org.eclipse.cdt.debug.core.CDebugUtils} instead. |
| */ |
| @Deprecated |
| public static ICProject getCProject(ILaunchConfiguration configuration) throws CoreException { |
| return CDebugUtils.getCProject(configuration); |
| } |
| |
| /** |
| * @deprecated Use {@link org.eclipse.cdt.debug.core.CDebugUtils} instead. |
| */ |
| @Deprecated |
| public static String getProjectName(ILaunchConfiguration configuration) throws CoreException { |
| return CDebugUtils.getProjectName(configuration); |
| } |
| |
| /** |
| * @deprecated Use {@link org.eclipse.cdt.debug.core.CDebugUtils} instead. |
| */ |
| @Deprecated |
| public static String getProgramName(ILaunchConfiguration configuration) throws CoreException { |
| return CDebugUtils.getProgramName(configuration); |
| } |
| |
| /** |
| * @deprecated Use {@link org.eclipse.cdt.debug.core.CDebugUtils} instead. |
| */ |
| @Deprecated |
| public static IPath getProgramPath(ILaunchConfiguration configuration) throws CoreException { |
| return CDebugUtils.getProgramPath(configuration); |
| } |
| |
| /** |
| * @param launch |
| * @param config |
| * @throws CoreException |
| * @deprecated |
| */ |
| @Deprecated |
| protected void setSourceLocator(ILaunch launch, ILaunchConfiguration config) throws CoreException { |
| setDefaultSourceLocator(launch, config); |
| } |
| |
| /** |
| * Assigns a default source locator to the given launch if a source locator |
| * has not yet been assigned to it, and the associated launch configuration |
| * does not specify a source locator. |
| * |
| * @param launch |
| * launch object |
| * @param configuration |
| * configuration being launched |
| * @exception CoreException |
| * if unable to set the source locator |
| */ |
| protected void setDefaultSourceLocator(ILaunch launch, ILaunchConfiguration configuration) throws CoreException { |
| // set default source locator if none specified |
| if (launch.getSourceLocator() == null) { |
| IPersistableSourceLocator sourceLocator; |
| String id = configuration.getAttribute(ILaunchConfiguration.ATTR_SOURCE_LOCATOR_ID, (String) null); |
| if (id == null) { |
| ICProject cProject = CDebugUtils.getCProject(configuration); |
| if (cProject == null) { |
| abort(LaunchMessages.Launch_common_Project_does_not_exist, null, |
| ICDTLaunchConfigurationConstants.ERR_NOT_A_C_PROJECT); |
| } |
| sourceLocator = CDebugUIPlugin.createDefaultSourceLocator(); |
| sourceLocator.initializeDefaults(configuration); |
| } else { |
| sourceLocator = DebugPlugin.getDefault().getLaunchManager().newSourceLocator(id); |
| String memento = configuration.getAttribute(ILaunchConfiguration.ATTR_SOURCE_LOCATOR_MEMENTO, |
| (String) null); |
| if (memento == null) { |
| sourceLocator.initializeDefaults(configuration); |
| } else { |
| sourceLocator.initializeFromMemento(memento); |
| } |
| } |
| launch.setSourceLocator(sourceLocator); |
| } |
| } |
| |
| /** |
| * Returns the program arguments as a String. |
| * |
| * @return the program arguments as a String |
| */ |
| public String getProgramArguments(ILaunchConfiguration config) throws CoreException { |
| return LaunchUtils.getProgramArguments(config); |
| } |
| |
| /** |
| * Returns the program arguments as an array of individual arguments. |
| * |
| * @return the program arguments as an array of individual arguments |
| */ |
| public String[] getProgramArgumentsArray(ILaunchConfiguration config) throws CoreException { |
| return LaunchUtils.getProgramArgumentsArray(config); |
| } |
| |
| protected String renderProcessLabel(String commandLine) { |
| String format = "{0} ({1})"; //$NON-NLS-1$ |
| String timestamp = DateFormat.getInstance().format(new Date(System.currentTimeMillis())); |
| return MessageFormat.format(format, new Object[] { commandLine, timestamp }); |
| } |
| |
| // temporary fix for #66015 |
| /** |
| * @deprecated |
| */ |
| @Deprecated |
| protected String renderDebuggerProcessLabel() { |
| String format = "{0} ({1})"; //$NON-NLS-1$ |
| String timestamp = DateFormat.getInstance().format(new Date(System.currentTimeMillis())); |
| return MessageFormat.format(format, |
| new Object[] { LaunchMessages.AbstractCLaunchDelegate_Debugger_Process, timestamp }); |
| } |
| |
| /** |
| * @param config |
| * @return |
| * @throws CoreException |
| * @deprecated Use <code>verifyProgramFile</code> instead. |
| */ |
| @Deprecated |
| protected IFile getProgramFile(ILaunchConfiguration config) throws CoreException { |
| ICProject cproject = CDebugUtils.verifyCProject(config); |
| String fileName = CDebugUtils.getProgramName(config); |
| if (fileName == null) { |
| abort(LaunchMessages.AbstractCLaunchDelegate_Program_file_not_specified, null, |
| ICDTLaunchConfigurationConstants.ERR_UNSPECIFIED_PROGRAM); |
| } |
| |
| IFile programPath = ((IProject) cproject.getResource()).getFile(fileName); |
| if (programPath == null || !programPath.exists() || !programPath.getLocation().toFile().exists()) { |
| abort(LaunchMessages.AbstractCLaunchDelegate_Program_file_does_not_exist, |
| new FileNotFoundException(NLS.bind(LaunchMessages.AbstractCLaunchDelegate_PROGRAM_PATH_not_found, |
| programPath.getLocation().toOSString())), |
| ICDTLaunchConfigurationConstants.ERR_PROGRAM_NOT_EXIST); |
| } |
| return programPath; |
| } |
| |
| /** |
| * @deprecated use {@link CDebugUtils#verifyCProject(ILaunchConfiguration)} |
| */ |
| @Deprecated |
| protected ICProject verifyCProject(ILaunchConfiguration config) throws CoreException { |
| return CDebugUtils.verifyCProject(config); |
| } |
| |
| /** |
| * @deprecated use {@link CDebugUtils#verifyProgramPath(ILaunchConfiguration) |
| */ |
| @Deprecated |
| protected IPath verifyProgramPath(ILaunchConfiguration config) throws CoreException { |
| return CDebugUtils.verifyProgramPath(config); |
| } |
| |
| protected IPath verifyProgramFile(ILaunchConfiguration config) throws CoreException { |
| return getProgramFile(config).getLocation(); |
| } |
| |
| /** |
| * Verifies the working directory specified by the given launch |
| * configuration exists, and returns the working directory, or |
| * <code>null</code> if none is specified. |
| * |
| * @param configuration |
| * launch configuration |
| * @return the working directory specified by the given launch |
| * configuration, or <code>null</code> if none |
| * @exception CoreException |
| * if unable to retrieve the attribute |
| */ |
| public File verifyWorkingDirectory(ILaunchConfiguration configuration) throws CoreException { |
| IPath path = getWorkingDirectoryPath(configuration); |
| if (path == null) { |
| // default working dir is the project if this config has a project |
| ICProject cp = CDebugUtils.getCProject(configuration); |
| if (cp != null) { |
| IProject p = cp.getProject(); |
| return p.getLocation().toFile(); |
| } |
| } else { |
| if (path.isAbsolute()) { |
| File dir = new File(path.toOSString()); |
| if (dir.isDirectory()) { |
| return dir; |
| } |
| abort(LaunchMessages.AbstractCLaunchDelegate_Working_directory_does_not_exist, |
| new FileNotFoundException( |
| NLS.bind(LaunchMessages.AbstractCLaunchDelegate_WORKINGDIRECTORY_PATH_not_found, |
| path.toOSString())), |
| ICDTLaunchConfigurationConstants.ERR_WORKING_DIRECTORY_DOES_NOT_EXIST); |
| } else { |
| IResource res = ResourcesPlugin.getWorkspace().getRoot().findMember(path); |
| if (res instanceof IContainer && res.exists()) { |
| return res.getLocation().toFile(); |
| } |
| abort(LaunchMessages.AbstractCLaunchDelegate_Working_directory_does_not_exist, |
| new FileNotFoundException( |
| NLS.bind(LaunchMessages.AbstractCLaunchDelegate_WORKINGDIRECTORY_PATH_not_found, |
| path.toOSString())), |
| ICDTLaunchConfigurationConstants.ERR_WORKING_DIRECTORY_DOES_NOT_EXIST); |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Recursively creates a set of projects referenced by the current project |
| * |
| * @param proj |
| * The current project |
| * @param referencedProjSet |
| * A set of referenced projects |
| * @throws CoreException |
| * if an error occurs while getting referenced projects from the |
| * current project |
| */ |
| private void getReferencedProjectSet(IProject proj, HashSet referencedProjSet) throws CoreException { |
| IProject[] projects = proj.getReferencedProjects(); |
| for (int i = 0; i < projects.length; i++) { |
| IProject refProject = projects[i]; |
| if (refProject.exists() && !referencedProjSet.contains(refProject)) { |
| referencedProjSet.add(refProject); |
| getReferencedProjectSet(refProject, referencedProjSet); |
| } |
| } |
| |
| } |
| |
| /** |
| * creates a list of project ordered by their build order from an unordered |
| * list of projects. |
| * |
| * @param resourceCollection |
| * The list of projects to sort. |
| * @return A new list of projects, ordered by build order. |
| */ |
| private List<IProject> getBuildOrder(List<IProject> resourceCollection) { |
| String[] orderedNames = ResourcesPlugin.getWorkspace().getDescription().getBuildOrder(); |
| if (orderedNames != null) { |
| List<IProject> orderedProjs = new ArrayList<>(resourceCollection.size()); |
| //Projects may not be in the build order but should be built if |
| // selected |
| List<IProject> unorderedProjects = new ArrayList<>(resourceCollection.size()); |
| unorderedProjects.addAll(resourceCollection); |
| |
| for (int i = 0; i < orderedNames.length; i++) { |
| String projectName = orderedNames[i]; |
| for (int j = 0; j < resourceCollection.size(); j++) { |
| IProject proj = resourceCollection.get(j); |
| if (proj.getName().equals(projectName)) { |
| orderedProjs.add(proj); |
| unorderedProjects.remove(proj); |
| break; |
| } |
| } |
| } |
| //Add anything not specified before we return |
| orderedProjs.addAll(unorderedProjects); |
| return orderedProjs; |
| } |
| |
| // Try the project prerequisite order then |
| IProject[] projects = new IProject[resourceCollection.size()]; |
| projects = resourceCollection.toArray(projects); |
| IWorkspace.ProjectOrder po = ResourcesPlugin.getWorkspace().computeProjectOrder(projects); |
| ArrayList<IProject> orderedProjs = new ArrayList<>(); |
| orderedProjs.addAll(Arrays.asList(po.projects)); |
| return orderedProjs; |
| } |
| |
| /** |
| * Builds the current project and all of it's prerequisite projects if |
| * necessary. Respects specified build order if any exists. |
| * |
| * @param configuration |
| * the configuration being launched |
| * @param mode |
| * the mode the configuration is being launched in |
| * @param monitor |
| * progress monitor |
| * @return whether the debug platform should perform an incremental |
| * workspace build before the launch |
| * @throws CoreException |
| * if an exception occurs while building |
| */ |
| @Override |
| public boolean buildForLaunch(ILaunchConfiguration configuration, String mode, IProgressMonitor monitor) |
| throws CoreException { |
| |
| buildFailed = false; |
| workspaceBuildBeforeLaunch = true; |
| |
| // check the build before launch setting and honor it |
| int buildBeforeLaunchValue = configuration.getAttribute( |
| ICDTLaunchConfigurationConstants.ATTR_BUILD_BEFORE_LAUNCH, |
| ICDTLaunchConfigurationConstants.BUILD_BEFORE_LAUNCH_USE_WORKSPACE_SETTING); |
| |
| // we shouldn't be getting called if the workspace setting is disabled, so assume we need to |
| // build unless the user explicitly disabled it in the main tab of the launch. |
| if (buildBeforeLaunchValue == ICDTLaunchConfigurationConstants.BUILD_BEFORE_LAUNCH_DISABLED) { |
| return false; |
| } |
| |
| //This matches the old code, but I don't know that it is the right behavior. |
| //We should be building the local project as well, not just the ordered projects |
| if (orderedProjects == null) { |
| return false; |
| } |
| |
| if (monitor == null) { |
| monitor = new NullProgressMonitor(); |
| } |
| |
| int scale = 1000; |
| int totalWork = (orderedProjects.size() + 1) * scale; |
| |
| try { |
| monitor.beginTask(LaunchMessages.AbstractCLaunchDelegate_building_projects, totalWork); |
| |
| try { |
| for (Iterator i = orderedProjects.iterator(); i.hasNext();) { |
| IProject proj = (IProject) i.next(); |
| monitor.subTask(LaunchMessages.AbstractCLaunchDelegate_building + proj.getName()); |
| proj.build(IncrementalProjectBuilder.INCREMENTAL_BUILD, |
| new LaunchUtils.BuildProgressMonitor(monitor, scale)); |
| } |
| |
| monitor.subTask(LaunchMessages.AbstractCLaunchDelegate_building + project.getName()); |
| setBuildConfiguration(configuration, project); |
| project.build(IncrementalProjectBuilder.INCREMENTAL_BUILD, |
| new LaunchUtils.BuildProgressMonitor(monitor, scale)); |
| } catch (Exception e) { |
| // Catch CoreException or OperationCancelledException possibly thrown by the build contract. |
| // Still allow the user to continue to the launch |
| buildFailed = true; |
| } |
| } finally { |
| monitor.done(); |
| } |
| |
| return false; |
| } |
| |
| /** |
| * 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 { |
| 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); |
| programPath = VariablesPlugin.getDefault().getStringVariableManager() |
| .performStringSubstitution(programPath); |
| 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 != null && buildConfigID.length() > 0 && projDes != null) { |
| ICConfigurationDescription buildConfiguration = projDes.getConfigurationById(buildConfigID); |
| if (buildConfiguration != null) { |
| preLaunchBuildConfiguration = projDes.getActiveConfiguration().getId(); |
| buildConfiguration.setActive(); |
| CDTPropertyManager.performOk(null); |
| } |
| } |
| |
| } catch (CoreException e) { |
| } |
| } |
| |
| /** |
| * Searches for compile errors in the current project and any of its |
| * prerequisite projects. If any compile errors, give the user a chance to |
| * abort the launch and correct the errors. |
| * |
| * @param configuration |
| * @param mode |
| * @param monitor |
| * @return whether the launch should proceed |
| * @throws CoreException |
| * if an exception occurs while checking for compile errors. |
| */ |
| @Override |
| public boolean finalLaunchCheck(ILaunchConfiguration configuration, String mode, IProgressMonitor monitor) |
| throws CoreException { |
| if (!workspaceBuildBeforeLaunch) { |
| // buildForLaunch was not called which means that the workspace pref is disabled. see if the user enabled the |
| // launch specific setting in the main tab. if so, we do call buildBeforeLaunch here. |
| if (ICDTLaunchConfigurationConstants.BUILD_BEFORE_LAUNCH_ENABLED == configuration.getAttribute( |
| ICDTLaunchConfigurationConstants.ATTR_BUILD_BEFORE_LAUNCH, |
| ICDTLaunchConfigurationConstants.BUILD_BEFORE_LAUNCH_USE_WORKSPACE_SETTING)) { |
| |
| try { |
| IProgressMonitor buildMonitor = new LaunchUtils.BuildProgressMonitor(monitor, 10, |
| SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK); |
| buildMonitor.beginTask(LaunchMessages.AbstractCLaunchDelegate_BuildBeforeLaunch, 10); |
| buildMonitor.subTask(LaunchMessages.AbstractCLaunchDelegate_PerformingBuild); |
| if (buildForLaunch(configuration, mode, new SubProgressMonitor(buildMonitor, 7))) { |
| buildMonitor.subTask(LaunchMessages.AbstractCLaunchDelegate_PerformingIncrementalBuild); |
| ResourcesPlugin.getWorkspace().build(IncrementalProjectBuilder.INCREMENTAL_BUILD, |
| new SubProgressMonitor(buildMonitor, 3)); |
| } else { |
| buildMonitor.worked(3); /* No incremental build required */ |
| } |
| } catch (Exception e) { |
| // Catch CoreException or OperationCancelledException possibly thrown by the build contract. |
| // Still allow the user to continue to the launch |
| buildFailed = true; |
| } |
| } |
| } |
| |
| boolean continueLaunch = true; |
| if (orderedProjects == null) { |
| return continueLaunch; |
| } |
| |
| if (monitor == null) { |
| monitor = new NullProgressMonitor(); |
| } |
| |
| int scale = 1000; |
| int totalWork = (orderedProjects.size() + 1) * scale; |
| try { |
| monitor.beginTask(LaunchMessages.AbstractCLaunchDelegate_searching_for_errors, totalWork); |
| boolean compileErrorsInProjs = buildFailed; |
| |
| //check prerequisite projects for compile errors. |
| if (!compileErrorsInProjs) { |
| for (Iterator i = orderedProjects.iterator(); i.hasNext();) { |
| IProject proj = (IProject) i.next(); |
| monitor.subTask(LaunchMessages.AbstractCLaunchDelegate_searching_for_errors_in + proj.getName()); |
| monitor.worked(scale); |
| compileErrorsInProjs = existsErrors(proj); |
| if (compileErrorsInProjs) { |
| break; |
| } |
| } |
| } |
| |
| //check current project, if prerequite projects were ok |
| if (!compileErrorsInProjs) { |
| monitor.subTask(LaunchMessages.AbstractCLaunchDelegate_searching_for_errors_in + project.getName()); |
| monitor.worked(scale); |
| compileErrorsInProjs = existsErrors(project); |
| } |
| |
| //if compile errors exist, ask the user before continuing. |
| if (compileErrorsInProjs) { |
| IStatusHandler prompter = DebugPlugin.getDefault().getStatusHandler(promptStatus); |
| if (prompter != null) { |
| continueLaunch = ((Boolean) prompter.handleStatus(complileErrorPromptStatus, null)).booleanValue(); |
| } |
| } |
| } finally { |
| monitor.done(); |
| } |
| |
| if (continueLaunch) // If no problems then restore the previous build configuration. Otherwise leave it so the user can fix the build issues. |
| resetBuildConfiguration(project); |
| |
| return continueLaunch; |
| } |
| |
| private void resetBuildConfiguration(IProject buildProject) { |
| // Restore the active configuration if it was changed for the launch |
| if (preLaunchBuildConfiguration != null) { |
| ICProjectDescription projDes = CDTPropertyManager.getProjectDescription(buildProject); |
| |
| if (preLaunchBuildConfiguration.length() > 0 && projDes != null) { |
| ICConfigurationDescription buildConfiguration = projDes |
| .getConfigurationById(preLaunchBuildConfiguration); |
| if (buildConfiguration != null) { |
| buildConfiguration.setActive(); |
| CDTPropertyManager.performOk(null); |
| } |
| } |
| |
| } |
| preLaunchBuildConfiguration = null; |
| } |
| |
| /** |
| * Searches for compile errors in the specified project |
| * |
| * @param proj |
| * The project to search |
| * @return true if compile errors exist, otherwise false |
| * @since 6.0 |
| */ |
| protected boolean existsErrors(IProject proj) throws CoreException { |
| IMarker[] markers = proj.findMarkers(ICModelMarker.C_MODEL_PROBLEM_MARKER, true, IResource.DEPTH_INFINITE); |
| |
| if (markers.length > 0) { |
| for (int j = 0; j < markers.length; j++) { |
| Object severityAttribute = markers[j].getAttribute(IMarker.SEVERITY); |
| if (severityAttribute != null && ((Integer) severityAttribute).intValue() == IMarker.SEVERITY_ERROR) { |
| return true; |
| } |
| } |
| } |
| |
| return false; |
| } |
| |
| @Override |
| public boolean preLaunchCheck(ILaunchConfiguration configuration, String mode, IProgressMonitor monitor) |
| throws CoreException { |
| if (monitor == null) { |
| monitor = new NullProgressMonitor(); |
| } |
| |
| if (!mode.equals(ILaunchManager.RUN_MODE)) |
| org.eclipse.cdt.launch.LaunchUtils.enableActivity("org.eclipse.cdt.debug.cdigdbActivity", true); //$NON-NLS-1$ |
| |
| workspaceBuildBeforeLaunch = false; |
| |
| int scale = 1000; |
| int totalWork = 2 * scale; |
| |
| try { |
| monitor.beginTask(LaunchMessages.AbstractCLaunchDelegate_20, totalWork); |
| |
| // build project list |
| orderedProjects = null; |
| ICProject cProject = CDebugUtils.getCProject(configuration); |
| if (cProject != null) { |
| project = cProject.getProject(); |
| HashSet<IProject> projectSet = new HashSet<>(); |
| getReferencedProjectSet(project, projectSet); |
| orderedProjects = getBuildOrder(new ArrayList<>(projectSet)); |
| } |
| monitor.worked(scale); |
| |
| // do generic launch checks |
| return super.preLaunchCheck(configuration, mode, new SubProgressMonitor(monitor, scale)); |
| } finally { |
| monitor.done(); |
| } |
| } |
| |
| /** |
| * @param project |
| * @param exePath |
| * @return |
| * @throws CoreException |
| */ |
| protected IBinaryObject verifyBinary(ICProject proj, IPath exePath) throws CoreException { |
| Exception exception; |
| try { |
| return LaunchUtils.getBinary(proj.getProject(), exePath); |
| } catch (ClassCastException e) { |
| exception = e; |
| } |
| Status status = new Status(IStatus.ERROR, getPluginID(), |
| ICDTLaunchConfigurationConstants.ERR_PROGRAM_NOT_BINARY, |
| LaunchMessages.AbstractCLaunchDelegate_Program_is_not_a_recognized_executable + " " //$NON-NLS-1$ |
| + exePath.toOSString(), |
| exception); |
| throw new CoreException(status); |
| } |
| |
| /** |
| * @param config |
| * @return |
| * @throws CoreException |
| */ |
| protected Properties getEnvironmentAsProperty(ILaunchConfiguration config) throws CoreException { |
| String[] envp = getEnvironment(config); |
| Properties p = new Properties(); |
| for (int i = 0; i < envp.length; i++) { |
| int idx = envp[i].indexOf('='); |
| if (idx != -1) { |
| String key = envp[i].substring(0, idx); |
| String value = envp[i].substring(idx + 1); |
| p.setProperty(key, value); |
| } else { |
| p.setProperty(envp[i], ""); //$NON-NLS-1$ |
| } |
| } |
| return p; |
| } |
| |
| /** |
| * Return the save environment variables in the configuration. The array |
| * does not include the default environment of the target. array[n] : |
| * name=value |
| * @throws CoreException |
| */ |
| protected String[] getEnvironment(ILaunchConfiguration config) throws CoreException { |
| try { |
| // Migrate old env settings to new. |
| Map map = config.getAttribute(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_ENVIROMENT_MAP, (Map) null); |
| ILaunchConfigurationWorkingCopy wc = config.getWorkingCopy(); |
| if (map != null) { |
| wc.setAttribute(ILaunchManager.ATTR_ENVIRONMENT_VARIABLES, map); |
| wc.setAttribute(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_ENVIROMENT_MAP, (Map) null); |
| config = wc.doSave(); |
| } |
| boolean append = config.getAttribute(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_ENVIROMENT_INHERIT, |
| true); |
| wc.setAttribute(ILaunchManager.ATTR_APPEND_ENVIRONMENT_VARIABLES, append); |
| } catch (CoreException e) { |
| } |
| String[] array = DebugPlugin.getDefault().getLaunchManager().getEnvironment(config); |
| if (array == null) { |
| return new String[0]; |
| } |
| return array; |
| } |
| |
| /** |
| * Return the save environment variables in the configuration. The array |
| * does not include the default environment of the target. array[n] : |
| * name=value |
| * @deprecated |
| */ |
| @Deprecated |
| protected String[] getEnvironmentArray(ILaunchConfiguration config) { |
| Map env = null; |
| try { |
| env = config.getAttribute(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_ENVIROMENT_MAP, (Map) null); |
| } catch (CoreException e) { |
| } |
| if (env == null) { |
| return new String[0]; |
| } |
| String[] array = new String[env.size()]; |
| Iterator entries = env.entrySet().iterator(); |
| Entry entry; |
| for (int i = 0; entries.hasNext() && i < array.length; i++) { |
| entry = (Entry) entries.next(); |
| array[i] = ((String) entry.getKey()) + "=" + ((String) entry.getValue()); //$NON-NLS-1$ |
| } |
| return array; |
| } |
| |
| /** |
| * Return the save environment variables of this configuration. The array |
| * does not include the default environment of the target. |
| * @deprecated |
| */ |
| @Deprecated |
| protected Properties getEnvironmentProperty(ILaunchConfiguration config) { |
| Properties prop = new Properties(); |
| Map env = null; |
| try { |
| env = config.getAttribute(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_ENVIROMENT_MAP, (Map) null); |
| } catch (CoreException e) { |
| } |
| if (env == null) |
| return prop; |
| Iterator entries = env.entrySet().iterator(); |
| Entry entry; |
| while (entries.hasNext()) { |
| entry = (Entry) entries.next(); |
| prop.setProperty((String) entry.getKey(), (String) entry.getValue()); |
| } |
| return prop; |
| } |
| |
| /** |
| * Returns the default process attribute map for C/C++ processes. |
| * |
| * @return default process attribute map for C/C++ processes |
| */ |
| protected Map getDefaultProcessMap() { |
| Map map = new HashMap(); |
| map.put(IProcess.ATTR_PROCESS_TYPE, ICDTLaunchConfigurationConstants.ID_PROGRAM_PROCESS_TYPE); |
| return map; |
| } |
| } |