From 192bfff688f78729376a5063ae91e387fd04534b Mon Sep 17 00:00:00 2001 From: Doug Schaefer Date: Mon, 25 Jan 2016 15:00:32 -0500 Subject: 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 --- qt/org.eclipse.cdt.qt.core/META-INF/MANIFEST.MF | 4 +- qt/org.eclipse.cdt.qt.core/plugin.xml | 37 +++++-- .../qt/core/build/QtBuildConfigurationFactory.java | 2 +- .../launch/QtLocalDebugLaunchConfigDelegate.java | 117 +++++++++++++++++++++ .../launch/QtLocalRunLaunchConfigDelegate.java | 78 +++----------- .../eclipse/cdt/qt/core/QtBuildConfiguration.java | 46 ++++++++ qt/org.eclipse.cdt.qt.ui/plugin.xml | 7 ++ 7 files changed, 216 insertions(+), 75 deletions(-) create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/launch/QtLocalDebugLaunchConfigDelegate.java (limited to 'qt') diff --git a/qt/org.eclipse.cdt.qt.core/META-INF/MANIFEST.MF b/qt/org.eclipse.cdt.qt.core/META-INF/MANIFEST.MF index ac5d70d56a1..b84b9e14d67 100644 --- a/qt/org.eclipse.cdt.qt.core/META-INF/MANIFEST.MF +++ b/qt/org.eclipse.cdt.qt.core/META-INF/MANIFEST.MF @@ -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 diff --git a/qt/org.eclipse.cdt.qt.core/plugin.xml b/qt/org.eclipse.cdt.qt.core/plugin.xml index f868e7ce665..0e6de1a7d7d 100644 --- a/qt/org.eclipse.cdt.qt.core/plugin.xml +++ b/qt/org.eclipse.cdt.qt.core/plugin.xml @@ -165,16 +165,6 @@ class="org.eclipse.cdt.internal.qt.core.build.QtScannerInfoProvider"> - - - - + + + + + + + + + + diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/build/QtBuildConfigurationFactory.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/build/QtBuildConfigurationFactory.java index 22c4fe143a6..6e9a589f483 100644 --- a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/build/QtBuildConfigurationFactory.java +++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/build/QtBuildConfigurationFactory.java @@ -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)) { diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/launch/QtLocalDebugLaunchConfigDelegate.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/launch/QtLocalDebugLaunchConfigDelegate.java new file mode 100644 index 00000000000..e360dcd0b35 --- /dev/null +++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/launch/QtLocalDebugLaunchConfigDelegate.java @@ -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 ready = new Query() { + @Override + protected void execute(final DataRequestMonitor 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)); + } + } + +} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/launch/QtLocalRunLaunchConfigDelegate.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/launch/QtLocalRunLaunchConfigDelegate.java index 238b40cac47..37049e0b434 100644 --- a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/launch/QtLocalRunLaunchConfigDelegate.java +++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/launch/QtLocalRunLaunchConfigDelegate.java @@ -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); + 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()); - } + // get the executable + Path exeFile = qtBuildConfig.getProgramPath(); - ProcessBuilder builder = new ProcessBuilder(exeFile.toString()) - .directory(qtBuildConfig.getProject().getLocation().toFile()); + ProcessBuilder builder = new ProcessBuilder(exeFile.toString()) + .directory(qtBuildConfig.getProject().getLocation().toFile()); - // need to add the Qt libraries to the env - Map 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; - } + // set up the environment + Map env = builder.environment(); + qtBuildConfig.setProgramEnvironment(env); - 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(); - } - return Status.OK_STATUS; - } - }.schedule(); + try { + Process process = builder.start(); + DebugPlugin.newProcess(launch, process, "main"); + } catch (IOException e) { + throw new CoreException(new Status(IStatus.ERROR, Activator.ID, "Failed to start", e)); + } } } diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/QtBuildConfiguration.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/QtBuildConfiguration.java index 0cc6762955a..fff397ac7c9 100644 --- a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/QtBuildConfiguration.java +++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/QtBuildConfiguration.java @@ -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 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 cmd = new ArrayList<>(); diff --git a/qt/org.eclipse.cdt.qt.ui/plugin.xml b/qt/org.eclipse.cdt.qt.ui/plugin.xml index 327cb18b55b..476e89cc8db 100644 --- a/qt/org.eclipse.cdt.qt.ui/plugin.xml +++ b/qt/org.eclipse.cdt.qt.ui/plugin.xml @@ -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"> + + + +