1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-23 22:52: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.CBuildConfiguration;
import org.eclipse.cdt.build.core.IBuildConfigurationManager; import org.eclipse.cdt.build.core.IBuildConfigurationManager;
import org.eclipse.cdt.core.CProjectNature;
import org.eclipse.core.resources.IBuildConfiguration; import org.eclipse.core.resources.IBuildConfiguration;
import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IResource;
@ -42,7 +43,7 @@ public class CBuildConfigurationManager
// TODO // TODO
CBuildConfiguration config = null; CBuildConfiguration config = null;
//configMap.put(config.getBuildConfiguration(), config); // configMap.put(config.getBuildConfiguration(), config);
return config; return config;
} }
@ -67,6 +68,13 @@ public class CBuildConfigurationManager
if (event.getType() == IResourceChangeEvent.PRE_CLOSE || event.getType() == IResourceChangeEvent.PRE_DELETE) { if (event.getType() == IResourceChangeEvent.PRE_CLOSE || event.getType() == IResourceChangeEvent.PRE_DELETE) {
if (event.getResource().getType() == IResource.PROJECT) { if (event.getResource().getType() == IResource.PROJECT) {
IProject project = event.getResource().getProject(); 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 // Clean up the configMap
try { try {

View file

@ -14,7 +14,8 @@ Require-Bundle: org.eclipse.core.runtime,
org.eclipse.core.variables, org.eclipse.core.variables,
org.eclipse.cdt.launch;bundle-version="6.1.0", org.eclipse.cdt.launch;bundle-version="6.1.0",
org.eclipse.cdt.gdb;bundle-version="7.0.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-ActivationPolicy: lazy
Bundle-RequiredExecutionEnvironment: JavaSE-1.7 Bundle-RequiredExecutionEnvironment: JavaSE-1.7
Export-Package: org.eclipse.cdt.dsf.gdb, Export-Package: org.eclipse.cdt.dsf.gdb,

View file

@ -296,11 +296,12 @@ public class GdbLaunchDelegate extends AbstractCLaunchDelegate2
} }
/** /**
* Returns the GDB version. * Returns the GDB version. Subclass can override for special need.
* Subclass can override for special need. *
*
* @since 2.0 * @since 2.0
* @deprecated Replaced by GdbLaunch.getGDBVersion() which can also be overridden
*/ */
@Deprecated
protected String getGDBVersion(ILaunchConfiguration config) throws CoreException { protected String getGDBVersion(ILaunchConfiguration config) throws CoreException {
return LaunchUtils.getGDBVersion(config); 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. * 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. * 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 { public static String getGDBVersion(final ILaunchConfiguration configuration) throws CoreException {
String cmd = getGDBPath(configuration).toOSString() + " --version"; //$NON-NLS-1$ 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 * Gets the CDT environment from the CDT project's configuration referenced by the
* launch * launch
* @since 3.0 * @since 3.0
* @deprecated Replaced with GdbLaunch.getLaunchEnvironment()
*/ */
@Deprecated
public static String[] getLaunchEnvironment(ILaunchConfiguration config) throws CoreException { public static String[] getLaunchEnvironment(ILaunchConfiguration config) throws CoreException {
// Get the project // Get the project
String projectName = config.getAttribute(ICDTLaunchConfigurationConstants.ATTR_PROJECT_NAME, (String)null); String projectName = config.getAttribute(ICDTLaunchConfigurationConstants.ATTR_PROJECT_NAME, (String)null);

View file

@ -18,7 +18,9 @@ Require-Bundle: org.eclipse.core.runtime,
org.eclipse.cdt.debug.core, org.eclipse.cdt.debug.core,
org.freemarker;bundle-version="2.3.22", org.freemarker;bundle-version="2.3.22",
org.eclipse.cdt.build.core;bundle-version="1.0.0", 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-RequiredExecutionEnvironment: JavaSE-1.8
Bundle-ActivationPolicy: lazy Bundle-ActivationPolicy: lazy
Bundle-Localization: plugin Bundle-Localization: plugin

View file

@ -165,16 +165,6 @@
class="org.eclipse.cdt.internal.qt.core.build.QtScannerInfoProvider"> class="org.eclipse.cdt.internal.qt.core.build.QtScannerInfoProvider">
</provider> </provider>
</extension> </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 <extension
point="org.eclipse.core.runtime.adapters"> point="org.eclipse.core.runtime.adapters">
<factory <factory
@ -192,4 +182,31 @@
targetTypeId="org.eclipse.launchbar.core.launchTargetType.local"> targetTypeId="org.eclipse.launchbar.core.launchTargetType.local">
</mapper> </mapper>
</extension> </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> </plugin>

View file

@ -124,7 +124,7 @@ public class QtBuildConfigurationFactory implements IAdapterFactory {
for (IBuildConfiguration config : project.getBuildConfigs()) { for (IBuildConfiguration config : project.getBuildConfigs()) {
configNames.add(config.getName()); configNames.add(config.getName());
} }
String baseName = qtInstall.getSpec() + ":" + launchMode; //$NON-NLS-1$ String baseName = qtInstall.getSpec() + "." + launchMode; //$NON-NLS-1$
String newName = baseName; String newName = baseName;
int n = 0; int n = 0;
while (configNames.contains(newName)) { 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; package org.eclipse.cdt.internal.qt.core.launch;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.Map; 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.CoreException;
import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.debug.core.DebugPlugin; import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.ILaunch; import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.debug.core.ILaunchConfiguration;
@ -34,70 +31,25 @@ public class QtLocalRunLaunchConfigDelegate extends QtLaunchConfigurationDelegat
@Override @Override
public void launch(ILaunchConfiguration configuration, String mode, ILaunch launch, IProgressMonitor monitor) public void launch(ILaunchConfiguration configuration, String mode, ILaunch launch, IProgressMonitor monitor)
throws CoreException { throws CoreException {
new Job("Running Qt App") { ILaunchTarget target = ((ITargetedLaunch) launch).getLaunchTarget();
@Override QtBuildConfiguration qtBuildConfig = getQtBuildConfiguration(configuration, mode, target, monitor);
protected IStatus run(IProgressMonitor monitor) {
try {
ILaunchTarget target = ((ITargetedLaunch) launch).getLaunchTarget();
QtBuildConfiguration qtBuildConfig = getQtBuildConfiguration(configuration, mode, target, monitor);
// get the executable // get the executable
Path buildFolder = qtBuildConfig.getBuildDirectory(); Path exeFile = qtBuildConfig.getProgramPath();
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());
}
ProcessBuilder builder = new ProcessBuilder(exeFile.toString()) ProcessBuilder builder = new ProcessBuilder(exeFile.toString())
.directory(qtBuildConfig.getProject().getLocation().toFile()); .directory(qtBuildConfig.getProject().getLocation().toFile());
// need to add the Qt libraries to the env // set up the environment
Map<String, String> env = builder.environment(); Map<String, String> env = builder.environment();
Path libPath = qtBuildConfig.getQtInstall().getLibPath(); qtBuildConfig.setProgramEnvironment(env);
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;
}
Process process = builder.start(); try {
DebugPlugin.newProcess(launch, process, "main"); Process process = builder.start();
} catch (IOException e) { DebugPlugin.newProcess(launch, process, "main");
return new Status(IStatus.ERROR, Activator.ID, "running", e); } catch (IOException e) {
} catch (CoreException e) { throw new CoreException(new Status(IStatus.ERROR, Activator.ID, "Failed to start", e));
return e.getStatus(); }
}
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.cdt.internal.qt.core.Activator;
import org.eclipse.core.resources.IBuildConfiguration; import org.eclipse.core.resources.IBuildConfiguration;
import org.eclipse.core.resources.IResource; 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.BackingStoreException;
import org.osgi.service.prefs.Preferences; 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) { public String getProperty(String key) {
if (properties == null) { if (properties == null) {
List<String> cmd = new ArrayList<>(); List<String> cmd = new ArrayList<>();

View file

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