From f138ad10e8026915f0970c8f73ccadc8fe033c31 Mon Sep 17 00:00:00 2001 From: Christian Walther Date: Tue, 17 Aug 2021 17:10:38 +0200 Subject: [PATCH] Bug 575490: "No rule" after removing last source file from root Include the top-level subdir.mk only when one was actually generated (i.e. when there are source files there), just like for all other subdir.mk, otherwise a stale one from earlier when there were source files that have since been removed may be picked up, causing "No rule to make target" errors. In some cases (from bug 303953), the removal would be noticed and the stale subdir.mk be overwritten by a correct empty one, avoiding the error, but not in the following cases: - When CommonBuilder.performCleanning() decides that a full rebuild is needed, regenerateMakefiles() is called instead of generateMakefiles(), which doesn't get the delta. - When the refresh in which Eclipse notices the removed source file happens as part of a build (one that probably failed because the makefiles weren't updated yet), the next build after that apparently does not get the delta containing the removal anymore. Change-Id: Id15b424f02dd5c513d2124620c0c8699d61874fd Signed-off-by: Christian Walther --- .../CDTFortranTest2/Benchmarks/makefile | 1 - .../Test 4.0 ConfigName.Dbg/makefile | 1 - .../test_40/Benchmarks/dbg 2/makefile | 1 - .../core/regressions/Bug_303953Test.java | 69 ++++++++++++++++++- .../makegen/gnu2/GnuMakefileGenerator.java | 10 +-- 5 files changed, 73 insertions(+), 9 deletions(-) diff --git a/build/org.eclipse.cdt.managedbuilder.core.tests/resources/test30Projects/CDTFortranTest2/Benchmarks/makefile b/build/org.eclipse.cdt.managedbuilder.core.tests/resources/test30Projects/CDTFortranTest2/Benchmarks/makefile index 254e4f9e3d1..92830e5c239 100644 --- a/build/org.eclipse.cdt.managedbuilder.core.tests/resources/test30Projects/CDTFortranTest2/Benchmarks/makefile +++ b/build/org.eclipse.cdt.managedbuilder.core.tests/resources/test30Projects/CDTFortranTest2/Benchmarks/makefile @@ -10,7 +10,6 @@ RM := rm -rf -include sources.mk -include module/subdir.mk -include Sources/subdir.mk --include subdir.mk -include objects.mk -include ../makefile.defs diff --git a/build/org.eclipse.cdt.managedbuilder.core.tests/resources/test40Projects/test_40/Benchmarks/Test 4.0 ConfigName.Dbg/makefile b/build/org.eclipse.cdt.managedbuilder.core.tests/resources/test40Projects/test_40/Benchmarks/Test 4.0 ConfigName.Dbg/makefile index a63e18c0cf1..40639006c5a 100644 --- a/build/org.eclipse.cdt.managedbuilder.core.tests/resources/test40Projects/test_40/Benchmarks/Test 4.0 ConfigName.Dbg/makefile +++ b/build/org.eclipse.cdt.managedbuilder.core.tests/resources/test40Projects/test_40/Benchmarks/Test 4.0 ConfigName.Dbg/makefile @@ -16,7 +16,6 @@ RM := rm -rf -include d1/d2/d3/subdir.mk -include d1/d2/subdir.mk -include d1/subdir.mk --include subdir.mk -include objects.mk ifneq ($(MAKECMDGOALS),clean) diff --git a/build/org.eclipse.cdt.managedbuilder.core.tests/resources/test40Projects/test_40/Benchmarks/dbg 2/makefile b/build/org.eclipse.cdt.managedbuilder.core.tests/resources/test40Projects/test_40/Benchmarks/dbg 2/makefile index f4acfa97436..8f2c8eb4acb 100644 --- a/build/org.eclipse.cdt.managedbuilder.core.tests/resources/test40Projects/test_40/Benchmarks/dbg 2/makefile +++ b/build/org.eclipse.cdt.managedbuilder.core.tests/resources/test40Projects/test_40/Benchmarks/dbg 2/makefile @@ -16,7 +16,6 @@ RM := rm -rf -include d1/d2/d3/subdir.mk -include d1/d2/subdir.mk -include d1/subdir.mk --include subdir.mk -include objects.mk ifneq ($(MAKECMDGOALS),clean) diff --git a/build/org.eclipse.cdt.managedbuilder.core.tests/tests/org/eclipse/cdt/managedbuilder/core/regressions/Bug_303953Test.java b/build/org.eclipse.cdt.managedbuilder.core.tests/tests/org/eclipse/cdt/managedbuilder/core/regressions/Bug_303953Test.java index 3d705a4d106..1211288aac8 100644 --- a/build/org.eclipse.cdt.managedbuilder.core.tests/tests/org/eclipse/cdt/managedbuilder/core/regressions/Bug_303953Test.java +++ b/build/org.eclipse.cdt.managedbuilder.core.tests/tests/org/eclipse/cdt/managedbuilder/core/regressions/Bug_303953Test.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2011 Broadcom Corporation and others. + * Copyright (c) 2011, 2021 Broadcom Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -13,21 +13,34 @@ *******************************************************************************/ package org.eclipse.cdt.managedbuilder.core.regressions; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertTrue; +import java.io.ByteArrayInputStream; +import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; +import org.eclipse.cdt.core.model.ICModelMarker; +import org.eclipse.cdt.core.settings.model.CSourceEntry; +import org.eclipse.cdt.core.settings.model.ICSourceEntry; +import org.eclipse.cdt.managedbuilder.core.ManagedBuildManager; import org.eclipse.cdt.managedbuilder.testplugin.AbstractBuilderTest; import org.eclipse.cdt.managedbuilder.testplugin.ResourceDeltaVerifier; +import org.eclipse.core.resources.IBuildConfiguration; import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IMarker; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IResourceDelta; import org.eclipse.core.resources.IncrementalProjectBuilder; import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.ICoreRunnable; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.Path; import org.junit.jupiter.api.Test; /** @@ -84,4 +97,58 @@ public class Bug_303953Test extends AbstractBuilderTest { verifyBuild(app, IncrementalProjectBuilder.INCREMENTAL_BUILD, verifier); } + /** + * Tests that source files in the root of the project are not treated + * specially with respect to removing the last of them (bug 575490). + */ + @Test + public void testBuildAfterRootSourcefileDelete() throws CoreException, UnsupportedEncodingException { + setWorkspace("regressions"); + final IProject app = loadProject("helloworldC"); + setActiveConfigurationByName(app, "Debug"); + + // Change the source folder from /src to / + ManagedBuildManager.getBuildInfo(app).getDefaultConfiguration() + .setSourceEntries(new ICSourceEntry[] { new CSourceEntry(Path.ROOT, null, 0) }); + + // Add a new source file in the root + app.getFile("additional.c").create(new ByteArrayInputStream("int x = 42;\n".getBytes("UTF-8")), true, null); + + // Build once: This will create a root subdir.mk referring to additional.c + ICoreRunnable build = new ICoreRunnable() { + @Override + public void run(IProgressMonitor monitor) throws CoreException { + getWorkspace().build(new IBuildConfiguration[] { app.getActiveBuildConfig() }, + IncrementalProjectBuilder.FULL_BUILD, true, monitor); + } + }; + getWorkspace().run(build, null); + IMarker[] markers = app.findMarkers(ICModelMarker.C_MODEL_PROBLEM_MARKER, true, IResource.DEPTH_INFINITE); + assertEquals(0, markers.length, "first build should succeed with no error markers"); + + // Remove additional.c behind Eclipse's back + app.getFile("additional.c").getLocation().toFile().delete(); + + // Build again: This is expected to fail because at the time the + // makefile is updated, the absence of additional.c hasn't been noticed + // yet. Only the refresh done at the end of this build will notice the + // removal. + getWorkspace().run(build, null); + markers = app.findMarkers(ICModelMarker.C_MODEL_PROBLEM_MARKER, true, IResource.DEPTH_INFINITE); + assertNotEquals(0, markers.length, "second build should produce an error marker"); + // commented out because the exact wording may depend on the version of 'make' used + // assertEquals("make: *** No rule to make target '../additional.c', needed by 'additional.o'. Stop.", + // markers[0].getAttribute(IMarker.MESSAGE)); + + // Build again: The FULL_BUILD will ignore the delta indicating the + // removal of additional.c and therefore not regenerate the root + // subdir.mk (because now there are no source files in the root), + // leaving the stale one there that still refers to additional.c. + // This should succeed - before the fix, it would fail because the + // stale subdir.mk would still be included. + getWorkspace().run(build, null); + markers = app.findMarkers(ICModelMarker.C_MODEL_PROBLEM_MARKER, true, IResource.DEPTH_INFINITE); + assertEquals(0, markers.length, "final build should succeed with no error markers"); + } + } diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/makegen/gnu2/GnuMakefileGenerator.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/makegen/gnu2/GnuMakefileGenerator.java index e1fecedcc38..78cb573d28c 100644 --- a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/makegen/gnu2/GnuMakefileGenerator.java +++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/makegen/gnu2/GnuMakefileGenerator.java @@ -1258,15 +1258,15 @@ public class GnuMakefileGenerator implements IManagedBuilderMakefileGenerator2 { List subDirList = new ArrayList<>(); for (IContainer subDir : getSubdirList()) { String projectRelativePath = subDir.getProjectRelativePath().toString(); - if (!projectRelativePath.isEmpty()) - subDirList.add(0, projectRelativePath); + subDirList.add(0, projectRelativePath); } Collections.sort(subDirList, Collections.reverseOrder()); for (String dir : subDirList) { - buffer.append("-include ").append(escapeWhitespaces(dir)).append(SEPARATOR).append("subdir.mk") //$NON-NLS-1$//$NON-NLS-2$ - .append(NEWLINE); + buffer.append("-include "); //$NON-NLS-1$ + if (!dir.isEmpty()) + buffer.append(escapeWhitespaces(dir)).append(SEPARATOR); + buffer.append(MODFILE_NAME).append(NEWLINE); } - buffer.append("-include subdir.mk").append(NEWLINE); //$NON-NLS-1$ buffer.append("-include objects.mk").append(NEWLINE).append(NEWLINE); //$NON-NLS-1$