1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-23 22:52:11 +02:00

Fix for bug 60957 and 63937. In the first case, the builder was being too strict when deciding what to do in the face of change notifications delivered by Eclipse during a build of a chain of dependent projects. In the second case, the managed build system needed to separate out the need to save project settings from the need to rebuild a project. Now there is a new set of variables to keep track of needing a rebuild.

This commit is contained in:
Sean Evoy 2004-05-27 15:53:16 +00:00
parent 8f92139ae5
commit e21a791587
9 changed files with 720 additions and 491 deletions

View file

@ -74,6 +74,15 @@ public interface IConfiguration extends IBuildObject {
*/
public boolean isDirty();
/**
* Answers whether the receiver has been changed and requires the
* project to be rebuilt.
*
* @return <code>true</code> if the receiver contains a change
* that needs the project to be rebuilt
*/
public boolean needsRebuild();
/**
* @param isDirty
*/
@ -119,6 +128,14 @@ public interface IConfiguration extends IBuildObject {
public void setOption(IOption option, String[] value)
throws BuildException;
/**
* Sets the rebuild state in the receiver.
*
* @param rebuild <code>true</code> will force a rebuild the next time the project builds
* @see org.eclipse.cdt.managedbuilder.core.IManagedBuildInfo#setRebuildState(boolean)
*/
void setRebuildState(boolean rebuild);
/**
* Overrides the tool command for a tool defined in the receiver.
*

View file

@ -208,6 +208,23 @@ public interface IManagedBuildInfo {
*/
public String getVersion();
/**
* Answers whether the receiver has been changed and requires the
* project to be rebuilt. When a project is first created, it is
* assumed that the user will need it to be fully rebuilt. However
* only option and tool command changes will trigger the build
* information for an existing project to require a rebuild.
* <p>
* Clients can reset the state to force or clear the rebuild status
* using <code>setRebuildState()</code>
* @see ManagedBuildInfo#setRebuildState(boolean)
*
* @return <code>true</code> if the resource managed by the
* receiver needs to be rebuilt
*/
public boolean needsRebuild();
/**
* Answers true if the build model has been changed by the user.
*
@ -248,6 +265,16 @@ public interface IManagedBuildInfo {
*/
public void setDefaultTarget(ITarget target);
/**
* Sets the rebuild state in the receiver to the value of the argument.
* This is a potentially expensive option, so setting it to true should
* only be done if a project resource or setting has been modified in a
* way that would invalidate the previous build.
*
* @param <code>true</code> will force a rebuild the next time the project builds
*/
public void setRebuildState(boolean rebuild);
/**
* Set the currently selected target. This is used while the project
* property pages are displayed

View file

@ -217,6 +217,15 @@ public interface ITarget extends IBuildObject {
*/
public boolean isTestTarget();
/**
* Answers whether the receiver has been changed and requires the
* project to be rebuilt.
*
* @return <code>true</code> if the receiver contains a change
* that needs the project to be rebuilt
*/
public boolean needsRebuild();
/**
* Removes the configuration with the ID specified in the argument.
*
@ -270,10 +279,19 @@ public interface ITarget extends IBuildObject {
*/
public void setErrorParserIds(String ids);
/**
* Set the rebuild state of the receiver.
*
* @param <code>true</code> will force a rebuild the next time the project builds
* @see org.eclipse.cdt.managedbuilder.core.IManagedBuildInfo#setRebuildState(boolean)
*/
public void setRebuildState(boolean rebuild);
/**
* Sets the resource that owns the receiver.
*
* @param resource
*/
public void updateOwner(IResource resource);
}

View file

@ -37,6 +37,7 @@ import org.w3c.dom.NodeList;
public class Configuration extends BuildObject implements IConfiguration {
private boolean isDirty = false;
private IConfiguration parent;
private boolean rebuildNeeded = false;
private boolean resolved = true;
private ITarget target;
private List toolReferences;
@ -374,6 +375,12 @@ public class Configuration extends BuildObject implements IConfiguration {
return isDirty;
}
/* (non-Javadoc)
* @see org.eclipse.cdt.managedbuilder.core.IConfiguration#needsRebuild()
*/
public boolean needsRebuild() {
return rebuildNeeded;
}
/* (non-Javadoc)
* @see org.eclipse.cdt.core.build.managed.IConfiguration#getParent()
@ -549,6 +556,7 @@ public class Configuration extends BuildObject implements IConfiguration {
if (option.getBooleanValue() != value) {
createOptionReference(option).setValue(value);
isDirty = true;
rebuildNeeded = true;
}
}
@ -567,6 +575,7 @@ public class Configuration extends BuildObject implements IConfiguration {
if (oldValue != null && !oldValue.equals(value)) {
createOptionReference(option).setValue(value);
isDirty = true;
rebuildNeeded = true;
}
}
@ -599,9 +608,17 @@ public class Configuration extends BuildObject implements IConfiguration {
if(!Arrays.equals(value, oldValue)) {
createOptionReference(option).setValue(value);
isDirty = true;
rebuildNeeded = true;
}
}
/* (non-Javadoc)
* @see org.eclipse.cdt.managedbuilder.core.IConfiguration#setRebuildState(boolean)
*/
public void setRebuildState(boolean rebuild) {
rebuildNeeded = rebuild;
}
/* (non-Javadoc)
* @see org.eclipse.cdt.managedbuilder.core.IConfiguration#setToolCommand(org.eclipse.cdt.managedbuilder.core.ITool, java.lang.String)
*/
@ -617,6 +634,7 @@ public class Configuration extends BuildObject implements IConfiguration {
// Set the ref's command
if (ref != null) {
isDirty = ref.setToolCommand(command);
rebuildNeeded = isDirty;
}
}
}

View file

@ -40,7 +40,6 @@ import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.IResourceDeltaVisitor;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.IncrementalProjectBuilder;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtension;
@ -53,6 +52,12 @@ import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.SubProgressMonitor;
/**
* This is the incremental builder associated with a managed build project. It dynamically
* decides the makefile generator it wants to use for a specific target.
*
* @since 1.2
*/
public class GeneratedMakefileBuilder extends ACBuilder {
// String constants
private static final String MESSAGE = "ManagedMakeBuilder.message"; //$NON-NLS-1$
@ -64,6 +69,7 @@ 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$
private static final String CONSOLE_HEADER = MESSAGE + ".console.header"; //$NON-NLS-1$
private static final String TYPE_CLEAN = "ManagedMakeBuilder.type.clean"; //$NON-NLS-1$
private static final String TYPE_FULL = "ManagedMakeBuilder.type.full"; //$NON-NLS-1$
private static final String TYPE_INC = "ManagedMakeBuider.type.incremental"; //$NON-NLS-1$
@ -73,13 +79,66 @@ public class GeneratedMakefileBuilder extends ACBuilder {
protected IManagedBuilderMakefileGenerator generator;
public class ResourceDeltaVisitor implements IResourceDeltaVisitor {
private boolean buildNeeded = false;
private boolean buildNeeded = true;
private IManagedBuildInfo buildInfo;
private List reservedNames;
/**
*
*/
public ResourceDeltaVisitor(IManagedBuildInfo info) {
buildInfo = info;
reservedNames = Arrays.asList(new String[]{".cdtbuild", ".cdtproject", ".project"}); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
/**
* @param changedResource
* @return
*/
private boolean isGeneratedResource(IResource resource) {
// Is this a generated directory ...
IPath path = resource.getProjectRelativePath();
String[] configNames = buildInfo.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;
}
/**
* @param resource
* @return
*/
private boolean isProjectFile(IResource resource) {
return reservedNames.contains(resource.getName());
}
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()) {
buildNeeded = true;
IResourceDelta[] kids = delta.getAffectedChildren();
for (int index = kids.length - 1; index >= 0; --index) {
IResource changedResource = kids[index].getResource();
String ext = changedResource.getFileExtension();
// There are some things we don't care about
if (resource.isDerived()) {
buildNeeded = false;
} else if (isGeneratedResource(changedResource)) {
buildNeeded = false;
} else if (buildInfo.buildsFileType(ext) || buildInfo.isHeaderFile(ext)) {
// We do care and there is no point checking anythings else
buildNeeded = true;
break;
} else if (isProjectFile(changedResource)) {
buildNeeded = false;
} else {
buildNeeded = true;
}
}
return false;
}
@ -92,7 +151,8 @@ public class GeneratedMakefileBuilder extends ACBuilder {
}
/**
*
* Zero-argument constructor needed to fulfill the contract of an
* incremental builder.
*/
public GeneratedMakefileBuilder() {
}
@ -101,23 +161,28 @@ public class GeneratedMakefileBuilder extends ACBuilder {
* @see org.eclipse.core.internal.events.InternalBuilder#build(int, java.util.Map, org.eclipse.core.runtime.IProgressMonitor)
*/
protected IProject[] build(int kind, Map args, IProgressMonitor monitor) throws CoreException {
IProject[] deps = getProject().getReferencedProjects();
// We should always tell the build system what projects we reference
IProject[] refdProjects = getProject().getReferencedProjects();
// Get the build information
IManagedBuildInfo info = ManagedBuildManager.getBuildInfo(getProject());
if (info == null) {
return deps;
return refdProjects;
}
if (kind == IncrementalProjectBuilder.FULL_BUILD || info.isDirty()) {
// So let's figure out why we got called
if (kind == CLEAN_BUILD) {
cleanBuild(monitor, info);
}
else if (kind == FULL_BUILD || info.needsRebuild()) {
fullBuild(monitor, info);
}
else if (kind == IncrementalProjectBuilder.AUTO_BUILD && info.isDirty()) {
else if (kind == AUTO_BUILD && info.needsRebuild()) {
fullBuild(monitor, info);
}
else {
// Create a delta visitor to make sure we should be rebuilding
ResourceDeltaVisitor visitor = new ResourceDeltaVisitor();
ResourceDeltaVisitor visitor = new ResourceDeltaVisitor(info);
IResourceDelta delta = getDelta(getProject());
if (delta == null) {
fullBuild(monitor, info);
@ -131,20 +196,33 @@ public class GeneratedMakefileBuilder extends ACBuilder {
}
// Scrub the build info of all the projects participating in the build
info.setDirty(false);
for (int i = 0; i < deps.length; i++) {
IProject project = deps[i];
info.setRebuildState(false);
for (int i = 0; i < refdProjects.length; i++) {
IProject project = refdProjects[i];
IManagedBuildInfo depInfo = ManagedBuildManager.getBuildInfo(project);
// May not be a managed project
if (depInfo != null) {
depInfo.setDirty(false);
depInfo.setRebuildState(false);
}
}
// Ask build mechanism to compute deltas for project dependencies next time
return deps;
return refdProjects;
}
/**
* @param monitor
* @param info
*/
protected void cleanBuild(IProgressMonitor monitor, IManagedBuildInfo info) {
// Make sure that there is a top level directory and a set of makefiles
// invoke make with the clean argument
}
/**
* Check whether the build has been canceled. Cancellation requests
* propagated to the caller by throwing <code>OperationCanceledException</code>.
@ -203,7 +281,7 @@ public class GeneratedMakefileBuilder extends ACBuilder {
monitor.subTask(statusMsg);
IPath topBuildDir = generator.getBuildWorkingDir();
if (topBuildDir != null) {
invokeMake(true, topBuildDir, info, monitor);
invokeMake(FULL_BUILD, topBuildDir, info, monitor);
} else {
statusMsg = ManagedMakeMessages.getFormattedString(NOTHING_BUILT, getProject().getName()); //$NON-NLS-1$
monitor.subTask(statusMsg);
@ -263,12 +341,18 @@ public class GeneratedMakefileBuilder extends ACBuilder {
* @param fullBuild
* @return
*/
protected String[] getMakeTargets(boolean fullBuild) {
protected String[] getMakeTargets(int buildType) {
List args = new ArrayList();
if (fullBuild) {
args.add("clean"); //$NON-NLS-1$
switch (buildType) {
case CLEAN_BUILD:
args.add("clean"); //$NON-NLS-1$
break;
case FULL_BUILD:
args.add("clean"); //$NON-NLS-1$
case INCREMENTAL_BUILD:
args.add("all"); //$NON-NLS-1$
break;
}
args.add("all"); //$NON-NLS-1$
return (String[])args.toArray(new String[args.size()]);
}
@ -349,11 +433,11 @@ public class GeneratedMakefileBuilder extends ACBuilder {
monitor.worked(1);
// Run the build
statusMsg = ManagedMakeMessages.getFormattedString("ManagedMakeBuilder.message.starting", getProject().getName());
statusMsg = ManagedMakeMessages.getFormattedString("ManagedMakeBuilder.message.starting", getProject().getName()); //$NON-NLS-1$
monitor.subTask(statusMsg);
IPath buildDir = new Path(info.getConfigurationName());
if (buildDir != null) {
invokeMake(false, buildDir, info, monitor);
invokeMake(INCREMENTAL_BUILD, buildDir, info, monitor);
} else {
statusMsg = ManagedMakeMessages.getFormattedString(NOTHING_BUILT, getProject().getName()); //$NON-NLS-1$
monitor.subTask(statusMsg);
@ -383,7 +467,7 @@ public class GeneratedMakefileBuilder extends ACBuilder {
* @param info
* @param monitor
*/
protected void invokeMake(boolean fullBuild, IPath buildDir, IManagedBuildInfo info, IProgressMonitor monitor) {
protected void invokeMake(int buildType, IPath buildDir, IManagedBuildInfo info, IProgressMonitor monitor) {
// Get the project and make sure there's a monitor to cancel the build
IProject currentProject = getProject();
if (monitor == null) {
@ -420,9 +504,18 @@ public class GeneratedMakefileBuilder extends ACBuilder {
console.start(currentProject);
ConsoleOutputStream consoleOutStream = console.getOutputStream();
String[] consoleHeader = new String[3];
consoleHeader[0] = fullBuild ?
ManagedMakeMessages.getResourceString(TYPE_FULL) :
ManagedMakeMessages.getResourceString(TYPE_INC);
switch (buildType) {
case FULL_BUILD:
consoleHeader[0] = ManagedMakeMessages.getResourceString(TYPE_FULL);
break;
case INCREMENTAL_BUILD:
consoleHeader[0] = ManagedMakeMessages.getResourceString(TYPE_INC);
break;
case CLEAN_BUILD:
consoleHeader[0] = ManagedMakeMessages.getResourceString(TYPE_CLEAN);
break;
}
consoleHeader[1] = info.getConfigurationName();
consoleHeader[2] = currentProject.getName();
buf.append(System.getProperty("line.separator", "\n")); //$NON-NLS-1$ //$NON-NLS-2$
@ -449,7 +542,7 @@ public class GeneratedMakefileBuilder extends ACBuilder {
makeArgs.add(args[i]);
}
}
makeArgs.addAll(Arrays.asList(getMakeTargets(fullBuild)));
makeArgs.addAll(Arrays.asList(getMakeTargets(buildType)));
String[] makeTargets = (String[]) makeArgs.toArray(new String[makeArgs.size()]);
// Get a launcher for the make command

View file

@ -47,6 +47,7 @@ import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.QualifiedName;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
@ -69,6 +70,7 @@ public class ManagedBuildInfo implements IManagedBuildInfo, IScannerInfo {
private String defaultTargetId;
private ITarget selectedTarget;
private boolean isDirty;
private boolean rebuildNeeded;
private IResource owner;
private Map targetMap;
private List targetList;
@ -100,15 +102,16 @@ public class ManagedBuildInfo implements IManagedBuildInfo, IScannerInfo {
if (entries.length > 0 && entries[0].equals(containerEntry)) {
} else {
Job initJob = new Job("Initializing path container") {
Job initJob = new Job("Initializing path container") { //$NON-NLS-1$
protected IStatus run(IProgressMonitor monitor) {
try {
// Set the raw path entries
cModelElement.setRawPathEntries(new IPathEntry[]{containerEntry}, new NullProgressMonitor());
} catch (CModelException e) {
ManagedBuilderCorePlugin.log(e);
return new Status(IStatus.ERROR, ManagedBuilderCorePlugin.getUniqueIdentifier(), -1, e.getLocalizedMessage(), e);
}
return null;
return new Status(IStatus.OK, ManagedBuilderCorePlugin.getUniqueIdentifier(), IStatus.OK, null, null);
}
};
@ -118,7 +121,9 @@ public class ManagedBuildInfo implements IManagedBuildInfo, IScannerInfo {
ManagedBuilderCorePlugin.log(e);
}
// Does not need a save but should be rebuilt
isDirty = false;
rebuildNeeded = true;
// The id of the default target from the project persistent settings store
IProject project = (IProject)owner;
@ -161,6 +166,9 @@ public class ManagedBuildInfo implements IManagedBuildInfo, IScannerInfo {
}
initializePathEntries();
// Switch the rebuild off since this is an existing project
rebuildNeeded = false;
}
/* (non-Javadoc)
@ -191,6 +199,17 @@ public class ManagedBuildInfo implements IManagedBuildInfo, IScannerInfo {
return false;
}
/* (non-Javadoc)
* @see org.eclipse.cdt.managedbuilder.core.IManagedBuildInfo#setRebuildState(boolean)
*/
public void setRebuildState(boolean rebuild) {
Iterator iter = getTargets().listIterator();
while (iter.hasNext()) {
((ITarget)iter.next()).setRebuildState(rebuild);
}
rebuildNeeded = rebuild;
}
/* (non-Javadoc)
* @see org.eclipse.cdt.managedbuilder.core.IManagedBuildInfo#getBuildArtifactExtension()
*/
@ -775,6 +794,21 @@ public class ManagedBuildInfo implements IManagedBuildInfo, IScannerInfo {
return false;
}
/* (non-Javadoc)
* @see org.eclipse.cdt.managedbuilder.core.IManagedBuildInfo#needsRebuild()
*/
public boolean needsRebuild() {
if (rebuildNeeded) return true;
Iterator iter = getTargets().listIterator();
while (iter.hasNext()) {
if (((ITarget)iter.next()).needsRebuild()) {
return true;
}
}
return false;
}
/* (non-Javadoc)
*
@ -943,6 +977,14 @@ public class ManagedBuildInfo implements IManagedBuildInfo, IScannerInfo {
}
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
public String toString() {
// Just print out the name of the project
return "Managed build information for " + owner.getName(); //$NON-NLS-1$
}
/**
* Sets the owner of the receiver to be the <code>IResource</code> specified
* in the argument.

View file

@ -24,6 +24,7 @@ ManagedMakeBuilder.message.no.build = Nothing to build for {0}
ManagedMakeBuilder.message.error = Build error
ManagedMakeBuilder.message.error.refresh = Error refreshing project
ManagedMakeBuilder.message.finished = Build complete for project {0}
ManagedMakeBuilder.type.clean = Clean-only build
ManagedMakeBuilder.type.full = Full rebuild
ManagedMakeBuider.type.incremental = Incremental build

View file

@ -853,6 +853,17 @@ public class Target extends BuildObject implements ITarget {
getLocalToolReferences().add(toolRef);
}
public boolean needsRebuild(){
// Iterate over the configurations and ask them if they need saving
Iterator iter = getConfigurationList().listIterator();
while (iter.hasNext()) {
if (((IConfiguration)iter.next()).needsRebuild()) {
return true;
}
}
return false;
}
/* (non-Javadoc)
* @see org.eclipse.cdt.managedbuilder.core.ITarget#setArtifactExtension(java.lang.String)
*/
@ -918,6 +929,17 @@ public class Target extends BuildObject implements ITarget {
isDirty = true;
}
}
/* (non-Javadoc)
* @see org.eclipse.cdt.managedbuilder.core.ITarget#setRebuildState(boolean)
*/
public void setRebuildState(boolean rebuild) {
Iterator iter = getConfigurationList().listIterator();
while (iter.hasNext()) {
((IConfiguration)iter.next()).setRebuildState(rebuild);
}
}
/* (non-Javadoc)
* @see org.eclipse.cdt.managedbuilder.core.ITarget#updateOwner(org.eclipse.core.resources.IResource)
@ -929,5 +951,4 @@ public class Target extends BuildObject implements ITarget {
}
}
}