[
Date Prev][
Date Next][
Thread Prev][
Thread Next][
Date Index][
Thread Index]
[
List Home]
[cdt-patch] Partial fix for 41826 and a fix for 43214
|
Hi All,
I have documented the patch in the change log; the only bonus is that it
fixes 43214 for free. The managed builder should now respond correctly to
deletions of any types of file in the project (or referenced projects).
This includes makefiles, intermediate files, and the build target. It
should also properly handle changes in the project settings in any
referenced project. Referenced projects should now get their project views
refreshed as a result of any changes.
There is only one significant use case left to cover for incremental
builds, namely changes to header file. Since it involves a build model
change, I will leave that patch until tomorrow to make this patch easier
for our overloaded committers to evaluate.
Sean Evoy
Rational Software - IBM Software Group
Ottawa, Ontario, Canada
Index: ChangeLog
===================================================================
RCS file: /home/tools/org.eclipse.cdt.managedbuilder.core/ChangeLog,v
retrieving revision 1.9
diff -u -r1.9 ChangeLog
--- ChangeLog 29 Sep 2003 18:49:06 -0000 1.9
+++ ChangeLog 29 Sep 2003 21:40:28 -0000
@@ -1,4 +1,40 @@
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
that A be built. Inthis case, the incremental builder is invoked, but it is passed a
Index: src/org/eclipse/cdt/managedbuilder/internal/core/GeneratedMakefileBuilder.java
===================================================================
RCS file: /home/tools/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/GeneratedMakefileBuilder.java,v
retrieving revision 1.5
diff -u -r1.5 GeneratedMakefileBuilder.java
--- src/org/eclipse/cdt/managedbuilder/internal/core/GeneratedMakefileBuilder.java 29 Sep 2003 18:49:05 -0000 1.5
+++ src/org/eclipse/cdt/managedbuilder/internal/core/GeneratedMakefileBuilder.java 29 Sep 2003 21:40:28 -0000
@@ -58,9 +58,6 @@
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 GeneratedMakefileBuilder() {
-
}
/* (non-Javadoc)
@@ -100,7 +96,8 @@
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 @@
}
}
}
+
+ // 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 @@
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 @@
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 @@
*/
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 @@
// 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 @@
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));
}
Index: src/org/eclipse/cdt/managedbuilder/internal/core/MakefileGenerator.java
===================================================================
RCS file: /home/tools/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/MakefileGenerator.java,v
retrieving revision 1.7
diff -u -r1.7 MakefileGenerator.java
--- src/org/eclipse/cdt/managedbuilder/internal/core/MakefileGenerator.java 29 Sep 2003 18:49:06 -0000 1.7
+++ src/org/eclipse/cdt/managedbuilder/internal/core/MakefileGenerator.java 29 Sep 2003 21:40:28 -0000
@@ -44,10 +44,8 @@
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 @@
protected IProject project;
protected List ruleList;
protected IPath topBuildDir;
- protected boolean shouldRunBuild;
private String target;
@@ -184,21 +181,12 @@
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 @@
} 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 @@
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 @@
/* (non-javadoc)
* Answers a <code>StringBuffer</code> 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 @@
/* (non-javadoc)
* Answers a <code>StrinBuffer</code> 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 @@
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 @@
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 @@
* targ_<prefix><target>.<extension>: $(OBJS) [<dep_proj_1_output> ... <dep_proj_n_output>]
* $(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 @@
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 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 @@
// 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 @@
}
/* (non-javadoc)
- * @return
+ *
+ * @return List
*/
private List getModifiedList() {
if (modifiedList == null) {
@@ -710,6 +697,7 @@
* 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 @@
/* (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 @@
/* (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 @@
/* (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 @@
* Answers the <code>IPath</code> of the top directory generated for the build
* output, or <code>null</code> if none has been generated.
*
- * @return
+ * @return IPath
*/
public IPath getTopBuildDir() {
return topBuildDir;
@@ -803,7 +792,7 @@
/**
* Answers <code>true</code> 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 @@
*
* @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 @@
/* (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 @@
// 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 @@
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;
- }
-
}