Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
[cdt-patch] Partial implementation of incremental build and some bug fixes

Hi All,
Details are in the change log, but this patch contains work that partially 
implements incremental build. There are 2 major use cases not implemented: 
full rebuild on project settings change and properly handling header file 
changes. Both problems require build model work, so I will deliver that 
functionality in another patch. There are also fixes for bugs 41412 and 
42735.

As always, I have run the JUnit tests on Solaris (Motif) and Linux (Gtk).

Sean Evoy
Rational Software - IBM Software Group
Ottawa, Ontario, Canada

Index: ChangeLog
===================================================================
RCS file: /home/tools/org.eclipse.cdt.core.tests/ChangeLog,v
retrieving revision 1.88
diff -u -r1.88 ChangeLog
--- ChangeLog	10 Sep 2003 13:21:53 -0000	1.88
+++ ChangeLog	10 Sep 2003 20:14:13 -0000
@@ -1,3 +1,9 @@
+2003-09-10 Sean Evoy
+	Added a test for resetting the value of a configuration to the defaults defined in the 
+	plugin file. Work completed to resolve [Bug 41412] Restore Default in Managed Build 
+	project's settings Not Working.
+	* build/org/eclipse/cdt/core/build/managed/tests/ManagedBuildTests.java
+
 2003-09-09 Hoda Amer
 	Moved three failed tests (bugs #42822, #42823, & #42822B)
 	from FailedCompleteParseASTExpressionTest to CompleteParseASTExpressionTest 
Index: build/org/eclipse/cdt/core/build/managed/tests/ManagedBuildTests.java
===================================================================
RCS file: /home/tools/org.eclipse.cdt.core.tests/build/org/eclipse/cdt/core/build/managed/tests/ManagedBuildTests.java,v
retrieving revision 1.2
diff -u -r1.2 ManagedBuildTests.java
--- build/org/eclipse/cdt/core/build/managed/tests/ManagedBuildTests.java	20 Aug 2003 17:52:27 -0000	1.2
+++ build/org/eclipse/cdt/core/build/managed/tests/ManagedBuildTests.java	10 Sep 2003 20:14:14 -0000
@@ -64,6 +64,7 @@
 		suite.addTest(new ManagedBuildTests("testExtensions"));
 		suite.addTest(new ManagedBuildTests("testProjectCreation"));
 		suite.addTest(new ManagedBuildTests("testConfigurations"));
+		suite.addTest(new ManagedBuildTests("testConfigurationReset"));
 		suite.addTest(new ManagedBuildTests("testTargetArtifacts"));
 		suite.addTest(new ManagedBuildTests("testScannerInfoInterface"));
 		suite.addTest(new ManagedBuildTests("cleanup"));
@@ -264,6 +265,39 @@
 
 		// Test the values in the new configuration
 		checkOptionReferences(project);
+	}
+	
+	public void testConfigurationReset() {
+		// Open the test project
+		IProject project = null;
+		try {
+			project = createProject(projectName);
+		} catch (CoreException e) {
+			fail("Failed to open project: " + e.getLocalizedMessage());
+		}
+
+		// Get the default configuration
+		IManagedBuildInfo info = ManagedBuildManager.getBuildInfo(project);
+		assertNotNull(info);
+		ITarget defaultTarget = info.getDefaultTarget();
+		assertNotNull(defaultTarget);
+		IConfiguration defaultConfig = info.getDefaultConfiguration(defaultTarget);
+		assertNotNull(defaultConfig);
+		
+		// See if it still contains the overridden values (see testProjectCreation())
+		try {
+			checkRootTarget(defaultTarget, "z");
+		} catch (BuildException e1) {
+			fail("Overridden root target check failed: " + e1.getLocalizedMessage());
+		}
+		
+		// Reset the config and retest
+		ManagedBuildManager.resetConfiguration(project, defaultConfig);
+		try {
+			checkRootTarget(defaultTarget, "x");
+		} catch (BuildException e2) {
+			fail("Reset root target check failed: " + e2.getLocalizedMessage());
+		}
 	}
 	
 	/**
Index: ChangeLog
===================================================================
RCS file: /home/tools/org.eclipse.cdt.ui/ChangeLog,v
retrieving revision 1.165
diff -u -r1.165 ChangeLog
--- ChangeLog	9 Sep 2003 17:54:02 -0000	1.165
+++ ChangeLog	10 Sep 2003 20:14:35 -0000
@@ -1,3 +1,11 @@
+2003-09-10 Sean Evoy
+	Work completed to resolve [Bug 41412] Restore Default in Managed Build 
+	project's settings Not Working. Added an event handler to reset the selected 
+	configuration settings back to the defaults defined in the plugin manifest.
+	Work to resolve [Bug 42736] New: C/C++ Build Settings not remembering Configuration.
+	Used the managed build info to get the current config for the target.
+	* build/org/eclipse/cdt/ui/build/properties/BuildPropertyPage.java
+	
 2003-09-08 Bogdan Gheorghe
 	- Changed search pop up menu in CEditor and CContentOutlinePage
 
Index: build/org/eclipse/cdt/ui/build/properties/BuildPropertyPage.java
===================================================================
RCS file: /home/tools/org.eclipse.cdt.ui/build/org/eclipse/cdt/ui/build/properties/BuildPropertyPage.java,v
retrieving revision 1.3
diff -u -r1.3 BuildPropertyPage.java
--- build/org/eclipse/cdt/ui/build/properties/BuildPropertyPage.java	20 Aug 2003 17:52:23 -0000	1.3
+++ build/org/eclipse/cdt/ui/build/properties/BuildPropertyPage.java	10 Sep 2003 20:14:36 -0000
@@ -18,6 +18,7 @@
 import java.util.Map;
 
 import org.eclipse.cdt.core.build.managed.IConfiguration;
+import org.eclipse.cdt.core.build.managed.IManagedBuildInfo;
 import org.eclipse.cdt.core.build.managed.IOptionCategory;
 import org.eclipse.cdt.core.build.managed.ITarget;
 import org.eclipse.cdt.core.build.managed.ManagedBuildManager;
@@ -276,7 +277,7 @@
 	 */
 	private void displayOptionsForCategory(IOptionCategory category) {
 		// Do nothing if the selected category is is unchanged
-		if (selectedCategory == category) {
+		if (category == selectedCategory) {
 			return;
 		}
 		selectedCategory = category;
@@ -451,13 +452,38 @@
 		populateConfigurations();		
 	}
 
-	/**
+	/* 
+	 *  (non-javadoc)
 	 * Initialize the relative weights (widths) of the 2 sides of the sash.
 	 */
 	protected void initializeSashForm() {
 		sashForm.setWeights(DEFAULT_SASH_WEIGHTS);
 	}
 
+	/*
+	 *  (non-Javadoc)
+	 * @see org.eclipse.jface.preference.PreferencePage#performDefaults()
+	 */
+	protected void performDefaults() {
+		// Empty the page list
+		List pages = getPagesForConfig();
+		pages.clear();
+		
+		// Get the build manager to reset build info for project
+		ManagedBuildManager.resetConfiguration(getProject(), getSelectedConfiguration());
+		
+		// Recreate the settings store for the configuration
+		settingsStore = new BuildToolsSettingsStore(getSelectedConfiguration());
+
+		// Reset the category selection and run selection event handler
+		selectedCategory = null;
+		handleOptionSelection();
+	}
+
+	/* 
+	 *  (non-Javadoc)
+	 * @see org.eclipse.jface.preference.IPreferencePage#performOk()
+	 */
 	public boolean performOk() {
 		// Force each settings page to update
 		List pages = getPagesForConfig();
@@ -485,7 +511,10 @@
 		configSelector.setItems(getConfigurationNames());
 		
 		// Make sure the active configuration is selected
-		configSelector.select(0);
+		IManagedBuildInfo info = ManagedBuildManager.getBuildInfo(getProject());
+		IConfiguration defaultConfig = info.getDefaultConfiguration(selectedTarget);
+		int index = configSelector.indexOf(defaultConfig.getName());
+		configSelector.select(index == -1 ? 0 : index);
 		handleConfigSelection();
 	}
 	
Index: ChangeLog
===================================================================
RCS file: /home/tools/org.eclipse.cdt.core/ChangeLog,v
retrieving revision 1.144
diff -u -r1.144 ChangeLog
--- ChangeLog	9 Sep 2003 17:53:51 -0000	1.144
+++ ChangeLog	10 Sep 2003 20:13:41 -0000
@@ -1,3 +1,34 @@
+2003-09-10 Sean Evoy
+	Work completed to resolve [Bug 41412] "Restore Default in Managed Build project's 
+	settings Not Working". The configuration now has a reset method that removes 
+	any user settings and replaces them with the values defined in the plugin 
+	manifest. The Configuration class also has a new, safe accessor for getting 
+	at the defined tool references. Replaced all the checks for null with the accessor. 
+	Added some string constants to the IConfiguration and ITarget interfaces 
+	so manifest element lookup will be easier to maintain should the element names change. 
+	Switched the Target class to use the new string constants during element lookup. 
+	Added back a method in IConfiguration to lookup the parent configuration (which is the 
+	plugin element I need to do the reset). 
+	* build/org/eclipse/cdt/internal/core/build/managed/Configuration.java
+	* build/org/eclipse/cdt/core/build/managed/IConfiguration.java
+	* build/org/eclipse/cdt/core/build/managed/ITarget.java
+	* build/org/eclipse/cdt/core/build/managed/ITool.java
+	* build/org/eclipse/cdt/internal/core/build/managed/Target.java
+	
+	Work to resolve [Bug 42735] "Manage Make will try to generate makefile for Release or 
+	Debug directory". Added a new method to return all the configuration names so 
+	the generator will know that the directory <project_root>/<config_name> should be ignored.
+	* build/org/eclipse/cdt/internal/core/build/managed/ManagedBuildInfo.java
+	* build/org/eclipse/cdt/core/build/managed/IManagedBuildInfo.java
+
+	Work to partially implement incremental build. New incremental build logic in the 
+	incrementalBuild() method in the GeneratedMakefileBuilder class. It now calls a 
+	specialized method in the makefile generator that calculates and generates the
+	needed makefiles and fragments. It then calls build if there are any changes worthy
+	of a build.
+	* src/org/eclipse/cdt/internal/core/GeneratedMakefileBuilder.java
+	* src/org/eclipse/cdt/internal/core/MakefileGenerator.java
+
 2003-09-05 Bogdan Gheorghe
 
 	Hooked in the dependency checking on file changes in Delta
Index: build/org/eclipse/cdt/core/build/managed/IConfiguration.java
===================================================================
RCS file: /home/tools/org.eclipse.cdt.core/build/org/eclipse/cdt/core/build/managed/IConfiguration.java,v
retrieving revision 1.7
diff -u -r1.7 IConfiguration.java
--- build/org/eclipse/cdt/core/build/managed/IConfiguration.java	31 Jul 2003 13:20:37 -0000	1.7
+++ build/org/eclipse/cdt/core/build/managed/IConfiguration.java	10 Sep 2003 20:13:41 -0000
@@ -14,8 +14,9 @@
 
 public interface IConfiguration extends IBuildObject {
 	// Schema element names
-	public static final String TOOL_REF = "toolReference";
-	public static final String PARENT = "parent";
+	public static final String CONFIGURATION_ELEMENT_NAME = "configuration";	//$NON-NLS-1$
+	public static final String TOOL_REF = "toolReference";	//$NON-NLS-1$
+	public static final String PARENT = "parent";	//$NON-NLS-1$
 
 	/**
 	 * Returns the target for this configuration.
@@ -29,6 +30,13 @@
 	 * @return
 	 */
 	public IResource getOwner();
+	
+	/**
+	 * Answers the configuration that the receiver is based on. 
+	 * 
+	 * @return
+	 */
+	public IConfiguration getParent();
 	
 	/**
 	 * Returns the tools that are used in this configuration.
Index: build/org/eclipse/cdt/core/build/managed/IManagedBuildInfo.java
===================================================================
RCS file: /home/tools/org.eclipse.cdt.core/build/org/eclipse/cdt/core/build/managed/IManagedBuildInfo.java,v
retrieving revision 1.3
diff -u -r1.3 IManagedBuildInfo.java
--- build/org/eclipse/cdt/core/build/managed/IManagedBuildInfo.java	25 Jul 2003 17:31:01 -0000	1.3
+++ build/org/eclipse/cdt/core/build/managed/IManagedBuildInfo.java	10 Sep 2003 20:13:41 -0000
@@ -52,6 +52,14 @@
 	 * @return
 	 */
 	public String getConfigurationName();
+	
+	/**
+	 * Answers a <code>String</code> array containing the names of all the configurations
+	 * defined for the project's current target.
+	 *  
+	 * @return
+	 */
+	public String[] getConfigurationNames();
 
 	/**
 	 * Get the default configuration associated with the receiver
Index: build/org/eclipse/cdt/core/build/managed/ITarget.java
===================================================================
RCS file: /home/tools/org.eclipse.cdt.core/build/org/eclipse/cdt/core/build/managed/ITarget.java,v
retrieving revision 1.10
diff -u -r1.10 ITarget.java
--- build/org/eclipse/cdt/core/build/managed/ITarget.java	29 Jul 2003 14:28:37 -0000	1.10
+++ build/org/eclipse/cdt/core/build/managed/ITarget.java	10 Sep 2003 20:13:41 -0000
@@ -17,6 +17,7 @@
  * is some type of resource built using a given collection of tools.
  */
 public interface ITarget extends IBuildObject {
+	public static final String TARGET_ELEMENT_NAME = "target";	//$NON-NLS-1$
 
 	/**
 	 * Creates a configuration for the target populated with the tools and
Index: build/org/eclipse/cdt/core/build/managed/ITool.java
===================================================================
RCS file: /home/tools/org.eclipse.cdt.core/build/org/eclipse/cdt/core/build/managed/ITool.java,v
retrieving revision 1.6
diff -u -r1.6 ITool.java
--- build/org/eclipse/cdt/core/build/managed/ITool.java	31 Jul 2003 13:20:37 -0000	1.6
+++ build/org/eclipse/cdt/core/build/managed/ITool.java	10 Sep 2003 20:13:41 -0000
@@ -15,15 +15,16 @@
  */
 public interface ITool extends IBuildObject {
 	// Schema element names
-	public static final String COMMAND = "command";
-	public static final String OPTION = "option";
-	public static final String OPTION_CAT = "optionCategory";
-	public static final String OPTION_REF = "optionReference";
-	public static final String OUTPUT_FLAG = "outputFlag";
-	public static final String OUTPUT_PREFIX = "outputPrefix";
-	public static final String OUTPUTS = "outputs";
-	public static final String SOURCES = "sources";
-	public static final String WHITE_SPACE = " ";
+	public static final String TOOL_ELEMENT_NAME = "tool";	//$NON-NLS-1$
+	public static final String COMMAND = "command";	//$NON-NLS-1$
+	public static final String OPTION = "option";	//$NON-NLS-1$
+	public static final String OPTION_CAT = "optionCategory";	//$NON-NLS-1$
+	public static final String OPTION_REF = "optionReference";	//$NON-NLS-1$
+	public static final String OUTPUT_FLAG = "outputFlag";	//$NON-NLS-1$
+	public static final String OUTPUT_PREFIX = "outputPrefix";	//$NON-NLS-1$
+	public static final String OUTPUTS = "outputs";	//$NON-NLS-1$
+	public static final String SOURCES = "sources";	//$NON-NLS-1$
+	public static final String WHITE_SPACE = " ";	//$NON-NLS-1$
 
 	/**
 	 * Return <code>true</code> if the receiver builds files with the
Index: build/org/eclipse/cdt/core/build/managed/ManagedBuildManager.java
===================================================================
RCS file: /home/tools/org.eclipse.cdt.core/build/org/eclipse/cdt/core/build/managed/ManagedBuildManager.java,v
retrieving revision 1.13
diff -u -r1.13 ManagedBuildManager.java
--- build/org/eclipse/cdt/core/build/managed/ManagedBuildManager.java	13 Aug 2003 17:45:30 -0000	1.13
+++ build/org/eclipse/cdt/core/build/managed/ManagedBuildManager.java	10 Sep 2003 20:13:41 -0000
@@ -31,6 +31,7 @@
 import org.eclipse.cdt.core.AbstractCExtension;
 import org.eclipse.cdt.core.CCorePlugin;
 import org.eclipse.cdt.core.parser.*;
+import org.eclipse.cdt.internal.core.build.managed.Configuration;
 import org.eclipse.cdt.internal.core.build.managed.ManagedBuildInfo;
 import org.eclipse.cdt.internal.core.build.managed.Target;
 import org.eclipse.core.resources.IFile;
@@ -52,11 +53,12 @@
 public class ManagedBuildManager extends AbstractCExtension implements IScannerInfoProvider {
 
 	private static final QualifiedName buildInfoProperty = new QualifiedName(CCorePlugin.PLUGIN_ID, "managedBuildInfo");
-	private static final String ROOT_ELEM_NAME = "ManagedProjectBuildInfo";
-	private static final String FILE_NAME = ".cdtbuild";
+	private static final String ROOT_ELEM_NAME = "ManagedProjectBuildInfo";	//$NON-NLS-1$
+	private static final String FILE_NAME = ".cdtbuild";	//$NON-NLS-1$
 	private static final ITarget[] emptyTargets = new ITarget[0];
-	public static final String INTERFACE_IDENTITY = CCorePlugin.PLUGIN_ID + "." + "ManagedBuildManager";
-
+	public static final String INTERFACE_IDENTITY = CCorePlugin.PLUGIN_ID + "." + "ManagedBuildManager";	//$NON-NLS-1$
+	public static final String EXTENSION_POINT_ID = "ManagedBuildInfo";		//$NON-NLS-1$
+	
 	// Targets defined by extensions (i.e., not associated with a resource)
 	private static boolean extensionTargetsLoaded = false;
 	private static List extensionTargets;
@@ -311,12 +313,56 @@
 		}
 	}
 
+	/**
+	 * @param resource
+	 */
 	public static void removeBuildInfo(IResource resource) {
 		try {
 			resource.setSessionProperty(buildInfoProperty, null);
 		} catch (CoreException e) {
 		}
 	}
+
+	/**
+	 * Resets the build information for the project and configuration specified in the arguments. 
+	 * The build information will contain the settings defined in the plugin manifest. 
+	 * 
+	 * @param project
+	 * @param configuration
+	 */
+	public static void resetConfiguration(IProject project, IConfiguration configuration) {
+		// Make sure the extensions are loaded
+		loadExtensions();
+
+		// Find out the parent of the configuration
+		IConfiguration parentConfig = configuration.getParent();
+		// Find the parent target the configuration 
+		ITarget parentTarget = parentConfig.getTarget();
+
+		// Get the extension point information		
+		IExtensionPoint extensionPoint = CCorePlugin.getDefault().getDescriptor().getExtensionPoint(EXTENSION_POINT_ID);
+		IExtension[] extensions = extensionPoint.getExtensions();
+		for (int i = 0; i < extensions.length; ++i) {
+			IExtension extension = extensions[i];
+			IConfigurationElement[] elements = extension.getConfigurationElements();
+			for (int j = 0; j < elements.length; ++j) {
+				IConfigurationElement element = elements[j];
+				if (element.getName().equals(ITarget.TARGET_ELEMENT_NAME) && 
+					element.getAttribute(ITarget.ID).equals(parentTarget.getId())) {
+					// We have the parent target so get the definition for the parent config
+					IConfigurationElement[] targetElements = element.getChildren();
+					for (int k = 0; k < targetElements.length; ++k) {
+						IConfigurationElement targetElement = targetElements[k];
+						if (targetElement.getName().equals(IConfiguration.CONFIGURATION_ELEMENT_NAME) && 
+							targetElement.getAttribute(IConfiguration.ID).equals(parentConfig.getId())) {
+							// We now have the plugin element the target was originally based on
+							((Configuration)configuration).reset(targetElement);							 
+						}
+					}
+				}
+			}
+		}
+	}
 	
 	// Private stuff
 
@@ -356,14 +402,14 @@
 			return;
 		extensionTargetsLoaded = true;
 
-		IExtensionPoint extensionPoint = CCorePlugin.getDefault().getDescriptor().getExtensionPoint("ManagedBuildInfo");
+		IExtensionPoint extensionPoint = CCorePlugin.getDefault().getDescriptor().getExtensionPoint(EXTENSION_POINT_ID);
 		IExtension[] extensions = extensionPoint.getExtensions();
 		for (int i = 0; i < extensions.length; ++i) {
 			IExtension extension = extensions[i];
 			IConfigurationElement[] elements = extension.getConfigurationElements();
 			for (int j = 0; j < elements.length; ++j) {
 				IConfigurationElement element = elements[j];
-				if (element.getName().equals("target")) {
+				if (element.getName().equals(ITarget.TARGET_ELEMENT_NAME)) {
 					new Target(element);
 				}
 			}
@@ -516,4 +562,5 @@
 			map.put(project, list);
 		}
 	}
+
 }
Index: build/org/eclipse/cdt/internal/core/build/managed/Configuration.java
===================================================================
RCS file: /home/tools/org.eclipse.cdt.core/build/org/eclipse/cdt/internal/core/build/managed/Configuration.java,v
retrieving revision 1.13
diff -u -r1.13 Configuration.java
--- build/org/eclipse/cdt/internal/core/build/managed/Configuration.java	11 Aug 2003 17:33:05 -0000	1.13
+++ build/org/eclipse/cdt/internal/core/build/managed/Configuration.java	10 Sep 2003 20:13:42 -0000
@@ -147,13 +147,12 @@
 		if (parent != null)
 			element.setAttribute(IConfiguration.PARENT, parent.getId());
 		
-		if (toolReferences != null)
-			for (int i = 0; i < toolReferences.size(); ++i) {
-				ToolReference toolRef = (ToolReference)toolReferences.get(i);
-				Element toolRefElement = doc.createElement(IConfiguration.TOOL_REF);
-				element.appendChild(toolRefElement);
-				toolRef.serialize(doc, toolRefElement);
-			}
+		for (int i = 0; i < getToolReferences().size(); ++i) {
+			ToolReference toolRef = (ToolReference)getToolReferences().get(i);
+			Element toolRefElement = doc.createElement(IConfiguration.TOOL_REF);
+			element.appendChild(toolRefElement);
+			toolRef.serialize(doc, toolRefElement);
+		}
 	}
 	
 	/* (non-Javadoc)
@@ -163,6 +162,16 @@
 		return (name == null && parent != null) ? parent.getName() : name;
 	}
 
+	/*
+	 * @return
+	 */
+	private List getToolReferences() {
+		if (toolReferences == null) {
+			toolReferences = new ArrayList();
+		}
+		return toolReferences;
+	}
+
 	/* (non-Javadoc)
 	 * @see org.eclipse.cdt.core.build.managed.IConfiguration#getTools()
 	 */
@@ -181,6 +190,21 @@
 		return tools;
 	}
 
+	/**
+	 * @param targetElement
+	 */
+	public void reset(IConfigurationElement element) {
+		// I just need to reset the tool references
+		getToolReferences().clear();
+		IConfigurationElement[] configElements = element.getChildren();
+		for (int l = 0; l < configElements.length; ++l) {
+			IConfigurationElement configElement = configElements[l];
+			if (configElement.getName().equals(IConfiguration.TOOL_REF)) {
+				new ToolReference(this, configElement);
+			}
+		}
+	}
+
 	/* (non-Javadoc)
 	 * @see org.eclipse.cdt.core.build.managed.IConfiguration#getParent()
 	 */
@@ -209,19 +233,16 @@
 	 * @return
 	 */
 	private ToolReference getToolReference(ITool tool) {
-		if (toolReferences != null)
-			for (int i = 0; i < toolReferences.size(); ++i) {
-				ToolReference toolRef = (ToolReference)toolReferences.get(i);
-				if (toolRef.references(tool))
-					return toolRef;
-			}
+		for (int i = 0; i < getToolReferences().size(); ++i) {
+			ToolReference toolRef = (ToolReference)getToolReferences().get(i);
+			if (toolRef.references(tool))
+				return toolRef;
+		}
 		return null;
 	}
 	
 	public void addToolReference(ToolReference toolRef) {
-		if (toolReferences == null)
-			toolReferences = new ArrayList();
-		toolReferences.add(toolRef);
+		getToolReferences().add(toolRef);
 	}
 	
 	public OptionReference createOptionReference(IOption option) {
@@ -293,4 +314,6 @@
 		if(!Arrays.equals(value, oldValue))
 			createOptionReference(option).setValue(value);
 	}
+
+
 }
Index: build/org/eclipse/cdt/internal/core/build/managed/ManagedBuildInfo.java
===================================================================
RCS file: /home/tools/org.eclipse.cdt.core/build/org/eclipse/cdt/internal/core/build/managed/ManagedBuildInfo.java,v
retrieving revision 1.6
diff -u -r1.6 ManagedBuildInfo.java
--- build/org/eclipse/cdt/internal/core/build/managed/ManagedBuildInfo.java	20 Aug 2003 17:52:32 -0000	1.6
+++ build/org/eclipse/cdt/internal/core/build/managed/ManagedBuildInfo.java	10 Sep 2003 20:13:42 -0000
@@ -134,6 +134,19 @@
 	}
 
 	/* (non-Javadoc)
+	 * @see org.eclipse.cdt.core.build.managed.IManagedBuildInfo#getConfigurationNames()
+	 */
+	public String[] getConfigurationNames() {
+		ArrayList configNames = new ArrayList();
+		IConfiguration[] configs = getDefaultTarget().getConfigurations();
+		for (int i = 0; i < configs.length; i++) {
+			IConfiguration configuration = configs[i];
+			configNames.add(configuration.getName());
+		}
+		return (String[])configNames.toArray(new String[configNames.size()]);
+	}
+
+	/* (non-Javadoc)
 	 * @see org.eclipse.cdt.core.build.managed.IManagedBuildInfo#getDefaultConfiguration()
 	 */
 	public IConfiguration getDefaultConfiguration(ITarget target) {
Index: build/org/eclipse/cdt/internal/core/build/managed/Target.java
===================================================================
RCS file: /home/tools/org.eclipse.cdt.core/build/org/eclipse/cdt/internal/core/build/managed/Target.java,v
retrieving revision 1.11
diff -u -r1.11 Target.java
--- build/org/eclipse/cdt/internal/core/build/managed/Target.java	29 Jul 2003 14:28:36 -0000	1.11
+++ build/org/eclipse/cdt/internal/core/build/managed/Target.java	10 Sep 2003 20:13:42 -0000
@@ -132,9 +132,9 @@
 		IConfigurationElement[] targetElements = element.getChildren();
 		for (int k = 0; k < targetElements.length; ++k) {
 			IConfigurationElement targetElement = targetElements[k];
-			if (targetElement.getName().equals("tool")) {
+			if (targetElement.getName().equals(ITool.TOOL_ELEMENT_NAME)) {
 				new Tool(this, targetElement);
-			} else if (targetElement.getName().equals("configuration")) {
+			} else if (targetElement.getName().equals(IConfiguration.CONFIGURATION_ELEMENT_NAME)) {
 				new Configuration(this, targetElement);
 			}
 		}
@@ -186,7 +186,7 @@
 	
 		Node child = element.getFirstChild();
 		while (child != null) {
-			if (child.getNodeName().equals("configuration")) {
+			if (child.getNodeName().equals(IConfiguration.CONFIGURATION_ELEMENT_NAME)) {
 				new Configuration(this, (Element)child);
 			}
 			child = child.getNextSibling();
Index: src/org/eclipse/cdt/internal/core/GeneratedMakefileBuilder.java
===================================================================
RCS file: /home/tools/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/GeneratedMakefileBuilder.java,v
retrieving revision 1.5
diff -u -r1.5 GeneratedMakefileBuilder.java
--- src/org/eclipse/cdt/internal/core/GeneratedMakefileBuilder.java	29 Jul 2003 14:28:36 -0000	1.5
+++ src/org/eclipse/cdt/internal/core/GeneratedMakefileBuilder.java	10 Sep 2003 20:13:43 -0000
@@ -64,18 +64,21 @@
 
 	
 	public class ResourceDeltaVisitor implements IResourceDeltaVisitor {
-		boolean bContinue;
+		private boolean buildNeeded = false;
 
 		public boolean visit(IResourceDelta delta) throws CoreException {
 			IResource resource = delta.getResource();
+			// If the project has changed, then a build is needed and we can stop
 			if (resource != null && resource.getProject() == getProject()) {
-				bContinue = true;
+				buildNeeded = true;
 				return false;
 			}
+
 			return true;
 		}
+
 		public boolean shouldBuild() {
-			return bContinue;
+			return buildNeeded;
 		}
 	}
 
@@ -255,10 +258,27 @@
 		}
 		statusMsg = CCorePlugin.getFormattedString(INCREMENTAL, currentProject.getName());
 		monitor.subTask(statusMsg);
-
+		
+		// Ask the makefile generator to generate any makefiles needed to build delta
 		IManagedBuildInfo info = ManagedBuildManager.getBuildInfo(getProject());
-		IPath buildDir = new Path(info.getConfigurationName());
-		invokeMake(false, buildDir, info, monitor);
+		MakefileGenerator generator = new MakefileGenerator(currentProject, info, monitor);
+		try {
+			generator.generateMakefiles(delta);
+		} catch (CoreException e) {
+			if (e.getStatus().getCode() == GeneratedMakefileBuilder.EMPTY_PROJECT_BUILD_ERROR) {
+				// There is nothing to build so bail
+				monitor.worked(1);
+				return;		
+			} else {
+				throw e;
+			}
+		}	
+
+		// Run the build if there is any relevant change
+		if (generator.shouldRunBuild()) {
+			IPath buildDir = new Path(info.getConfigurationName());
+			invokeMake(false, buildDir, info, monitor);
+		}
 		
 		monitor.worked(1);		
 	}
Index: src/org/eclipse/cdt/internal/core/MakefileGenerator.java
===================================================================
RCS file: /home/tools/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/MakefileGenerator.java,v
retrieving revision 1.4
diff -u -r1.4 MakefileGenerator.java
--- src/org/eclipse/cdt/internal/core/MakefileGenerator.java	18 Aug 2003 17:34:23 -0000	1.4
+++ src/org/eclipse/cdt/internal/core/MakefileGenerator.java	10 Sep 2003 20:13:43 -0000
@@ -29,6 +29,8 @@
 import org.eclipse.core.resources.IFolder;
 import org.eclipse.core.resources.IProject;
 import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IResourceDelta;
+import org.eclipse.core.resources.IResourceDeltaVisitor;
 import org.eclipse.core.resources.IResourceProxy;
 import org.eclipse.core.resources.IResourceProxyVisitor;
 import org.eclipse.core.resources.IResourceStatus;
@@ -69,11 +71,13 @@
 
 	// Local variables needed by generator
 	protected IManagedBuildInfo info;
-	protected List moduleList;
+	protected List modifiedList;
 	protected IProgressMonitor monitor;
+	protected List subdirList;
 	protected IProject project;
 	protected List ruleList;
 	protected IPath topBuildDir;
+	protected boolean shouldRunBuild;
 	
 	/**
 	 * This class is used to recursively walk the project and determine which
@@ -107,7 +111,9 @@
 				IResource resource = proxy.requestResource();
 				String ext = resource.getFileExtension();
 				if (info.buildsFileType(ext)) {
-					generator.appendModule(resource);
+					if (!generator.isGeneratedResource(resource)) {
+						generator.appendBuildSubdirectory(resource);
+					}
 				}
 				return false;
 			}
@@ -118,6 +124,77 @@
 
 	}
 
+	public class ResourceDeltaVisitor implements IResourceDeltaVisitor {
+		private MakefileGenerator generator;
+		private IManagedBuildInfo info;
+
+		/**
+		 * 
+		 */
+		public ResourceDeltaVisitor(MakefileGenerator generator, IManagedBuildInfo info) {
+			this.generator = generator;
+			this.info = info;
+		}
+
+		/* (non-Javadoc)
+		 * @see org.eclipse.core.resources.IResourceDeltaVisitor#visit(org.eclipse.core.resources.IResourceDelta)
+		 */
+		public boolean visit(IResourceDelta delta) throws CoreException {
+			// Should the visitor keep iterating in current directory 
+			boolean keepLooking = false;
+			IResource resource = delta.getResource();
+			
+			// What kind of resource change has occurred
+			if (resource.getType() == IResource.FILE) {
+				String ext = resource.getFileExtension();
+				switch (delta.getKind()) {
+					case IResourceDelta.ADDED:
+					case IResourceDelta.REMOVED:
+						// Add the container of the resource and any resources that depend on it
+						if (info.buildsFileType(ext)) {
+							if (!generator.isGeneratedResource(resource)) {
+								// Here's the container
+								generator.appendModifiedSubdirectory(resource);
+								// and all the dependents
+								DependencyManager depMgr = CCorePlugin.getDefault().getCoreModel().getDependencyManager();
+								List deps = depMgr.getProjectDependsForFile(resource.getLocation().toOSString());
+								if (deps != null) {
+									ListIterator iter = deps.listIterator();
+									while (iter.hasNext()) {
+										generator.appendModifiedSubdirectory(resource);
+									}
+								}
+								// A build should run						
+								generator.shouldRunBuild(true);
+							}
+						}
+						break;
+					case IResourceDelta.CHANGED:
+						if (info.buildsFileType(ext)) {
+							switch (delta.getFlags()) {
+								case IResourceDelta.CONTENT:
+									// If the contents changed then just do a build
+									generator.shouldRunBuild(true);
+									keepLooking = true;
+								default:
+									keepLooking = true;
+							}							
+						}
+						break;
+					default:
+						keepLooking = true;
+						break;
+				}
+			} else {
+				// If the resource is part of the generated directory structure don't recurse
+				if (!generator.isGeneratedResource(resource)) {
+					keepLooking = true;
+				}
+			}
+			return keepLooking;
+		}
+	}	
+
 	public MakefileGenerator(IProject project, IManagedBuildInfo info, IProgressMonitor monitor) {
 		super();
 		// Save the project so we can get path and member information
@@ -126,9 +203,12 @@
 		this.monitor = monitor;
 		// Get the build info for the project
 		this.info = info;
+		// By default a build never runs
+		shouldRunBuild = false;
 	}
 
-	/**
+	/* (non-javadoc)
+	 * 
 	 * @param module
 	 * @return
 	 */
@@ -184,7 +264,7 @@
 		return buffer;
 	}
 
-	/**
+	/* (non-javadoc)
 	 * @param buffer
 	 * @param info
 	 */
@@ -202,13 +282,13 @@
 		buffer.append("C_SRCS := " + NEWLINE);
 		buffer.append("CC_SRCS := " + NEWLINE + NEWLINE);
 		
-		// Add the libraries this project dependes on
+		// Add the libraries this project depends on
 		buffer.append("LIBS := ");
 		buffer.append(NEWLINE + NEWLINE);
 		return buffer;
 	}
 
-	/**
+	/* (non-javadoc)
 	 * @return
 	 */
 	protected StringBuffer addModules() {
@@ -216,16 +296,21 @@
 		// Add the comment
 		buffer.append(CCorePlugin.getResourceString(MOD_LIST) + NEWLINE);
 		buffer.append("MODULES := " + LINEBREAK + NEWLINE);
-		buffer.append("." + LINEBREAK + NEWLINE);
 		
 		// Get all the module names
-		ListIterator iter = getModuleList().listIterator();
+		ListIterator iter = getSubdirList().listIterator();
 		while (iter.hasNext()) {
 			IContainer container = (IContainer) iter.next();
-			IPath path = container.getProjectRelativePath();
-			buffer.append(path.toString() +  WHITESPACE + LINEBREAK + NEWLINE);
+			// Check the special case where the module is the project root
+			if (container.getFullPath() == project.getFullPath()) {
+				buffer.append("." +  WHITESPACE + LINEBREAK + NEWLINE);
+			} else {
+				IPath path = container.getProjectRelativePath();
+				buffer.append(path.toString() +  WHITESPACE + LINEBREAK + NEWLINE);
+			}
 		}
 
+		// Now add the makefile instruction to include all the subdirectory makefile fragments
 		buffer.append(NEWLINE);
 		buffer.append(CCorePlugin.getResourceString(MOD_INCL) + NEWLINE);
 		buffer.append("include ${patsubst %, %/module.mk, $(MODULES)}" + NEWLINE);
@@ -235,7 +320,7 @@
 	}
 
 
-	/**
+	/* (non-javadoc)
 	 * Answers a <code>StringBuffer</code> containing all of the sources contributed by
 	 * a container to the build.
 	 * @param module
@@ -282,7 +367,7 @@
 		return buffer;
 	}
 
-	/**
+	/* (non-javadoc)
 	 * Answers a <code>StrinBuffer</code> containing all of the required targets to
 	 * properly build the project.
 	 */
@@ -398,26 +483,36 @@
 	}
 	
 	/**
+	 * Adds the container of the argument to the list of folders in the project that
+	 * contribute source files to the build. The resource visitor has already established 
+	 * that the build model knows how to build the files. It has also checked that
+	 * the resouce is not generated as part of the build.
+	 *  
 	 * @param resource
 	 */
-	public void appendModule(IResource resource) {
-		// The build model knows how to build this file
+	public void appendBuildSubdirectory(IResource resource) {
 		IContainer container = resource.getParent();
-
-		// But is this a generated directory ...
-		IPath root = new Path(info.getConfigurationName());
-		IPath path = container.getProjectRelativePath();
-		if (root.isPrefixOf(path)) {
-			return;
+		if (!getSubdirList().contains(container)) {
+			getSubdirList().add(container);		
 		}
-
-		if (!getModuleList().contains(container)) {
-			getModuleList().add(container);		
+	}
+	
+	/**
+	 * Adds the container of the argument to a list of subdirectories that are part 
+	 * of an incremental rebuild of the project. The makefile fragments for these 
+	 * directories will be regenerated as a result of the build.
+	 * 
+	 * @param resource
+	 */
+	public void appendModifiedSubdirectory(IResource resource) {
+		IContainer container = resource.getParent();
+		if (!getModifiedList().contains(container)) {
+			getModifiedList().add(container);		
 		}
 	}
 
 	/**
-	 * Check whether the build has been canceled. Cancellation requests 
+	 * Check whether the build has been cancelled. Cancellation requests 
 	 * propagated to the caller by throwing <code>OperationCanceledException</code>.
 	 * 
 	 * @see org.eclipse.core.runtime.OperationCanceledException#OperationCanceledException()
@@ -428,17 +523,93 @@
 		}
 	}
 
+
 	/**
-	 * @return
+	 * Clients call this method when an incremental rebuild is required. The argument
+	 * contains a set of resource deltas that will be used to determine which 
+	 * subdirectories need a new makefile and dependency list (if any). 
+	 * 
+	 * @param delta
+	 * @throws CoreException
 	 */
-	private List getModuleList() {
-		if (moduleList == null) {
-			moduleList = new ArrayList();
+	public void generateMakefiles(IResourceDelta delta) throws CoreException {
+		/*
+		 * Let's do a sanity check right now. This is an incremental build, so if the top-level directory is not there, then
+		 * a rebuild is needed anyway.
+		 */
+		IFolder folder = project.getFolder(info.getConfigurationName());
+		if (!folder.exists()) {
+			regenerateMakefiles();
+			shouldRunBuild(true);
+			return;
+		}
+
+		// Visit the resources in the delta and compile a list of subdirectories to regenerate
+		ResourceDeltaVisitor visitor = new ResourceDeltaVisitor(this, info);
+		delta.accept(visitor);
+		// There may be nothing to regenerate and no content changes that require a rebuild 
+		if (getModifiedList().isEmpty() && !shouldRunBuild()) {
+			// There is nothing to build
+			IStatus status = new Status(IStatus.INFO, CCorePlugin.PLUGIN_ID, GeneratedMakefileBuilder.EMPTY_PROJECT_BUILD_ERROR, "", null);
+			throw new CoreException(status);
+		}
+
+		// See if the user has cancelled the build
+		checkCancel();
+	
+		// The top-level makefile needs this information
+		ResourceProxyVisitor resourceVisitor = new ResourceProxyVisitor(this, info);
+		project.accept(resourceVisitor, IResource.NONE);
+		if (getSubdirList().isEmpty()) {
+			// There is nothing to build (but we should never throw this exception)
+			IStatus status = new Status(IStatus.INFO, CCorePlugin.PLUGIN_ID, GeneratedMakefileBuilder.EMPTY_PROJECT_BUILD_ERROR, "", null);
+			throw new CoreException(status);
+		}
+		checkCancel();
+
+		// Regenerate any fragments that are missing for the exisiting directories NOT modified
+		Iterator iter = getSubdirList().listIterator();
+		while (iter.hasNext()) {
+			IContainer subdirectory = (IContainer)iter.next();
+			if (!getModifiedList().contains(subdirectory)) {
+				// Make sure a fragment makefile and dependency file exist
+				IFile makeFragment = project.getFile(subdirectory.getFullPath().addTrailingSeparator().append(MODFILE_NAME));
+				IFile depFragment = project.getFile(subdirectory.getFullPath().addTrailingSeparator().append(DEPFILE_NAME));
+				if (!makeFragment.exists() || !depFragment.exists()) {
+					// If one or both are missing, then add it to the list to be generated
+					getModifiedList().add(subdirectory);
+				}
+			}
+		}
+
+		// Re-create the top-level makefile
+		topBuildDir = createDirectory(info.getConfigurationName());
+		IPath makefilePath = topBuildDir.addTrailingSeparator().append(MAKEFILE_NAME);
+		IFile makefileHandle = createFile(makefilePath);
+		populateTopMakefile(makefileHandle);
+		checkCancel();
+		
+		// Regenerate any fragments for modified directories
+		iter = getModifiedList().listIterator();
+		while (iter.hasNext()) {
+			populateFragmentMakefile((IContainer) iter.next());
+			checkCancel();
 		}
-		return moduleList;
 	}
 	
-	/**
+	/* (non-javadoc)
+	 * @return
+	 */
+	private List getModifiedList() {
+		if (modifiedList == null) {
+			modifiedList = new ArrayList();
+		}
+		return modifiedList;
+	}
+
+	/* (non-javadoc)
+	 * Answers the list of known build rules. This keeps me from generating duplicate
+	 * rules for known file extensions.
 	 * 
 	 */
 	private List getRuleList() {
@@ -448,7 +619,18 @@
 		return ruleList;
 	}
 
-	/**
+	/* (non-javadoc)
+	 * Answers the list of subdirectories contributing source code to the build
+	 * @return
+	 */
+	private List getSubdirList() {
+		if (subdirList == null) {
+			subdirList = new ArrayList();
+		}
+		return subdirList;
+	}
+
+	/* (non-javadoc)
 	 * @param string
 	 * @return
 	 */
@@ -481,7 +663,7 @@
 		return folder.getFullPath();
 	}
 
-	/**
+	/* (non-javadoc)
 	 * @param makefilePath
 	 * @param monitor
 	 * @return
@@ -505,7 +687,7 @@
 			else
 				throw e;
 		}
-		// TODO handle long running file operation
+
 		return newFile;
 	}
 
@@ -520,13 +702,32 @@
 	}
 
 	/**
+	 * Answers <code>true</code> if the argument is found in a generated container 
+	 * @param resource
+	 * @return
+	 */
+	public boolean isGeneratedResource(IResource resource) {
+		// Is this a generated directory ...
+		IPath path = resource.getProjectRelativePath();
+		String[] configNames = info.getConfigurationNames();
+		for (int i = 0; i < configNames.length; i++) {
+			String name = configNames[i];
+			IPath root = new Path(name);
+			// It is if it is a root of the resource pathname
+			if (root.isPrefixOf(path)) return true;
+		}
+		
+		return false;
+	}
+
+	/* (non-javadoc)
 	 * Create the entire contents of the makefile.
 	 * 
 	 * @param fileHandle The file to place the contents in.
 	 * @param info
 	 * @param monitor
 	 */
-	protected void populateMakefile(IFile fileHandle) {
+	protected void populateTopMakefile(IFile fileHandle) {
 		StringBuffer buffer = new StringBuffer();
 		
 		// Add the macro definitions
@@ -541,16 +742,16 @@
 		// Save the file
 		try {
 			Util.save(buffer, fileHandle);
-		} catch (CoreException e1) {
+		} catch (CoreException e) {
 			// TODO Auto-generated catch block
-			e1.printStackTrace();
+			e.printStackTrace();
 		}
 	}
 
-	/**
+	/* (non-javadoc)
 	 * @param module
 	 */
-	protected void populateModMakefile(IContainer module) throws CoreException {
+	protected void populateFragmentMakefile(IContainer module) throws CoreException {
 		// Calcualte the new directory relative to the build output
 		IPath moduleRelativePath = module.getProjectRelativePath();
 		IPath buildRoot = getTopBuildDir().removeFirstSegments(1);
@@ -578,11 +779,14 @@
 	}
 
 
+	/**
+	 * @throws CoreException
+	 */
 	public void regenerateMakefiles() throws CoreException {
 		// Visit the resources in the project
 		ResourceProxyVisitor visitor = new ResourceProxyVisitor(this, info);
 		project.accept(visitor, IResource.NONE);
-		if (getModuleList().isEmpty()) {
+		if (getSubdirList().isEmpty()) {
 			// There is nothing to build
 			IStatus status = new Status(IStatus.INFO, CCorePlugin.PLUGIN_ID, GeneratedMakefileBuilder.EMPTY_PROJECT_BUILD_ERROR, "", null);
 			throw new CoreException(status);
@@ -599,15 +803,33 @@
 		IFile makefileHandle = createFile(makefilePath);
 		
 		// Populate the makefile
-		populateMakefile(makefileHandle);
+		populateTopMakefile(makefileHandle);
 		checkCancel();
 		
 		// Now populate the module makefiles
-		ListIterator iter = getModuleList().listIterator();
+		ListIterator iter = getSubdirList().listIterator();
 		while (iter.hasNext()) {
-			populateModMakefile((IContainer)iter.next());
+			populateFragmentMakefile((IContainer)iter.next());
 			checkCancel();
 		}
+	}
+	/**
+	 * Answers whether a build is required after the makefiles have been 
+	 * generated.
+	 * 
+	 * @return
+	 */
+	public boolean shouldRunBuild() {
+		return shouldRunBuild;
+	}
+
+	/**
+	 * Sets the build flag to the value of the argument.
+	 * 
+	 * @param b
+	 */
+	public void shouldRunBuild(boolean b) {
+		shouldRunBuild = b;
 	}
 
 }

Back to the top