/******************************************************************************* * Copyright (c) 2004, 2008, 2009, 2012 Red Hat, Inc. 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 * * Contributors: * Kent Sebastian <ksebasti@redhat.com> - initial API and implementation * Keith Seitz <keiths@redhat.com> - setup code in launch the method, initially * written in the now-defunct OprofileSession class * QNX Software Systems and others - the section of code marked in the launch * method, and the exec method * Red Hat Inc. - Added automatic enablement of options if they are not set * Red Hat Inc. - modification of OProfileLaunchConfigurationDelegate to here *******************************************************************************/ package org.eclipse.linuxtools.internal.gcov.launch; import java.io.File; import java.util.List; import org.eclipse.cdt.debug.core.CDebugUtils; import org.eclipse.cdt.launch.AbstractCLaunchDelegate; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.Path; import org.eclipse.debug.core.DebugPlugin; import org.eclipse.debug.core.ILaunch; import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.debug.core.ILaunchManager; import org.eclipse.debug.core.ILaunchesListener2; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.linuxtools.internal.gcov.parser.CovManager; import org.eclipse.linuxtools.internal.gcov.view.CovView; import org.eclipse.linuxtools.internal.gcov.view.annotatedsource.GcovAnnotationModelTracker; import org.eclipse.linuxtools.profiling.launch.IRemoteCommandLauncher; import org.eclipse.linuxtools.profiling.launch.RemoteProxyManager; import org.eclipse.linuxtools.profiling.ui.CProjectBuildHelpers; import org.eclipse.linuxtools.profiling.ui.CProjectBuildHelpers.ProjectBuildType; import org.eclipse.linuxtools.profiling.ui.MessageDialogSyncedRunnable; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.PlatformUI; public class GcovLaunchConfigurationDelegate extends AbstractCLaunchDelegate { protected ILaunchConfiguration config; protected IProject project; //used in many places. @Override public void launch(ILaunchConfiguration config, String mode, ILaunch launch, IProgressMonitor monitor) throws CoreException { this.config = config; this.project = getProject(); IPath exePath = getExePath(config); //If pre-requisites fail, (e.g flag is not set & user does not wish to have them set automatically), //then cancle the launch process. if (! preRequisiteCheck()) { return; } /* * this code written by QNX Software Systems and others and was * originally in the CDT under LocalCDILaunchDelegate::RunLocalApplication */ //set up and launch the local c/c++ program IRemoteCommandLauncher launcher = RemoteProxyManager.getInstance().getLauncher(getProject()); File workDir = getWorkingDirectory(config); if (workDir == null) { workDir = new File(System.getProperty("user.home", ".")); //$NON-NLS-1$ //$NON-NLS-2$ } String arguments[] = getProgramArgumentsArray( config ); //add a listener for termination of the launch ILaunchManager lmgr = DebugPlugin.getDefault().getLaunchManager(); lmgr.addLaunchListener(new LaunchTerminationWatcher(launch, exePath)); //gcov.out is generated here: Process process = launcher.execute(exePath, arguments, getEnvironment(config), new Path(workDir.getAbsolutePath()), monitor); DebugPlugin.newProcess( launch, process, renderProcessLabel( exePath.toOSString() ) ); } /** * <h1>Prerequiste check for gcov option.</h1> * <p> * Check if the pg flag was specified in the configuration. <br> * If not, prompt user. <br> * If user wishes to have the option added, add the option and re-build the project. <br> * </p> */ private boolean preRequisiteCheck() { /* Test notes: * CDT: * [tested] Cpp * [tested] C * Autotools * [tested] C * [tested] Cpp (with Jeff's fix.) * * Last tested: * 2014.07.25 */ //Different project types are handled differently. (see this enum for details) ProjectBuildType projectBuildType = CProjectBuildHelpers.getProjectType(project); if (projectBuildType == ProjectBuildType.AUTO_TOOLS) { return preRequisiteCheckAutotools(projectBuildType); } else if (projectBuildType == ProjectBuildType.MANAGED_MAKEFILE) { return preRequisiteCheckManagedBuild(projectBuildType); } else { //This is a Makefile project or a project type that we have not checked. //we don't check flag in this case. //(there is room for expanding to check other project types thou). //User will be given a generic prompt in case gmon.out is not produced. return true; } } private boolean preRequisiteCheckAutotools(ProjectBuildType projectBuildType) { String optionId = "cflags-gcov"; //$NON-NLS-1$ //See if option was checked. if (CProjectBuildHelpers.isOptionCheckedInAutotoolsPrefStore(project, optionId)) { return true; } else { return askUserAboutFlag(optionId, projectBuildType); } } private boolean preRequisiteCheckManagedBuild(ProjectBuildType projectBuildType) { // Distinguish between C & C++. // Find out what flag should we check for String optionId = null; if (CProjectBuildHelpers.isCppType(project)) { optionId = "gnu.cpp.compiler.option.debugging.codecov"; //$NON-NLS-1$ } else if (CProjectBuildHelpers.isCType(project)) { optionId = "gnu.c.compiler.option.debugging.codecov"; //$NON-NLS-1$ } // Check that both flags are checked. if ( CProjectBuildHelpers.isOptionCheckedInCDT(project, optionId) ) { return true; } else { //If either one of the flags is not checked, check it. return askUserAboutFlag(optionId, projectBuildType); } } /** * <h1>Ask user for flags.</h1> * Tell the user that the required gcov flag is not set in the configuration. * * <p> Offer to have it automatically checked. </p> */ private boolean askUserAboutFlag(final String optionId, final ProjectBuildType projectBuildType) { //Construct Message box that will prompt the user. //Content of message will vary depending on project type String title = GcovLaunchMessages.GcovMissingFlag_Title; String msg = GcovLaunchMessages.GcovMissingFlag_MainMsg; if (projectBuildType == ProjectBuildType.AUTO_TOOLS) { msg += GcovLaunchMessages.GcovMissingFlag_AutotoolsInfo; } else if (projectBuildType == ProjectBuildType.MANAGED_MAKEFILE) { msg += GcovLaunchMessages.GcovMissingFlag_CDTInfo; } msg += GcovLaunchMessages.GcovMissingFlag_PostQuestion; //Open Dialogue. boolean okPressed = MessageDialogSyncedRunnable.openQuestionSyncedRunnable(title, msg); if (okPressed) { enableOption(optionId, projectBuildType); CProjectBuildHelpers.rebuildProject(project); return true; } else { return false; } } private void enableOption(String optionId, ProjectBuildType projectBuildType) { if (projectBuildType == ProjectBuildType.MANAGED_MAKEFILE) CProjectBuildHelpers.setOptionInCDT(project, optionId, true); else if (projectBuildType == ProjectBuildType.AUTO_TOOLS) { CProjectBuildHelpers.setOptionInAutotools(project, optionId, "true"); //$NON-NLS-1$ } } //A class used to listen for the termination of the current launch, and // run some functions when it is finished. class LaunchTerminationWatcher implements ILaunchesListener2 { private ILaunch launch; private IPath exePath; public LaunchTerminationWatcher(ILaunch il, IPath exePath) { launch = il; this.exePath = exePath; } @Override public void launchesTerminated(ILaunch[] launches) { for (ILaunch l : launches) { /** * Dump samples from the daemon, * shut down the daemon, * activate the OProfile view (open it if it isn't already), * refresh the view (which parses the data/ui model and displays it). */ if (l.equals(launch)) { //need to run this in the ui thread otherwise get SWT Exceptions // based on concurrency issues Display.getDefault().syncExec(() -> { String s = exePath.toOSString(); CovManager cvrgeMnger = new CovManager(s, getProject()); try { List<String> gcdaPaths = cvrgeMnger.getGCDALocations(); if (gcdaPaths.isEmpty()) { String title = GcovLaunchMessages.GcovCompilerOptions_msg; String message = GcovLaunchMessages.GcovCompileAgain_msg; Shell parent = PlatformUI.getWorkbench().getDisplay().getActiveShell(); MessageDialog.openWarning(parent, title, message); } CovView.displayCovResults(s, null); GcovAnnotationModelTracker.getInstance().addProject(getProject(), exePath); GcovAnnotationModelTracker.getInstance().annotateAllCEditors(); } catch (InterruptedException e) { // Do nothing } }); } } } @Override public void launchesAdded(ILaunch[] launches) { /* dont care */} @Override public void launchesChanged(ILaunch[] launches) { /* dont care */ } @Override public void launchesRemoved(ILaunch[] launches) { /* dont care */ } } @Override protected String getPluginID() { return GcovLaunchPlugin.PLUGIN_ID; } /* all these functions exist to be overridden by the test class in order to allow launch testing */ private IProject getProject(){ try{ return CDebugUtils.verifyCProject(config).getProject(); } catch (CoreException e) { e.printStackTrace(); } return null; } /** * * Return the exe path of the binary to be profiled. * @param config * @return the exe path of the binary stored in the configuration * @throws CoreException * @since 1.1 */ private static IPath getExePath(ILaunchConfiguration config) throws CoreException{ return CDebugUtils.verifyProgramPath( config ); } }