Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [cdt-dev] Build variables in CDT

Hi,

As nobody answered on my suggestions in previous mail I decided to provide the patches implementing them. I haven't file the bugs yet just because I am not sure that these suggestions will be accepted by the community. If they are I'll do it.

The "cdt_vars_in_capplication_path.patch" implements variables substitution for "C/C++ Application" field in Launch Configuration dialog. It also adds the "Variables..." buttons for the Main tab (actually they are two different patches merged in one to be logically completed, however I can provide them separately if necessary).

The "cdt_build_variables.patch" implements a few Eclipse variables "cdt_config_name" and "cdt_config_description" which return the CDT active configuration name/description for the project specified as an argument.

Please let me know whether such suggestions (and solutions) are accepteble and if they are I'll file the bugs and we'll discuss the details there.


Thanks,
Anton

-------- Original message --------
Hi,

Recently I investigated how the CDT build variables work in different places. I discovered the following:
  • in Launch Configuration dialog only Eclipse Platform variables work and only in "Arguments" and "Working directory" fields, but not in "C/C++ Application".
  • in project properties --> "C/C++ Build" and "Paths and Symbols" there are also a lot of useful variables (ConfigName, ConfigDescription, CDTVersion and others).
  • in "Modify Make Target" dialog the Eclipse and CDT variables work fine, however there is no "Variables..." button.
Probably there are also other places where variables are substituted, but I want to discuss these ones.

Firstly, I am wondering why variable substitution does not work for "C/C++ Application". It seems it is easy to implement the necessary functionality similarly to the "Working directory". If it was not implemented just because nobody need it and there is no objections I can file a bug and provide a patch.

Secondly, I cannot understand why CDT variables are implemented via the own manager, but not as Eclipse Platform variables. I also found the bug 180256 ("Launch configurations should support build variables") in which Doug describes the problem with platform variables extension. However I cannot see the problem. I tried to implement ConfigName as a Platform variable like this:
public class MyCDTVersion implements IDynamicVariableResolver {
    @Override
    public String resolveValue(IDynamicVariable variable, String argument) throws CoreException {
        IDynamicVariable projectName = VariablesPlugin.getDefault().getStringVariableManager().getDynamicVariable("project_name");
        IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName.getValue(null));
        ICProjectDescription projectDescription = CoreModel.getDefault().getProjectDescription(project);
        return projectDescription.getActiveConfiguration().getName();
    }
}
And it works fine. It seems that other variables can also be implemented. So is that comment actual for now? I want to have at least ConfigName and ConfigDescription to use them in Launch Configuration Dialog. I can provide a patch for that.

An the last one, probably "Modify Make Target" dialog should be updated. I cannot find the corresponding bug. Did I miss it or should I create a new one?


Thanks,
Anton.
_______________________________________________ cdt-dev mailing list cdt-dev@xxxxxxxxxxx https://dev.eclipse.org/mailman/listinfo/cdt-dev


diff --git a/core/org.eclipse.cdt.core/plugin.xml b/core/org.eclipse.cdt.core/plugin.xml
index c4e1a38..6395aed 100644
--- a/core/org.eclipse.cdt.core/plugin.xml
+++ b/core/org.eclipse.cdt.core/plugin.xml
@@ -589,6 +589,22 @@
       </variable>
    </extension>
    <extension
+         point="org.eclipse.core.variables.dynamicVariables">
+      <variable
+            name="cdt_config_name"
+            resolver="org.eclipse.cdt.internal.core.ConfigurationNameVariableResolver"
+            description="Returns the CDT active configuration name for the project specified as an argument">
+      </variable>
+   </extension>
+   <extension
+         point="org.eclipse.core.variables.dynamicVariables">
+      <variable
+            name="cdt_config_description"
+            resolver="org.eclipse.cdt.internal.core.ConfigurationDescriptionVariableResolver"
+            description="Returns the CDT active configuration description for the project specified as an argument">
+      </variable>
+   </extension>
+   <extension
          point="org.eclipse.cdt.core.CBuildConsole">
       <CBuildConsole
             class="org.eclipse.cdt.internal.core.SystemBuildConsole"
diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/CCorePluginResources.properties b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/CCorePluginResources.properties
index 36637f2..1e13e84 100644
--- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/CCorePluginResources.properties
+++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/CCorePluginResources.properties
@@ -1,5 +1,5 @@
 ###############################################################################
-# Copyright (c) 2000, 2010 QNX Software Systems and others.
+# Copyright (c) 2000, 2010, 2012 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
@@ -9,6 +9,7 @@
 #     QNX Software Systems - Initial API and implementation
 #     Markus Schorn (Wind River Systems)
 #     Anton Leherbauer (Wind River Systems)
+#     Anton Gorenkov
 ###############################################################################
 ACBuilder.ProblemsView.Location=line {0}, external location: {1}
 CBuilder.build_error= Build Error	
@@ -68,6 +69,9 @@
 
 PathEntryVariableResolver.0=CDT PathEntry variable not specified
 
+ConfigurationInfoVariableResolver.noProjectName=Project name should be specified as variable argument for '${'{0}'}' variable
+ConfigurationInfoVariableResolver.wrongProjectName=The "{0}" project referenced by the '${'{1}'}' variable does not exist
+
 CTagsIndexMarker.fileMissing=CTags output file missing
 CTagsIndexMarker.CTagsMissing=CTags not installed or not in path
 DOMIndexerMarker.EmptyScannerInfo=File not indexed because it was not built
diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/ConfigurationDescriptionVariableResolver.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/ConfigurationDescriptionVariableResolver.java
new file mode 100644
index 0000000..822c591
--- /dev/null
+++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/ConfigurationDescriptionVariableResolver.java
@@ -0,0 +1,22 @@
+/*******************************************************************************
+ * Copyright (c) 2012 Anton Gorenkov 
+ * 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:
+ *     Anton Gorenkov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.internal.core;
+
+import org.eclipse.cdt.core.settings.model.ICConfigurationDescription;
+
+public class ConfigurationDescriptionVariableResolver extends ConfigurationInfoVariableResolver {
+
+	@Override
+	protected String fetchConfigurationInfo(ICConfigurationDescription configuration) {
+		return configuration.getDescription();
+	}
+	
+}
diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/ConfigurationInfoVariableResolver.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/ConfigurationInfoVariableResolver.java
new file mode 100644
index 0000000..81913f0
--- /dev/null
+++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/ConfigurationInfoVariableResolver.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * Copyright (c) 2012 Anton Gorenkov 
+ * 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:
+ *     Anton Gorenkov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.internal.core;
+
+import org.eclipse.cdt.core.CCorePlugin;
+import org.eclipse.cdt.core.model.CoreModel;
+import org.eclipse.cdt.core.settings.model.ICConfigurationDescription;
+import org.eclipse.cdt.core.settings.model.ICProjectDescription;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.variables.IDynamicVariable;
+import org.eclipse.core.variables.IDynamicVariableResolver;
+import org.eclipse.osgi.util.NLS;
+
+public abstract class ConfigurationInfoVariableResolver implements IDynamicVariableResolver {
+
+	@Override
+	public String resolveValue(IDynamicVariable variable, String argument) throws CoreException {
+		if (argument == null) {
+			String message = NLS.bind(CCorePlugin.getResourceString("ConfigurationInfoVariableResolver.noProjectName"), variable.getName()); //$NON-NLS-1$
+			throw new CoreException(new Status(IStatus.ERROR, CCorePlugin.PLUGIN_ID, message, null));
+		}
+        IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(argument);
+		if (!project.exists()) {
+			String message = NLS.bind(CCorePlugin.getResourceString("ConfigurationInfoVariableResolver.wrongProjectName"), argument, variable.getName()); //$NON-NLS-1$
+			throw new CoreException(new Status(IStatus.ERROR, CCorePlugin.PLUGIN_ID, message, null));
+		}
+    	ICProjectDescription projectDescription = CoreModel.getDefault().getProjectDescription(project);
+    	return fetchConfigurationInfo(projectDescription.getActiveConfiguration());
+	}
+	
+	protected abstract String fetchConfigurationInfo(ICConfigurationDescription configuration);
+	
+}
diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/ConfigurationNameVariableResolver.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/ConfigurationNameVariableResolver.java
new file mode 100644
index 0000000..8dae7a5
--- /dev/null
+++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/ConfigurationNameVariableResolver.java
@@ -0,0 +1,22 @@
+/*******************************************************************************
+ * Copyright (c) 2012 Anton Gorenkov 
+ * 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:
+ *     Anton Gorenkov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.internal.core;
+
+import org.eclipse.cdt.core.settings.model.ICConfigurationDescription;
+
+public class ConfigurationNameVariableResolver extends ConfigurationInfoVariableResolver {
+
+	@Override
+	protected String fetchConfigurationInfo(ICConfigurationDescription configuration) {
+		return configuration.getName();
+	}
+	
+}
diff --git a/debug/org.eclipse.cdt.debug.core/META-INF/MANIFEST.MF b/debug/org.eclipse.cdt.debug.core/META-INF/MANIFEST.MF
index b2cab8e..5675a8a 100644
--- a/debug/org.eclipse.cdt.debug.core/META-INF/MANIFEST.MF
+++ b/debug/org.eclipse.cdt.debug.core/META-INF/MANIFEST.MF
@@ -27,7 +27,8 @@ Require-Bundle: org.eclipse.core.resources;bundle-version="[3.2.0,4.0.0)",
  org.eclipse.debug.core;bundle-version="[3.2.0,4.0.0)",
  org.eclipse.cdt.core;bundle-version="[5.0.0,6.0.0)",
  org.eclipse.core.runtime;bundle-version="[3.2.0,4.0.0)",
- org.eclipse.core.filesystem;bundle-version="1.2.0"
+ org.eclipse.core.filesystem;bundle-version="1.2.0",
+ org.eclipse.core.variables;bundle-version="[3.1.100,4.0.0)"
 Bundle-ActivationPolicy: lazy
 Bundle-RequiredExecutionEnvironment: JavaSE-1.6
 Import-Package: com.ibm.icu.text
diff --git a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/CDebugUtils.java b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/CDebugUtils.java
index 342b66e..4431890 100644
--- a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/CDebugUtils.java
+++ b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/CDebugUtils.java
@@ -52,6 +52,7 @@ import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.Path;
 import org.eclipse.core.runtime.Status;
 import org.eclipse.core.runtime.preferences.IEclipsePreferences;
+import org.eclipse.core.variables.VariablesPlugin;
 import org.eclipse.debug.core.DebugPlugin;
 import org.eclipse.debug.core.ILaunchConfiguration;
 import org.eclipse.debug.core.IStatusHandler;
@@ -542,7 +543,11 @@ public class CDebugUtils {
      * @since 6.0
      */
     public static String getProgramName(ILaunchConfiguration configuration) throws CoreException {
-        return configuration.getAttribute(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_NAME, (String)null);
+        String programName = configuration.getAttribute(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_NAME, (String)null);
+        if (programName != null) {
+        	programName = VariablesPlugin.getDefault().getStringVariableManager().performStringSubstitution(programName);
+        }
+        return programName;
     }
 
     /**
diff --git a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/sourcelookup/ProgramRelativePathSourceContainer.java b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/sourcelookup/ProgramRelativePathSourceContainer.java
index b8d9889..b1e337b 100644
--- a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/sourcelookup/ProgramRelativePathSourceContainer.java
+++ b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/sourcelookup/ProgramRelativePathSourceContainer.java
@@ -24,6 +24,7 @@ import org.eclipse.debug.core.sourcelookup.containers.AbstractSourceContainer;
 import org.eclipse.debug.core.sourcelookup.containers.LocalFileStorage;
 import org.eclipse.core.runtime.IPath;
 import org.eclipse.core.runtime.Path;
+import org.eclipse.core.variables.VariablesPlugin;
 import org.eclipse.debug.core.ILaunchConfiguration;
 
 /**
@@ -159,6 +160,7 @@ public class ProgramRelativePathSourceContainer extends AbstractSourceContainer{
 			if (programName == null) {
 				return fProgramPath; // return empty path
 			}
+        	programName = VariablesPlugin.getDefault().getStringVariableManager().performStringSubstitution(programName);
 
 			// get executable file
 			IFile exeFile = null;
diff --git a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/CDebugAdapter.java b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/CDebugAdapter.java
index 84210cd..82b5a23 100644
--- a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/CDebugAdapter.java
+++ b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/CDebugAdapter.java
@@ -33,6 +33,7 @@ import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.MultiStatus;
 import org.eclipse.core.runtime.Path;
 import org.eclipse.core.runtime.Status;
+import org.eclipse.core.variables.VariablesPlugin;
 import org.eclipse.debug.core.DebugPlugin;
 import org.eclipse.debug.core.ILaunch;
 import org.eclipse.debug.core.ILaunchConfiguration;
@@ -123,7 +124,11 @@ public class CDebugAdapter implements ICDIDebugger {
 	}
 
 	public static String getProgramName(ILaunchConfiguration configuration) throws CoreException {
-		return configuration.getAttribute(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_NAME, (String)null);
+        String programName = configuration.getAttribute(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_NAME, (String)null);
+        if (programName != null) {
+        	programName = VariablesPlugin.getDefault().getStringVariableManager().performStringSubstitution(programName);
+        }
+        return programName;
 	}
 
 	public static IPath getProgramPath(ILaunchConfiguration configuration) throws CoreException {
diff --git a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/srcfinder/CSourceFinder.java b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/srcfinder/CSourceFinder.java
index 8c6eb44..6dee6b9 100644
--- a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/srcfinder/CSourceFinder.java
+++ b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/srcfinder/CSourceFinder.java
@@ -32,6 +32,7 @@ import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IAdaptable;
 import org.eclipse.core.runtime.IPath;
 import org.eclipse.core.runtime.Path;
+import org.eclipse.core.variables.VariablesPlugin;
 import org.eclipse.debug.core.DebugPlugin;
 import org.eclipse.debug.core.ILaunch;
 import org.eclipse.debug.core.ILaunchConfiguration;
@@ -275,6 +276,7 @@ public class CSourceFinder implements ISourceFinder, ILaunchConfigurationListene
 				String programNameConfig = config.getAttribute(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_NAME, ""); //$NON-NLS-1$
 				IProject project = resource.getProject();
 				if (project != null && project.getName().equals(projectNameConfig)) {
+					programNameConfig = VariablesPlugin.getDefault().getStringVariableManager().performStringSubstitution(programNameConfig);
 					Path path = new Path(programNameConfig);
 					if (!path.isEmpty()) {
 						IFile file = project.getFile(path);
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/launching/CLaunchConfigurationTab.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/launching/CLaunchConfigurationTab.java
index 8596f82..19ed78f 100644
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/launching/CLaunchConfigurationTab.java
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/launching/CLaunchConfigurationTab.java
@@ -26,6 +26,7 @@ import org.eclipse.core.resources.ResourcesPlugin;
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IPath;
 import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.variables.VariablesPlugin;
 import org.eclipse.debug.core.ILaunchConfiguration;
 import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
 import org.eclipse.debug.ui.AbstractLaunchConfigurationTab;
@@ -54,6 +55,9 @@ public abstract class CLaunchConfigurationTab extends AbstractLaunchConfiguratio
 		try {
 			projectName = config.getAttribute(ICDTLaunchConfigurationConstants.ATTR_PROJECT_NAME, (String)null);
 			programName = config.getAttribute(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_NAME, (String)null);
+	        if (programName != null) {
+	        	programName = VariablesPlugin.getDefault().getStringVariableManager().performStringSubstitution(programName);
+	        }
 		} catch (CoreException e) {
 		}
 		if (projectName != null && !projectName.equals("")) { //$NON-NLS-1$
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/launching/CMainTab.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/launching/CMainTab.java
index 73e8e39..d596771 100644
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/launching/CMainTab.java
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/launching/CMainTab.java
@@ -139,7 +139,6 @@ public class CMainTab extends CAbstractMainTab {
 	protected void createExeFileGroup(Composite parent, int colSpan) {
 		Composite mainComp = new Composite(parent, SWT.NONE);
 		GridLayout mainLayout = new GridLayout();
-		mainLayout.numColumns = 3;
 		mainLayout.marginHeight = 0;
 		mainLayout.marginWidth = 0;
 		mainComp.setLayout(mainLayout);
@@ -149,7 +148,6 @@ public class CMainTab extends CAbstractMainTab {
 		fProgLabel = new Label(mainComp, SWT.NONE);
 		fProgLabel.setText(LaunchMessages.getString("CMainTab.C/C++_Application")); //$NON-NLS-1$
 		gd = new GridData();
-		gd.horizontalSpan = 3;
 		fProgLabel.setLayoutData(gd);
 		fProgText = new Text(mainComp, SWT.SINGLE | SWT.BORDER);
 		gd = new GridData(GridData.FILL_HORIZONTAL);
@@ -161,7 +159,17 @@ public class CMainTab extends CAbstractMainTab {
 			}
 		});
 
-		fSearchButton = createPushButton(mainComp, LaunchMessages.getString("CMainTab.Search..."), null); //$NON-NLS-1$
+		Composite buttonComp = new Composite(mainComp, SWT.NONE);
+		GridLayout layout = new GridLayout(3, false);
+		layout.marginHeight = 0;
+		layout.marginWidth = 0;
+		buttonComp.setLayout(layout);
+		gd = new GridData(GridData.HORIZONTAL_ALIGN_END);
+		buttonComp.setLayoutData(gd);
+		buttonComp.setFont(parent.getFont());
+
+		createVariablesButton(buttonComp, LaunchMessages.getString("CMainTab.Variables"), fProgText); //$NON-NLS-1$
+		fSearchButton = createPushButton(buttonComp, LaunchMessages.getString("CMainTab.Search..."), null); //$NON-NLS-1$
 		fSearchButton.addSelectionListener(new SelectionAdapter() {
 			@Override
 			public void widgetSelected(SelectionEvent evt) {
@@ -171,7 +179,7 @@ public class CMainTab extends CAbstractMainTab {
 		});
 
 		Button browseForBinaryButton;
-		browseForBinaryButton = createPushButton(mainComp, LaunchMessages.getString("Launch.common.Browse_2"), null); //$NON-NLS-1$
+		browseForBinaryButton = createPushButton(buttonComp, LaunchMessages.getString("Launch.common.Browse_2"), null); //$NON-NLS-1$
 		browseForBinaryButton.addSelectionListener(new SelectionAdapter() {
 			@Override
 			public void widgetSelected(SelectionEvent evt) {
@@ -444,6 +452,11 @@ public class CMainTab extends CAbstractMainTab {
 
 		if (!fDontCheckProgram) {
 			String programName = fProgText.getText().trim();
+       		try {
+				programName = VariablesPlugin.getDefault().getStringVariableManager().performStringSubstitution(programName);
+			} catch (CoreException e) {
+				// Silently ignore substitution failure (for consistency with "Arguments" and "Work directory" fields)
+			}
 			if (programName.length() == 0) {
 				setErrorMessage(LaunchMessages.getString("CMainTab.Program_not_specified")); //$NON-NLS-1$
 				return false;
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/launching/LaunchMessages.properties b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/launching/LaunchMessages.properties
index 472f9ef..1b82691 100644
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/launching/LaunchMessages.properties
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/launching/LaunchMessages.properties
@@ -94,6 +94,7 @@ CMainTab.CoreFile_type=Core file
 CMainTab.TraceFile_type=Trace file
 CMainTab.CoreFile_path=Core file (leave blank or select root directory to trigger prompt):
 CMainTab.TraceFile_path=Trace data file (leave blank or select root directory to trigger prompt):
+CMainTab.Variables=&Variables...
 CMainTab.Search...=Searc&h Project...
 CMainTab.Choose_program_to_run=Choose a &program to run:
 CMainTab.Choose_program_to_run_from_NAME=Choose a program to run from {0}:
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/launching/LaunchUtils.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/launching/LaunchUtils.java
index c1e69f7..5eb1373 100644
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/launching/LaunchUtils.java
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/launching/LaunchUtils.java
@@ -105,7 +105,8 @@ public class LaunchUtils {
 			abort(LaunchMessages.getString("AbstractCLaunchDelegate.Program_file_not_specified"), null, //$NON-NLS-1$
 				  ICDTLaunchConfigurationConstants.ERR_NOT_A_C_PROJECT);
 		}
-		
+        programName = VariablesPlugin.getDefault().getStringVariableManager().performStringSubstitution(programName);
+	
 		IPath programPath = new Path(programName);    			 
 		if (programPath.isEmpty()) {
 			abort(LaunchMessages.getString("AbstractCLaunchDelegate.Program_file_does_not_exist"), null, //$NON-NLS-1$
diff --git a/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/AbstractCLaunchDelegate.java b/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/AbstractCLaunchDelegate.java
index 5df21eb..8bf2cc4 100644
--- a/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/AbstractCLaunchDelegate.java
+++ b/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/AbstractCLaunchDelegate.java
@@ -60,6 +60,7 @@ import org.eclipse.core.runtime.Path;
 import org.eclipse.core.runtime.Status;
 import org.eclipse.core.runtime.SubProgressMonitor;
 import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.core.variables.VariablesPlugin;
 import org.eclipse.debug.core.DebugPlugin;
 import org.eclipse.debug.core.ILaunch;
 import org.eclipse.debug.core.ILaunchConfiguration;
@@ -645,6 +646,7 @@ abstract public class AbstractCLaunchDelegate extends LaunchConfigurationDelegat
 
 			if (configuration.getAttribute(ICDTLaunchConfigurationConstants.ATTR_PROJECT_BUILD_CONFIG_AUTO, false)) {
 				String programPath = configuration.getAttribute(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_NAME, EMPTY_STR);
+				programPath = VariablesPlugin.getDefault().getStringVariableManager().performStringSubstitution(programPath);
 				ICConfigurationDescription buildConfig = LaunchUtils.getBuildConfigByProgramPath(buildProject, programPath);
 				if (buildConfig != null)
 					buildConfigID = buildConfig.getId();
diff --git a/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/AbstractCLaunchDelegate2.java b/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/AbstractCLaunchDelegate2.java
index ba922b6..bd983a4 100644
--- a/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/AbstractCLaunchDelegate2.java
+++ b/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/AbstractCLaunchDelegate2.java
@@ -43,6 +43,7 @@ import org.eclipse.core.runtime.MultiStatus;
 import org.eclipse.core.runtime.OperationCanceledException;
 import org.eclipse.core.runtime.Status;
 import org.eclipse.core.runtime.SubMonitor;
+import org.eclipse.core.variables.VariablesPlugin;
 import org.eclipse.debug.core.DebugPlugin;
 import org.eclipse.debug.core.ILaunch;
 import org.eclipse.debug.core.ILaunchConfiguration;
@@ -253,6 +254,7 @@ public abstract class AbstractCLaunchDelegate2 extends LaunchConfigurationDelega
 			// If automatic configuration detection then discover the build config corresponding to the executable
 			if (configuration.getAttribute(ICDTLaunchConfigurationConstants.ATTR_PROJECT_BUILD_CONFIG_AUTO, false)) {
 				String programPath = configuration.getAttribute(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_NAME, ""); //$NON-NLS-1$
+				programPath = VariablesPlugin.getDefault().getStringVariableManager().performStringSubstitution(programPath);
 				ICConfigurationDescription buildConfig = LaunchUtils.getBuildConfigByProgramPath(project, programPath);
 				if (buildConfig != null)
 					buildConfigID = buildConfig.getId();
diff --git a/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/internal/ui/LaunchMessages.java b/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/internal/ui/LaunchMessages.java
index cc9e0b9..470a875 100644
--- a/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/internal/ui/LaunchMessages.java
+++ b/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/internal/ui/LaunchMessages.java
@@ -75,6 +75,7 @@ public class LaunchMessages extends NLS {
 	public static String CMainTab_ProjectColon;
 	public static String CMainTab_C_Application;
 	public static String CMainTab_CoreFile_path;
+	public static String CMainTab_Variables;
 	public static String CMainTab_Search;
 	public static String CMainTab_Choose_program_to_run;
 	public static String CMainTab_Choose_program_to_run_from_NAME;
diff --git a/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/internal/ui/LaunchMessages.properties b/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/internal/ui/LaunchMessages.properties
index c11f42f..9cd4c09 100644
--- a/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/internal/ui/LaunchMessages.properties
+++ b/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/internal/ui/LaunchMessages.properties
@@ -81,6 +81,7 @@ CMainTab_Main=Main
 CMainTab_ProjectColon=&Project:
 CMainTab_C_Application=C/C++ Application:
 CMainTab_CoreFile_path=Core file (leave blank to trigger prompt):
+CMainTab_Variables=&Variables...
 CMainTab_Search=Searc&h Project...
 CMainTab_Choose_program_to_run=Choose a &program to run:
 CMainTab_Choose_program_to_run_from_NAME=Choose a program to run from {0}:
diff --git a/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/internal/ui/WorkingDirectoryBlock.java b/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/internal/ui/WorkingDirectoryBlock.java
index 0c7072e..dfd257b 100644
--- a/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/internal/ui/WorkingDirectoryBlock.java
+++ b/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/internal/ui/WorkingDirectoryBlock.java
@@ -26,7 +26,6 @@ import org.eclipse.core.variables.IStringVariableManager;
 import org.eclipse.core.variables.VariablesPlugin;
 import org.eclipse.debug.core.ILaunchConfiguration;
 import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
-import org.eclipse.debug.ui.StringVariableSelectionDialog;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.accessibility.AccessibleAdapter;
 import org.eclipse.swt.accessibility.AccessibleEvent;
@@ -83,8 +82,6 @@ public class WorkingDirectoryBlock extends CLaunchConfigurationTab {
 				handleWorkingDirBrowseButtonSelected();
 			} else if (source == fUseDefaultWorkingDirButton) {
 				handleUseDefaultWorkingDirButtonSelected();
-			} else if (source == fVariablesButton) {
-				handleWorkingDirVariablesButtonSelected();
 			}
 		}
 	}
@@ -148,8 +145,7 @@ public class WorkingDirectoryBlock extends CLaunchConfigurationTab {
 		fFileSystemButton = createPushButton(buttonComp, LaunchMessages.WorkingDirectoryBlock_1, null); 
 		fFileSystemButton.addSelectionListener(fListener);
 
-		fVariablesButton = createPushButton(buttonComp, LaunchMessages.WorkingDirectoryBlock_17, null); 
-		fVariablesButton.addSelectionListener(fListener);
+		fVariablesButton = createVariablesButton(buttonComp, LaunchMessages.WorkingDirectoryBlock_17, null); 
 	}
 
 	/*
@@ -234,19 +230,6 @@ public class WorkingDirectoryBlock extends CLaunchConfigurationTab {
 		fFileSystemButton.setEnabled(!def);
 	}
 
-	protected void handleWorkingDirVariablesButtonSelected() {
-		String variableText = getVariable();
-		if (variableText != null) {
-			fWorkingDirText.append(variableText);
-		}
-	}
-
-	private String getVariable() {
-		StringVariableSelectionDialog dialog = new StringVariableSelectionDialog(getShell());
-		dialog.open();
-		return dialog.getVariableExpression();
-	}
-
 	/**
 	 * Sets the default working directory
 	 */
diff --git a/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/ui/CArgumentsTab.java b/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/ui/CArgumentsTab.java
index 9d54a8a..1f43564 100644
--- a/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/ui/CArgumentsTab.java
+++ b/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/ui/CArgumentsTab.java
@@ -20,15 +20,12 @@ import org.eclipse.core.runtime.CoreException;
 import org.eclipse.debug.core.ILaunchConfiguration;
 import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
 import org.eclipse.debug.ui.ILaunchConfigurationDialog;
-import org.eclipse.debug.ui.StringVariableSelectionDialog;
 import org.eclipse.osgi.util.NLS;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.accessibility.AccessibleAdapter;
 import org.eclipse.swt.accessibility.AccessibleEvent;
 import org.eclipse.swt.events.ModifyEvent;
 import org.eclipse.swt.events.ModifyListener;
-import org.eclipse.swt.events.SelectionAdapter;
-import org.eclipse.swt.events.SelectionEvent;
 import org.eclipse.swt.graphics.Font;
 import org.eclipse.swt.graphics.Image;
 import org.eclipse.swt.layout.GridData;
@@ -120,43 +117,12 @@ public class CArgumentsTab extends CLaunchConfigurationTab {
 				updateLaunchConfigurationDialog();
 			}
 		});
-		fArgumentVariablesButton= createPushButton(group, LaunchMessages.CArgumentsTab_Variables, null); 
+		fArgumentVariablesButton= createVariablesButton(group, LaunchMessages.CArgumentsTab_Variables, fPrgmArgumentsText); 
 		gd = new GridData(GridData.HORIZONTAL_ALIGN_END);
 		fArgumentVariablesButton.setLayoutData(gd);
-		fArgumentVariablesButton.addSelectionListener(new SelectionAdapter() {
-			/* (non-Javadoc)
-			 * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
-			 */
-			@Override
-			public void widgetSelected(SelectionEvent arg0) {
-				handleVariablesButtonSelected(fPrgmArgumentsText);
-			}
-		});
 		addControlAccessibleListener(fArgumentVariablesButton, fArgumentVariablesButton.getText()); // need to strip the mnemonic from buttons
 	}
 
-	/**
-	 * A variable entry button has been pressed for the given text
-	 * field. Prompt the user for a variable and enter the result
-	 * in the given field.
-	 */
-	protected void handleVariablesButtonSelected(Text textField) {
-		String variable = getVariable();
-		if (variable != null) {
-			textField.append(variable);
-		}
-	}
-
-	/**
-	 * Prompts the user to choose and configure a variable and returns
-	 * the resulting string, suitable to be used as an attribute.
-	 */
-	private String getVariable() {
-		StringVariableSelectionDialog dialog = new StringVariableSelectionDialog(getShell());
-		dialog.open();
-		return dialog.getVariableExpression();
-	}
-
 	public void addControlAccessibleListener(Control control, String controlName) {
 		//strip mnemonic (&)
 		String[] strs = controlName.split("&"); //$NON-NLS-1$
diff --git a/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/ui/CDebuggerTab.java b/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/ui/CDebuggerTab.java
index 62390e0..b27bf8e 100644
--- a/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/ui/CDebuggerTab.java
+++ b/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/ui/CDebuggerTab.java
@@ -35,6 +35,7 @@ import org.eclipse.cdt.launch.internal.ui.LaunchUIPlugin;
 import org.eclipse.core.resources.IProject;
 import org.eclipse.core.resources.ResourcesPlugin;
 import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.variables.VariablesPlugin;
 import org.eclipse.debug.core.ILaunchConfiguration;
 import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
 import org.eclipse.jface.dialogs.Dialog;
@@ -375,6 +376,9 @@ public class CDebuggerTab extends AbstractCDebuggerTab {
 		try {
 			projectName = config.getAttribute(ICDTLaunchConfigurationConstants.ATTR_PROJECT_NAME, (String)null);
 			programName = config.getAttribute(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_NAME, (String)null);
+			if (programName != null) {
+				programName = VariablesPlugin.getDefault().getStringVariableManager().performStringSubstitution(programName);
+			}
 		} catch (CoreException e) {
 		}
 		if (programName != null) {
diff --git a/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/ui/CLaunchConfigurationTab.java b/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/ui/CLaunchConfigurationTab.java
index 8e25576..1225a3e 100644
--- a/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/ui/CLaunchConfigurationTab.java
+++ b/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/ui/CLaunchConfigurationTab.java
@@ -26,11 +26,18 @@ import org.eclipse.core.resources.ResourcesPlugin;
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IPath;
 import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.variables.VariablesPlugin;
 import org.eclipse.debug.core.ILaunchConfiguration;
 import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
 import org.eclipse.debug.ui.AbstractLaunchConfigurationTab;
+import org.eclipse.debug.ui.StringVariableSelectionDialog;
 import org.eclipse.jface.viewers.ISelection;
 import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Text;
 import org.eclipse.ui.IEditorInput;
 import org.eclipse.ui.IEditorPart;
 import org.eclipse.ui.IFileEditorInput;
@@ -54,6 +61,9 @@ public abstract class CLaunchConfigurationTab extends AbstractLaunchConfiguratio
 		try {
 			projectName = config.getAttribute(ICDTLaunchConfigurationConstants.ATTR_PROJECT_NAME, (String)null);
 			programName = config.getAttribute(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_NAME, (String)null);
+			if (programName != null) {
+				programName = VariablesPlugin.getDefault().getStringVariableManager().performStringSubstitution(programName);
+			}
 		} catch (CoreException e) {
 		}
 		if (projectName != null && !projectName.equals("")) { //$NON-NLS-1$
@@ -160,4 +170,43 @@ public abstract class CLaunchConfigurationTab extends AbstractLaunchConfiguratio
 			return platform;
 		}
 	}
+	
+	protected Button createVariablesButton(Composite parent, String label, final Text textField) {
+		Button variablesButton = createPushButton(parent, label, null); 
+		variablesButton.addSelectionListener(new SelectionAdapter() {
+			
+			/* (non-Javadoc)
+			 * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+			 */
+			@Override
+			public void widgetSelected(SelectionEvent arg0) {
+				handleVariablesButtonSelected(textField);
+			}
+		});
+		return variablesButton;
+	}
+
+	/**
+	 * A variable entry button has been pressed for the given text
+	 * field. Prompt the user for a variable and enter the result
+	 * in the given field.
+	 */
+	private void handleVariablesButtonSelected(Text textField) {
+		String variable = getVariable();
+		if (variable != null) {
+			// We should use insert() but not append() to be consistent with the Platform behavior (e.g. Common tab)
+			textField.insert(variable);
+		}
+	}
+
+	/**
+	 * Prompts the user to choose and configure a variable and returns
+	 * the resulting string, suitable to be used as an attribute.
+	 */
+	private String getVariable() {
+		StringVariableSelectionDialog dialog = new StringVariableSelectionDialog(getShell());
+		dialog.open();
+		return dialog.getVariableExpression();
+	}
+	
 }
diff --git a/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/ui/CMainTab.java b/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/ui/CMainTab.java
index 14df978..863219f 100644
--- a/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/ui/CMainTab.java
+++ b/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/ui/CMainTab.java
@@ -31,6 +31,7 @@ import org.eclipse.core.resources.ResourcesPlugin;
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IPath;
 import org.eclipse.core.runtime.Path;
+import org.eclipse.core.variables.VariablesPlugin;
 import org.eclipse.debug.core.ILaunchConfiguration;
 import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
 import org.eclipse.debug.ui.DebugUITools;
@@ -343,7 +344,6 @@ public class CMainTab extends CAbstractMainTab {
 	protected void createExeFileGroup(Composite parent, int colSpan) {
 		Composite mainComp = new Composite(parent, SWT.NONE);
 		GridLayout mainLayout = new GridLayout();
-		mainLayout.numColumns = 3;
 		mainLayout.marginHeight = 0;
 		mainLayout.marginWidth = 0;
 		mainComp.setLayout(mainLayout);
@@ -353,7 +353,6 @@ public class CMainTab extends CAbstractMainTab {
 		fProgLabel = new Label(mainComp, SWT.NONE);
 		fProgLabel.setText(LaunchMessages.CMainTab_C_Application); 
 		gd = new GridData();
-		gd.horizontalSpan = 3;
 		fProgLabel.setLayoutData(gd);
 		fProgText = new Text(mainComp, SWT.SINGLE | SWT.BORDER);
 		gd = new GridData(GridData.FILL_HORIZONTAL);
@@ -365,7 +364,17 @@ public class CMainTab extends CAbstractMainTab {
 			}
 		});
 
-		fSearchButton = createPushButton(mainComp, LaunchMessages.CMainTab_Search, null); 
+		Composite buttonComp = new Composite(mainComp, SWT.NONE);
+		GridLayout layout = new GridLayout(3, false);
+		layout.marginHeight = 0;
+		layout.marginWidth = 0;
+		buttonComp.setLayout(layout);
+		gd = new GridData(GridData.HORIZONTAL_ALIGN_END);
+		buttonComp.setLayoutData(gd);
+		buttonComp.setFont(parent.getFont());
+
+		createVariablesButton(buttonComp, LaunchMessages.CMainTab_Variables, fProgText);
+		fSearchButton = createPushButton(buttonComp, LaunchMessages.CMainTab_Search, null); 
 		fSearchButton.addSelectionListener(new SelectionAdapter() {
 			@Override
 			public void widgetSelected(SelectionEvent evt) {
@@ -375,7 +384,7 @@ public class CMainTab extends CAbstractMainTab {
 		});
 
 		Button fBrowseForBinaryButton;
-		fBrowseForBinaryButton = createPushButton(mainComp, LaunchMessages.Launch_common_Browse_2, null); 
+		fBrowseForBinaryButton = createPushButton(buttonComp, LaunchMessages.Launch_common_Browse_2, null); 
 		fBrowseForBinaryButton.addSelectionListener(new SelectionAdapter() {
 			@Override
 			public void widgetSelected(SelectionEvent evt) {
@@ -432,6 +441,11 @@ public class CMainTab extends CAbstractMainTab {
 			}
 	
 			name = fProgText.getText().trim();
+       		try {
+       			name = VariablesPlugin.getDefault().getStringVariableManager().performStringSubstitution(name);
+			} catch (CoreException e) {
+				// Silently ignore substitution failure (for consistency with "Arguments" and "Work directory" fields)
+			}
 			if (name.length() == 0) {
 				setErrorMessage(LaunchMessages.CMainTab_Program_not_specified); 
 				return false;

Back to the top