1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-23 14:42:11 +02:00

Bug 486509 - Add support for debugging local Qt apps.

We reuse GDBLaunch but need to override some settings that are
normally in the launch configuration. These things are calculated
at launch time.

Note there is also an added dependency to the launch bar core
to make GDBLaunch a targeted launch so we can set the target properly.
At some point we'll move this launch target stuff lower down, maybe
to the debug platform.

Change-Id: Ibbf6b794a9ecf25b79d46093cc624ea69dc04641
This commit is contained in:
Doug Schaefer 2016-01-25 15:00:32 -05:00 committed by Gerrit Code Review @ Eclipse.org
parent 99426ce65a
commit 192bfff688
13 changed files with 1615 additions and 1061 deletions

View file

@ -18,6 +18,7 @@ import java.util.Map;
import org.eclipse.cdt.build.core.CBuildConfiguration;
import org.eclipse.cdt.build.core.IBuildConfigurationManager;
import org.eclipse.cdt.core.CProjectNature;
import org.eclipse.core.resources.IBuildConfiguration;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
@ -67,6 +68,13 @@ public class CBuildConfigurationManager
if (event.getType() == IResourceChangeEvent.PRE_CLOSE || event.getType() == IResourceChangeEvent.PRE_DELETE) {
if (event.getResource().getType() == IResource.PROJECT) {
IProject project = event.getResource().getProject();
try {
if (!project.hasNature(CProjectNature.C_NATURE_ID))
return;
} catch (CoreException e) {
Activator.log(e.getStatus());
return;
}
// Clean up the configMap
try {

View file

@ -14,7 +14,8 @@ Require-Bundle: org.eclipse.core.runtime,
org.eclipse.core.variables,
org.eclipse.cdt.launch;bundle-version="6.1.0",
org.eclipse.cdt.gdb;bundle-version="7.0.0",
org.eclipse.core.resources
org.eclipse.core.resources,
org.eclipse.launchbar.core;bundle-version="2.0.0";visibility:=reexport
Bundle-ActivationPolicy: lazy
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
Export-Package: org.eclipse.cdt.dsf.gdb,

View file

@ -13,12 +13,32 @@
*******************************************************************************/
package org.eclipse.cdt.dsf.gdb.launching;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.RejectedExecutionException;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.cdtvariables.CdtVariableException;
import org.eclipse.cdt.core.cdtvariables.ICdtVariable;
import org.eclipse.cdt.core.envvar.IEnvironmentVariable;
import org.eclipse.cdt.core.model.CoreModel;
import org.eclipse.cdt.core.model.ICProject;
import org.eclipse.cdt.core.parser.util.StringUtil;
import org.eclipse.cdt.core.settings.model.ICConfigurationDescription;
import org.eclipse.cdt.core.settings.model.ICProjectDescription;
import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants;
import org.eclipse.cdt.debug.internal.core.CRequest;
import org.eclipse.cdt.dsf.concurrent.ConfinedToDsfExecutor;
import org.eclipse.cdt.dsf.concurrent.DefaultDsfExecutor;
@ -36,7 +56,9 @@ import org.eclipse.cdt.dsf.debug.internal.provisional.model.IMemoryBlockRetrieva
import org.eclipse.cdt.dsf.debug.model.DsfLaunch;
import org.eclipse.cdt.dsf.debug.service.IDsfDebugServicesFactory;
import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService.ICommandControlShutdownDMEvent;
import org.eclipse.cdt.dsf.gdb.IGDBLaunchConfigurationConstants;
import org.eclipse.cdt.dsf.gdb.IGdbDebugConstants;
import org.eclipse.cdt.dsf.gdb.IGdbDebugPreferenceConstants;
import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin;
import org.eclipse.cdt.dsf.gdb.internal.memory.GdbMemoryBlockRetrievalManager;
import org.eclipse.cdt.dsf.gdb.service.command.IGDBControl;
@ -44,15 +66,28 @@ import org.eclipse.cdt.dsf.mi.service.command.AbstractCLIProcess;
import org.eclipse.cdt.dsf.service.DsfServiceEventHandler;
import org.eclipse.cdt.dsf.service.DsfServicesTracker;
import org.eclipse.cdt.dsf.service.DsfSession;
import org.eclipse.cdt.utils.CommandLineUtil;
import org.eclipse.cdt.utils.spawner.ProcessFactory;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
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.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.core.variables.VariablesPlugin;
import org.eclipse.debug.core.DebugException;
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.commands.IDebugCommandRequest;
import org.eclipse.debug.core.commands.IDisconnectHandler;
@ -60,14 +95,14 @@ import org.eclipse.debug.core.commands.ITerminateHandler;
import org.eclipse.debug.core.model.IDisconnect;
import org.eclipse.debug.core.model.ISourceLocator;
import org.eclipse.debug.core.model.ITerminate;
import org.eclipse.launchbar.core.target.ILaunchTarget;
import org.eclipse.launchbar.core.target.launch.ITargetedLaunch;
/**
* The only object in the model that implements the traditional interfaces.
*/
@ThreadSafe
public class GdbLaunch extends DsfLaunch
implements ITerminate, IDisconnect, ITracedLaunch
{
public class GdbLaunch extends DsfLaunch implements ITerminate, IDisconnect, ITracedLaunch, ITargetedLaunch {
private DefaultDsfExecutor fExecutor;
private DsfSession fSession;
private DsfServicesTracker fTracker;
@ -75,6 +110,7 @@ public class GdbLaunch extends DsfLaunch
private boolean fShutDown = false;
private IMemoryBlockRetrievalManager fMemRetrievalManager;
private IDsfDebugServicesFactory fServiceFactory;
private ILaunchTarget fLaunchTarget;
public GdbLaunch(ILaunchConfiguration launchConfiguration, String mode, ISourceLocator locator) {
super(launchConfiguration, mode, locator);
@ -87,17 +123,21 @@ public class GdbLaunch extends DsfLaunch
fSession = DsfSession.startSession(fExecutor, GdbLaunchDelegate.GDB_DEBUG_MODEL_ID);
}
public DsfExecutor getDsfExecutor() { return fExecutor; }
public IDsfDebugServicesFactory getServiceFactory() { return fServiceFactory; }
public DsfExecutor getDsfExecutor() {
return fExecutor;
}
public void initialize()
{
public IDsfDebugServicesFactory getServiceFactory() {
return fServiceFactory;
}
public void initialize() {
/*
* Registering the launch as an adapter. This ensures that this launch
* will be associated with all DMContexts from this session.
* We do this here because we want to have access to the launch even
* if we run headless, but when we run headless, GdbAdapterFactory is
* not initialized.
* will be associated with all DMContexts from this session. We do this
* here because we want to have access to the launch even if we run
* headless, but when we run headless, GdbAdapterFactory is not
* initialized.
*/
fSession.registerModelAdapter(ILaunch.class, this);
@ -116,44 +156,49 @@ public class GdbLaunch extends DsfLaunch
try {
fExecutor.submit(initRunnable).get();
} catch (InterruptedException e) {
new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, IDsfStatusConstants.INTERNAL_ERROR, "Error initializing launch", e); //$NON-NLS-1$
new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, IDsfStatusConstants.INTERNAL_ERROR,
"Error initializing launch", e); //$NON-NLS-1$
} catch (ExecutionException e) {
new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, IDsfStatusConstants.INTERNAL_ERROR, "Error initializing launch", e); //$NON-NLS-1$
new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, IDsfStatusConstants.INTERNAL_ERROR,
"Error initializing launch", e); //$NON-NLS-1$
}
}
public void initializeControl()
throws CoreException
{
public void initializeControl() throws CoreException {
// Create a memory retrieval manager and register it with the session
// To maintain a mapping of memory contexts to the corresponding memory retrieval in this session
// To maintain a mapping of memory contexts to the corresponding memory
// retrieval in this session
try {
fExecutor.submit(new Callable<Object>() {
@Override
public Object call() throws CoreException {
fMemRetrievalManager = new GdbMemoryBlockRetrievalManager(GdbLaunchDelegate.GDB_DEBUG_MODEL_ID, getLaunchConfiguration(), fSession);
fMemRetrievalManager = new GdbMemoryBlockRetrievalManager(GdbLaunchDelegate.GDB_DEBUG_MODEL_ID,
getLaunchConfiguration(), fSession);
fSession.registerModelAdapter(IMemoryBlockRetrievalManager.class, fMemRetrievalManager);
fSession.addServiceEventListener(fMemRetrievalManager, null);
return null;
}
}).get();
} catch (InterruptedException e) {
throw new CoreException(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, 0, "Interrupted while waiting for get process callable.", e)); //$NON-NLS-1$
throw new CoreException(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, 0,
"Interrupted while waiting for get process callable.", e)); //$NON-NLS-1$
} catch (ExecutionException e) {
throw (CoreException) e.getCause();
} catch (RejectedExecutionException e) {
throw new CoreException(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, 0, "Debugger shut down before launch was completed.", e)); //$NON-NLS-1$
throw new CoreException(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, 0,
"Debugger shut down before launch was completed.", e)); //$NON-NLS-1$
}
}
public DsfSession getSession() { return fSession; }
public DsfSession getSession() {
return fSession;
}
@ThreadSafeAndProhibitedFromDsfExecutor("getDsfExecutor()")
public void addCLIProcess(String label) throws CoreException {
try {
// Add the CLI process object to the launch.
AbstractCLIProcess cliProc =
getDsfExecutor().submit( new Callable<AbstractCLIProcess>() {
AbstractCLIProcess cliProc = getDsfExecutor().submit(new Callable<AbstractCLIProcess>() {
@Override
public AbstractCLIProcess call() throws CoreException {
IGDBControl gdb = fTracker.getService(IGDBControl.class);
@ -173,11 +218,13 @@ public class GdbLaunch extends DsfLaunch
IGdbDebugConstants.GDB_PROCESS_CREATION_VALUE);
DebugPlugin.newProcess(this, cliProc, label, attributes);
} catch (InterruptedException e) {
throw new CoreException(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, 0, "Interrupted while waiting for get process callable.", e)); //$NON-NLS-1$
throw new CoreException(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, 0,
"Interrupted while waiting for get process callable.", e)); //$NON-NLS-1$
} catch (ExecutionException e) {
throw (CoreException) e.getCause();
} catch (RejectedExecutionException e) {
throw new CoreException(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, 0, "Debugger shut down before launch was completed.", e)); //$NON-NLS-1$
throw new CoreException(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, 0,
"Debugger shut down before launch was completed.", e)); //$NON-NLS-1$
}
}
@ -187,7 +234,8 @@ public class GdbLaunch extends DsfLaunch
///////////////////////////////////////////////////////////////////////////
// IServiceEventListener
@DsfServiceEventHandler public void eventDispatched(ICommandControlShutdownDMEvent event) {
@DsfServiceEventHandler
public void eventDispatched(ICommandControlShutdownDMEvent event) {
shutdownSession(new ImmediateRequestMonitor());
}
@ -229,7 +277,9 @@ public class GdbLaunch extends DsfLaunch
return fInitialized && super.canTerminate();
}
/* (non-Javadoc)
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.core.Launch#terminate()
*/
@Override
@ -278,16 +328,18 @@ public class GdbLaunch extends DsfLaunch
///////////////////////////////////////////////////////////////////////////
/**
* Terminates the gdb session, shuts down the services, the session and
* the executor associated with this launch.
* Terminates the gdb session, shuts down the services, the session and the
* executor associated with this launch.
* <p>
* Note: The argument request monitor to this method should NOT use the
* executor that belongs to this launch. By the time the shutdown is
* complete, this executor will not be dispatching anymore and the
* request monitor will never be invoked. Instead callers should use
* the {@link ImmediateExecutor}.
* complete, this executor will not be dispatching anymore and the request
* monitor will never be invoked. Instead callers should use the
* {@link ImmediateExecutor}.
* </p>
* @param rm The request monitor invoked when the shutdown is complete.
*
* @param rm
* The request monitor invoked when the shutdown is complete.
*/
@ConfinedToDsfExecutor("getSession().getExecutor()")
public void shutdownSession(final RequestMonitor rm) {
@ -297,8 +349,7 @@ public class GdbLaunch extends DsfLaunch
}
fShutDown = true;
final Sequence shutdownSeq = new ShutdownSequence(
getDsfExecutor(), fSession.getId(),
final Sequence shutdownSeq = new ShutdownSequence(getDsfExecutor(), fSession.getId(),
new RequestMonitor(fSession.getExecutor(), rm) {
@Override
public void handleCompleted() {
@ -309,19 +360,23 @@ public class GdbLaunch extends DsfLaunch
fSession.removeServiceEventListener(GdbLaunch.this);
if (!isSuccess()) {
GdbPlugin.getDefault().getLog().log(new MultiStatus(
GdbPlugin.PLUGIN_ID, -1, new IStatus[]{getStatus()}, "Session shutdown failed", null)); //$NON-NLS-1$
GdbPlugin.getDefault().getLog().log(new MultiStatus(GdbPlugin.PLUGIN_ID, -1,
new IStatus[] { getStatus() }, "Session shutdown failed", null)); //$NON-NLS-1$
}
// Last order of business, shutdown the dispatch queue.
fTracker.dispose();
fTracker = null;
DsfSession.endSession(fSession);
// 'fireTerminate()' removes this launch from the list of 'DebugEvent'
// listeners. The launch may not be terminated at this point: the inferior
// and gdb processes are monitored in separate threads. This will prevent
// 'fireTerminate()' removes this launch from the list
// of 'DebugEvent'
// listeners. The launch may not be terminated at this
// point: the inferior
// and gdb processes are monitored in separate threads.
// This will prevent
// updating of some of the Debug view actions.
// 'DebugEvent.TERMINATE' will be fired when each of the corresponding processes
// 'DebugEvent.TERMINATE' will be fired when each of the
// corresponding processes
// exits and handled by 'handleDebugEvents()' method.
if (isTerminated()) {
fireTerminate();
@ -332,8 +387,7 @@ public class GdbLaunch extends DsfLaunch
}
});
final Step[] steps = new Step[] {
new Step() {
final Step[] steps = new Step[] { new Step() {
@Override
public void execute(RequestMonitor rm) {
IGDBControl control = fTracker.getService(IGDBControl.class);
@ -350,8 +404,7 @@ public class GdbLaunch extends DsfLaunch
public void execute(RequestMonitor rm) {
fExecutor.execute(shutdownSeq);
}
}
};
} };
fExecutor.execute(new Sequence(fExecutor) {
@ -383,4 +436,471 @@ public class GdbLaunch extends DsfLaunch
}
super.launchRemoved(launch);
}
/**
* Returns the path to gdb.
*
* @since 5.0
*/
public IPath getGDBPath() {
String defaultGdbCommand = Platform.getPreferencesService().getString(GdbPlugin.PLUGIN_ID,
IGdbDebugPreferenceConstants.PREF_DEFAULT_GDB_COMMAND,
IGDBLaunchConfigurationConstants.DEBUGGER_DEBUG_NAME_DEFAULT, null);
IPath retVal = new Path(defaultGdbCommand);
try {
String gdb = getAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUG_NAME);
if (gdb == null) {
gdb = getLaunchConfiguration().getAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUG_NAME,
defaultGdbCommand);
}
gdb = VariablesPlugin.getDefault().getStringVariableManager().performStringSubstitution(gdb, false);
retVal = new Path(gdb);
} catch (CoreException e) {
}
return retVal;
}
/**
* Set the path to gdb
*
* @param path
* the path to gdb
* @since 5.0
*/
public void setGDBPath(String path) {
setAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUG_NAME, path);
}
/**
* This method actually launches 'gdb --version' to determine the version of
* the GDB that is being used. This method should ideally be called only
* once per session and the resulting version string stored for future uses.
*
* A timeout is scheduled which will kill the process if it takes too long.
*
* @since 5.0
*/
public String getGDBVersion() throws CoreException {
String cmd = getGDBPath().toOSString() + " --version"; //$NON-NLS-1$
// Parse cmd to properly handle spaces and such things (bug 458499)
String[] args = CommandLineUtil.argumentsToArray(cmd);
Process process = null;
Job timeoutJob = null;
try {
process = ProcessFactory.getFactory().exec(args, getLaunchEnvironment());
// Start a timeout job to make sure we don't get stuck waiting for
// an answer from a gdb that is hanging
// Bug 376203
final Process finalProc = process;
timeoutJob = new Job("GDB version timeout job") { //$NON-NLS-1$
{
setSystem(true);
}
@Override
protected IStatus run(IProgressMonitor arg) {
// Took too long. Kill the gdb process and
// let things clean up.
finalProc.destroy();
return Status.OK_STATUS;
}
};
timeoutJob.schedule(10000);
String streamOutput = readStream(process.getInputStream());
String gdbVersion = LaunchUtils.getGDBVersionFromText(streamOutput);
if (gdbVersion == null || gdbVersion.isEmpty()) {
Exception detailedException = null;
if (!streamOutput.isEmpty()) {
// We got some output but couldn't parse it. Make that
// output visible to the user in the error dialog.
detailedException = new Exception("Unexpected output format: \n\n" + streamOutput); //$NON-NLS-1$
} else {
// We got no output. Check if we got something on the error
// stream.
streamOutput = readStream(process.getErrorStream());
if (!streamOutput.isEmpty()) {
detailedException = new Exception(streamOutput);
}
}
throw new DebugException(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, DebugException.REQUEST_FAILED,
"Could not determine GDB version using command: " + StringUtil.join(args, " "), //$NON-NLS-1$ //$NON-NLS-2$
detailedException));
}
return gdbVersion;
} catch (IOException e) {
throw new DebugException(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, DebugException.REQUEST_FAILED,
"Error with command: " + StringUtil.join(args, " "), e));//$NON-NLS-1$ //$NON-NLS-2$
} finally {
// If we get here we are obviously not stuck reading the stream so
// we can cancel the timeout job.
// Note that it may already have executed, but that is not a
// problem.
if (timeoutJob != null) {
timeoutJob.cancel();
}
if (process != null) {
process.destroy();
}
}
}
/**
* Read from the specified stream and return what was read.
*
* @param stream
* The input stream to be used to read the data. This method will
* close the stream.
* @return The data read from the stream
* @throws IOException
* If an IOException happens when reading the stream
*/
private static String readStream(InputStream stream) throws IOException {
StringBuilder cmdOutput = new StringBuilder(200);
try {
Reader r = new InputStreamReader(stream);
BufferedReader reader = new BufferedReader(r);
String line;
while ((line = reader.readLine()) != null) {
cmdOutput.append(line);
cmdOutput.append('\n');
}
return cmdOutput.toString();
} finally {
// Cleanup to avoid leaking pipes
// Bug 345164
if (stream != null) {
try {
stream.close();
} catch (IOException e) {
}
}
}
}
/**
* Gets the CDT environment from the CDT project's configuration referenced
* by the launch
*
* @since 5.0
*/
public String[] getLaunchEnvironment() throws CoreException {
// Get the project
String projectName = getLaunchConfiguration().getAttribute(ICDTLaunchConfigurationConstants.ATTR_PROJECT_NAME,
(String) null);
IProject project = null;
if (projectName == null) {
IResource[] resources = getLaunchConfiguration().getMappedResources();
if (resources != null && resources.length > 0 && resources[0] instanceof IProject) {
project = (IProject) resources[0];
}
} else {
projectName = projectName.trim();
if (projectName.length() == 0) {
return null;
}
project = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName);
}
if (project == null || !project.isAccessible()) {
// No project
return null;
}
HashMap<String, String> envMap = new HashMap<String, String>();
ICProjectDescription projDesc = CoreModel.getDefault().getProjectDescription(project, false);
if (projDesc != null) {
String buildConfigID = getLaunchConfiguration()
.getAttribute(ICDTLaunchConfigurationConstants.ATTR_PROJECT_BUILD_CONFIG_ID, ""); //$NON-NLS-1$
ICConfigurationDescription cfg = null;
if (buildConfigID.length() != 0) {
cfg = projDesc.getConfigurationById(buildConfigID);
}
// if configuration is null fall-back to active
if (cfg == null) {
cfg = projDesc.getActiveConfiguration();
}
// Environment variables and inherited vars
IEnvironmentVariable[] vars = CCorePlugin.getDefault().getBuildEnvironmentManager().getVariables(cfg, true);
for (IEnvironmentVariable var : vars) {
envMap.put(var.getName(), var.getValue());
}
// Add variables from build info
ICdtVariable[] buildVars = CCorePlugin.getDefault().getCdtVariableManager().getVariables(cfg);
for (ICdtVariable var : buildVars) {
try {
// The project_classpath variable contributed by JDT is
// useless
// for running C/C++
// binaries, but it can be lethal if it has a very large
// value
// that exceeds shell
// limit. See
// http://bugs.eclipse.org/bugs/show_bug.cgi?id=408522
if (!"project_classpath".equals(var.getName())) {//$NON-NLS-1$
envMap.put(var.getName(), var.getStringValue());
}
} catch (CdtVariableException e) {
// Some Eclipse dynamic variables can't be resolved
// dynamically... we don't care.
}
}
}
// Turn it into an envp format
List<String> strings = new ArrayList<String>(envMap.size());
for (Entry<String, String> entry : envMap.entrySet()) {
StringBuffer buffer = new StringBuffer(entry.getKey());
buffer.append('=').append(entry.getValue());
strings.add(buffer.toString());
}
return strings.toArray(new String[strings.size()]);
}
/**
* Get the location of the gdbinit file.
*
* @return gdbinit file location
* @throws CoreException
* @since 5.0
*/
public String getGDBInitFile() throws CoreException {
String defaultGdbInit = Platform.getPreferencesService().getString(GdbPlugin.PLUGIN_ID,
IGdbDebugPreferenceConstants.PREF_DEFAULT_GDB_INIT,
IGDBLaunchConfigurationConstants.DEBUGGER_GDB_INIT_DEFAULT, null);
return getLaunchConfiguration().getAttribute(IGDBLaunchConfigurationConstants.ATTR_GDB_INIT, defaultGdbInit);
}
/**
* Get the working directory.
*
* @return the working directory
* @throws CoreException
* @since 5.0
*/
public IPath getGDBWorkingDirectory() throws CoreException {
// First try to use the user-specified working directory for the
// debugged program.
// This is fine only with local debug.
// For remote debug, the working dir of the debugged program will be
// on remote device
// and hence not applicable. In such case we may just use debugged
// program path on host
// as the working dir for GDB.
// However, we cannot find a standard/common way to distinguish
// remote debug from local
// debug. For instance, a local debug may also use gdbserver+gdb. So
// it's up to each
// debugger implementation to make the distinction.
//
IPath path = null;
String location = getLaunchConfiguration().getAttribute(ICDTLaunchConfigurationConstants.ATTR_WORKING_DIRECTORY,
(String) null);
if (location != null) {
String expandedLocation = VariablesPlugin.getDefault().getStringVariableManager()
.performStringSubstitution(location);
if (!expandedLocation.isEmpty()) {
path = new Path(expandedLocation);
}
}
if (path != null) {
// Some validity check. Should have been done by UI code.
if (path.isAbsolute()) {
File dir = new File(path.toPortableString());
if (!dir.isDirectory())
path = null;
} else {
IResource res = ResourcesPlugin.getWorkspace().getRoot().findMember(path);
if (res instanceof IContainer && res.exists()) {
path = res.getLocation();
} else
// Relative but not found in workspace.
path = null;
}
}
if (path == null) {
// default working dir is the project if this config has a
// project
ICProject cp = LaunchUtils.getCProject(getLaunchConfiguration());
if (cp != null) {
IProject p = cp.getProject();
path = p.getLocation();
} else {
// no meaningful value found. Just return null.
}
}
return path;
}
/**
* Get the program arguments
*
* @return program arguments
* @throws CoreException
* @since 5.0
*/
public String getProgramArguments() throws CoreException {
String programArguments = getLaunchConfiguration()
.getAttribute(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_ARGUMENTS, (String) null);
if (programArguments != null) {
programArguments = VariablesPlugin.getDefault().getStringVariableManager()
.performStringSubstitution(programArguments);
}
return programArguments;
}
/**
* Return the program path
*
* @return the program path
* @since 5.0
*/
public String getProgramPath() throws CoreException {
String programPath = getAttribute(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_NAME);
if (programPath == null) {
programPath = getLaunchConfiguration().getAttribute(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_NAME,
(String) null);
}
return programPath;
}
/**
* Sets the program path
*
* @param programPath
* the program path
* @throws CoreException
* @since 5.0
*/
public void setProgramPath(String programPath) throws CoreException {
setAttribute(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_NAME, programPath);
}
/**
* Return shared library paths
*
* @return shared library paths
* @throws CoreException
* @since 5.0
*/
public List<String> getSharedLibraryPaths() throws CoreException {
return getLaunchConfiguration().getAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_SOLIB_PATH,
new ArrayList<String>(0));
}
/**
* return the environment
*
* @return the environment
* @throws CoreException
* @since 5.0
*/
public Properties getEnvironmentVariables() throws CoreException {
Properties envVariables = new Properties();
// if the attribute ATTR_APPEND_ENVIRONMENT_VARIABLES is set,
// the LaunchManager will return both the new variables and the
// existing ones.
// That would force us to delete all the variables in GDB, and then
// re-create then all
// that is not very efficient. So, let's fool the LaunchManager into
// returning just the
// list of new variables.
boolean append = getLaunchConfiguration().getAttribute(ILaunchManager.ATTR_APPEND_ENVIRONMENT_VARIABLES, true);
String[] properties;
if (append) {
ILaunchConfigurationWorkingCopy wc = getLaunchConfiguration().copy(""); //$NON-NLS-1$
// Don't save this change, it is just temporary, and in just a
// copy of our launchConfig.
wc.setAttribute(ILaunchManager.ATTR_APPEND_ENVIRONMENT_VARIABLES, false);
properties = DebugPlugin.getDefault().getLaunchManager().getEnvironment(wc);
} else {
// We're getting rid of the environment anyway, so this call
// will only yield the new variables.
properties = DebugPlugin.getDefault().getLaunchManager().getEnvironment(getLaunchConfiguration());
}
if (properties == null) {
properties = new String[0];
}
for (String property : properties) {
int idx = property.indexOf('=');
if (idx != -1) {
String key = property.substring(0, idx);
String value = property.substring(idx + 1);
envVariables.setProperty(key, value);
} else {
envVariables.setProperty(property, ""); //$NON-NLS-1$
}
}
return envVariables;
}
/**
* Get whether to clear the environment before applying the variables
*
* @return clear
* @throws CoreException
* @since 5.0
*/
public boolean getClearEnvironment() throws CoreException {
return !getLaunchConfiguration().getAttribute(ILaunchManager.ATTR_APPEND_ENVIRONMENT_VARIABLES, true);
}
/**
* Get whether to update thread list on suspend
*
* @return whether
* @throws CoreException
* @since 5.0
*/
public boolean getUpdateThreadListOnSuspend() throws CoreException {
return getLaunchConfiguration().getAttribute(
IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_UPDATE_THREADLIST_ON_SUSPEND,
IGDBLaunchConfigurationConstants.DEBUGGER_UPDATE_THREADLIST_ON_SUSPEND_DEFAULT);
}
/**
* Set the launch target
*
* @param launchTarget
* the launch target
* @since 5.0
*/
public void setLaunchTarget(ILaunchTarget launchTarget) {
this.fLaunchTarget = launchTarget;
}
/**
* Return the launch target
*
* @since 5.0
*/
@Override
public ILaunchTarget getLaunchTarget() {
return fLaunchTarget;
}
}

View file

@ -296,11 +296,12 @@ public class GdbLaunchDelegate extends AbstractCLaunchDelegate2
}
/**
* Returns the GDB version.
* Subclass can override for special need.
* Returns the GDB version. Subclass can override for special need.
*
* @since 2.0
* @deprecated Replaced by GdbLaunch.getGDBVersion() which can also be overridden
*/
@Deprecated
protected String getGDBVersion(ILaunchConfiguration config) throws CoreException {
return LaunchUtils.getGDBVersion(config);
}

View file

@ -273,7 +273,10 @@ public class LaunchUtils {
* only once per session and the resulting version string stored for future uses.
*
* A timeout is scheduled which will kill the process if it takes too long.
*
* @deprecated Replaced with GdbLaunch.getLaunchEnvironment()
*/
@Deprecated
public static String getGDBVersion(final ILaunchConfiguration configuration) throws CoreException {
String cmd = getGDBPath(configuration).toOSString() + " --version"; //$NON-NLS-1$
@ -476,7 +479,9 @@ public class LaunchUtils {
* Gets the CDT environment from the CDT project's configuration referenced by the
* launch
* @since 3.0
* @deprecated Replaced with GdbLaunch.getLaunchEnvironment()
*/
@Deprecated
public static String[] getLaunchEnvironment(ILaunchConfiguration config) throws CoreException {
// Get the project
String projectName = config.getAttribute(ICDTLaunchConfigurationConstants.ATTR_PROJECT_NAME, (String)null);

View file

@ -16,29 +16,24 @@
package org.eclipse.cdt.dsf.gdb.service;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import org.eclipse.cdt.core.model.ICProject;
import org.eclipse.cdt.core.parser.util.StringUtil;
import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants;
import org.eclipse.cdt.dsf.concurrent.DsfRunnable;
import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
import org.eclipse.cdt.dsf.concurrent.ImmediateRequestMonitor;
import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
import org.eclipse.cdt.dsf.concurrent.Sequence;
import org.eclipse.cdt.dsf.gdb.IGDBLaunchConfigurationConstants;
import org.eclipse.cdt.dsf.gdb.IGdbDebugPreferenceConstants;
import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin;
import org.eclipse.cdt.dsf.gdb.launching.GdbLaunch;
import org.eclipse.cdt.dsf.gdb.launching.LaunchUtils;
import org.eclipse.cdt.dsf.gdb.service.command.GDBControl.InitializationShutdownStep;
import org.eclipse.cdt.dsf.mi.service.IMIBackend;
@ -50,30 +45,22 @@ import org.eclipse.cdt.dsf.service.DsfSession;
import org.eclipse.cdt.utils.CommandLineUtil;
import org.eclipse.cdt.utils.spawner.ProcessFactory;
import org.eclipse.cdt.utils.spawner.Spawner;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
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.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.core.variables.VariablesPlugin;
import org.eclipse.debug.core.DebugException;
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.osgi.framework.BundleContext;
/**
* Implementation of {@link IGDBBackend} for the common case where GDB is launched
* in local file system on host PC where Eclipse runs. This also manages some GDB parameters
* from a given launch configuration.<br>
* Implementation of {@link IGDBBackend} for the common case where GDB is
* launched in local file system on host PC where Eclipse runs. This also
* manages some GDB parameters from a given launch configuration.<br>
* <br>
* You can subclass for you special needs.
*
@ -86,18 +73,11 @@ public class GDBBackend extends AbstractDsfService implements IGDBBackend, IMIBa
/*
* Parameters for launching GDB.
*/
private IPath fProgramPath;
private IPath fGDBWorkingDirectory;
private String fGDBInitFile;
private List<String> fSharedLibPaths;
private String fProgramArguments;
private Properties fEnvVariables;
private SessionType fSessionType;
private Boolean fAttach;
private State fBackendState = State.NOT_INITIALIZED;
/**
/*
* Unique ID of this service instance.
*/
private final String fBackendId;
@ -112,25 +92,15 @@ public class GDBBackend extends AbstractDsfService implements IGDBBackend, IMIBa
private int fGDBLaunchTimeout = 30;
/**
* A Job that will set a failed status
* in the proper request monitor, if the interrupt
* did not succeed after a certain time.
* A Job that will set a failed status in the proper request monitor, if the
* interrupt did not succeed after a certain time.
*/
private MonitorInterruptJob fInterruptFailedJob;
public GDBBackend(DsfSession session, ILaunchConfiguration lc) {
super(session);
this.fLaunchConfiguration = lc;
fBackendId = "gdb[" + Integer.toString(fgInstanceCounter++) + "]"; //$NON-NLS-1$//$NON-NLS-2$
fLaunchConfiguration = lc;
try {
// Don't call verifyCProject, because the JUnit tests are not setting a project
ICProject cproject = LaunchUtils.getCProject(lc);
fProgramPath = LaunchUtils.verifyProgramPath(lc, cproject);
} catch (CoreException e) {
fProgramPath = new Path(""); //$NON-NLS-1$
}
}
@Override
@ -152,11 +122,13 @@ public class GDBBackend extends AbstractDsfService implements IGDBBackend, IMIBa
final Sequence.Step[] initializeSteps = new Sequence.Step[] {
new GDBProcessStep(InitializationShutdownStep.Direction.INITIALIZING),
new MonitorJobStep(InitializationShutdownStep.Direction.INITIALIZING),
new RegisterStep(InitializationShutdownStep.Direction.INITIALIZING),
};
new RegisterStep(InitializationShutdownStep.Direction.INITIALIZING), };
return new Sequence(getExecutor(), requestMonitor) {
@Override public Step[] getSteps() { return initializeSteps; }
@Override
public Step[] getSteps() {
return initializeSteps;
}
};
}
@ -175,23 +147,28 @@ public class GDBBackend extends AbstractDsfService implements IGDBBackend, IMIBa
final Sequence.Step[] shutdownSteps = new Sequence.Step[] {
new RegisterStep(InitializationShutdownStep.Direction.SHUTTING_DOWN),
new MonitorJobStep(InitializationShutdownStep.Direction.SHUTTING_DOWN),
new GDBProcessStep(InitializationShutdownStep.Direction.SHUTTING_DOWN),
};
new GDBProcessStep(InitializationShutdownStep.Direction.SHUTTING_DOWN), };
return new Sequence(getExecutor(), requestMonitor) {
@Override public Step[] getSteps() { return shutdownSteps; }
@Override
public Step[] getSteps() {
return shutdownSteps;
}
};
}
private GdbLaunch getGDBLaunch() {
return (GdbLaunch) getSession().getModelAdapter(ILaunch.class);
}
/** @since 4.0 */
protected IPath getGDBPath() {
return LaunchUtils.getGDBPath(fLaunchConfiguration);
return getGDBLaunch().getGDBPath();
}
/**
* Options for GDB process.
* Allow subclass to override.
* Options for GDB process. Allow subclass to override.
*
* @deprecated Use {@link #getGDBCommandLineArray()} instead
*/
@Deprecated
@ -201,9 +178,9 @@ public class GDBBackend extends AbstractDsfService implements IGDBBackend, IMIBa
}
/**
* Options for GDB process.
* Returns the GDB command and its arguments as an array.
* Allow subclass to override.
* Options for GDB process. Returns the GDB command and its arguments as an
* array. Allow subclass to override.
*
* @since 4.6
*/
protected String[] getGDBCommandLineArray() {
@ -211,8 +188,7 @@ public class GDBBackend extends AbstractDsfService implements IGDBBackend, IMIBa
// All configuration should be done in the final launch sequence
// to allow for more flexibility.
String cmd = getGDBPath().toOSString() +
" --interpreter" + //$NON-NLS-1$
String cmd = getGDBPath().toOSString() + " --interpreter" + //$NON-NLS-1$
// We currently work with MI version 2. Don't use just 'mi' because it
// points to the latest MI version, while we want mi2 specifically.
" mi2" + //$NON-NLS-1$
@ -226,188 +202,79 @@ public class GDBBackend extends AbstractDsfService implements IGDBBackend, IMIBa
@Override
public String getGDBInitFile() throws CoreException {
if (fGDBInitFile == null) {
String defaultGdbInit = Platform.getPreferencesService().getString(GdbPlugin.PLUGIN_ID,
IGdbDebugPreferenceConstants.PREF_DEFAULT_GDB_INIT,
IGDBLaunchConfigurationConstants.DEBUGGER_GDB_INIT_DEFAULT, null);
fGDBInitFile = fLaunchConfiguration.getAttribute(IGDBLaunchConfigurationConstants.ATTR_GDB_INIT, defaultGdbInit);
}
return fGDBInitFile;
return getGDBLaunch().getGDBInitFile();
}
@Override
public IPath getGDBWorkingDirectory() throws CoreException {
if (fGDBWorkingDirectory == null) {
// First try to use the user-specified working directory for the debugged program.
// This is fine only with local debug.
// For remote debug, the working dir of the debugged program will be on remote device
// and hence not applicable. In such case we may just use debugged program path on host
// as the working dir for GDB.
// However, we cannot find a standard/common way to distinguish remote debug from local
// debug. For instance, a local debug may also use gdbserver+gdb. So it's up to each
// debugger implementation to make the distinction.
//
IPath path = null;
String location = fLaunchConfiguration.getAttribute(ICDTLaunchConfigurationConstants.ATTR_WORKING_DIRECTORY, (String)null);
if (location != null) {
String expandedLocation = VariablesPlugin.getDefault().getStringVariableManager().performStringSubstitution(location);
if (!expandedLocation.isEmpty()) {
path = new Path(expandedLocation);
}
}
if (path != null) {
// Some validity check. Should have been done by UI code.
if (path.isAbsolute()) {
File dir = new File(path.toPortableString());
if (! dir.isDirectory())
path = null;
} else {
IResource res = ResourcesPlugin.getWorkspace().getRoot().findMember(path);
if (res instanceof IContainer && res.exists()) {
path = res.getLocation();
}
else
// Relative but not found in workspace.
path = null;
}
}
if (path == null) {
// default working dir is the project if this config has a project
ICProject cp = LaunchUtils.getCProject(fLaunchConfiguration);
if (cp != null) {
IProject p = cp.getProject();
path = p.getLocation();
}
else {
// no meaningful value found. Just return null.
}
}
fGDBWorkingDirectory = path;
}
return fGDBWorkingDirectory;
return getGDBLaunch().getGDBWorkingDirectory();
}
@Override
public String getProgramArguments() throws CoreException {
if (fProgramArguments == null) {
fProgramArguments = fLaunchConfiguration.getAttribute(
ICDTLaunchConfigurationConstants.ATTR_PROGRAM_ARGUMENTS,
(String)null);
if (fProgramArguments != null) {
fProgramArguments = VariablesPlugin.getDefault().getStringVariableManager().performStringSubstitution(fProgramArguments);
}
}
return fProgramArguments;
return getGDBLaunch().getProgramArguments();
}
@Override
public IPath getProgramPath() {
return fProgramPath;
try {
return new Path(getGDBLaunch().getProgramPath());
} catch (CoreException e) {
return new Path(""); //$NON-NLS-1$
}
}
@Override
public List<String> getSharedLibraryPaths() throws CoreException {
if (fSharedLibPaths == null) {
fSharedLibPaths = fLaunchConfiguration.getAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_SOLIB_PATH,
new ArrayList<String>(0));
}
return fSharedLibPaths;
return getGDBLaunch().getSharedLibraryPaths();
}
/** @since 3.0 */
@Override
public Properties getEnvironmentVariables() throws CoreException {
if (fEnvVariables == null) {
fEnvVariables = new Properties();
// if the attribute ATTR_APPEND_ENVIRONMENT_VARIABLES is set,
// the LaunchManager will return both the new variables and the existing ones.
// That would force us to delete all the variables in GDB, and then re-create then all
// that is not very efficient. So, let's fool the LaunchManager into returning just the
// list of new variables.
boolean append = fLaunchConfiguration.getAttribute(ILaunchManager.ATTR_APPEND_ENVIRONMENT_VARIABLES, true);
String[] properties;
if (append) {
ILaunchConfigurationWorkingCopy wc = fLaunchConfiguration.copy(""); //$NON-NLS-1$
// Don't save this change, it is just temporary, and in just a copy of our launchConfig.
wc.setAttribute(ILaunchManager.ATTR_APPEND_ENVIRONMENT_VARIABLES, false);
properties = DebugPlugin.getDefault().getLaunchManager().getEnvironment(wc);
} else {
// We're getting rid of the environment anyway, so this call will only yield the new variables.
properties = DebugPlugin.getDefault().getLaunchManager().getEnvironment(fLaunchConfiguration);
}
if (properties == null) {
properties = new String[0];
}
for (String property : properties) {
int idx = property.indexOf('=');
if (idx != -1) {
String key = property.substring(0, idx);
String value = property.substring(idx + 1);
fEnvVariables.setProperty(key, value);
} else {
fEnvVariables.setProperty(property, ""); //$NON-NLS-1$
}
}
}
return fEnvVariables;
return getGDBLaunch().getEnvironmentVariables();
}
/** @since 3.0 */
@Override
public boolean getClearEnvironment() throws CoreException {
return !fLaunchConfiguration.getAttribute(ILaunchManager.ATTR_APPEND_ENVIRONMENT_VARIABLES, true);
return getGDBLaunch().getClearEnvironment();
}
/** @since 3.0 */
@Override
public boolean getUpdateThreadListOnSuspend() throws CoreException {
return fLaunchConfiguration
.getAttribute(
IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_UPDATE_THREADLIST_ON_SUSPEND,
IGDBLaunchConfigurationConstants.DEBUGGER_UPDATE_THREADLIST_ON_SUSPEND_DEFAULT);
return getGDBLaunch().getUpdateThreadListOnSuspend();
}
private Process launchGDBProcess() throws CoreException {
// Keep calling deprecated getGDBCommandLine() in case it was overridden
String command = getGDBCommandLine();
// Keep calling deprecated launchGDBProcess(String) in case it was overridden
// Keep calling deprecated launchGDBProcess(String) in case it was
// overridden
return launchGDBProcess(command);
}
/**
* Launch GDB process.
* Allow subclass to override.
* Launch GDB process. Allow subclass to override.
*
* @deprecated Use {@link #launchGDBProcess(String[])} instead
*/
@Deprecated
protected Process launchGDBProcess(String commandLine) throws CoreException {
// Backwards-compatibility check
// If the commandLine parameter is not the same as the command line array we provide
// it implies that the commandLine was modified by an extender and should be used as
// is. If it is the same, we can use the command line array instead using the more robust
// If the commandLine parameter is not the same as the command line
// array we provide
// it implies that the commandLine was modified by an extender and
// should be used as
// is. If it is the same, we can use the command line array instead
// using the more robust
// non-deprecated call to launchGDBProcess.
String unmodifiedCmdLine = StringUtil.join(getGDBCommandLineArray(), " ").trim(); //$NON-NLS-1$
if (unmodifiedCmdLine.equals(commandLine.trim()) == false) {
Process proc = null;
try {
proc = ProcessFactory.getFactory().exec(commandLine, LaunchUtils.getLaunchEnvironment(fLaunchConfiguration));
proc = ProcessFactory.getFactory().exec(commandLine, getGDBLaunch().getLaunchEnvironment());
} catch (IOException e) {
String message = "Error while launching command " + commandLine; //$NON-NLS-1$
throw new CoreException(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, -1, message, e));
@ -420,14 +287,15 @@ public class GDBBackend extends AbstractDsfService implements IGDBBackend, IMIBa
}
/**
* Launch GDB process with command and arguments.
* Allow subclass to override.
* Launch GDB process with command and arguments. Allow subclass to
* override.
*
* @since 4.6
*/
protected Process launchGDBProcess(String[] commandLine) throws CoreException {
Process proc = null;
try {
proc = ProcessFactory.getFactory().exec(commandLine, LaunchUtils.getLaunchEnvironment(fLaunchConfiguration));
proc = ProcessFactory.getFactory().exec(commandLine, getGDBLaunch().getLaunchEnvironment());
} catch (IOException e) {
String message = "Error while launching command: " + StringUtil.join(commandLine, " "); //$NON-NLS-1$ //$NON-NLS-2$
throw new CoreException(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, -1, message, e));
@ -473,8 +341,7 @@ public class GDBBackend extends AbstractDsfService implements IGDBBackend, IMIBa
// See https://bugs.eclipse.org/bugs/show_bug.cgi?id=304096#c54
if (getSessionType() == SessionType.REMOTE) {
gdbSpawner.interrupt();
}
else {
} else {
gdbSpawner.interruptCTRLC();
}
}
@ -495,13 +362,13 @@ public class GDBBackend extends AbstractDsfService implements IGDBBackend, IMIBa
// See https://bugs.eclipse.org/bugs/show_bug.cgi?id=304096#c54
if (getSessionType() == SessionType.REMOTE) {
gdbSpawner.interrupt();
}
else {
} else {
gdbSpawner.interruptCTRLC();
}
fInterruptFailedJob = new MonitorInterruptJob(timeout, rm);
} else {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, IDsfStatusConstants.NOT_SUPPORTED, "Cannot interrupt.", null)); //$NON-NLS-1$
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, IDsfStatusConstants.NOT_SUPPORTED,
"Cannot interrupt.", null)); //$NON-NLS-1$
rm.done();
}
}
@ -516,7 +383,8 @@ public class GDBBackend extends AbstractDsfService implements IGDBBackend, IMIBa
gdbSpawner.raise((int) pid, gdbSpawner.INT);
fInterruptFailedJob = new MonitorInterruptJob(timeout, rm);
} else {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, IDsfStatusConstants.NOT_SUPPORTED, "Cannot interrupt.", null)); //$NON-NLS-1$
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, IDsfStatusConstants.NOT_SUPPORTED,
"Cannot interrupt.", null)); //$NON-NLS-1$
rm.done();
}
}
@ -565,7 +433,9 @@ public class GDBBackend extends AbstractDsfService implements IGDBBackend, IMIBa
}
protected class GDBProcessStep extends InitializationShutdownStep {
GDBProcessStep(Direction direction) { super(direction); }
GDBProcessStep(Direction direction) {
super(direction);
}
@Override
public void initialize(final RequestMonitor requestMonitor) {
@ -579,7 +449,9 @@ public class GDBBackend extends AbstractDsfService implements IGDBBackend, IMIBa
}
protected class MonitorJobStep extends InitializationShutdownStep {
MonitorJobStep(Direction direction) { super(direction); }
MonitorJobStep(Direction direction) {
super(direction);
}
@Override
public void initialize(final RequestMonitor requestMonitor) {
@ -593,7 +465,10 @@ public class GDBBackend extends AbstractDsfService implements IGDBBackend, IMIBa
}
protected class RegisterStep extends InitializationShutdownStep {
RegisterStep(Direction direction) { super(direction); }
RegisterStep(Direction direction) {
super(direction);
}
@Override
public void initialize(RequestMonitor requestMonitor) {
doRegisterStep(requestMonitor);
@ -634,7 +509,8 @@ public class GDBBackend extends AbstractDsfService implements IGDBBackend, IMIBa
@Override
protected IStatus run(IProgressMonitor monitor) {
if (gdbLaunchRequestMonitor.isCanceled()) {
gdbLaunchRequestMonitor.setStatus(new Status(IStatus.CANCEL, GdbPlugin.PLUGIN_ID, -1, "Canceled starting GDB", null)); //$NON-NLS-1$
gdbLaunchRequestMonitor.setStatus(
new Status(IStatus.CANCEL, GdbPlugin.PLUGIN_ID, -1, "Canceled starting GDB", null)); //$NON-NLS-1$
gdbLaunchRequestMonitor.done();
return Status.OK_STATUS;
}
@ -642,15 +518,18 @@ public class GDBBackend extends AbstractDsfService implements IGDBBackend, IMIBa
try {
fProcess = launchGDBProcess();
// Need to do this on the executor for thread-safety
getExecutor().submit(
new DsfRunnable() {
getExecutor().submit(new DsfRunnable() {
@Override
public void run() { fBackendState = State.STARTED; }
public void run() {
fBackendState = State.STARTED;
}
});
// Don't send the backendStarted event yet. We wait until we have registered this service
// Don't send the backendStarted event yet. We wait
// until we have registered this service
// so that other services can have access to it.
} catch (CoreException e) {
gdbLaunchRequestMonitor.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, -1, e.getMessage(), e));
gdbLaunchRequestMonitor
.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, -1, e.getMessage(), e));
gdbLaunchRequestMonitor.done();
return Status.OK_STATUS;
}
@ -677,17 +556,18 @@ public class GDBBackend extends AbstractDsfService implements IGDBBackend, IMIBa
if (errorInfo == null) {
errorInfo = "GDB prompt not read"; //$NON-NLS-1$
}
gdbLaunchRequestMonitor.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, -1, errorInfo, null));
gdbLaunchRequestMonitor
.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, -1, errorInfo, null));
}
} catch (IOException e) {
success = false;
gdbLaunchRequestMonitor.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, -1, "Error reading GDB output", e)); //$NON-NLS-1$
gdbLaunchRequestMonitor.setStatus(
new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, -1, "Error reading GDB output", e)); //$NON-NLS-1$
}
// In the case of failure, close the MI streams so
// they are not leaked.
if (!success)
{
if (!success) {
if (inputReader != null) {
try {
inputReader.close();
@ -711,18 +591,20 @@ public class GDBBackend extends AbstractDsfService implements IGDBBackend, IMIBa
getExecutor().schedule(new Runnable() {
@Override
public void run() {
// Only process the event if we have not finished yet (hit the breakpoint).
// Only process the event if we have not finished yet (hit
// the breakpoint).
if (!fGDBLaunchMonitor.fLaunched) {
fGDBLaunchMonitor.fTimedOut = true;
Thread jobThread = startGdbJob.getThread();
if (jobThread != null) {
jobThread.interrupt();
}
requestMonitor.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, DebugException.TARGET_REQUEST_FAILED, "Timed out trying to launch GDB.", null)); //$NON-NLS-1$
requestMonitor.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID,
DebugException.TARGET_REQUEST_FAILED, "Timed out trying to launch GDB.", null)); //$NON-NLS-1$
requestMonitor.done();
}
}},
fGDBLaunchTimeout, TimeUnit.SECONDS);
}
}, fGDBLaunchTimeout, TimeUnit.SECONDS);
}
/** @since 5.0 */
@ -745,16 +627,15 @@ public class GDBBackend extends AbstractDsfService implements IGDBBackend, IMIBa
// Need to do this on the executor for thread-safety
// And we should wait for it to complete since we then
// check if the killing of GDB worked.
getExecutor().submit(
new DsfRunnable() {
getExecutor().submit(new DsfRunnable() {
@Override
public void run() {
destroy();
if (fMonitorJob.fMonitorExited) {
// Now that we have destroyed the process,
// and that the monitoring thread was killed,
// we need to set our state and send the event
// Now that we have destroyed the process, and
// that the monitoring thread was killed, we
// need to set our state and send the event
fBackendState = State.TERMINATED;
getSession().dispatchEvent(
new BackendStateChangedEvent(getSession().getId(), getId(), State.TERMINATED),
@ -769,8 +650,10 @@ public class GDBBackend extends AbstractDsfService implements IGDBBackend, IMIBa
int attempts = 0;
while (attempts < 10) {
try {
// Don't know if we really need the exit value... but what the heck.
fGDBExitValue = fProcess.exitValue(); // throws exception if process not exited
// Don't know if we really need the exit value...
// but what the heck.
// throws exception if process not exited
fGDBExitValue = fProcess.exitValue();
requestMonitor.done();
return Status.OK_STATUS;
@ -782,8 +665,8 @@ public class GDBBackend extends AbstractDsfService implements IGDBBackend, IMIBa
}
attempts++;
}
requestMonitor.setStatus(new Status(
IStatus.ERROR, GdbPlugin.PLUGIN_ID, IDsfStatusConstants.REQUEST_FAILED, "GDB terminate failed", null)); //$NON-NLS-1$
requestMonitor.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID,
IDsfStatusConstants.REQUEST_FAILED, "GDB terminate failed", null)); //$NON-NLS-1$
requestMonitor.done();
return Status.OK_STATUS;
}
@ -792,9 +675,7 @@ public class GDBBackend extends AbstractDsfService implements IGDBBackend, IMIBa
/** @since 5.0 */
protected void doMonitorJobStep(final RequestMonitor requestMonitor) {
fMonitorJob = new MonitorJob(
fProcess,
new DsfRunnable() {
fMonitorJob = new MonitorJob(fProcess, new DsfRunnable() {
@Override
public void run() {
requestMonitor.done();
@ -813,24 +694,21 @@ public class GDBBackend extends AbstractDsfService implements IGDBBackend, IMIBa
/** @since 5.0 */
protected void doRegisterStep(RequestMonitor requestMonitor) {
register(new String[]{ IMIBackend.class.getName(),
IMIBackend2.class.getName(),
IGDBBackend.class.getName() },
register(new String[] { IMIBackend.class.getName(), IMIBackend2.class.getName(), IGDBBackend.class.getName() },
new Hashtable<String, String>());
getSession().addServiceEventListener(GDBBackend.this, null);
/*
* This event is not consumed by any one at present, instead it's
* the GDBControlInitializedDMEvent that's used to indicate that GDB
* back end is ready for MI commands. But we still fire the event as
* it does no harm and may be needed sometime.... 09/29/2008
* This event is not consumed by any one at present, instead it's the
* GDBControlInitializedDMEvent that's used to indicate that GDB back
* end is ready for MI commands. But we still fire the event as it does
* no harm and may be needed sometime.... 09/29/2008
*
* We send the event in the register step because that is when
* other services have access to it.
* We send the event in the register step because that is when other
* services have access to it.
*/
getSession().dispatchEvent(
new BackendStateChangedEvent(getSession().getId(), getId(), State.STARTED),
getSession().dispatchEvent(new BackendStateChangedEvent(getSession().getId(), getId(), State.STARTED),
getProperties());
requestMonitor.done();
@ -844,8 +722,8 @@ public class GDBBackend extends AbstractDsfService implements IGDBBackend, IMIBa
}
/**
* Monitors a system process, waiting for it to terminate, and
* then notifies the associated runtime process.
* Monitors a system process, waiting for it to terminate, and then notifies
* the associated runtime process.
*/
private class MonitorJob extends Job {
boolean fMonitorExited = false;
@ -861,8 +739,7 @@ public class GDBBackend extends AbstractDsfService implements IGDBBackend, IMIBa
fGDBExitValue = fMonProcess.exitValue();
// Need to do this on the executor for thread-safety
getExecutor().submit(
new DsfRunnable() {
getExecutor().submit(new DsfRunnable() {
@Override
public void run() {
destroy();
@ -899,19 +776,17 @@ public class GDBBackend extends AbstractDsfService implements IGDBBackend, IMIBa
}
/**
* Stores the request monitor that must be dealt with for
* the result of the interrupt operation. If the interrupt
* successfully suspends the backend, the request monitor can
* be retrieved and completed successfully, and then this job
* should be canceled. If this job is not canceled before
* the time is up, it will imply the interrupt did not
* successfully suspend the backend, and the current job will
* indicate this in the request monitor.
* Stores the request monitor that must be dealt with for the result of the
* interrupt operation. If the interrupt successfully suspends the backend,
* the request monitor can be retrieved and completed successfully, and then
* this job should be canceled. If this job is not canceled before the time
* is up, it will imply the interrupt did not successfully suspend the
* backend, and the current job will indicate this in the request monitor.
*
* The specified timeout is used to indicate how many milliseconds
* this job should wait for. INTERRUPT_TIMEOUT_DEFAULT indicates
* to use the default of 5 seconds. The default is also use if the
* timeout value is 0 or negative.
* The specified timeout is used to indicate how many milliseconds this job
* should wait for. INTERRUPT_TIMEOUT_DEFAULT indicates to use the default
* of 5 seconds. The default is also use if the timeout value is 0 or
* negative.
*
* @since 3.0
*/
@ -936,19 +811,22 @@ public class GDBBackend extends AbstractDsfService implements IGDBBackend, IMIBa
@Override
protected IStatus run(IProgressMonitor monitor) {
getExecutor().submit(
new DsfRunnable() {
getExecutor().submit(new DsfRunnable() {
@Override
public void run() {
fInterruptFailedJob = null;
fRequestMonitor.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, IDsfStatusConstants.REQUEST_FAILED, "Interrupt failed.", null)); //$NON-NLS-1$
fRequestMonitor.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID,
IDsfStatusConstants.REQUEST_FAILED, "Interrupt failed.", null)); //$NON-NLS-1$
fRequestMonitor.done();
}
});
return Status.OK_STATUS;
}
public RequestMonitor getRequestMonitor() { return fRequestMonitor; }
public RequestMonitor getRequestMonitor() {
return fRequestMonitor;
}
}
/**

View file

@ -18,7 +18,9 @@ Require-Bundle: org.eclipse.core.runtime,
org.eclipse.cdt.debug.core,
org.freemarker;bundle-version="2.3.22",
org.eclipse.cdt.build.core;bundle-version="1.0.0",
org.eclipse.cdt.build.gcc.core;bundle-version="1.0.0"
org.eclipse.cdt.build.gcc.core;bundle-version="1.0.0",
org.eclipse.cdt.dsf.gdb;bundle-version="5.0.0",
org.eclipse.cdt.dsf;bundle-version="2.6.0"
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Bundle-ActivationPolicy: lazy
Bundle-Localization: plugin

View file

@ -165,16 +165,6 @@
class="org.eclipse.cdt.internal.qt.core.build.QtScannerInfoProvider">
</provider>
</extension>
<extension
point="org.eclipse.debug.core.launchConfigurationTypes">
<launchConfigurationType
delegate="org.eclipse.cdt.internal.qt.core.launch.QtLocalRunLaunchConfigDelegate"
id="org.eclipse.cdt.qt.core.launchConfigurationType"
modes="run"
name="Qt Local Application"
public="true">
</launchConfigurationType>
</extension>
<extension
point="org.eclipse.core.runtime.adapters">
<factory
@ -192,4 +182,31 @@
targetTypeId="org.eclipse.launchbar.core.launchTargetType.local">
</mapper>
</extension>
<extension
point="org.eclipse.debug.core.launchConfigurationTypes">
<launchConfigurationType
id="org.eclipse.cdt.qt.core.launchConfigurationType"
name="Qt Local Application"
public="true">
</launchConfigurationType>
</extension>
<extension
point="org.eclipse.debug.core.launchDelegates">
<launchDelegate
delegate="org.eclipse.cdt.internal.qt.core.launch.QtLocalRunLaunchConfigDelegate"
id="org.eclipse.cdt.qt.core.launchDelegate.run.local"
modes="run"
name="Qt Local Run launcher"
type="org.eclipse.cdt.qt.core.launchConfigurationType">
</launchDelegate>
<launchDelegate
delegate="org.eclipse.cdt.internal.qt.core.launch.QtLocalDebugLaunchConfigDelegate"
id="org.eclipse.cdt.qt.core.launchDelegate.debug.local"
modes="debug"
name="Qt Local Debug launcher"
sourceLocatorId="org.eclipse.cdt.debug.core.sourceLocator"
sourcePathComputerId="org.eclipse.cdt.debug.core.sourcePathComputer"
type="org.eclipse.cdt.qt.core.launchConfigurationType">
</launchDelegate>
</extension>
</plugin>

View file

@ -124,7 +124,7 @@ public class QtBuildConfigurationFactory implements IAdapterFactory {
for (IBuildConfiguration config : project.getBuildConfigs()) {
configNames.add(config.getName());
}
String baseName = qtInstall.getSpec() + ":" + launchMode; //$NON-NLS-1$
String baseName = qtInstall.getSpec() + "." + launchMode; //$NON-NLS-1$
String newName = baseName;
int n = 0;
while (configNames.contains(newName)) {

View file

@ -0,0 +1,117 @@
/*******************************************************************************
* Copyright (c) 2016 QNX Software Systems and others.
* 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
*******************************************************************************/
package org.eclipse.cdt.internal.qt.core.launch;
import java.nio.file.Path;
import java.util.concurrent.ExecutionException;
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor;
import org.eclipse.cdt.dsf.concurrent.Query;
import org.eclipse.cdt.dsf.concurrent.RequestMonitorWithProgress;
import org.eclipse.cdt.dsf.concurrent.Sequence;
import org.eclipse.cdt.dsf.debug.sourcelookup.DsfSourceLookupDirector;
import org.eclipse.cdt.dsf.gdb.launching.GdbLaunch;
import org.eclipse.cdt.dsf.gdb.launching.ServicesLaunchSequence;
import org.eclipse.cdt.dsf.gdb.service.GdbDebugServicesFactory;
import org.eclipse.cdt.dsf.gdb.service.command.IGDBControl;
import org.eclipse.cdt.dsf.service.DsfServicesTracker;
import org.eclipse.cdt.internal.qt.core.Activator;
import org.eclipse.cdt.qt.core.QtBuildConfiguration;
import org.eclipse.cdt.qt.core.QtLaunchConfigurationDelegate;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.launchbar.core.target.ILaunchTarget;
import org.eclipse.launchbar.core.target.launch.ITargetedLaunch;
public class QtLocalDebugLaunchConfigDelegate extends QtLaunchConfigurationDelegate {
@Override
public ITargetedLaunch getLaunch(ILaunchConfiguration configuration, String mode, ILaunchTarget target)
throws CoreException {
GdbLaunch launch = new GdbLaunch(configuration, mode, null);
launch.setLaunchTarget(target);
launch.initialize();
DsfSourceLookupDirector locator = new DsfSourceLookupDirector(launch.getSession());
String memento = configuration.getAttribute(ILaunchConfiguration.ATTR_SOURCE_LOCATOR_MEMENTO, (String) null);
if (memento == null) {
locator.initializeDefaults(configuration);
} else {
locator.initializeFromMemento(memento, configuration);
}
launch.setSourceLocator(locator);
return launch;
}
@Override
public void launch(ILaunchConfiguration configuration, String mode, ILaunch launch, IProgressMonitor monitor)
throws CoreException {
GdbLaunch gdbLaunch = (GdbLaunch) launch;
ILaunchTarget target = ((ITargetedLaunch) launch).getLaunchTarget();
QtBuildConfiguration qtBuildConfig = getQtBuildConfiguration(configuration, mode, target, monitor);
// TODO get it from the toolchain
gdbLaunch.setGDBPath("/usr/local/bin/gdb");
String gdbVersion = gdbLaunch.getGDBVersion();
Path exeFile = qtBuildConfig.getProgramPath();
gdbLaunch.setProgramPath(exeFile.toString());
gdbLaunch.setServiceFactory(new GdbDebugServicesFactory(gdbVersion));
Sequence servicesLaunchSequence = new ServicesLaunchSequence(gdbLaunch.getSession(), gdbLaunch, monitor);
gdbLaunch.getSession().getExecutor().execute(servicesLaunchSequence);
try {
servicesLaunchSequence.get();
} catch (InterruptedException | ExecutionException e) {
throw new DebugException(new Status(IStatus.ERROR, Activator.ID, "Failure launching with gdb", e));
}
gdbLaunch.initializeControl();
gdbLaunch.addCLIProcess(gdbLaunch.getGDBPath().toOSString() + " (" + gdbVersion + ")"); //$NON-NLS-1$ //$NON-NLS-2$
Query<Object> ready = new Query<Object>() {
@Override
protected void execute(final DataRequestMonitor<Object> rm) {
DsfServicesTracker tracker = new DsfServicesTracker(
Activator.getDefault().getBundle().getBundleContext(), gdbLaunch.getSession().getId());
IGDBControl control = tracker.getService(IGDBControl.class);
tracker.dispose();
control.completeInitialization(
new RequestMonitorWithProgress(ImmediateExecutor.getInstance(), monitor) {
@Override
protected void handleCompleted() {
if (isCanceled()) {
rm.cancel();
} else {
rm.setStatus(getStatus());
}
rm.done();
}
});
}
};
// Start it up
gdbLaunch.getSession().getExecutor().execute(ready);
try {
ready.get();
} catch (ExecutionException | InterruptedException e) {
throw new DebugException(new Status(IStatus.ERROR, Activator.ID, "Failure to start debug session", e));
}
}
}

View file

@ -7,7 +7,6 @@
*******************************************************************************/
package org.eclipse.cdt.internal.qt.core.launch;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Map;
@ -18,9 +17,7 @@ import org.eclipse.cdt.qt.core.QtLaunchConfigurationDelegate;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.ILaunchConfiguration;
@ -34,70 +31,25 @@ public class QtLocalRunLaunchConfigDelegate extends QtLaunchConfigurationDelegat
@Override
public void launch(ILaunchConfiguration configuration, String mode, ILaunch launch, IProgressMonitor monitor)
throws CoreException {
new Job("Running Qt App") {
@Override
protected IStatus run(IProgressMonitor monitor) {
try {
ILaunchTarget target = ((ITargetedLaunch) launch).getLaunchTarget();
QtBuildConfiguration qtBuildConfig = getQtBuildConfiguration(configuration, mode, target, monitor);
// get the executable
Path buildFolder = qtBuildConfig.getBuildDirectory();
Path exeFile;
switch (Platform.getOS()) {
case Platform.OS_MACOSX:
// TODO this is mac local specific and really should be
// in the config
// TODO also need to pull the app name out of the pro
// file name
Path appFolder = buildFolder.resolve("main.app");
Path contentsFolder = appFolder.resolve("Contents");
Path macosFolder = contentsFolder.resolve("MacOS");
exeFile = macosFolder.resolve("main");
break;
case Platform.OS_WIN32:
Path releaseFolder = buildFolder.resolve("release");
exeFile = releaseFolder.resolve("main.exe");
break;
default:
return new Status(IStatus.ERROR, Activator.ID, "platform not supported: " + Platform.getOS());
}
Path exeFile = qtBuildConfig.getProgramPath();
ProcessBuilder builder = new ProcessBuilder(exeFile.toString())
.directory(qtBuildConfig.getProject().getLocation().toFile());
// need to add the Qt libraries to the env
// set up the environment
Map<String, String> env = builder.environment();
Path libPath = qtBuildConfig.getQtInstall().getLibPath();
switch (Platform.getOS()) {
case Platform.OS_MACOSX:
String libPathEnv = env.get("DYLD_LIBRARY_PATH");
if (libPathEnv == null) {
libPathEnv = libPath.toString();
} else {
libPathEnv = libPath.toString() + File.pathSeparator + libPathEnv;
}
env.put("DYLD_LIBRARY_PATH", libPathEnv);
break;
case Platform.OS_WIN32:
String path = env.get("PATH");
// TODO really need a bin path
// and resolve doesn't work properly on Windows
path = "C:/Qt/5.5/mingw492_32/bin;" + path;
env.put("PATH", path);
break;
}
qtBuildConfig.setProgramEnvironment(env);
try {
Process process = builder.start();
DebugPlugin.newProcess(launch, process, "main");
} catch (IOException e) {
return new Status(IStatus.ERROR, Activator.ID, "running", e);
} catch (CoreException e) {
return e.getStatus();
throw new CoreException(new Status(IStatus.ERROR, Activator.ID, "Failed to start", e));
}
return Status.OK_STATUS;
}
}.schedule();
}
}

View file

@ -29,6 +29,10 @@ import org.eclipse.cdt.core.parser.IScannerInfo;
import org.eclipse.cdt.internal.qt.core.Activator;
import org.eclipse.core.resources.IBuildConfiguration;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.osgi.service.prefs.BackingStoreException;
import org.osgi.service.prefs.Preferences;
@ -107,6 +111,48 @@ public class QtBuildConfiguration extends CBuildConfiguration {
}
}
public Path getProgramPath() throws CoreException {
switch (Platform.getOS()) {
case Platform.OS_MACOSX:
// TODO this is mac local specific and really should be
// in the config
// TODO also need to pull the app name out of the pro
// file name
Path appFolder = getBuildDirectory().resolve("main.app");
Path contentsFolder = appFolder.resolve("Contents");
Path macosFolder = contentsFolder.resolve("MacOS");
return macosFolder.resolve("main");
case Platform.OS_WIN32:
Path releaseFolder = getBuildDirectory().resolve("release");
return releaseFolder.resolve("main.exe");
default:
throw new CoreException(
new Status(IStatus.ERROR, Activator.ID, "platform not supported: " + Platform.getOS()));
}
}
public void setProgramEnvironment(Map<String, String> env) {
Path libPath = getQtInstall().getLibPath();
switch (Platform.getOS()) {
case Platform.OS_MACOSX:
String libPathEnv = env.get("DYLD_LIBRARY_PATH");
if (libPathEnv == null) {
libPathEnv = libPath.toString();
} else {
libPathEnv = libPath.toString() + File.pathSeparator + libPathEnv;
}
env.put("DYLD_LIBRARY_PATH", libPathEnv);
break;
case Platform.OS_WIN32:
String path = env.get("PATH");
// TODO really need a bin path
// and resolve doesn't work properly on Windows
path = "C:/Qt/5.5/mingw492_32/bin;" + path;
env.put("PATH", path);
break;
}
}
public String getProperty(String key) {
if (properties == null) {
List<String> cmd = new ArrayList<>();

View file

@ -86,6 +86,13 @@
class="org.eclipse.cdt.internal.qt.ui.launch.QtLocalLaunchConfigurationTabGroup"
id="org.eclipse.cdt.qt.ui.launchConfigurationTabGroup"
type="org.eclipse.cdt.qt.core.launchConfigurationType">
<launchMode
mode="run">
</launchMode>
<launchMode
mode="debug"
perspective="org.eclipse.debug.ui.DebugPerspective">
</launchMode>
</launchConfigurationTabGroup>
</extension>
<extension