/******************************************************************************* * Copyright (c) 2014 Red Hat, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Red Hat Inc. - initial API and implementation *******************************************************************************/ package org.eclipse.cdt.internal.debug.application; import java.io.File; import java.util.Arrays; import java.util.Collection; import java.util.List; import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.language.settings.providers.ILanguageSettingsProvider; import org.eclipse.cdt.core.language.settings.providers.ILanguageSettingsProvidersKeeper; import org.eclipse.cdt.core.language.settings.providers.LanguageSettingsManager; import org.eclipse.cdt.core.model.CoreModel; 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.core.settings.model.ICProjectDescriptionManager; import org.eclipse.cdt.debug.application.ICDTStandaloneDebugLaunchConstants; import org.eclipse.cdt.debug.application.Messages; import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants; import org.eclipse.cdt.debug.core.executables.Executable; import org.eclipse.cdt.debug.core.executables.ExecutablesManager; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IWorkspace; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.QualifiedName; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.debug.core.DebugPlugin; import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.debug.core.ILaunchConfigurationType; import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; import org.eclipse.debug.core.ILaunchManager; import org.eclipse.ui.IWorkbench; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.PlatformUI; public class DebugExecutable { private static final String GCC_BUILTIN_PROVIDER_ID = "org.eclipse.cdt.managedbuilder.core.GCCBuiltinSpecsDetector"; //$NON-NLS-1$ private static final String GCC_COMPILE_OPTIONS_PROVIDER_ID = "org.eclipse.cdt.debug.application.DwarfLanguageSettingsProvider"; //$NON-NLS-1$ private static final String GCC_BUILD_OPTIONS_PROVIDER_ID = "org.eclipse.cdt.managedbuilder.core.GCCBuildCommandParser"; //$NON-NLS-1$ private static final String STANDALONE_QUALIFIER = "org.eclipse.cdt.debug.application"; //$NON-NLS-1$ private static final String LAST_LAUNCH = "lastLaunch"; //$NON-NLS-1$ public DebugExecutable() { } public static ILaunchManager getLaunchManager() { return DebugPlugin.getDefault().getLaunchManager(); } /** * Import given executable into the Executables project then create a launch configuration. * * @param monitor * @param executable * @param buildLog * @param arguments * @throws CoreException * @throws InterruptedException */ public static ILaunchConfiguration importAndCreateLaunchConfig(IProgressMonitor monitor, String executable, String buildLog, String arguments, boolean startup) throws CoreException, InterruptedException { ILaunchConfiguration config = null; File executableFile = new File(executable); String defaultProjectName = "Executables"; //$NON-NLS-1$ ICProject cProject = CoreModel.getDefault().getCModel() .getCProject(defaultProjectName); // if a valid executable is specified, remove any executables already loaded in workspace if (startup && cProject.exists() && executableFile.exists()) { monitor.subTask(Messages.RemoveOldExecutable); IProject proj = cProject.getProject(); Collection<Executable> elist = ExecutablesManager.getExecutablesManager().getExecutablesForProject(proj); Executable[] executables = new Executable[elist.size()]; elist.toArray(executables); @SuppressWarnings("unused") IStatus rc = ExecutablesManager.getExecutablesManager().removeExecutables(executables, new NullProgressMonitor()); // Remove all old members of the Executables project from the last run IResource[] resources = proj.members(); for (IResource resource : resources) { resource.delete(IResource.ALWAYS_DELETE_PROJECT_CONTENT|IResource.FORCE, new NullProgressMonitor()); } monitor.worked(1); // Find last launch if one exists String memento = ResourcesPlugin.getWorkspace().getRoot().getPersistentProperty(new QualifiedName(STANDALONE_QUALIFIER, LAST_LAUNCH)); if (memento != null) { ILaunchConfiguration lastConfiguration = getLaunchManager().getLaunchConfiguration(memento); try { lastConfiguration.getType(); if (lastConfiguration.exists()) lastConfiguration.delete(); } catch (CoreException e) { // do nothing } } // Delete all launch configurations that specify the project we are about to delete ILaunchConfiguration lconfigs[] = getLaunchManager().getLaunchConfigurations(); for (ILaunchConfiguration lconfig : lconfigs) { if (lconfig.getAttribute(ICDTLaunchConfigurationConstants.ATTR_PROJECT_NAME, "").equals(proj.getName())) //$NON-NLS-1$ lconfig.delete(); } // Delete project because we have deleted .cproject and settings files // by this point so just create a new Executables C project to use for // importing the new executable. proj.delete(true, new NullProgressMonitor()); monitor.worked(1); } final String[] fileNames = { executable }; Job importJob = new Job(Messages.ExecutablesView_ImportExecutables) { @Override public IStatus run(IProgressMonitor monitor) { ExecutablesManager.getExecutablesManager().importExecutables( fileNames, monitor); return Status.OK_STATUS; } }; monitor.subTask(Messages.ImportExecutable); importJob.schedule(); importJob.join(); monitor.worked(3); if (importJob.getResult() == Status.OK_STATUS) { // See if the default project exists Collection<Executable> executables = ExecutablesManager.getExecutablesManager().getExecutables(); for (Executable exec : executables) { if (exec.getName().contains(executableFile.getName())) cProject = CoreModel.getDefault().getCModel().getCProject(exec.getProject().getName()); } if (cProject.exists()) { File buildLogFile = null; final IProject project = cProject.getProject(); final ICProjectDescriptionManager projDescManager = CCorePlugin .getDefault().getProjectDescriptionManager(); ICProjectDescription projectDescription = projDescManager .getProjectDescription(project, ICProjectDescriptionManager.GET_WRITABLE); monitor.subTask(Messages.SetLanguageProviders); final ICConfigurationDescription ccd = projectDescription .getActiveConfiguration(); String[] langProviderIds = ((ILanguageSettingsProvidersKeeper) ccd) .getDefaultLanguageSettingsProvidersIds(); boolean found = false; for (int i = 0; i < langProviderIds.length; ++i) { if (langProviderIds[i].equals(GCC_BUILTIN_PROVIDER_ID)) { found = true; break; } } // Look for the GCC builtin LanguageSettingsProvider id. If it isn't already // there, add it. if (!found) { langProviderIds = Arrays.copyOf(langProviderIds, langProviderIds.length + 1); langProviderIds[langProviderIds.length - 1] = GCC_BUILTIN_PROVIDER_ID; } found = false; for (int i = 0; i < langProviderIds.length; ++i) { if (langProviderIds[i].equals(GCC_COMPILE_OPTIONS_PROVIDER_ID)) { found = true; break; } } // Look for our macro parser provider id. If it isn't added already, do so now. if (!found) { langProviderIds = Arrays.copyOf(langProviderIds, langProviderIds.length + 1); langProviderIds[langProviderIds.length - 1] = GCC_COMPILE_OPTIONS_PROVIDER_ID; } if (buildLog != null) { File f = new File(buildLog); if (f.exists()) { buildLogFile = f; found = false; for (int i = 0; i < langProviderIds.length; ++i) { if (langProviderIds[i].equals(GCC_BUILD_OPTIONS_PROVIDER_ID)) { found = true; break; } } // Look for our macro parser provider id. If it isn't added already, do so now. if (!found) { langProviderIds = Arrays.copyOf(langProviderIds, langProviderIds.length + 1); langProviderIds[langProviderIds.length - 1] = GCC_BUILD_OPTIONS_PROVIDER_ID; } } } // Create all the LanguageSettingsProviders List<ILanguageSettingsProvider> providers = LanguageSettingsManager .createLanguageSettingsProviders(langProviderIds); // Update the providers for the configuration. ((ILanguageSettingsProvidersKeeper) ccd) .setLanguageSettingProviders(providers); monitor.worked(1); // Update the project description. projDescManager.setProjectDescription(project, projectDescription); // Serialize the language settings for the project now in case we don't run a // language settings provider which will do this in shutdown. ICProjectDescription projDescReadOnly = projDescManager .getProjectDescription(project, false); LanguageSettingsManager.serializeLanguageSettings(projDescReadOnly); monitor.worked(1); if (!("".equals(executable))) //$NON-NLS-1$ // We need to parse the macro compile options if they exist. We need to lock the // workspace when we do this so we don't have multiple copies of our GCCCompilerOptionsParser // LanguageSettingsProvider and we end up filling in the wrong one. project.getWorkspace().run(new CompilerOptionParser(project, executable), ResourcesPlugin.getWorkspace().getRoot(), IWorkspace.AVOID_UPDATE, new NullProgressMonitor()); if (buildLogFile != null) // We need to parse the build log to get compile options. We need to lock the // workspace when we do this so we don't have multiple copies of GCCBuildOptionsParser // LanguageSettingsProvider and we end up filling in the wrong one. project.getWorkspace().run(new BuildOptionsParser(project, buildLogFile), ResourcesPlugin.getWorkspace().getRoot(), IWorkspace.AVOID_UPDATE, new NullProgressMonitor()); } IWorkbench workbench = PlatformUI.getWorkbench(); if (workbench != null) { final IWorkbenchWindow workbenchWindow = workbench.getActiveWorkbenchWindow(); if (workbenchWindow != null) { final IWorkbenchPage activePage = workbenchWindow.getActivePage(); if (activePage != null) activePage.closeAllEditors(false); } } config = createConfiguration(executable, arguments, buildLog, true); // If we are starting up the debugger, save the executable as the default executable to use if (startup) { String memento = config.getMemento(); ResourcesPlugin.getWorkspace().getRoot().setPersistentProperty(new QualifiedName(STANDALONE_QUALIFIER, LAST_LAUNCH), memento); } monitor.worked(1); } else { System.out.println("Import job failed"); //$NON-NLS-1$ return null; } return config; } protected static ILaunchConfigurationType getLaunchConfigType() { return getLaunchManager().getLaunchConfigurationType(ICDTLaunchConfigurationConstants.ID_LAUNCH_C_APP); } protected static ILaunchConfiguration createConfiguration(String bin, String arguments, String buildLog, boolean save) { ILaunchConfiguration config = null; try { String progName = bin; ILaunchConfigurationType configType = getLaunchConfigType(); ILaunchConfigurationWorkingCopy wc = configType.newInstance( null, getLaunchManager().generateLaunchConfigurationName(bin)); wc.setAttribute(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_NAME, progName); wc.setAttribute(ICDTLaunchConfigurationConstants.ATTR_PROJECT_NAME, "Executables"); //$NON-NLS-1$ wc.setAttribute(ICDTStandaloneDebugLaunchConstants.BUILD_LOG_LOCATION, buildLog); wc.setAttribute( ICDTLaunchConfigurationConstants.ATTR_WORKING_DIRECTORY, (String) null); if (arguments != null) { wc.setAttribute(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_ARGUMENTS, arguments); } // Use the PWD as the working directory for the application being launched wc.setAttribute(ICDTLaunchConfigurationConstants.ATTR_WORKING_DIRECTORY, System.getProperty("user.dir")); //$NON-NLS-1$ if (save) { config = wc.doSave(); } else { config = wc; } } catch (CoreException e) { e.printStackTrace(); } return config; } }