diff --git a/build/org.eclipse.cdt.managedbuilder.core/ChangeLog b/build/org.eclipse.cdt.managedbuilder.core/ChangeLog
index 8b80491cb2b..7085a3aadc4 100644
--- a/build/org.eclipse.cdt.managedbuilder.core/ChangeLog
+++ b/build/org.eclipse.cdt.managedbuilder.core/ChangeLog
@@ -1,3 +1,39 @@
+2003-09-26 Sean Evoy
+ A partial implementation for bug 41826. This patch contains the logic to properly
+ respond in the face of the following project changes:
+
+ 1. A generated project element, such as the build target or an intermediate file,
+ is deleted in the build project, or any projects it references.
+ 2. The build settings change in the build project or any projects it
+ references.
+
+ In order to actually do this correctly, I had to stop being so precious during the
+ build. The makefile generator was was calculating the "build needed" state as it
+ walked the change delta. However, the Eclipse core has already determined that I
+ need to do a build. Further, as I discovered earlier, it doesn't always pass what
+ has changed in referenced projects as part of the delta. Essentially, that means I
+ will never be able to fully calculate the change set in the makefile generator's
+ delta visitor, and to even approximate a decent set of cases, the logic would quickly
+ bog down in complexity.
+
+ The solution is to trust Eclipse and alway invoke make when my incremental builder
+ is called. At worst, if there is no significant change, make will execute and
+ report nothing to be done.
+
+ The modified makefile builder no longer asks the makefile generator if it should
+ build. It also no longer cares if the change set is empty (make will report that).
+ Since it responds to changes in referenced project's build information, it also
+ scrubs all relevant projects after building. Since a build might involve building
+ referenced project elements, those projects get their project views refreshed after
+ build. The build markers for referenced projects are removed prior to build.
+ * src/org/eclipse/cdt/managedbuilder/internal/core/GeneratedMakefileBuilder.java
+
+ The makefile generator has been simplified. The resource delta visitor logic no
+ longer trie to decide if a build should occur. The method to ask has been removed.
+ The class no longer throws an exception if the change set is empty. I am also a bit
+ more careful to call make with the right targets if a referenced project is built.
+ * src/org/eclipse/cdt/managedbuilder/internal/core/MakefileGenerator.java
+
2003-09-26 Sean Evoy
I added a fix to the builder and makefile generator to properly handle the following case.
Project A depends on Project B. Something changes in project B and the user requests
diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/GeneratedMakefileBuilder.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/GeneratedMakefileBuilder.java
index 3b45d2b72f2..5b8ed071467 100644
--- a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/GeneratedMakefileBuilder.java
+++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/GeneratedMakefileBuilder.java
@@ -58,9 +58,6 @@ public class GeneratedMakefileBuilder extends ACBuilder {
private static final String REFRESH = MESSAGE + ".updating"; //$NON-NLS-1$
private static final String MARKERS = MESSAGE + ".creating.markers"; //$NON-NLS-1$
- // Status codes
- public static final int EMPTY_PROJECT_BUILD_ERROR = 1;
-
// Local variables
protected List resourcesToBuild;
protected List ruleList;
@@ -89,7 +86,6 @@ public class GeneratedMakefileBuilder extends ACBuilder {
*
*/
public GeneratedMakefileBuilder() {
-
}
/* (non-Javadoc)
@@ -100,7 +96,8 @@ public class GeneratedMakefileBuilder extends ACBuilder {
if (statusMsg != null) {
monitor.subTask(statusMsg);
}
-
+
+ // Get the build information
IManagedBuildInfo info = ManagedBuildManager.getBuildInfo(getProject());
if (kind == IncrementalProjectBuilder.FULL_BUILD || info.isDirty()) {
@@ -123,10 +120,18 @@ public class GeneratedMakefileBuilder extends ACBuilder {
}
}
}
+
+ // Scrub the build info of all the projects participating in the build
info.setDirty(false);
+ IProject[] deps = getProject().getReferencedProjects();
+ for (int i = 0; i < deps.length; i++) {
+ IProject project = deps[i];
+ IManagedBuildInfo depInfo = ManagedBuildManager.getBuildInfo(project);
+ depInfo.setDirty(false);
+ }
// Ask build mechanism to compute deltas for project dependencies next time
- return getProject().getReferencedProjects();
+ return deps;
}
/**
@@ -150,15 +155,8 @@ public class GeneratedMakefileBuilder extends ACBuilder {
monitor = new NullProgressMonitor();
}
- // We also need one of these ...
- IProject currentProject = getProject();
- if (currentProject == null) {
- // Flag some sort of error and bail
- return;
- }
-
// Regenerate the makefiles for any managed projects this project depends on
- IProject[] deps = currentProject.getReferencedProjects();
+ IProject[] deps = getProject().getReferencedProjects();
for (int i = 0; i < deps.length; i++) {
IProject depProject = deps[i];
if (ManagedBuildManager.manages(depProject)) {
@@ -167,32 +165,23 @@ public class GeneratedMakefileBuilder extends ACBuilder {
try {
generator.regenerateMakefiles();
} catch (CoreException e) {
- // This may be an empty project exception
- if (e.getStatus().getCode() == GeneratedMakefileBuilder.EMPTY_PROJECT_BUILD_ERROR) {
- // Just keep looking for other projects
- continue;
- } else {
- // Throw the exception back to the builder
- throw e;
- }
+ // Throw the exception back to the builder
+ throw e;
}
}
}
// Need to report status to the user
- String statusMsg = ManagedBuilderCorePlugin.getFormattedString(REBUILD, currentProject.getName());
+ String statusMsg = ManagedBuilderCorePlugin.getFormattedString(REBUILD, getProject().getName());
monitor.subTask(statusMsg);
// Regenerate the makefiles for this project
- MakefileGenerator generator = new MakefileGenerator(currentProject, info, monitor);
+ MakefileGenerator generator = new MakefileGenerator(getProject(), info, monitor);
try {
generator.regenerateMakefiles();
} catch (CoreException e) {
- // See if this is an empty project
- if (e.getStatus().getCode() == GeneratedMakefileBuilder.EMPTY_PROJECT_BUILD_ERROR) {
- monitor.worked(1);
- return;
- }
+ // Throw the exception back to the builder
+ throw e;
}
IPath topBuildDir = generator.getTopBuildDir();
@@ -254,35 +243,43 @@ public class GeneratedMakefileBuilder extends ACBuilder {
*/
protected void incrementalBuild(IResourceDelta delta, IManagedBuildInfo info, IProgressMonitor monitor) throws CoreException {
// Rebuild the resource tree in the delta
- IProject currentProject = getProject();
String statusMsg = null;
// Need to report status to the user
if (monitor == null) {
monitor = new NullProgressMonitor();
}
- statusMsg = ManagedBuilderCorePlugin.getFormattedString(INCREMENTAL, currentProject.getName());
+ statusMsg = ManagedBuilderCorePlugin.getFormattedString(INCREMENTAL, getProject().getName());
monitor.subTask(statusMsg);
+ // Regenerate the makefiles for any managed projects this project depends on
+ IProject[] deps = getProject().getReferencedProjects();
+ for (int i = 0; i < deps.length; i++) {
+ IProject depProject = deps[i];
+ if (ManagedBuildManager.manages(depProject)) {
+ IManagedBuildInfo depInfo = ManagedBuildManager.getBuildInfo(depProject);
+ MakefileGenerator generator = new MakefileGenerator(depProject, depInfo, monitor);
+ try {
+ generator.regenerateMakefiles();
+ } catch (CoreException e) {
+ // Throw the exception back to the builder
+ throw e;
+ }
+ }
+ }
+
// Ask the makefile generator to generate any makefiles needed to build delta
- MakefileGenerator generator = new MakefileGenerator(currentProject, info, monitor);
+ MakefileGenerator generator = new MakefileGenerator(getProject(), 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;
- }
+ // Throw the exception back to the builder
+ 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);
- }
+ // Run the build
+ IPath buildDir = new Path(info.getConfigurationName());
+ invokeMake(false, buildDir, info, monitor);
monitor.worked(1);
}
@@ -310,6 +307,11 @@ public class GeneratedMakefileBuilder extends ACBuilder {
// Remove all markers for this project
removeAllMarkers(currentProject);
+ IProject[] deps = currentProject.getReferencedProjects();
+ for (int i = 0; i < deps.length; i++) {
+ IProject project = deps[i];
+ removeAllMarkers(project);
+ }
IPath workingDirectory = getWorkingDirectory().append(buildDir);
@@ -361,12 +363,16 @@ public class GeneratedMakefileBuilder extends ACBuilder {
errMsg = launcher.getErrorMessage();
}
- // Force a resync of the project without allowing the user to cancel.
+ // Force a resync of the projects without allowing the user to cancel.
// This is probably unkind, but short of this there is no way to insure
// the UI is up-to-date with the build results
monitor.subTask(ManagedBuilderCorePlugin.getResourceString(REFRESH));
try {
currentProject.refreshLocal(IResource.DEPTH_INFINITE, null);
+ for (int j = 0; j < deps.length; ++j) {
+ IProject project = deps[j];
+ project.refreshLocal(IResource.DEPTH_INFINITE, null);
+ }
} catch (CoreException e) {
monitor.subTask(ManagedBuilderCorePlugin.getResourceString(REFRESH_ERROR));
}
diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/MakefileGenerator.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/MakefileGenerator.java
index 19db6c8247b..14659171fab 100644
--- a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/MakefileGenerator.java
+++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/MakefileGenerator.java
@@ -44,10 +44,8 @@ import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.Path;
-import org.eclipse.core.runtime.Status;
public class MakefileGenerator {
// String constants for messages
@@ -83,7 +81,6 @@ public class MakefileGenerator {
protected IProject project;
protected List ruleList;
protected IPath topBuildDir;
- protected boolean shouldRunBuild;
private String target;
@@ -184,21 +181,12 @@ public class MakefileGenerator {
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;
- }
+ keepLooking = true;
}
break;
default:
@@ -208,9 +196,7 @@ public class MakefileGenerator {
} if (resource.getType() == IResource.PROJECT) {
// If there is a zero-length delta, something the project depends on has changed so just call make
IResourceDelta[] children = delta.getAffectedChildren();
- if (children != null && children.length == 0) {
- generator.shouldRunBuild(true);
- } else {
+ if (children != null && children.length > 0) {
keepLooking = true;
}
} else {
@@ -237,8 +223,6 @@ public class MakefileGenerator {
this.monitor = monitor;
// Get the build info for the project
this.info = info;
- // By default a build never runs
- shouldRunBuild = false;
// Get the name of the build target
target = info.getBuildArtifactName();
// Get its extension
@@ -386,8 +370,9 @@ public class MakefileGenerator {
/* (non-javadoc)
* Answers a StringBuffer
containing all of the sources contributed by
* a container to the build.
+ *
* @param module
- * @return
+ * @return StringBuffer
*/
protected StringBuffer addSources(IContainer module) throws CoreException {
// Calculate the new directory relative to the build output
@@ -450,6 +435,8 @@ public class MakefileGenerator {
/* (non-javadoc)
* Answers a StrinBuffer
containing all of the required targets to
* properly build the project.
+ *
+ * @return StringBuffer
*/
protected StringBuffer addTargets(boolean rebuild) {
StringBuffer buffer = new StringBuffer();
@@ -492,6 +479,7 @@ public class MakefileGenerator {
for (int i = 0; i < deps.length; i++) {
IProject dep = deps[i];
String buildDir = dep.getLocation().toString();
+ String depTargets = targets;
if (ManagedBuildManager.manages(dep)) {
// Add the current configuration to the makefile path
IManagedBuildInfo depInfo = ManagedBuildManager.getBuildInfo(dep);
@@ -501,9 +489,12 @@ public class MakefileGenerator {
String depTarget = depInfo.getBuildArtifactName();
String depExt = (new Path(depTarget)).getFileExtension();
String depPrefix = depInfo.getOutputPrefix(depExt);
+ if (depInfo.isDirty()) {
+ depTargets = "clean all";
+ }
managedProjectOutputs.add(buildDir + SEPARATOR + depPrefix + depTarget);
}
- buffer.append(TAB + "cd" + WHITESPACE + buildDir + SEMI_COLON + WHITESPACE + "$(MAKE) " + targets + NEWLINE);
+ buffer.append(TAB + "cd" + WHITESPACE + buildDir + SEMI_COLON + WHITESPACE + "$(MAKE) " + depTargets + NEWLINE);
}
}
buffer.append(NEWLINE);
@@ -514,7 +505,6 @@ public class MakefileGenerator {
* targ_.: $(OBJS) [ ... ]
* $(BUILD_TOOL) $(FLAGS) $(OUTPUT_FLAG) $@ $(OBJS) $(USER_OBJS) $(LIB_DEPS)
*/
- //
buffer.append(outputPrefix + target + COLON + WHITESPACE + "$(OBJS)");
Iterator iter = managedProjectOutputs.listIterator();
while (iter.hasNext()) {
@@ -535,6 +525,12 @@ public class MakefileGenerator {
return buffer;
}
+ /* (non-javadoc)
+ *
+ * @param relativePath
+ * @param buffer
+ * @param resource
+ */
protected void addRule(String relativePath, StringBuffer buffer, IResource resource) {
String rule = null;
String cmd = null;
@@ -633,25 +629,20 @@ public class MakefileGenerator {
*/
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.
+ * Let's do a sanity check right now.
+ *
+ * 1. This is an incremental build, so if the top-level directory is not
+ * there, then a rebuild is needed.
*/
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, ManagedBuilderCorePlugin.getUniqueIdentifier(), GeneratedMakefileBuilder.EMPTY_PROJECT_BUILD_ERROR, "", null);
- throw new CoreException(status);
- }
// See if the user has cancelled the build
checkCancel();
@@ -659,11 +650,6 @@ public class MakefileGenerator {
// 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, ManagedBuilderCorePlugin.getUniqueIdentifier(), GeneratedMakefileBuilder.EMPTY_PROJECT_BUILD_ERROR, "", null);
- throw new CoreException(status);
- }
checkCancel();
// Regenerate any fragments that are missing for the exisiting directories NOT modified
@@ -697,7 +683,8 @@ public class MakefileGenerator {
}
/* (non-javadoc)
- * @return
+ *
+ * @return List
*/
private List getModifiedList() {
if (modifiedList == null) {
@@ -710,6 +697,7 @@ public class MakefileGenerator {
* Answers the list of known build rules. This keeps me from generating duplicate
* rules for known file extensions.
*
+ * @return List
*/
private List getRuleList() {
if (ruleList == null) {
@@ -720,7 +708,8 @@ public class MakefileGenerator {
/* (non-javadoc)
* Answers the list of subdirectories contributing source code to the build
- * @return
+ *
+ * @return List
*/
private List getSubdirList() {
if (subdirList == null) {
@@ -731,7 +720,7 @@ public class MakefileGenerator {
/* (non-javadoc)
* @param string
- * @return
+ * @return IPath
*/
private IPath createDirectory(String dirName) throws CoreException {
// Create or get the handle for the build directory
@@ -765,7 +754,7 @@ public class MakefileGenerator {
/* (non-javadoc)
* @param makefilePath
* @param monitor
- * @return
+ * @return IFile
*/
private IFile createFile(IPath makefilePath) throws CoreException {
// Create or get the handle for the makefile
@@ -794,7 +783,7 @@ public class MakefileGenerator {
* Answers the IPath
of the top directory generated for the build
* output, or null
if none has been generated.
*
- * @return
+ * @return IPath
*/
public IPath getTopBuildDir() {
return topBuildDir;
@@ -803,7 +792,7 @@ public class MakefileGenerator {
/**
* Answers true
if the argument is found in a generated container
* @param resource
- * @return
+ * @return boolean
*/
public boolean isGeneratedResource(IResource resource) {
// Is this a generated directory ...
@@ -824,6 +813,7 @@ public class MakefileGenerator {
*
* @param fileHandle The file to place the contents in.
* @param rebuild FLag signalling that the user is doing a full rebuild
+ * @throws CoreException
*/
protected void populateTopMakefile(IFile fileHandle, boolean rebuild) throws CoreException {
StringBuffer buffer = new StringBuffer();
@@ -843,6 +833,7 @@ public class MakefileGenerator {
/* (non-javadoc)
* @param module
+ * @throws CoreException
*/
protected void populateFragmentMakefile(IContainer module) throws CoreException {
// Calcualte the new directory relative to the build output
@@ -879,11 +870,6 @@ public class MakefileGenerator {
// Visit the resources in the project
ResourceProxyVisitor visitor = new ResourceProxyVisitor(this, info);
project.accept(visitor, IResource.NONE);
- if (getSubdirList().isEmpty()) {
- // There is nothing to build
- IStatus status = new Status(IStatus.INFO, ManagedBuilderCorePlugin.getUniqueIdentifier(), GeneratedMakefileBuilder.EMPTY_PROJECT_BUILD_ERROR, "", null);
- throw new CoreException(status);
- }
// See if the user has cancelled the build
checkCancel();
@@ -906,23 +892,4 @@ public class MakefileGenerator {
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;
- }
-
}