From 8d173637f78996dba60c8fa2100688a8cad39888 Mon Sep 17 00:00:00 2001
From: Jonah Graham <jonah@kichwacoders.com>
Date: Fri, 10 Sep 2021 13:56:25 -0400
Subject: [PATCH] Bug 505882: Fork the GnuMakefileGenerator into non-API

The GnuMakefileGenerator is a huge file that needs lots of fixes.
However most of the time to implement the fixes are taken up trying
to not break API. Most extenders of CDT provide their own
implementation of GnuMakefileGenerator by copying the CDT one
and modifying it. Therefore CDT is going to take that same
approach internally and leave the existing GnuMakefileGenerator
in its unmodifiable state.

Change-Id: I12fafb5e347112648a02d4593267bd88a47b5c88
---
 .../plugin.xml                                |   54 +-
 .../core/tests/BuildFileGenerator.java        |    2 +-
 .../core/tests/ManagedBuildCoreTests.java     |    2 +-
 .../META-INF/MANIFEST.MF                      |    1 +
 .../plugin.xml                                |    2 +-
 .../core/ManagedBuildManager.java             |    2 +-
 .../makegen/gnu/GnuDependencyGroupInfo.java   |   10 +-
 .../makegen/gnu/GnuMakefileGenerator.java     |    2 +
 .../makegen/gnu/IManagedBuildGnuToolInfo.java |    2 +
 .../makegen/gnu/ManagedBuildGnuToolInfo.java  |    2 +
 .../makegen/gnu2/GnuMakefileGenerator.java    | 4790 +++++++++++++++++
 .../gnu2/IManagedBuildGnuToolInfo.java        |  128 +
 .../makegen/gnu2/ManagedBuildGnuToolInfo.java | 1004 ++++
 .../META-INF/MANIFEST.MF                      |    2 +-
 .../plugin.xml                                |    2 +-
 .../guide/deprecated_API_removals.html        |   22 +
 16 files changed, 5992 insertions(+), 35 deletions(-)
 create mode 100644 build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/makegen/gnu2/GnuMakefileGenerator.java
 create mode 100644 build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/makegen/gnu2/IManagedBuildGnuToolInfo.java
 create mode 100644 build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/makegen/gnu2/ManagedBuildGnuToolInfo.java

diff --git a/build/org.eclipse.cdt.managedbuilder.core.tests/plugin.xml b/build/org.eclipse.cdt.managedbuilder.core.tests/plugin.xml
index 2d145e30ce0..51e116fb6f4 100644
--- a/build/org.eclipse.cdt.managedbuilder.core.tests/plugin.xml
+++ b/build/org.eclipse.cdt.managedbuilder.core.tests/plugin.xml
@@ -1234,7 +1234,7 @@
 		              name="Dbg Builder"
 		              command="make"
 		              arguments="-k"
-		              buildfileGenerator="org.eclipse.cdt.managedbuilder.makegen.gnu.GnuMakefileGenerator">
+		              buildfileGenerator="org.eclipse.cdt.managedbuilder.makegen.gnu2.GnuMakefileGenerator">
 		     	  </builder>               
                   <tool
                       id="cdt.managedbuild.tool.testgnu.c.compiler.exe.debug"
@@ -2603,7 +2603,7 @@
 		              name="MBS30BuilderName.Dbg"
 		              command="make"
 		              arguments="-k"
-		              buildfileGenerator="org.eclipse.cdt.managedbuilder.makegen.gnu.GnuMakefileGenerator">
+		              buildfileGenerator="org.eclipse.cdt.managedbuilder.makegen.gnu2.GnuMakefileGenerator">
 		     	  </builder>               
                   <tool
                       id="cdt.managedbuild.tool.testgnu30.c.compiler.exe.debug"
@@ -2668,7 +2668,7 @@
 		              name="MBS30BuilderName.Rel"		              
 		              command="make"
 		              arguments="-k"
-		              buildfileGenerator="org.eclipse.cdt.managedbuilder.makegen.gnu.GnuMakefileGenerator">
+		              buildfileGenerator="org.eclipse.cdt.managedbuilder.makegen.gnu2.GnuMakefileGenerator">
 				  </builder> 
                   <tool
                       id="cdt.managedbuild.tool.testgnu30.c.compiler.exe.release"
@@ -2741,7 +2741,7 @@
 		              name="MBS30BuilderName.Dbg"
 		              command="make"
 		              arguments="-k"
-		              buildfileGenerator="org.eclipse.cdt.managedbuilder.makegen.gnu.GnuMakefileGenerator">		              
+		              buildfileGenerator="org.eclipse.cdt.managedbuilder.makegen.gnu2.GnuMakefileGenerator">
 				  </builder>               		         
 				  <tool
 				      id="cdt.managedbuild.tool.testgnu30.c.compiler.so.debug"
@@ -2831,7 +2831,7 @@
 		              name="MBS30BuilderName.Rel"
 		              command="make"
 		              arguments="-k"
-		              buildfileGenerator="org.eclipse.cdt.managedbuilder.makegen.gnu.GnuMakefileGenerator">		              
+		              buildfileGenerator="org.eclipse.cdt.managedbuilder.makegen.gnu2.GnuMakefileGenerator">
 				  </builder>               
 				  <tool				     
 				      id="cdt.managedbuild.tool.testgnu30.c.compiler.so.release"
@@ -2928,7 +2928,7 @@
 					  name="MBS30BuilderName.Dbg"
 					  command="make"
 					  arguments="-k"
-					  buildfileGenerator="org.eclipse.cdt.managedbuilder.makegen.gnu.GnuMakefileGenerator">		              
+					  buildfileGenerator="org.eclipse.cdt.managedbuilder.makegen.gnu2.GnuMakefileGenerator">
 			      </builder>               		         
 				  <tool
 					  id="cdt.managedbuild.tool.testgnu30.c.compiler.lib.debug"
@@ -2990,7 +2990,7 @@
 		              name="MBS30BuilderName.Rel"
 		              command="make"
 		              arguments="-k"
-		              buildfileGenerator="org.eclipse.cdt.managedbuilder.makegen.gnu.GnuMakefileGenerator">		              
+		              buildfileGenerator="org.eclipse.cdt.managedbuilder.makegen.gnu2.GnuMakefileGenerator">
 				  </builder>               		            
 		          <tool
 					  id="cdt.managedbuild.tool.testgnu30.c.compiler.lib.release"
@@ -3093,7 +3093,7 @@
 		              name="BuilderDbg"
 		              command="make"
 		              arguments="-k"
-		              buildfileGenerator="org.eclipse.cdt.managedbuilder.makegen.gnu.GnuMakefileGenerator">
+		              buildfileGenerator="org.eclipse.cdt.managedbuilder.makegen.gnu2.GnuMakefileGenerator">
 		     	  </builder>               
                   <tool
                       id="cdt.managedbuild.tool.Testprepost30.gnu.c.compiler.exe.debug"
@@ -3179,7 +3179,7 @@
 				  <builder
 		              id="test30_1.gnu.so.builder"
 		              name="Builder for test30_1"
-		              buildfileGenerator="org.eclipse.cdt.managedbuilder.makegen.gnu.GnuMakefileGenerator">
+		              buildfileGenerator="org.eclipse.cdt.managedbuilder.makegen.gnu2.GnuMakefileGenerator">
 		     	  </builder>               
                   <tool
                       id="test30_1.gnu.so.c.compiler"
@@ -3393,7 +3393,7 @@
                      name="Platform for test30_sto"
                      osList="all"/>
                <builder
-                     buildfileGenerator="org.eclipse.cdt.managedbuilder.makegen.gnu.GnuMakefileGenerator"
+                     buildfileGenerator="org.eclipse.cdt.managedbuilder.makegen.gnu2.GnuMakefileGenerator"
                      id="test30_sto.dummy.builder"
                      isAbstract="false"
                      name="Builder for test30_sto"/>
@@ -3513,7 +3513,7 @@
 				  <builder
 		              id="test30_2.tar.builder"
 		              name="Builder for test30_2"
-		              buildfileGenerator="org.eclipse.cdt.managedbuilder.makegen.gnu.GnuMakefileGenerator">
+		              buildfileGenerator="org.eclipse.cdt.managedbuilder.makegen.gnu2.GnuMakefileGenerator">
 		     	  </builder>               
 			      <tool
 			      		name="tar-create"
@@ -3658,7 +3658,7 @@
 		              variableFormat="@="
 		              isVariableCaseSensitive="false"
 		              reservedMacroNames="PATH"		              
-		              buildfileGenerator="org.eclipse.cdt.managedbuilder.makegen.gnu.GnuMakefileGenerator">
+		              buildfileGenerator="org.eclipse.cdt.managedbuilder.makegen.gnu2.GnuMakefileGenerator">
 		     	  </builder>               
                   <tool
                       id="cdt.managedbuild.tool.testenv.c.compiler.exe.debug"
@@ -4030,7 +4030,7 @@
 		              variableFormat="@="
 		              isVariableCaseSensitive="false"
 		              reservedMacroNames="PATH"		              
-		              buildfileGenerator="org.eclipse.cdt.managedbuilder.makegen.gnu.GnuMakefileGenerator">
+		              buildfileGenerator="org.eclipse.cdt.managedbuilder.makegen.gnu2.GnuMakefileGenerator">
 		     	  </builder>               
                   <tool
                       id="cdt.managedbuild.tool.testMultipleVersions.c.compiler.exe.debug_1.1.0"
@@ -4171,7 +4171,7 @@
 		              variableFormat="@="
 		              isVariableCaseSensitive="false"
 		              reservedMacroNames="PATH"		              
-		              buildfileGenerator="org.eclipse.cdt.managedbuilder.makegen.gnu.GnuMakefileGenerator">
+		              buildfileGenerator="org.eclipse.cdt.managedbuilder.makegen.gnu2.GnuMakefileGenerator">
 		     	  </builder>               
                   <tool
                       id="tool.testProjectConverterConvenienceRoutines.c.compiler.exe.debug_1.1.0"
@@ -4201,7 +4201,7 @@
                  targetTool="org.eclipse.cdt.managedbuilder.core.tests.BDMacroSupportBarTool">
               <builder
                     arguments="-k"
-                    buildfileGenerator="org.eclipse.cdt.managedbuilder.makegen.gnu.GnuMakefileGenerator"
+                    buildfileGenerator="org.eclipse.cdt.managedbuilder.makegen.gnu2.GnuMakefileGenerator"
                     command="make"
                     id="org.eclipse.cdt.managedbuilder.core.tests.BDMacroSupportBuilder"
                     isAbstract="false"
@@ -4335,7 +4335,7 @@
 		              name="Test Builder Version 1.0"		              
 		              command="make"
 		              arguments="-k"
-		              buildfileGenerator="org.eclipse.cdt.managedbuilder.makegen.gnu.GnuMakefileGenerator">
+		              buildfileGenerator="org.eclipse.cdt.managedbuilder.makegen.gnu2.GnuMakefileGenerator">
 				  </builder> 
                   <tool
                       id="test.tool1_1.0.0"
@@ -4378,7 +4378,7 @@
 		              name="Test Builder Version 2.0"		              
 		              command="make"
 		              arguments="-k"
-		              buildfileGenerator="org.eclipse.cdt.managedbuilder.makegen.gnu.GnuMakefileGenerator">
+		              buildfileGenerator="org.eclipse.cdt.managedbuilder.makegen.gnu2.GnuMakefileGenerator">
 				  </builder> 
                   <tool
                       id="test.tool1_2.0.0"
@@ -4481,7 +4481,7 @@
 		              name="Test Builder Version 1.0"		              
 		              command="make"
 		              arguments="-k"
-		              buildfileGenerator="org.eclipse.cdt.managedbuilder.makegen.gnu.GnuMakefileGenerator">
+		              buildfileGenerator="org.eclipse.cdt.managedbuilder.makegen.gnu2.GnuMakefileGenerator">
 				  </builder> 
                   <tool
                       id="testProject.tool1_1.0.0"
@@ -4522,7 +4522,7 @@
 		              name="Test Builder Version 2.0"		              
 		              command="make"
 		              arguments="-k"
-		              buildfileGenerator="org.eclipse.cdt.managedbuilder.makegen.gnu.GnuMakefileGenerator">
+		              buildfileGenerator="org.eclipse.cdt.managedbuilder.makegen.gnu2.GnuMakefileGenerator">
 				  </builder> 
                   <tool
                       id="testProject.tool1_2.0.0"
@@ -4750,7 +4750,7 @@
 		            name="Builder.Executable.Release"		              
 		            command="make"
                     arguments="-k"
-                    buildfileGenerator="org.eclipse.cdt.managedbuilder.makegen.gnu.GnuMakefileGenerator">                      
+                    buildfileGenerator="org.eclipse.cdt.managedbuilder.makegen.gnu2.GnuMakefileGenerator">
 				</builder> 				  				  
 				<tool
 				    id="cdt.test.fortran.compilestep.executable.release"
@@ -4794,7 +4794,7 @@
 		            name="Builder.Executable.Debug"		              
 		            command="make"
                     arguments="-k"
-                    buildfileGenerator="org.eclipse.cdt.managedbuilder.makegen.gnu.GnuMakefileGenerator">                      
+                    buildfileGenerator="org.eclipse.cdt.managedbuilder.makegen.gnu2.GnuMakefileGenerator">
 				</builder> 				  				  
 				<tool
 				    id="cdt.test.fortran.compilestep.executable.debug"
@@ -4852,7 +4852,7 @@
 		            name="AssignToOption Builder"		              
 		            command="make"
                     arguments="-k"
-                    buildfileGenerator="org.eclipse.cdt.managedbuilder.makegen.gnu.GnuMakefileGenerator">                      
+                    buildfileGenerator="org.eclipse.cdt.managedbuilder.makegen.gnu2.GnuMakefileGenerator">
 				</builder> 				  				  
             </toolChain>
          </configuration>
@@ -5166,7 +5166,7 @@
 		            name="Builder"		              
 		            command="make"
                     arguments="-k"
-                    buildfileGenerator="org.eclipse.cdt.managedbuilder.makegen.gnu.GnuMakefileGenerator">                      
+                    buildfileGenerator="org.eclipse.cdt.managedbuilder.makegen.gnu2.GnuMakefileGenerator">
 				</builder> 				  				  
             </toolChain>
          </configuration>
@@ -5239,7 +5239,7 @@
 		            name="Builder"		              
 		            command="make"
                     arguments="-k"
-                    buildfileGenerator="org.eclipse.cdt.managedbuilder.makegen.gnu.GnuMakefileGenerator">                      
+                    buildfileGenerator="org.eclipse.cdt.managedbuilder.makegen.gnu2.GnuMakefileGenerator">
 				</builder> 				  				  
             </toolChain>
          </configuration>
@@ -5283,7 +5283,7 @@
 		              variableFormat="@="
 		              isVariableCaseSensitive="false"
 		              reservedMacroNames="PATH"		              
-		              buildfileGenerator="org.eclipse.cdt.managedbuilder.makegen.gnu.GnuMakefileGenerator">
+		              buildfileGenerator="org.eclipse.cdt.managedbuilder.makegen.gnu2.GnuMakefileGenerator">
 		     	  </builder>               
                   <tool
                       id="enablement.this.child_1.2.3"
@@ -6474,7 +6474,7 @@
 		              name="MBS30BuilderName.Dbg"
 		              command="make"
 		              arguments="-k"
-		              buildfileGenerator="org.eclipse.cdt.managedbuilder.makegen.gnu.GnuMakefileGenerator">
+		              buildfileGenerator="org.eclipse.cdt.managedbuilder.makegen.gnu2.GnuMakefileGenerator">
 		     	  </builder>               
                   <tool
                       id="cdt.managedbuild.tool.bdm.c.compiler.exe.debug"
@@ -8151,7 +8151,7 @@
           variableFormat="${=}"
           isVariableCaseSensitive="true"
           reservedMacroNames="ROOT,DEPS,OBJS,.*_SRCS,EXECUTABLES,SUBDIRS,LIBS,USER_OBJS,.*_INPUTS,.*_OUTPUTS"
-          buildfileGenerator="org.eclipse.cdt.managedbuilder.makegen.gnu.GnuMakefileGenerator"
+          buildfileGenerator="org.eclipse.cdt.managedbuilder.makegen.gnu2.GnuMakefileGenerator"
           macroInputFileNameValue="$(notdir $&lt;)"
           macroInputFileExtValue="$(suffix $(notdir $&lt;))"
           macroInputFileBaseNameValue="$(basename $(notdir $&lt;))"
diff --git a/build/org.eclipse.cdt.managedbuilder.core.tests/tests/org/eclipse/cdt/managedbuilder/core/tests/BuildFileGenerator.java b/build/org.eclipse.cdt.managedbuilder.core.tests/tests/org/eclipse/cdt/managedbuilder/core/tests/BuildFileGenerator.java
index a7711b4af50..e93050dbdc3 100644
--- a/build/org.eclipse.cdt.managedbuilder.core.tests/tests/org/eclipse/cdt/managedbuilder/core/tests/BuildFileGenerator.java
+++ b/build/org.eclipse.cdt.managedbuilder.core.tests/tests/org/eclipse/cdt/managedbuilder/core/tests/BuildFileGenerator.java
@@ -15,7 +15,7 @@ package org.eclipse.cdt.managedbuilder.core.tests;
 
 import org.eclipse.cdt.managedbuilder.core.IManagedBuildInfo;
 import org.eclipse.cdt.managedbuilder.makegen.IManagedBuilderMakefileGenerator;
-import org.eclipse.cdt.managedbuilder.makegen.gnu.GnuMakefileGenerator;
+import org.eclipse.cdt.managedbuilder.makegen.gnu2.GnuMakefileGenerator;
 import org.eclipse.core.resources.IProject;
 import org.eclipse.core.resources.IResource;
 import org.eclipse.core.resources.IResourceDelta;
diff --git a/build/org.eclipse.cdt.managedbuilder.core.tests/tests/org/eclipse/cdt/managedbuilder/core/tests/ManagedBuildCoreTests.java b/build/org.eclipse.cdt.managedbuilder.core.tests/tests/org/eclipse/cdt/managedbuilder/core/tests/ManagedBuildCoreTests.java
index 65b84a4c73f..824d75d7362 100644
--- a/build/org.eclipse.cdt.managedbuilder.core.tests/tests/org/eclipse/cdt/managedbuilder/core/tests/ManagedBuildCoreTests.java
+++ b/build/org.eclipse.cdt.managedbuilder.core.tests/tests/org/eclipse/cdt/managedbuilder/core/tests/ManagedBuildCoreTests.java
@@ -85,7 +85,7 @@ public class ManagedBuildCoreTests extends TestCase {
 		String expectedCommand = "make";
 		String expectedArguments = "-k";
 		String[] expectedBuilderName = { "Dbg Builder", "Rel Builder" };
-		String expectedBuilderInfo = "org.eclipse.cdt.managedbuilder.makegen.gnu.GnuMakefileGenerator";
+		String expectedBuilderInfo = "org.eclipse.cdt.managedbuilder.makegen.gnu2.GnuMakefileGenerator";
 		String[] expectedToolId1 = { "cdt.managedbuild.tool.testgnu.c.compiler.exe.debug",
 				"cdt.managedbuild.tool.testgnu.c.compiler.exe.release" };
 		String expectedSuperToolId1 = "cdt.managedbuild.tool.testgnu.c.compiler";
diff --git a/build/org.eclipse.cdt.managedbuilder.core/META-INF/MANIFEST.MF b/build/org.eclipse.cdt.managedbuilder.core/META-INF/MANIFEST.MF
index 4a1aa871d86..42f24c079f3 100644
--- a/build/org.eclipse.cdt.managedbuilder.core/META-INF/MANIFEST.MF
+++ b/build/org.eclipse.cdt.managedbuilder.core/META-INF/MANIFEST.MF
@@ -24,6 +24,7 @@ Export-Package: org.eclipse.cdt.build.core.scannerconfig,
  org.eclipse.cdt.managedbuilder.macros,
  org.eclipse.cdt.managedbuilder.makegen,
  org.eclipse.cdt.managedbuilder.makegen.gnu,
+ org.eclipse.cdt.managedbuilder.makegen.gnu2;x-internal:=true,
  org.eclipse.cdt.managedbuilder.makegen.internal;x-internal:=true,
  org.eclipse.cdt.managedbuilder.pdomdepgen,
  org.eclipse.cdt.managedbuilder.projectconverter,
diff --git a/build/org.eclipse.cdt.managedbuilder.core/plugin.xml b/build/org.eclipse.cdt.managedbuilder.core/plugin.xml
index 2d94d704647..b054e00a424 100644
--- a/build/org.eclipse.cdt.managedbuilder.core/plugin.xml
+++ b/build/org.eclipse.cdt.managedbuilder.core/plugin.xml
@@ -355,7 +355,7 @@
           variableFormat="${=}"
           isVariableCaseSensitive="true"
           reservedMacroNames="ROOT,DEPS,OBJS,.*_SRCS,EXECUTABLES,SUBDIRS,LIBS,USER_OBJS,.*_INPUTS,.*_OUTPUTS"
-          buildfileGenerator="org.eclipse.cdt.managedbuilder.makegen.gnu.GnuMakefileGenerator"
+          buildfileGenerator="org.eclipse.cdt.managedbuilder.makegen.gnu2.GnuMakefileGenerator"
           macroInputFileNameValue="$(notdir $&lt;)"
           macroInputFileExtValue="$(suffix $(notdir $&lt;))"
           macroInputFileBaseNameValue="$(basename $(notdir $&lt;))"
diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/ManagedBuildManager.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/ManagedBuildManager.java
index ab494da8e7d..36a52608c23 100644
--- a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/ManagedBuildManager.java
+++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/ManagedBuildManager.java
@@ -111,7 +111,7 @@ import org.eclipse.cdt.managedbuilder.internal.macros.BuildMacroProvider;
 import org.eclipse.cdt.managedbuilder.internal.tcmodification.ToolChainModificationManager;
 import org.eclipse.cdt.managedbuilder.macros.IBuildMacroProvider;
 import org.eclipse.cdt.managedbuilder.makegen.IManagedBuilderMakefileGenerator;
-import org.eclipse.cdt.managedbuilder.makegen.gnu.GnuMakefileGenerator;
+import org.eclipse.cdt.managedbuilder.makegen.gnu2.GnuMakefileGenerator;
 import org.eclipse.cdt.managedbuilder.projectconverter.UpdateManagedProjectManager;
 import org.eclipse.cdt.managedbuilder.tcmodification.IToolChainModificationManager;
 import org.eclipse.core.resources.ICommand;
diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/makegen/gnu/GnuDependencyGroupInfo.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/makegen/gnu/GnuDependencyGroupInfo.java
index 2284b7f3404..18445bbd704 100644
--- a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/makegen/gnu/GnuDependencyGroupInfo.java
+++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/makegen/gnu/GnuDependencyGroupInfo.java
@@ -23,8 +23,14 @@ package org.eclipse.cdt.managedbuilder.makegen.gnu;
 public class GnuDependencyGroupInfo {
 
 	//  Member Variables
-	String groupBuildVar;
-	boolean conditionallyInclude;
+	/**
+	 * @noreference
+	 */
+	public String groupBuildVar;
+	/**
+	 * @noreference
+	 */
+	public boolean conditionallyInclude;
 	//	ArrayList groupFiles;
 
 	//  Constructor
diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/makegen/gnu/GnuMakefileGenerator.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/makegen/gnu/GnuMakefileGenerator.java
index 3d5d89b195c..94dd491cc1c 100644
--- a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/makegen/gnu/GnuMakefileGenerator.java
+++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/makegen/gnu/GnuMakefileGenerator.java
@@ -112,7 +112,9 @@ import org.eclipse.core.runtime.SubProgressMonitor;
  *
  * @since 1.2
  * @noinstantiate This class is not intended to be instantiated by clients.
+ * @deprecated Replaced by {@link org.eclipse.cdt.managedbuilder.makegen.gnu2.GnuMakefileGenerator}
  */
+@Deprecated
 public class GnuMakefileGenerator implements IManagedBuilderMakefileGenerator2 {
 	private static final IPath DOT_SLASH_PATH = new Path("./"); //$NON-NLS-1$
 
diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/makegen/gnu/IManagedBuildGnuToolInfo.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/makegen/gnu/IManagedBuildGnuToolInfo.java
index af854c47c40..a954e777a59 100644
--- a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/makegen/gnu/IManagedBuildGnuToolInfo.java
+++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/makegen/gnu/IManagedBuildGnuToolInfo.java
@@ -21,7 +21,9 @@ import java.util.Vector;
  *
  * @noextend This class is not intended to be subclassed by clients.
  * @noimplement This interface is not intended to be implemented by clients.
+ * @deprecated Replaced by {@link org.eclipse.cdt.managedbuilder.makegen.gnu2.IManagedBuildGnuToolInfo}
  */
+@Deprecated
 public interface IManagedBuildGnuToolInfo {
 	public final String DOT = "."; //$NON-NLS-1$
 
diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/makegen/gnu/ManagedBuildGnuToolInfo.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/makegen/gnu/ManagedBuildGnuToolInfo.java
index d7e08aaf0c5..3aead3fdd1e 100644
--- a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/makegen/gnu/ManagedBuildGnuToolInfo.java
+++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/makegen/gnu/ManagedBuildGnuToolInfo.java
@@ -54,7 +54,9 @@ import org.eclipse.core.runtime.Path;
  * and outputs while a Gnu makefile is being generated.
  *
  * @noextend This class is not intended to be subclassed by clients.
+ * @deprecated Replaced by {@link org.eclipse.cdt.managedbuilder.makegen.gnu2.ManagedBuildGnuToolInfo}
  */
+@Deprecated
 public class ManagedBuildGnuToolInfo implements IManagedBuildGnuToolInfo {
 
 	/*
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
new file mode 100644
index 00000000000..28b0c288f4c
--- /dev/null
+++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/makegen/gnu2/GnuMakefileGenerator.java
@@ -0,0 +1,4790 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2016 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     IBM Rational Software - Initial API and implementation
+ *     ARM Ltd. - Minor changes to echo commands
+ *     IBM Corporation
+ *     Anna Dushistova  (Mentor Graphics) - [307244] extend visibility of fields in GnuMakefileGenerator
+ *     James Blackburn (Broadcom Corp.)
+ *     Marc-Andre Laperle
+ *     Liviu Ionescu - [322168]
+ *     Dorothea Pilz-Roeder (Advantest Europe GmbH) - [180451]
+ *******************************************************************************/
+package org.eclipse.cdt.managedbuilder.makegen.gnu2;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.Vector;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.eclipse.cdt.core.CCorePlugin;
+import org.eclipse.cdt.core.settings.model.CSourceEntry;
+import org.eclipse.cdt.core.settings.model.ICConfigurationDescription;
+import org.eclipse.cdt.core.settings.model.ICSettingEntry;
+import org.eclipse.cdt.core.settings.model.ICSourceEntry;
+import org.eclipse.cdt.core.settings.model.util.CDataUtil;
+import org.eclipse.cdt.core.settings.model.util.IPathSettingsContainerVisitor;
+import org.eclipse.cdt.core.settings.model.util.PathSettingsContainer;
+import org.eclipse.cdt.managedbuilder.core.BuildException;
+import org.eclipse.cdt.managedbuilder.core.IBuildObject;
+import org.eclipse.cdt.managedbuilder.core.IBuilder;
+import org.eclipse.cdt.managedbuilder.core.IConfiguration;
+import org.eclipse.cdt.managedbuilder.core.IFileInfo;
+import org.eclipse.cdt.managedbuilder.core.IFolderInfo;
+import org.eclipse.cdt.managedbuilder.core.IInputType;
+import org.eclipse.cdt.managedbuilder.core.IManagedBuildInfo;
+import org.eclipse.cdt.managedbuilder.core.IManagedCommandLineGenerator;
+import org.eclipse.cdt.managedbuilder.core.IManagedCommandLineInfo;
+import org.eclipse.cdt.managedbuilder.core.IManagedOutputNameProvider;
+import org.eclipse.cdt.managedbuilder.core.IOption;
+import org.eclipse.cdt.managedbuilder.core.IOutputType;
+import org.eclipse.cdt.managedbuilder.core.IResourceInfo;
+import org.eclipse.cdt.managedbuilder.core.ITool;
+import org.eclipse.cdt.managedbuilder.core.ManagedBuildManager;
+import org.eclipse.cdt.managedbuilder.core.ManagedBuilderCorePlugin;
+import org.eclipse.cdt.managedbuilder.internal.core.ManagedMakeMessages;
+import org.eclipse.cdt.managedbuilder.internal.core.Tool;
+import org.eclipse.cdt.managedbuilder.internal.macros.BuildMacroProvider;
+import org.eclipse.cdt.managedbuilder.internal.macros.FileContextData;
+import org.eclipse.cdt.managedbuilder.macros.BuildMacroException;
+import org.eclipse.cdt.managedbuilder.macros.IBuildMacroProvider;
+import org.eclipse.cdt.managedbuilder.makegen.IManagedBuilderMakefileGenerator;
+import org.eclipse.cdt.managedbuilder.makegen.IManagedBuilderMakefileGenerator2;
+import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyCalculator;
+import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyCommands;
+import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyGenerator;
+import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyGenerator2;
+import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyGeneratorType;
+import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyInfo;
+import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyPreBuild;
+import org.eclipse.cdt.managedbuilder.makegen.gnu.DefaultGCCDependencyCalculator3;
+import org.eclipse.cdt.managedbuilder.makegen.gnu.GnuDependencyGroupInfo;
+import org.eclipse.cdt.utils.EFSExtensionManager;
+import org.eclipse.core.resources.IContainer;
+import org.eclipse.core.resources.IFile;
+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;
+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.MultiStatus;
+import org.eclipse.core.runtime.OperationCanceledException;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.SubProgressMonitor;
+
+/**
+ * This is a specialized makefile generator that takes advantage of the
+ * extensions present in Gnu Make.
+ * <p>
+ * If sub-classing and using {@link DefaultGCCDependencyCalculator3}, make sure to also override
+ * {@link DefaultGCCDependencyCalculator3#createMakefileGenerator()} to return the appropriate result.
+ *
+ * @since 1.2
+ * @noinstantiate This class is not intended to be instantiated by clients.
+ */
+public class GnuMakefileGenerator implements IManagedBuilderMakefileGenerator2 {
+	private static final IPath DOT_SLASH_PATH = new Path("./"); //$NON-NLS-1$
+
+	private Pattern doubleQuotedOption = Pattern.compile("--?[a-zA-Z]+.*?\\\".*?\\\".*"); //$NON-NLS-1$
+	private Pattern singleQuotedOption = Pattern.compile("--?[a-zA-Z]+.*?'.*?'.*"); //$NON-NLS-1$
+
+	/**
+	 * This class walks the delta supplied by the build system to determine
+	 * what resources have been changed. The logic is very simple. If a
+	 * buildable resource (non-header) has been added or removed, the directories
+	 * in which they are located are "dirty" so the makefile fragments for them
+	 * have to be regenerated.
+	 * <p>
+	 * The actual dependencies are recalculated as a result of the build step
+	 * itself. We are relying on make to do the right things when confronted
+	 * with a dependency on a moved header file. That said, make will treat
+	 * the missing header file in a dependency rule as a target it has to build
+	 * unless told otherwise. These dummy targets are added to the makefile
+	 * to avoid a missing target error.
+	 */
+	public class ResourceDeltaVisitor implements IResourceDeltaVisitor {
+		private final GnuMakefileGenerator generator;
+		//		private IManagedBuildInfo info;
+		private final IConfiguration config;
+
+		/**
+		 * The constructor
+		 */
+		public ResourceDeltaVisitor(GnuMakefileGenerator generator, IManagedBuildInfo info) {
+			this.generator = generator;
+			this.config = info.getDefaultConfiguration();
+		}
+
+		public ResourceDeltaVisitor(GnuMakefileGenerator generator, IConfiguration cfg) {
+			this.generator = generator;
+			this.config = cfg;
+		}
+
+		/* (non-Javadoc)
+		 * @see org.eclipse.core.resources.IResourceDeltaVisitor#visit(org.eclipse.core.resources.IResourceDelta)
+		 */
+		@Override
+		public boolean visit(IResourceDelta delta) throws CoreException {
+			// Should the visitor keep iterating in current directory
+			boolean keepLooking = false;
+			IResource resource = delta.getResource();
+			IResourceInfo rcInfo = config.getResourceInfo(resource.getProjectRelativePath(), false);
+			IFolderInfo fo = null;
+			boolean isSource = isSource(resource.getProjectRelativePath());
+			if (rcInfo instanceof IFolderInfo) {
+				fo = (IFolderInfo) rcInfo;
+			}
+			// What kind of resource change has occurred
+			if (/*!rcInfo.isExcluded() && */isSource) {
+				if (resource.getType() == IResource.FILE) {
+					String ext = resource.getFileExtension();
+					switch (delta.getKind()) {
+					case IResourceDelta.ADDED:
+						if (!generator.isGeneratedResource(resource)) {
+							// This is a source file so just add its container
+							if (fo == null || fo.buildsFileType(ext)) {
+								generator.appendModifiedSubdirectory(resource);
+							}
+						}
+						break;
+					case IResourceDelta.REMOVED:
+						// we get this notification if a resource is moved too
+						if (!generator.isGeneratedResource(resource)) {
+							// This is a source file so just add its container
+							if (fo == null || fo.buildsFileType(ext)) {
+								generator.appendDeletedFile(resource);
+								generator.appendModifiedSubdirectory(resource);
+							}
+						}
+						break;
+					default:
+						keepLooking = true;
+						break;
+					}
+				}
+
+				if (resource.getType() == IResource.FOLDER) {
+					// I only care about delete event
+					switch (delta.getKind()) {
+					case IResourceDelta.REMOVED:
+						if (!generator.isGeneratedResource(resource)) {
+							generator.appendDeletedSubdirectory((IContainer) resource);
+						}
+						break;
+					}
+				}
+			}
+			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) {
+					keepLooking = true;
+				}
+			} else {
+				// If the resource is part of the generated directory structure don't recurse
+				if (resource.getType() == IResource.ROOT || (isSource && !generator.isGeneratedResource(resource))) {
+					keepLooking = true;
+				}
+			}
+
+			return keepLooking;
+		}
+	}
+
+	/**
+	 * This class is used to recursively walk the project and determine which
+	 * modules contribute buildable source files.
+	 */
+	protected class ResourceProxyVisitor implements IResourceProxyVisitor {
+		private final GnuMakefileGenerator generator;
+		private final IConfiguration config;
+		//		private IManagedBuildInfo info;
+
+		/**
+		 * Constructs a new resource proxy visitor to quickly visit project
+		 * resources.
+		 */
+		public ResourceProxyVisitor(GnuMakefileGenerator generator, IManagedBuildInfo info) {
+			this.generator = generator;
+			this.config = info.getDefaultConfiguration();
+		}
+
+		public ResourceProxyVisitor(GnuMakefileGenerator generator, IConfiguration cfg) {
+			this.generator = generator;
+			this.config = cfg;
+		}
+
+		/* (non-Javadoc)
+		 * @see org.eclipse.core.resources.IResourceProxyVisitor#visit(org.eclipse.core.resources.IResourceProxy)
+		 */
+		@Override
+		public boolean visit(IResourceProxy proxy) throws CoreException {
+			// No point in proceeding, is there
+			if (generator == null) {
+				return false;
+			}
+
+			IResource resource = proxy.requestResource();
+			boolean isSource = isSource(resource.getProjectRelativePath());
+
+			// Is this a resource we should even consider
+			if (proxy.getType() == IResource.FILE) {
+				// If this resource has a Resource Configuration and is not excluded or
+				// if it has a file extension that one of the tools builds, add the sudirectory to the list
+				//				boolean willBuild = false;
+				IResourceInfo rcInfo = config.getResourceInfo(resource.getProjectRelativePath(), false);
+				if (isSource/* && !rcInfo.isExcluded()*/) {
+					boolean willBuild = false;
+					if (rcInfo instanceof IFolderInfo) {
+						String ext = resource.getFileExtension();
+						if (((IFolderInfo) rcInfo).buildsFileType(ext) &&
+						// If this file resource is a generated resource, then it is uninteresting
+								!generator.isGeneratedResource(resource)) {
+							willBuild = true;
+						}
+					} else {
+						willBuild = true;
+					}
+
+					if (willBuild)
+						generator.appendBuildSubdirectory(resource);
+				}
+				//				if (willBuild) {
+				//					if ((resConfig == null) || (!(resConfig.isExcluded()))) {
+				//						generator.appendBuildSubdirectory(resource);
+				//					}
+				//				}
+				return false;
+			} else if (proxy.getType() == IResource.FOLDER) {
+
+				if (!isSource || generator.isGeneratedResource(resource))
+					return false;
+				return true;
+			}
+
+			// Recurse into subdirectories
+			return true;
+		}
+
+	}
+
+	// String constants for makefile contents and messages
+	private static final String COMMENT = "MakefileGenerator.comment"; //$NON-NLS-1$
+	//private static final String AUTO_DEP = COMMENT + ".autodeps";	//$NON-NLS-1$
+	//private static final String MESSAGE = "ManagedMakeBuilder.message";	//$NON-NLS-1$
+	//private static final String BUILD_ERROR = MESSAGE + ".error";	//$NON-NLS-1$
+
+	//private static final String DEP_INCL = COMMENT + ".module.dep.includes";	//$NON-NLS-1$
+	private static final String HEADER = COMMENT + ".header"; //$NON-NLS-1$
+
+	protected static final String MESSAGE_FINISH_BUILD = ManagedMakeMessages
+			.getResourceString("MakefileGenerator.message.finish.build"); //$NON-NLS-1$
+	protected static final String MESSAGE_FINISH_FILE = ManagedMakeMessages
+			.getResourceString("MakefileGenerator.message.finish.file"); //$NON-NLS-1$
+	protected static final String MESSAGE_START_BUILD = ManagedMakeMessages
+			.getResourceString("MakefileGenerator.message.start.build"); //$NON-NLS-1$
+	protected static final String MESSAGE_START_FILE = ManagedMakeMessages
+			.getResourceString("MakefileGenerator.message.start.file"); //$NON-NLS-1$
+	protected static final String MESSAGE_START_DEPENDENCY = ManagedMakeMessages
+			.getResourceString("MakefileGenerator.message.start.dependency"); //$NON-NLS-1$
+	protected static final String MESSAGE_NO_TARGET_TOOL = ManagedMakeMessages
+			.getResourceString("MakefileGenerator.message.no.target"); //$NON-NLS-1$
+	//private static final String MOD_INCL = COMMENT + ".module.make.includes";	//$NON-NLS-1$
+	private static final String MOD_LIST = COMMENT + ".module.list"; //$NON-NLS-1$
+	private static final String MOD_VARS = COMMENT + ".module.variables"; //$NON-NLS-1$
+	private static final String MOD_RULES = COMMENT + ".build.rule"; //$NON-NLS-1$
+	private static final String BUILD_TOP = COMMENT + ".build.toprules"; //$NON-NLS-1$
+	private static final String ALL_TARGET = COMMENT + ".build.alltarget"; //$NON-NLS-1$
+	private static final String MAINBUILD_TARGET = COMMENT + ".build.mainbuildtarget"; //$NON-NLS-1$
+	private static final String BUILD_TARGETS = COMMENT + ".build.toptargets"; //$NON-NLS-1$
+	private static final String SRC_LISTS = COMMENT + ".source.list"; //$NON-NLS-1$
+
+	private static final String EMPTY_STRING = ""; //$NON-NLS-1$
+	private static final String[] EMPTY_STRING_ARRAY = new String[0];
+
+	private static final String OBJS_MACRO = "OBJS"; //$NON-NLS-1$
+	private static final String MACRO_ADDITION_ADDPREFIX_HEADER = "${addprefix "; //$NON-NLS-1$
+	private static final String MACRO_ADDITION_ADDPREFIX_SUFFIX = "," + WHITESPACE + LINEBREAK; //$NON-NLS-1$
+	private static final String MACRO_ADDITION_PREFIX_SUFFIX = "+=" + WHITESPACE + LINEBREAK; //$NON-NLS-1$
+	private static final String PREBUILD = "pre-build"; //$NON-NLS-1$
+	private static final String MAINBUILD = "main-build"; //$NON-NLS-1$
+	private static final String POSTBUILD = "post-build"; //$NON-NLS-1$
+	private static final String SECONDARY_OUTPUTS = "secondary-outputs"; //$NON-NLS-1$
+
+	// Enumerations
+	public static final int PROJECT_RELATIVE = 1, PROJECT_SUBDIR_RELATIVE = 2, ABSOLUTE = 3;
+
+	class ToolInfoHolder {
+		ITool[] buildTools;
+		boolean[] buildToolsUsed;
+		ManagedBuildGnuToolInfo[] gnuToolInfos;
+		Set<String> outputExtensionsSet;
+		List<IPath> dependencyMakefiles;
+	}
+
+	// Local variables needed by generator
+	private String buildTargetName;
+	private String buildTargetExt;
+	private IConfiguration config;
+	private IBuilder builder;
+	//	private ITool[] buildTools;
+	//	private boolean[] buildToolsUsed;
+	//	private ManagedBuildGnuToolInfo[] gnuToolInfos;
+	private PathSettingsContainer toolInfos;
+	private Vector<IResource> deletedFileList;
+	private Vector<IResource> deletedDirList;
+	//	private IManagedBuildInfo info;
+	//	private IConfiguration cfg
+	private Vector<IResource> invalidDirList;
+	/** Collection of Folders in which sources files have been modified */
+	private Collection<IContainer> modifiedList;
+	private IProgressMonitor monitor;
+	private IProject project;
+	private IResource[] projectResources;
+	private Vector<String> ruleList;
+	private Vector<String> depLineList; //  String's of additional dependency lines
+	private Vector<String> depRuleList; //  String's of rules for generating dependency files
+	/** Collection of Containers which contribute source files to the build */
+	private Collection<IContainer> subdirList;
+	private IPath topBuildDir; //  Build directory - relative to the workspace
+	//	private Set outputExtensionsSet;
+	//=== Maps of macro names (String) to values (List)
+	//  Map of source file build variable names to a List of source file Path's
+	private final HashMap<String, List<IPath>> buildSrcVars = new HashMap<>();
+	//  Map of output file build variable names to a List of output file Path's
+	private final HashMap<String, List<IPath>> buildOutVars = new HashMap<>();
+	//  Map of dependency file build variable names to a List of GnuDependencyGroupInfo objects
+	private final HashMap<String, GnuDependencyGroupInfo> buildDepVars = new HashMap<>();
+	private final LinkedHashMap<String, String> topBuildOutVars = new LinkedHashMap<>();
+	// Dependency file variables
+	//	private Vector dependencyMakefiles;		//  IPath's - relative to the top build directory or absolute
+
+	private ICSourceEntry srcEntries[];
+
+	public GnuMakefileGenerator() {
+		super();
+	}
+
+	/*************************************************************************
+	 *   IManagedBuilderMakefileGenerator   M E T H O D S
+	 ************************************************************************/
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.cdt.managedbuilder.makegen.IManagedBuilderMakefileGenerator#initialize(IProject, IManagedBuildInfo, IProgressMonitor)
+	 */
+	@Override
+	public void initialize(IProject project, IManagedBuildInfo info, IProgressMonitor monitor) {
+		// Save the project so we can get path and member information
+		this.project = project;
+		try {
+			projectResources = project.members();
+		} catch (CoreException e) {
+			projectResources = null;
+		}
+		// Save the monitor reference for reporting back to the user
+		this.monitor = monitor;
+		// Get the build info for the project
+		//		this.info = info;
+		// Get the name of the build target
+		buildTargetName = info.getBuildArtifactName();
+		// Get its extension
+		buildTargetExt = info.getBuildArtifactExtension();
+
+		try {
+			//try to resolve the build macros in the target extension
+			buildTargetExt = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(buildTargetExt,
+					"", //$NON-NLS-1$
+					" ", //$NON-NLS-1$
+					IBuildMacroProvider.CONTEXT_CONFIGURATION, info.getDefaultConfiguration());
+		} catch (BuildMacroException e) {
+		}
+
+		try {
+			//try to resolve the build macros in the target name
+			String resolved = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(buildTargetName,
+					"", //$NON-NLS-1$
+					" ", //$NON-NLS-1$
+					IBuildMacroProvider.CONTEXT_CONFIGURATION, info.getDefaultConfiguration());
+			if (resolved != null && (resolved = resolved.trim()).length() > 0)
+				buildTargetName = resolved;
+		} catch (BuildMacroException e) {
+		}
+
+		if (buildTargetExt == null) {
+			buildTargetExt = ""; //$NON-NLS-1$
+		}
+		// Cache the build tools
+		config = info.getDefaultConfiguration();
+		builder = config.getEditableBuilder();
+		initToolInfos();
+		//set the top build dir path
+		initializeTopBuildDir(info.getConfigurationName());
+	}
+
+	/**
+	 * This method calls the dependency postprocessors defined for the tool chain
+	 */
+	private void callDependencyPostProcessors(IResourceInfo rcInfo, ToolInfoHolder h, IFile depFile,
+			IManagedDependencyGenerator2[] postProcessors, // This array is the same size as the buildTools array and has
+			// an entry set when the corresponding tool has a dependency calculator
+			boolean callPopulateDummyTargets, boolean force) throws CoreException {
+		try {
+			//			IPath path = depFile.getFullPath();
+			//			path = inFullPathFromOutFullPath(path);
+			//			IResourceInfo rcInfo = config.getResourceInfo(path, false);
+			//			IFolderInfo fo;
+			//			if(rcInfo instanceof IFileInfo){
+			//				fo = (IFolderInfo)config.getResourceInfo(path.removeLastSegments(1), false);
+			//			} else {
+			//				fo = (IFolderInfo)rcInfo;
+			//			}
+			//			ToolInfoHolder h = getToolInfo(fo.getPath());
+			updateMonitor(ManagedMakeMessages.getFormattedString("GnuMakefileGenerator.message.postproc.dep.file", //$NON-NLS-1$
+					depFile.getName()));
+			if (postProcessors != null) {
+				IPath absolutePath = new Path(
+						EFSExtensionManager.getDefault().getPathFromURI(depFile.getLocationURI()));
+				// Convert to build directory relative
+				IPath depPath = ManagedBuildManager.calculateRelativePath(getTopBuildDir(), absolutePath);
+				for (int i = 0; i < postProcessors.length; i++) {
+					IManagedDependencyGenerator2 depGen = postProcessors[i];
+					if (depGen != null) {
+						depGen.postProcessDependencyFile(depPath, config, h.buildTools[i], getTopBuildDir());
+					}
+				}
+			}
+			if (callPopulateDummyTargets) {
+				populateDummyTargets(rcInfo, depFile, force);
+			}
+		} catch (CoreException e) {
+			throw e;
+		} catch (IOException e) {
+		}
+	}
+
+	/**
+	 * This method collects the dependency postprocessors and file extensions defined for the tool chain
+	 */
+	private boolean collectDependencyGeneratorInformation(ToolInfoHolder h, Vector<String> depExts, //  Vector of dependency file extensions
+			IManagedDependencyGenerator2[] postProcessors) {
+
+		boolean callPopulateDummyTargets = false;
+		for (int i = 0; i < h.buildTools.length; i++) {
+			ITool tool = h.buildTools[i];
+			IManagedDependencyGeneratorType depType = tool
+					.getDependencyGeneratorForExtension(tool.getDefaultInputExtension());
+			if (depType != null) {
+				int calcType = depType.getCalculatorType();
+				if (calcType <= IManagedDependencyGeneratorType.TYPE_OLD_TYPE_LIMIT) {
+					if (calcType == IManagedDependencyGeneratorType.TYPE_COMMAND) {
+						callPopulateDummyTargets = true;
+						depExts.add(DEP_EXT);
+					}
+				} else {
+					if (calcType == IManagedDependencyGeneratorType.TYPE_BUILD_COMMANDS
+							|| calcType == IManagedDependencyGeneratorType.TYPE_PREBUILD_COMMANDS) {
+						IManagedDependencyGenerator2 depGen = (IManagedDependencyGenerator2) depType;
+						String depExt = depGen.getDependencyFileExtension(config, tool);
+						if (depExt != null) {
+							postProcessors[i] = depGen;
+							depExts.add(depExt);
+						}
+					}
+				}
+			}
+		}
+		return callPopulateDummyTargets;
+	}
+
+	protected boolean isSource(IPath path) {
+		return !CDataUtil.isExcluded(path, srcEntries);
+		//		path = path.makeRelative();
+		//		for(int i = 0; i < srcPaths.length; i++){
+		//			if(srcPaths[i].isPrefixOf(path))
+		//				return true;
+		//		}
+		//		return false;
+	}
+
+	private class DepInfo {
+		Vector<String> depExts;
+		IManagedDependencyGenerator2[] postProcessors;
+		boolean callPopulateDummyTargets;
+	}
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.cdt.managedbuilder.makegen.IManagedBuilderMakefileGenerator#generateDependencies()
+	 */
+	@Override
+	public void generateDependencies() throws CoreException {
+		final PathSettingsContainer postProcs = PathSettingsContainer.createRootContainer();
+		// Note: PopulateDummyTargets is a hack for the pre-3.x GCC compilers
+
+		// Collect the methods that will need to be called
+		toolInfos.accept(new IPathSettingsContainerVisitor() {
+			@Override
+			public boolean visit(PathSettingsContainer container) {
+				ToolInfoHolder h = (ToolInfoHolder) container.getValue();
+				Vector<String> depExts = new Vector<>(); //  Vector of dependency file extensions
+				IManagedDependencyGenerator2[] postProcessors = new IManagedDependencyGenerator2[h.buildTools.length];
+				boolean callPopulateDummyTargets = collectDependencyGeneratorInformation(h, depExts, postProcessors);
+
+				// Is there anyone to call if we do find dependency files?
+				if (!callPopulateDummyTargets) {
+					int i;
+					for (i = 0; i < postProcessors.length; i++) {
+						if (postProcessors[i] != null)
+							break;
+					}
+					if (i == postProcessors.length)
+						return true;
+				}
+
+				PathSettingsContainer child = postProcs.getChildContainer(container.getPath(), true, true);
+				DepInfo di = new DepInfo();
+				di.depExts = depExts;
+				di.postProcessors = postProcessors;
+				di.callPopulateDummyTargets = callPopulateDummyTargets;
+				child.setValue(di);
+
+				return true;
+			}
+		});
+
+		IWorkspaceRoot root = CCorePlugin.getWorkspace().getRoot();
+		for (IResource res : getSubdirList()) {
+			// The builder creates a subdir with same name as source in the build location
+			IContainer subDir = (IContainer) res;
+			IPath projectRelativePath = subDir.getProjectRelativePath();
+			IResourceInfo rcInfo = config.getResourceInfo(projectRelativePath, false);
+			PathSettingsContainer cr = postProcs.getChildContainer(rcInfo.getPath(), false, true);
+			if (cr == null || cr.getValue() == null)
+				continue;
+
+			DepInfo di = (DepInfo) cr.getValue();
+
+			ToolInfoHolder h = getToolInfo(projectRelativePath);
+			IPath buildRelativePath = topBuildDir.append(projectRelativePath);
+			IFolder buildFolder = root.getFolder(buildRelativePath);
+			if (buildFolder == null)
+				continue;
+
+			// Find all of the dep files in the generated subdirectories
+			IResource[] files = buildFolder.members();
+			for (IResource file : files) {
+				String fileExt = file.getFileExtension();
+				for (String ext : di.depExts) {
+					if (ext.equals(fileExt)) {
+						IFile depFile = root.getFile(file.getFullPath());
+						if (depFile == null)
+							continue;
+						callDependencyPostProcessors(rcInfo, h, depFile, di.postProcessors, di.callPopulateDummyTargets,
+								false);
+					}
+				}
+			}
+		}
+	}
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.cdt.managedbuilder.makegen.IManagedBuilderMakefileGenerator#generateMakefiles(org.eclipse.core.resources.IResourceDelta)
+	 */
+	@Override
+	public MultiStatus generateMakefiles(IResourceDelta delta) throws CoreException {
+		/*
+		 * 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(computeTopBuildDir(config.getName()));
+		if (!folder.exists()) {
+			return regenerateMakefiles();
+		}
+
+		// Return value
+		MultiStatus status;
+
+		// Visit the resources in the delta and compile a list of subdirectories to regenerate
+		updateMonitor(
+				ManagedMakeMessages.getFormattedString("MakefileGenerator.message.calc.delta", project.getName())); //$NON-NLS-1$
+		ResourceDeltaVisitor visitor = new ResourceDeltaVisitor(this, config);
+		delta.accept(visitor);
+		checkCancel();
+
+		// Get all the subdirectories participating in the build
+		updateMonitor(
+				ManagedMakeMessages.getFormattedString("MakefileGenerator.message.finding.sources", project.getName())); //$NON-NLS-1$
+		ResourceProxyVisitor resourceVisitor = new ResourceProxyVisitor(this, config);
+		project.accept(resourceVisitor, IResource.NONE);
+		checkCancel();
+
+		// Bug 303953: Ensure that if all resources have been removed from a folder, than the folder still
+		// appears in the subdir list so it's subdir.mk is correctly regenerated
+		getSubdirList().addAll(getModifiedList());
+
+		// Make sure there is something to build
+		if (getSubdirList().isEmpty()) {
+			String info = ManagedMakeMessages.getFormattedString("MakefileGenerator.warning.no.source", //$NON-NLS-1$
+					project.getName());
+			updateMonitor(info);
+			status = new MultiStatus(ManagedBuilderCorePlugin.getUniqueIdentifier(), IStatus.INFO, "", //$NON-NLS-1$
+					null);
+			status.add(new Status(IStatus.INFO, ManagedBuilderCorePlugin.getUniqueIdentifier(), NO_SOURCE_FOLDERS, info,
+					null));
+			return status;
+		}
+
+		// Make sure the build directory is available
+		ensureTopBuildDir();
+		checkCancel();
+
+		// Make sure that there is a makefile containing all the folders participating
+		IPath srcsFilePath = topBuildDir.append(SRCSFILE_NAME);
+		IFile srcsFileHandle = createFile(srcsFilePath);
+		buildSrcVars.clear();
+		buildOutVars.clear();
+		buildDepVars.clear();
+		topBuildOutVars.clear();
+		populateSourcesMakefile(srcsFileHandle);
+		checkCancel();
+
+		// Regenerate any fragments that are missing for the exisiting directories NOT modified
+		for (IResource res : getSubdirList()) {
+			IContainer subdirectory = (IContainer) res;
+			if (!getModifiedList().contains(subdirectory)) {
+				// Make sure the directory exists (it may have been deleted)
+				if (!subdirectory.exists()) {
+					appendDeletedSubdirectory(subdirectory);
+					continue;
+				}
+				// Make sure a fragment makefile exists
+				IPath fragmentPath = getBuildWorkingDir().append(subdirectory.getProjectRelativePath())
+						.append(MODFILE_NAME);
+				IFile makeFragment = project.getFile(fragmentPath);
+				if (!makeFragment.exists()) {
+					// If one or both are missing, then add it to the list to be generated
+					getModifiedList().add(subdirectory);
+				}
+			}
+		}
+
+		// Delete the old dependency files for any deleted resources
+		for (IResource deletedFile : getDeletedFileList()) {
+			deleteDepFile(deletedFile);
+			deleteBuildTarget(deletedFile);
+		}
+
+		// Regenerate any fragments for modified directories
+		for (IResource res : getModifiedList()) {
+			IContainer subDir = (IContainer) res;
+			// Make sure the directory exists (it may have been deleted)
+			if (!subDir.exists()) {
+				appendDeletedSubdirectory(subDir);
+				continue;
+			}
+			//populateFragmentMakefile(subDir);    //  See below
+			checkCancel();
+		}
+
+		// Recreate all module makefiles
+		// NOTE WELL: For now, always recreate all of the fragment makefile.  This is necessary
+		//     in order to re-populate the buildVariable lists.  In the future, the list could
+		//     possibly segmented by subdir so that all fragments didn't need to be
+		//     regenerated
+		for (IResource res : getSubdirList()) {
+			IContainer subDir = (IContainer) res;
+			try {
+				populateFragmentMakefile(subDir);
+			} catch (CoreException e) {
+				// Probably should ask user if they want to continue
+				checkCancel();
+				continue;
+			}
+			checkCancel();
+		}
+
+		// Calculate the inputs and outputs of the Tools to be generated in the main makefile
+		calculateToolInputsOutputs();
+		checkCancel();
+
+		// Re-create the top-level makefile
+		IPath makefilePath = topBuildDir.append(MAKEFILE_NAME);
+		IFile makefileHandle = createFile(makefilePath);
+		populateTopMakefile(makefileHandle, false);
+		checkCancel();
+
+		// Remove deleted folders from generated build directory
+		for (IResource res : getDeletedDirList()) {
+			IContainer subDir = (IContainer) res;
+			removeGeneratedDirectory(subDir);
+			checkCancel();
+		}
+
+		// How did we do
+		if (!getInvalidDirList().isEmpty()) {
+			status = new MultiStatus(ManagedBuilderCorePlugin.getUniqueIdentifier(), IStatus.WARNING, "", //$NON-NLS-1$
+					null);
+			// Add a new status for each of the bad folders
+			// TODO: fix error message
+			for (IResource res : getInvalidDirList()) {
+				IContainer subDir = (IContainer) res;
+				status.add(new Status(IStatus.WARNING, ManagedBuilderCorePlugin.getUniqueIdentifier(), SPACES_IN_PATH,
+						subDir.getFullPath().toString(), null));
+			}
+		} else {
+			status = new MultiStatus(ManagedBuilderCorePlugin.getUniqueIdentifier(), IStatus.OK, "", //$NON-NLS-1$
+					null);
+		}
+
+		return status;
+	}
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.cdt.managedbuilder.makegen.IManagedBuilderMakefileGenerator#getBuildWorkingDir()
+	 */
+	@Override
+	public IPath getBuildWorkingDir() {
+		if (topBuildDir != null) {
+			return topBuildDir.removeFirstSegments(1);
+		}
+		return null;
+	}
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.cdt.managedbuilder.makegen.IManagedBuilderMakefileGenerator#getMakefileName()
+	 */
+	@Override
+	public String getMakefileName() {
+		return MAKEFILE_NAME;
+	}
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.cdt.managedbuilder.makegen.IManagedBuilderMakefileGenerator#isGeneratedResource(org.eclipse.core.resources.IResource)
+	 */
+	@Override
+	public boolean isGeneratedResource(IResource resource) {
+		// Is this a generated directory ...
+		IPath path = resource.getProjectRelativePath();
+		//TODO: fix to use builder output dir instead
+		String[] configNames = ManagedBuildManager.getBuildInfo(project).getConfigurationNames();
+		for (String name : configNames) {
+			IPath pathOfConfig = computeTopBuildDir(name);
+			if (pathOfConfig.isPrefixOf(path)) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+	private static void save(StringBuffer buffer, IFile file) throws CoreException {
+		String encoding = null;
+		try {
+			encoding = file.getCharset();
+		} catch (CoreException ce) {
+			// use no encoding
+		}
+
+		byte[] bytes = null;
+		if (encoding != null) {
+			try {
+				bytes = buffer.toString().getBytes(encoding);
+			} catch (Exception e) {
+			}
+		} else {
+			bytes = buffer.toString().getBytes();
+		}
+
+		byte[] oldBytes = null;
+		try (InputStream is = file.getContents(true)) {
+			oldBytes = is.readAllBytes();
+		} catch (IOException e) {
+		}
+
+		// Only write file if content differs
+		if (!Arrays.equals(oldBytes, bytes)) {
+			ByteArrayInputStream stream = new ByteArrayInputStream(bytes);
+			// use a platform operation to update the resource contents
+			boolean force = true;
+			file.setContents(stream, force, false, null); // Don't record history
+		}
+	}
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.cdt.managedbuilder.makegen.IManagedBuilderMakefileGenerator#regenerateDependencies()
+	 */
+	@Override
+	public void regenerateDependencies(boolean force) throws CoreException {
+		// A hack for the pre-3.x GCC compilers is to put dummy targets for deps
+		final IWorkspaceRoot root = CCorePlugin.getWorkspace().getRoot();
+		final CoreException[] es = new CoreException[1];
+
+		toolInfos.accept(new IPathSettingsContainerVisitor() {
+			@Override
+			public boolean visit(PathSettingsContainer container) {
+				ToolInfoHolder h = (ToolInfoHolder) container.getValue();
+				// Collect the methods that will need to be called
+				Vector<String> depExts = new Vector<>(); //  Vector of dependency file extensions
+				IManagedDependencyGenerator2[] postProcessors = new IManagedDependencyGenerator2[h.buildTools.length];
+				boolean callPopulateDummyTargets = collectDependencyGeneratorInformation(h, depExts, postProcessors);
+
+				// Is there anyone to call if we do find dependency files?
+				if (!callPopulateDummyTargets) {
+					int i;
+					for (i = 0; i < postProcessors.length; i++) {
+						if (postProcessors[i] != null)
+							break;
+					}
+					if (i == postProcessors.length)
+						return true;
+				}
+
+				IResourceInfo rcInfo = config.getResourceInfo(container.getPath(), false);
+				for (IPath path : getDependencyMakefiles(h)) {
+					// The path to search for the dependency makefile
+					IPath relDepFilePath = topBuildDir.append(path);
+					IFile depFile = root.getFile(relDepFilePath);
+					if (depFile == null || !depFile.isAccessible())
+						continue;
+					try {
+						callDependencyPostProcessors(rcInfo, h, depFile, postProcessors, callPopulateDummyTargets,
+								true);
+					} catch (CoreException e) {
+						es[0] = e;
+						return false;
+					}
+				}
+				return true;
+			}
+		});
+
+		if (es[0] != null)
+			throw es[0];
+	}
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.cdt.managedbuilder.makegen.IManagedBuilderMakefileGenerator#regenerateMakefiles()
+	 */
+	@Override
+	public MultiStatus regenerateMakefiles() throws CoreException {
+		MultiStatus status;
+		// Visit the resources in the project
+		ResourceProxyVisitor visitor = new ResourceProxyVisitor(this, config);
+		project.accept(visitor, IResource.NONE);
+
+		// See if the user has cancelled the build
+		checkCancel();
+
+		// Populate the makefile if any buildable source files have been found in the project
+		if (getSubdirList().isEmpty()) {
+			String info = ManagedMakeMessages.getFormattedString("MakefileGenerator.warning.no.source", //$NON-NLS-1$
+					project.getName());
+			updateMonitor(info);
+			status = new MultiStatus(ManagedBuilderCorePlugin.getUniqueIdentifier(), IStatus.INFO, "", //$NON-NLS-1$
+					null);
+			status.add(new Status(IStatus.INFO, ManagedBuilderCorePlugin.getUniqueIdentifier(), NO_SOURCE_FOLDERS, info,
+					null));
+			return status;
+		}
+
+		// Create the top-level directory for the build output
+		ensureTopBuildDir();
+		checkCancel();
+
+		// Get the list of subdirectories
+		IPath srcsFilePath = topBuildDir.append(SRCSFILE_NAME);
+		IFile srcsFileHandle = createFile(srcsFilePath);
+		buildSrcVars.clear();
+		buildOutVars.clear();
+		buildDepVars.clear();
+		topBuildOutVars.clear();
+		populateSourcesMakefile(srcsFileHandle);
+		checkCancel();
+
+		// Now populate the module makefiles
+		for (IResource res : getSubdirList()) {
+			IContainer subDir = (IContainer) res;
+			try {
+				populateFragmentMakefile(subDir);
+			} catch (CoreException e) {
+				// Probably should ask user if they want to continue
+				checkCancel();
+				continue;
+			}
+			checkCancel();
+		}
+
+		// Calculate the inputs and outputs of the Tools to be generated in the main makefile
+		calculateToolInputsOutputs();
+		checkCancel();
+
+		// Create the top-level makefile
+		IPath makefilePath = topBuildDir.append(MAKEFILE_NAME);
+		IFile makefileHandle = createFile(makefilePath);
+		populateTopMakefile(makefileHandle, true);
+		checkCancel();
+
+		// Now finish up by adding all the object files
+		IPath objFilePath = topBuildDir.append(OBJECTS_MAKFILE);
+		IFile objsFileHandle = createFile(objFilePath);
+		populateObjectsMakefile(objsFileHandle);
+		checkCancel();
+
+		// How did we do
+		if (!getInvalidDirList().isEmpty()) {
+			status = new MultiStatus(ManagedBuilderCorePlugin.getUniqueIdentifier(), IStatus.WARNING, "", //$NON-NLS-1$
+					null);
+			// Add a new status for each of the bad folders
+			// TODO: fix error message
+			for (IResource dir : getInvalidDirList()) {
+				status.add(new Status(IStatus.WARNING, ManagedBuilderCorePlugin.getUniqueIdentifier(), SPACES_IN_PATH,
+						dir.getFullPath().toString(), null));
+			}
+		} else {
+			status = new MultiStatus(ManagedBuilderCorePlugin.getUniqueIdentifier(), IStatus.OK, "", //$NON-NLS-1$
+					null);
+		}
+		return status;
+	}
+
+	/*************************************************************************
+	 *   M A K E F I L E S   P O P U L A T I O N   M E T H O D S
+	 ************************************************************************/
+
+	/**
+	 * This method generates a "fragment" make file (subdir.mk).
+	 * One of these is generated for each project directory/subdirectory
+	 * that contains source files.
+	 */
+	protected void populateFragmentMakefile(IContainer module) throws CoreException {
+		// Calculate the new directory relative to the build output
+		IPath moduleRelativePath = module.getProjectRelativePath();
+		IPath buildRoot = getBuildWorkingDir();
+		if (buildRoot == null) {
+			return;
+		}
+
+		IPath moduleOutputPath = buildRoot.append(moduleRelativePath);
+		updateMonitor(ManagedMakeMessages.getFormattedString("MakefileGenerator.message.gen.source.makefile", //$NON-NLS-1$
+				moduleOutputPath.toString()));
+
+		// Now create the directory
+		IPath moduleOutputDir = createDirectory(moduleOutputPath.toString());
+
+		// Create a module makefile
+		IFile modMakefile = createFile(moduleOutputDir.append(MODFILE_NAME));
+		StringBuffer makeBuf = new StringBuffer();
+		makeBuf.append(addFragmentMakefileHeader());
+		makeBuf.append(addSources(module));
+
+		// Save the files
+		save(makeBuf, modMakefile);
+	}
+
+	/**
+	 * The makefile generator generates a Macro for each type of output, other than final artifact,
+	 * created by the build.
+	 *
+	 * @param fileHandle The file that should be populated with the output
+	 */
+	protected void populateObjectsMakefile(IFile fileHandle) throws CoreException {
+
+		// Master list of "object" dependencies, i.e. dependencies between input files and output files.
+		StringBuffer macroBuffer = new StringBuffer();
+		List<String> valueList;
+		macroBuffer.append(addDefaultHeader());
+
+		// Map of macro names (String) to its definition (List of Strings)
+		HashMap<String, List<String>> outputMacros = new HashMap<>();
+
+		// Add the predefined LIBS, USER_OBJS macros
+
+		// Add the libraries this project depends on
+		valueList = new ArrayList<>();
+		String[] libs = config.getLibs(buildTargetExt);
+		for (String lib : libs) {
+			valueList.add(lib);
+		}
+		outputMacros.put("LIBS", valueList); //$NON-NLS-1$
+
+		// Add the extra user-specified objects
+		valueList = new ArrayList<>();
+		String[] userObjs = config.getUserObjects(buildTargetExt);
+		for (String obj : userObjs) {
+			valueList.add(obj);
+		}
+		outputMacros.put("USER_OBJS", valueList); //$NON-NLS-1$
+
+		//  Write every macro to the file
+		for (Entry<String, List<String>> entry : outputMacros.entrySet()) {
+			macroBuffer.append(entry.getKey()).append(" :="); //$NON-NLS-1$
+			valueList = entry.getValue();
+			for (String path : valueList) {
+				// These macros will also be used within commands.
+				// Make all the slashes go forward so they aren't
+				// interpreted as escapes and get lost.
+				// See https://bugs.eclipse.org/163672.
+				path = path.replace('\\', '/');
+
+				path = ensurePathIsGNUMakeTargetRuleCompatibleSyntax(path);
+
+				macroBuffer.append(WHITESPACE);
+				macroBuffer.append(path);
+			}
+			// terminate the macro definition line
+			macroBuffer.append(NEWLINE);
+			// leave a blank line before the next macro
+			macroBuffer.append(NEWLINE);
+		}
+
+		// For now, just save the buffer that was populated when the rules were created
+		save(macroBuffer, fileHandle);
+
+	}
+
+	protected void populateSourcesMakefile(IFile fileHandle) throws CoreException {
+		// Add the comment
+		StringBuffer buffer = addDefaultHeader();
+
+		// Determine the set of macros
+		toolInfos.accept(new IPathSettingsContainerVisitor() {
+
+			@Override
+			public boolean visit(PathSettingsContainer container) {
+				ToolInfoHolder h = (ToolInfoHolder) container.getValue();
+				ITool[] buildTools = h.buildTools;
+				HashSet<String> handledInputExtensions = new HashSet<>();
+				String buildMacro;
+				for (ITool buildTool : buildTools) {
+					if (buildTool.getCustomBuildStep())
+						continue;
+					// Add the known sources macros
+					String[] extensionsList = buildTool.getAllInputExtensions();
+					for (String ext : extensionsList) {
+						// create a macro of the form "EXTENSION_SRCS :="
+						String extensionName = ext;
+						if (//!getOutputExtensions().contains(extensionName) &&
+						!handledInputExtensions.contains(extensionName)) {
+							handledInputExtensions.add(extensionName);
+							buildMacro = getSourceMacroName(extensionName).toString();
+							if (!buildSrcVars.containsKey(buildMacro)) {
+								buildSrcVars.put(buildMacro, new ArrayList<IPath>());
+							}
+							// Add any generated dependency file macros
+							IManagedDependencyGeneratorType depType = buildTool
+									.getDependencyGeneratorForExtension(extensionName);
+							if (depType != null) {
+								int calcType = depType.getCalculatorType();
+								if (calcType == IManagedDependencyGeneratorType.TYPE_COMMAND
+										|| calcType == IManagedDependencyGeneratorType.TYPE_BUILD_COMMANDS
+										|| calcType == IManagedDependencyGeneratorType.TYPE_PREBUILD_COMMANDS) {
+									buildMacro = getDepMacroName(extensionName).toString();
+									if (!buildDepVars.containsKey(buildMacro)) {
+										buildDepVars.put(buildMacro, new GnuDependencyGroupInfo(buildMacro,
+												(calcType != IManagedDependencyGeneratorType.TYPE_PREBUILD_COMMANDS)));
+									}
+									if (!buildOutVars.containsKey(buildMacro)) {
+										buildOutVars.put(buildMacro, new ArrayList<IPath>());
+									}
+								}
+							}
+						}
+					}
+					// Add the specified output build variables
+					IOutputType[] outTypes = buildTool.getOutputTypes();
+					if (outTypes != null && outTypes.length > 0) {
+						for (IOutputType outputType : outTypes) {
+							buildMacro = outputType.getBuildVariable();
+							if (!buildOutVars.containsKey(buildMacro)) {
+								buildOutVars.put(buildMacro, new ArrayList<IPath>());
+							}
+						}
+					} else {
+						// For support of pre-CDT 3.0 integrations.
+						buildMacro = OBJS_MACRO;
+						if (!buildOutVars.containsKey(buildMacro)) {
+							buildOutVars.put(buildMacro, new ArrayList<IPath>());
+						}
+					}
+				}
+				return true;
+			}
+		});
+		// Add the macros to the makefile
+		for (Entry<String, List<IPath>> entry : buildSrcVars.entrySet()) {
+			String macroName = entry.getKey();
+			buffer.append(macroName).append(WHITESPACE).append(":=").append(WHITESPACE).append(NEWLINE); //$NON-NLS-1$
+		}
+		Set<Entry<String, List<IPath>>> set = buildOutVars.entrySet();
+		for (Entry<String, List<IPath>> entry : set) {
+			String macroName = entry.getKey();
+			buffer.append(macroName).append(WHITESPACE).append(":=").append(WHITESPACE).append(NEWLINE); //$NON-NLS-1$
+		}
+
+		// Add a list of subdirectories to the makefile
+		buffer.append(NEWLINE).append(addSubdirectories());
+
+		// Save the file
+		save(buffer, fileHandle);
+	}
+
+	/**
+	 * Create the entire contents of the makefile.
+	 *
+	 * @param fileHandle The file to place the contents in.
+	 * @param rebuild FLag signaling that the user is doing a full rebuild
+	 */
+	protected void populateTopMakefile(IFile fileHandle, boolean rebuild) throws CoreException {
+		StringBuffer buffer = new StringBuffer();
+
+		// Add the header
+		buffer.append(addTopHeader());
+
+		// Add the macro definitions
+		buffer.append(addMacros());
+
+		// List to collect needed build output variables
+		List<String> outputVarsAdditionsList = new ArrayList<>();
+
+		// Determine target rules
+		StringBuffer targetRules = addTargets(outputVarsAdditionsList, rebuild);
+
+		// Add outputMacros that were added to by the target rules
+		buffer.append(writeTopAdditionMacros(outputVarsAdditionsList, getTopBuildOutputVars()));
+
+		// Add target rules
+		buffer.append(targetRules);
+
+		// Save the file
+		save(buffer, fileHandle);
+	}
+
+	/*************************************************************************
+	 *   M A I N (makefile)   M A K E F I L E   M E T H O D S
+	 ************************************************************************/
+
+	/**
+	 * Answers a <code>StringBuffer</code> containing the comment(s)
+	 * for the top-level makefile.
+	 */
+	protected StringBuffer addTopHeader() {
+		return addDefaultHeader();
+	}
+
+	/**
+	 */
+	private StringBuffer addMacros() {
+		StringBuffer buffer = new StringBuffer();
+
+		// Add the ROOT macro
+		//buffer.append("ROOT := ..").append(NEWLINE); //$NON-NLS-1$
+		//buffer.append(NEWLINE);
+
+		// include makefile.init supplementary makefile
+		buffer.append("-include " + reachProjectRoot() + SEPARATOR + MAKEFILE_INIT).append(NEWLINE); //$NON-NLS-1$
+		buffer.append(NEWLINE);
+
+		// Get the clean command from the build model
+		buffer.append("RM := "); //$NON-NLS-1$
+
+		// support macros in the clean command
+		String cleanCommand = config.getCleanCommand();
+
+		try {
+			cleanCommand = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(
+					config.getCleanCommand(), EMPTY_STRING, WHITESPACE, IBuildMacroProvider.CONTEXT_CONFIGURATION,
+					config);
+		} catch (BuildMacroException e) {
+		}
+
+		buffer.append(cleanCommand).append(NEWLINE);
+
+		buffer.append(NEWLINE);
+
+		// Now add the source providers
+		buffer.append(COMMENT_SYMBOL).append(WHITESPACE).append(ManagedMakeMessages.getResourceString(SRC_LISTS))
+				.append(NEWLINE);
+		buffer.append("-include sources.mk").append(NEWLINE); //$NON-NLS-1$
+
+		// Add includes for each subdir in child-subdir-first order (required for makefile rule matching to work).
+		List<String> subDirList = new ArrayList<>();
+		for (IContainer subDir : getSubdirList()) {
+			String projectRelativePath = subDir.getProjectRelativePath().toString();
+			if (!projectRelativePath.isEmpty())
+				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 subdir.mk").append(NEWLINE); //$NON-NLS-1$
+
+		buffer.append("-include objects.mk").append(NEWLINE).append(NEWLINE); //$NON-NLS-1$
+
+		// Include generated dependency makefiles if non-empty AND a "clean" has not been requested
+		if (!buildDepVars.isEmpty()) {
+			buffer.append("ifneq ($(MAKECMDGOALS),clean)").append(NEWLINE); //$NON-NLS-1$
+
+			for (Entry<String, GnuDependencyGroupInfo> entry : buildDepVars.entrySet()) {
+				String depsMacro = entry.getKey();
+				GnuDependencyGroupInfo info = entry.getValue();
+				buffer.append("ifneq ($(strip $(").append(depsMacro).append(")),)").append(NEWLINE); //$NON-NLS-1$ //$NON-NLS-2$
+				if (info.conditionallyInclude) {
+					buffer.append("-include $(").append(depsMacro).append(')').append(NEWLINE); //$NON-NLS-1$
+				} else {
+					buffer.append("include $(").append(depsMacro).append(')').append(NEWLINE); //$NON-NLS-1$
+				}
+				buffer.append("endif").append(NEWLINE); //$NON-NLS-1$
+			}
+
+			buffer.append("endif").append(NEWLINE).append(NEWLINE); //$NON-NLS-1$
+		}
+
+		// Include makefile.defs supplemental makefile
+		buffer.append("-include ").append(reachProjectRoot()).append(SEPARATOR).append(MAKEFILE_DEFS).append(NEWLINE); //$NON-NLS-1$
+
+		final String wildcardFileFmt = "$(wildcard %s)" + WHITESPACE + LINEBREAK; //$NON-NLS-1$
+		buffer.append(NEWLINE).append("OPTIONAL_TOOL_DEPS :=").append(WHITESPACE).append(LINEBREAK); //$NON-NLS-1$
+		buffer.append(String.format(wildcardFileFmt, reachProjectRoot() + SEPARATOR + MAKEFILE_DEFS));
+		buffer.append(String.format(wildcardFileFmt, reachProjectRoot() + SEPARATOR + MAKEFILE_INIT));
+		buffer.append(String.format(wildcardFileFmt, reachProjectRoot() + SEPARATOR + MAKEFILE_TARGETS));
+		buffer.append(NEWLINE);
+
+		String ext = config.getArtifactExtension();
+		// try to resolve the build macros in the artifact extension
+		try {
+			ext = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(ext, EMPTY_STRING,
+					WHITESPACE, IBuildMacroProvider.CONTEXT_CONFIGURATION, config);
+		} catch (BuildMacroException e) {
+		}
+
+		String name = config.getArtifactName();
+		// try to resolve the build macros in the artifact name
+		try {
+			String resolved = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(name,
+					EMPTY_STRING, WHITESPACE, IBuildMacroProvider.CONTEXT_CONFIGURATION, config);
+			if ((resolved = resolved.trim()).length() > 0) {
+				name = resolved;
+			}
+		} catch (BuildMacroException e) {
+		}
+
+		String prefix = EMPTY_STRING;
+		ITool targetTool = config.calculateTargetTool();
+		if (targetTool != null) {
+			prefix = targetTool.getOutputPrefix();
+			if (prefix == null) {
+				prefix = EMPTY_STRING;
+			}
+		}
+		// try to resolve the build macros in the artifact prefix
+		try {
+			String resolved = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(prefix,
+					EMPTY_STRING, WHITESPACE, IBuildMacroProvider.CONTEXT_CONFIGURATION, config);
+			if ((resolved = resolved.trim()).length() > 0) {
+				prefix = resolved;
+			}
+		} catch (BuildMacroException e) {
+		}
+
+		@SuppressWarnings("nls")
+		String[][] buildArtifactVars = new String[][] { //
+				{ "BUILD_ARTIFACT_NAME", name }, //
+				{ "BUILD_ARTIFACT_EXTENSION", ext }, //
+				{ "BUILD_ARTIFACT_PREFIX", prefix }, //
+				{ "BUILD_ARTIFACT",
+						"$(BUILD_ARTIFACT_PREFIX)$(BUILD_ARTIFACT_NAME)$(if $(BUILD_ARTIFACT_EXTENSION),.$(BUILD_ARTIFACT_EXTENSION),)" }, //
+		};
+
+		buffer.append(NEWLINE);
+		for (String[] var : buildArtifactVars) {
+			buffer.append(var[0]).append(" :="); //$NON-NLS-1$
+			if (!var[1].isEmpty()) {
+				buffer.append(WHITESPACE).append(var[1]);
+			}
+			buffer.append(NEWLINE);
+		}
+
+		return (buffer.append(NEWLINE));
+	}
+
+	/**
+	 * Answers a <code>StringBuffer</code> containing all of the required targets to
+	 * properly build the project.
+	 *
+	 * @param outputVarsAdditionsList  list to add needed build output variables to
+	 */
+	private StringBuffer addTargets(List<String> outputVarsAdditionsList, boolean rebuild) {
+		StringBuffer buffer = new StringBuffer();
+
+		//		IConfiguration config = info.getDefaultConfiguration();
+
+		// Assemble the information needed to generate the targets
+		String prebuildStep = config.getPrebuildStep();
+		try {
+			//try to resolve the build macros in the prebuild step
+			prebuildStep = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(prebuildStep,
+					EMPTY_STRING, WHITESPACE, IBuildMacroProvider.CONTEXT_CONFIGURATION, config);
+		} catch (BuildMacroException e) {
+		}
+		prebuildStep = prebuildStep.trim(); // Remove leading and trailing whitespace (and control characters)
+
+		String postbuildStep = config.getPostbuildStep();
+		try {
+			//try to resolve the build macros in the postbuild step
+			postbuildStep = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(postbuildStep,
+					EMPTY_STRING, WHITESPACE, IBuildMacroProvider.CONTEXT_CONFIGURATION, config);
+
+		} catch (BuildMacroException e) {
+		}
+		postbuildStep = postbuildStep.trim(); // Remove leading and trailing whitespace (and control characters)
+		String preannouncebuildStep = config.getPreannouncebuildStep();
+		String postannouncebuildStep = config.getPostannouncebuildStep();
+		String targets = rebuild ? "clean all" : "all"; //$NON-NLS-1$ //$NON-NLS-2$
+
+		ITool targetTool = config.calculateTargetTool();
+		//		if (targetTool == null) {
+		//			targetTool = info.getToolFromOutputExtension(buildTargetExt);
+		//		}
+
+		// Get all the projects the build target depends on
+		// If this configuration produces a static archive, building the archive doesn't depend on the output
+		// from any of the referenced configurations
+		IConfiguration[] refConfigs = new IConfiguration[0];
+		if (config.getBuildArtefactType() == null || !ManagedBuildManager.BUILD_ARTEFACT_TYPE_PROPERTY_STATICLIB
+				.equals(config.getBuildArtefactType().getId()))
+			refConfigs = ManagedBuildManager.getReferencedConfigurations(config);
+
+		// Add the comment for the "All" target
+		buffer.append(COMMENT_SYMBOL).append(WHITESPACE).append(ManagedMakeMessages.getResourceString(ALL_TARGET))
+				.append(NEWLINE);
+
+		if (!prebuildStep.isEmpty() || !postbuildStep.isEmpty()) {
+			// all:
+			buffer.append("all").append(COLON).append(NEWLINE); //$NON-NLS-1$
+
+			String makeNoPrintDir = MAKE + WHITESPACE + NO_PRINT_DIR + WHITESPACE;
+			buffer.append(TAB).append("+@"); //$NON-NLS-1$
+			if (!prebuildStep.isEmpty()) {
+				buffer.append(makeNoPrintDir).append(PREBUILD).append(WHITESPACE).append(LOGICAL_AND)
+						.append(WHITESPACE);
+			}
+			buffer.append(makeNoPrintDir).append(MAINBUILD);
+			if (!postbuildStep.isEmpty()) {
+				buffer.append(WHITESPACE).append(LOGICAL_AND).append(WHITESPACE).append(makeNoPrintDir)
+						.append(POSTBUILD);
+			}
+
+			buffer.append(NEWLINE);
+
+		} else {
+			// all: main-build
+			buffer.append("all").append(COLON).append(WHITESPACE).append(MAINBUILD).append(NEWLINE); //$NON-NLS-1$
+		}
+		buffer.append(NEWLINE);
+
+		// Add the comment for the "main-build" target
+		buffer.append(COMMENT_SYMBOL).append(WHITESPACE).append(ManagedMakeMessages.getResourceString(MAINBUILD_TARGET))
+				.append(NEWLINE);
+
+		// Write out the main-build target first in case someone just runs make
+		// main-build: <target_name>
+
+		String outputPrefix = EMPTY_STRING;
+		if (targetTool != null) {
+			outputPrefix = targetTool.getOutputPrefix();
+		}
+		buffer.append(MAINBUILD).append(COLON).append(WHITESPACE).append(outputPrefix)
+				.append(ensurePathIsGNUMakeTargetRuleCompatibleSyntax(buildTargetName));
+		if (buildTargetExt.length() > 0) {
+			buffer.append(DOT).append(buildTargetExt);
+		}
+
+		// Add the Secondary Outputs to the all target, if any
+		IOutputType[] secondaryOutputs = config.getToolChain().getSecondaryOutputs();
+		if (secondaryOutputs.length > 0) {
+			buffer.append(WHITESPACE).append(SECONDARY_OUTPUTS);
+		}
+
+		buffer.append(NEWLINE).append(NEWLINE);
+
+		/*
+		 * The build target may depend on other projects in the workspace. These
+		 * are captured in the deps target: deps: <cd <Proj_Dep_1/build_dir>;
+		 * $(MAKE) [clean all | all]>
+		 */
+		//		Vector managedProjectOutputs = new Vector(refdProjects.length);
+		//		if (refdProjects.length > 0) {
+		Vector<String> managedProjectOutputs = new Vector<>(refConfigs.length);
+		if (refConfigs.length > 0) {
+			boolean addDeps = true;
+			//			if (refdProjects != null) {
+			for (IConfiguration depCfg : refConfigs) {
+				//					IProject dep = refdProjects[i];
+				if (!depCfg.isManagedBuildOn())
+					continue;
+
+				//					if (!dep.exists()) continue;
+				if (addDeps) {
+					buffer.append("dependents:").append(NEWLINE); //$NON-NLS-1$
+					addDeps = false;
+				}
+				String buildDir = depCfg.getOwner().getLocation().toString();
+				String depTargets = targets;
+				//					if (ManagedBuildManager.manages(dep)) {
+				// Add the current configuration to the makefile path
+				//						IManagedBuildInfo depInfo = ManagedBuildManager.getBuildInfo(dep);
+				buildDir += SEPARATOR + depCfg.getName();
+
+				// Extract the build artifact to add to the dependency list
+				String depTarget = depCfg.getArtifactName();
+				String depExt = depCfg.getArtifactExtension();
+
+				try {
+					//try to resolve the build macros in the artifact extension
+					depExt = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(depExt, "", //$NON-NLS-1$
+							" ", //$NON-NLS-1$
+							IBuildMacroProvider.CONTEXT_CONFIGURATION, depCfg);
+				} catch (BuildMacroException e) {
+				}
+
+				try {
+					//try to resolve the build macros in the artifact name
+					String resolved = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(
+							depTarget, "", //$NON-NLS-1$
+							" ", //$NON-NLS-1$
+							IBuildMacroProvider.CONTEXT_CONFIGURATION, depCfg);
+					if ((resolved = resolved.trim()).length() > 0)
+						depTarget = resolved;
+				} catch (BuildMacroException e) {
+				}
+
+				String depPrefix = depCfg.getOutputPrefix(depExt);
+				if (depCfg.needsRebuild()) {
+					depTargets = "clean all"; //$NON-NLS-1$
+				}
+				String dependency = buildDir + SEPARATOR + depPrefix + depTarget;
+				if (depExt.length() > 0) {
+					dependency += DOT + depExt;
+				}
+				dependency = escapeWhitespaces(dependency);
+				managedProjectOutputs.add(dependency);
+				//}
+				buffer.append(TAB).append("-cd").append(WHITESPACE).append(escapeWhitespaces(buildDir)) //$NON-NLS-1$
+						.append(WHITESPACE).append(LOGICAL_AND).append(WHITESPACE).append("$(MAKE) ").append(depTargets) //$NON-NLS-1$
+						.append(NEWLINE);
+			}
+			//			}
+			buffer.append(NEWLINE);
+		}
+
+		// Add the targets tool rules
+		buffer.append(addTargetsRules(targetTool, outputVarsAdditionsList, managedProjectOutputs));
+
+		// Add the prebuild step target, if specified
+		if (prebuildStep.length() > 0) {
+			buffer.append(PREBUILD).append(COLON).append(NEWLINE);
+			if (preannouncebuildStep.length() > 0) {
+				buffer.append(TAB).append(DASH).append(AT).append(escapedEcho(preannouncebuildStep));
+			}
+			buffer.append(TAB).append(DASH).append(prebuildStep).append(NEWLINE);
+			buffer.append(TAB).append(DASH).append(AT).append(ECHO_BLANK_LINE).append(NEWLINE);
+		}
+
+		// Add the postbuild step, if specified
+		if (postbuildStep.length() > 0) {
+			buffer.append(POSTBUILD).append(COLON).append(NEWLINE);
+			if (postannouncebuildStep.length() > 0) {
+				buffer.append(TAB).append(DASH).append(AT).append(escapedEcho(postannouncebuildStep));
+			}
+			buffer.append(TAB).append(DASH).append(postbuildStep).append(NEWLINE);
+			buffer.append(TAB).append(DASH).append(AT).append(ECHO_BLANK_LINE).append(NEWLINE);
+		}
+
+		// Add the Secondary Outputs target, if needed
+		if (secondaryOutputs.length > 0) {
+			buffer.append(SECONDARY_OUTPUTS).append(COLON);
+			Vector<String> outs2 = calculateSecondaryOutputs(secondaryOutputs);
+			for (int i = 0; i < outs2.size(); i++) {
+				buffer.append(WHITESPACE).append("$(").append(outs2.get(i)).append(')'); //$NON-NLS-1$
+			}
+			buffer.append(NEWLINE).append(NEWLINE);
+		}
+
+		// Add all the needed dummy and phony targets
+		buffer.append(".PHONY: all clean dependents").append(WHITESPACE).append(MAINBUILD); //$NON-NLS-1$
+		if (prebuildStep.length() > 0) {
+			buffer.append(WHITESPACE).append(PREBUILD);
+		}
+		if (postbuildStep.length() > 0) {
+			buffer.append(WHITESPACE).append(POSTBUILD);
+		}
+		buffer.append(NEWLINE);
+		for (String output : managedProjectOutputs) {
+			buffer.append(output).append(COLON).append(NEWLINE);
+		}
+		buffer.append(NEWLINE);
+
+		// Include makefile.targets supplemental makefile
+		buffer.append("-include ").append(reachProjectRoot()).append(SEPARATOR).append(MAKEFILE_TARGETS) //$NON-NLS-1$
+				.append(NEWLINE);
+
+		return buffer;
+	}
+
+	/**
+	 * Returns the targets rules.  The targets make file (top makefile) contains:
+	 *  1  the rule for the final target tool
+	 *  2  the rules for all of the tools that use multipleOfType in their primary input type
+	 *  3  the rules for all tools that use the output of #2 tools
+	 *
+	 * @param outputVarsAdditionsList  list to add needed build output variables to
+	 * @param managedProjectOutputs  Other projects in the workspace that this project depends upon
+	 * @return StringBuffer
+	 */
+	private StringBuffer addTargetsRules(ITool targetTool, List<String> outputVarsAdditionsList,
+			Vector<String> managedProjectOutputs) {
+		StringBuffer buffer = new StringBuffer();
+		// Add the comment
+		buffer.append(COMMENT_SYMBOL).append(WHITESPACE).append(ManagedMakeMessages.getResourceString(BUILD_TOP))
+				.append(NEWLINE);
+
+		ToolInfoHolder h = (ToolInfoHolder) toolInfos.getValue();
+		ITool[] buildTools = h.buildTools;
+		boolean[] buildToolsUsed = h.buildToolsUsed;
+		//  Get the target tool and generate the rule
+		if (targetTool != null) {
+			// Note that the name of the target we pass to addRuleForTool does not
+			// appear to be used there (and tool outputs are consulted directly), but
+			// we quote it anyway just in case it starts to use it in future.
+			if (addRuleForTool(targetTool, buffer, true, ensurePathIsGNUMakeTargetRuleCompatibleSyntax(buildTargetName),
+					buildTargetExt, outputVarsAdditionsList, managedProjectOutputs, false)) {
+				//  Mark the target tool as processed
+				for (int i = 0; i < buildTools.length; i++) {
+					if (targetTool == buildTools[i]) {
+						buildToolsUsed[i] = true;
+					}
+				}
+			}
+		} else {
+			buffer.append(TAB).append(AT).append(escapedEcho(MESSAGE_NO_TARGET_TOOL + WHITESPACE + OUT_MACRO));
+		}
+
+		//  Generate the rules for all Tools that specify InputType.multipleOfType, and any Tools that
+		//  consume the output of those tools.  This does not apply to pre-3.0 integrations, since
+		//  the only "multipleOfType" tool is the "target" tool
+		for (int i = 0; i < buildTools.length; i++) {
+			ITool tool = buildTools[i];
+			IInputType type = tool.getPrimaryInputType();
+			if (type != null && type.getMultipleOfType()) {
+				if (!buildToolsUsed[i]) {
+					addRuleForTool(tool, buffer, false, null, null, outputVarsAdditionsList, null, false);
+					//  Mark the target tool as processed
+					buildToolsUsed[i] = true;
+					// Look for tools that consume the output
+					generateRulesForConsumers(tool, outputVarsAdditionsList, buffer);
+				}
+			}
+		}
+
+		// Add the comment
+		buffer.append(COMMENT_SYMBOL).append(WHITESPACE).append(ManagedMakeMessages.getResourceString(BUILD_TARGETS))
+				.append(NEWLINE);
+
+		// Always add a clean target
+		buffer.append("clean:").append(NEWLINE); //$NON-NLS-1$
+		buffer.append(TAB).append("-$(RM)").append(WHITESPACE); //$NON-NLS-1$
+		for (Entry<String, List<IPath>> entry : buildOutVars.entrySet()) {
+			String macroName = entry.getKey();
+			buffer.append("$(").append(macroName).append(')'); //$NON-NLS-1$
+		}
+		String outputPrefix = EMPTY_STRING;
+		if (targetTool != null) {
+			outputPrefix = targetTool.getOutputPrefix();
+		}
+		String completeBuildTargetName = outputPrefix + buildTargetName;
+		if (buildTargetExt.length() > 0) {
+			completeBuildTargetName = completeBuildTargetName + DOT + buildTargetExt;
+		}
+		if (completeBuildTargetName.contains(" ")) { //$NON-NLS-1$
+			buffer.append(WHITESPACE).append('"').append(completeBuildTargetName).append('"');
+		} else {
+			buffer.append(WHITESPACE).append(completeBuildTargetName);
+		}
+		buffer.append(NEWLINE);
+		buffer.append(TAB).append(DASH).append(AT).append(ECHO_BLANK_LINE).append(NEWLINE);
+
+		return buffer;
+	}
+
+	/**
+	 * @deprecated Use {@link #addRuleForTool(ITool, StringBuffer, boolean, String, String, List, Vector)}
+	 */
+	@Deprecated
+	protected boolean addRuleForTool(ITool tool, StringBuffer buffer, boolean bTargetTool, String targetName,
+			String targetExt, List<String> outputVarsAdditionsList, Vector<String> managedProjectOutputs,
+			boolean bEmitPostBuildStepCall) {
+		return addRuleForTool(tool, buffer, bTargetTool, targetName, targetExt, outputVarsAdditionsList,
+				managedProjectOutputs);
+	}
+
+	/**
+	 * Create the rule
+	 *
+	 * @param buffer  Buffer to add makefile rules to
+	 * @param bTargetTool True if this is the target tool
+	 * @param targetName  If this is the "targetTool", the target file name, else <code>null</code>
+	 * @param targetExt  If this is the "targetTool", the target file extension, else <code>null</code>
+	 * @param outputVarsAdditionsList  list to add needed build output variables to
+	 * @param managedProjectOutputs  Other projects in the workspace that this project depends upon
+	 * @since 9.3
+	 */
+	protected boolean addRuleForTool(ITool tool, StringBuffer buffer, boolean bTargetTool, String targetName,
+			String targetExt, List<String> outputVarsAdditionsList, Vector<String> managedProjectOutputs) {
+
+		//  Get the tool's inputs and outputs
+		Vector<String> inputs = new Vector<>();
+		Vector<String> dependencies = new Vector<>();
+		Vector<String> outputs = new Vector<>();
+		Vector<String> enumeratedPrimaryOutputs = new Vector<>();
+		Vector<String> enumeratedSecondaryOutputs = new Vector<>();
+		Vector<String> outputVariables = new Vector<>();
+		Vector<String> additionalTargets = new Vector<>();
+		String outputPrefix = EMPTY_STRING;
+
+		if (!getToolInputsOutputs(tool, inputs, dependencies, outputs, enumeratedPrimaryOutputs,
+				enumeratedSecondaryOutputs, outputVariables, additionalTargets, bTargetTool, managedProjectOutputs)) {
+			return false;
+		}
+
+		//  If we have no primary output, make all of the secondary outputs the primary output
+		if (enumeratedPrimaryOutputs.size() == 0) {
+			enumeratedPrimaryOutputs = enumeratedSecondaryOutputs;
+			enumeratedSecondaryOutputs.clear();
+		}
+
+		//  Add the output variables for this tool to our list
+		outputVarsAdditionsList.addAll(outputVariables);
+
+		//  Create the build rule
+		String buildRule = EMPTY_STRING;
+		String outflag = tool.getOutputFlag();
+
+		String primaryOutputs = EMPTY_STRING;
+		String primaryOutputsQuoted = EMPTY_STRING;
+		boolean first = true;
+		for (int i = 0; i < enumeratedPrimaryOutputs.size(); i++) {
+			String output = enumeratedPrimaryOutputs.get(i);
+			if (!first) {
+				primaryOutputs += WHITESPACE;
+				primaryOutputsQuoted += WHITESPACE;
+			}
+			first = false;
+			primaryOutputs += output;
+			primaryOutputsQuoted += ensurePathIsGNUMakeTargetRuleCompatibleSyntax(output);
+		}
+
+		buildRule += (primaryOutputsQuoted + COLON + WHITESPACE);
+
+		first = true;
+		String calculatedDependencies = EMPTY_STRING;
+		for (int i = 0; i < dependencies.size(); i++) {
+			String input = dependencies.get(i);
+			if (!first)
+				calculatedDependencies += WHITESPACE;
+			first = false;
+			calculatedDependencies += input;
+		}
+		buildRule += calculatedDependencies;
+		buildRule += WHITESPACE + MAKEFILE_NAME; // makefile itself
+		buildRule += WHITESPACE + OBJECTS_MAKFILE; // objects.mk
+		buildRule += WHITESPACE + "$(OPTIONAL_TOOL_DEPS)"; //$NON-NLS-1$ // Optional dep to generated makefile extension files
+
+		// We can't have duplicates in a makefile
+		if (getRuleList().contains(buildRule)) {
+		} else {
+			getRuleList().add(buildRule);
+			buffer.append(buildRule).append(NEWLINE);
+			if (bTargetTool) {
+				buffer.append(TAB).append(AT).append(escapedEcho(MESSAGE_START_BUILD + WHITESPACE + OUT_MACRO));
+			}
+			buffer.append(TAB).append(AT).append(escapedEcho(tool.getAnnouncement()));
+
+			// Get the command line for this tool invocation
+			String[] flags;
+			try {
+				flags = tool.getToolCommandFlags(null, null);
+			} catch (BuildException ex) {
+				// TODO  report error
+				flags = EMPTY_STRING_ARRAY;
+			}
+			String command = tool.getToolCommand();
+			try {
+				//try to resolve the build macros in the tool command
+				String resolvedCommand = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(
+						command, EMPTY_STRING, WHITESPACE, IBuildMacroProvider.CONTEXT_FILE,
+						new FileContextData(null, null, null, tool));
+				if ((resolvedCommand = resolvedCommand.trim()).length() > 0)
+					command = resolvedCommand;
+
+			} catch (BuildMacroException e) {
+			}
+			String[] cmdInputs = inputs.toArray(new String[inputs.size()]);
+			IManagedCommandLineGenerator gen = tool.getCommandLineGenerator();
+			IManagedCommandLineInfo cmdLInfo = gen.generateCommandLineInfo(tool, command, flags, outflag, outputPrefix,
+					primaryOutputs, cmdInputs, tool.getCommandLinePattern());
+
+			// The command to build
+			String buildCmd = null;
+			if (cmdLInfo == null) {
+				String toolFlags;
+				try {
+					toolFlags = tool.getToolCommandFlagsString(null, null);
+				} catch (BuildException ex) {
+					// TODO report error
+					toolFlags = EMPTY_STRING;
+				}
+				buildCmd = command + WHITESPACE + toolFlags + WHITESPACE + outflag + WHITESPACE + outputPrefix
+						+ primaryOutputs + WHITESPACE + IN_MACRO;
+			} else
+				buildCmd = cmdLInfo.getCommandLine();
+
+			// resolve any remaining macros in the command after it has been
+			// generated
+			try {
+				String resolvedCommand = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(
+						buildCmd, EMPTY_STRING, WHITESPACE, IBuildMacroProvider.CONTEXT_FILE,
+						new FileContextData(null, null, null, tool));
+				if ((resolvedCommand = resolvedCommand.trim()).length() > 0)
+					buildCmd = resolvedCommand;
+
+			} catch (BuildMacroException e) {
+			}
+
+			//buffer.append(TAB).append(AT).append(escapedEcho(buildCmd));
+			//buffer.append(TAB).append(AT).append(buildCmd);
+			buffer.append(TAB).append(buildCmd);
+
+			// TODO
+			// NOTE WELL:  Dependency file generation is not handled for this type of Tool
+
+			// Echo finished message
+			buffer.append(NEWLINE);
+			buffer.append(TAB).append(AT).append(
+					escapedEcho((bTargetTool ? MESSAGE_FINISH_BUILD : MESSAGE_FINISH_FILE) + WHITESPACE + OUT_MACRO));
+			buffer.append(TAB).append(AT).append(ECHO_BLANK_LINE);
+
+			// Just emit a blank line
+			buffer.append(NEWLINE);
+		}
+
+		// If we have secondary outputs, output dependency rules without commands
+		if (enumeratedSecondaryOutputs.size() > 0 || additionalTargets.size() > 0) {
+			String primaryOutput = enumeratedPrimaryOutputs.get(0);
+			Vector<String> addlOutputs = new Vector<>();
+			addlOutputs.addAll(enumeratedSecondaryOutputs);
+			addlOutputs.addAll(additionalTargets);
+			for (int i = 0; i < addlOutputs.size(); i++) {
+				String output = addlOutputs.get(i);
+				String depLine = output + COLON + WHITESPACE + primaryOutput + WHITESPACE + calculatedDependencies
+						+ NEWLINE;
+				if (!getDepLineList().contains(depLine)) {
+					getDepLineList().add(depLine);
+					buffer.append(depLine);
+				}
+			}
+			buffer.append(NEWLINE);
+		}
+		return true;
+	}
+
+	/**
+	 * @param outputVarsAdditionsList  list to add needed build output variables to
+	 * @param buffer  buffer to add rules to
+	 */
+	private void generateRulesForConsumers(ITool generatingTool, List<String> outputVarsAdditionsList,
+			StringBuffer buffer) {
+		//  Generate a build rule for any tool that consumes the output of this tool
+		ToolInfoHolder h = (ToolInfoHolder) toolInfos.getValue();
+		ITool[] buildTools = h.buildTools;
+		boolean[] buildToolsUsed = h.buildToolsUsed;
+		IOutputType[] outTypes = generatingTool.getOutputTypes();
+		for (IOutputType outType : outTypes) {
+			String[] outExts = outType.getOutputExtensions(generatingTool);
+			String outVariable = outType.getBuildVariable();
+			if (outExts != null) {
+				for (String outExt : outExts) {
+					for (int k = 0; k < buildTools.length; k++) {
+						ITool tool = buildTools[k];
+						if (!buildToolsUsed[k]) {
+							// Also has to match build variables if specified
+							IInputType inType = tool.getInputType(outExt);
+							if (inType != null) {
+								String inVariable = inType.getBuildVariable();
+								if ((outVariable == null && inVariable == null) || (outVariable != null
+										&& inVariable != null && outVariable.equals(inVariable))) {
+									if (addRuleForTool(buildTools[k], buffer, false, null, null,
+											outputVarsAdditionsList, null, false)) {
+										buildToolsUsed[k] = true;
+										// Look for tools that consume the output
+										generateRulesForConsumers(buildTools[k], outputVarsAdditionsList, buffer);
+									}
+								}
+							}
+						}
+					}
+				}
+			}
+		}
+	}
+
+	protected boolean getToolInputsOutputs(ITool tool, Vector<String> inputs, Vector<String> dependencies,
+			Vector<String> outputs, Vector<String> enumeratedPrimaryOutputs, Vector<String> enumeratedSecondaryOutputs,
+			Vector<String> outputVariables, Vector<String> additionalTargets, boolean bTargetTool,
+			Vector<String> managedProjectOutputs) {
+		ToolInfoHolder h = (ToolInfoHolder) toolInfos.getValue();
+		ITool[] buildTools = h.buildTools;
+		ManagedBuildGnuToolInfo[] gnuToolInfos = h.gnuToolInfos;
+		//  Get the information regarding the tool's inputs and outputs from the objects
+		//  created by calculateToolInputsOutputs
+		IManagedBuildGnuToolInfo toolInfo = null;
+		for (int i = 0; i < buildTools.length; i++) {
+			if (tool == buildTools[i]) {
+				toolInfo = gnuToolInfos[i];
+				break;
+			}
+		}
+		if (toolInfo == null)
+			return false;
+
+		//  Populate the output Vectors
+		inputs.addAll(toolInfo.getCommandInputs());
+		outputs.addAll(toolInfo.getCommandOutputs());
+		enumeratedPrimaryOutputs.addAll(toolInfo.getEnumeratedPrimaryOutputs());
+		enumeratedSecondaryOutputs.addAll(toolInfo.getEnumeratedSecondaryOutputs());
+		outputVariables.addAll(toolInfo.getOutputVariables());
+
+		Vector<String> unprocessedDependencies = toolInfo.getCommandDependencies();
+		for (String path : unprocessedDependencies) {
+			dependencies.add(ensurePathIsGNUMakeTargetRuleCompatibleSyntax(path));
+		}
+		additionalTargets.addAll(toolInfo.getAdditionalTargets());
+
+		if (bTargetTool && managedProjectOutputs != null) {
+			for (String output : managedProjectOutputs) {
+				dependencies.add(output);
+			}
+		}
+		return true;
+	}
+
+	protected Vector<String> calculateSecondaryOutputs(IOutputType[] secondaryOutputs) {
+		ToolInfoHolder h = (ToolInfoHolder) toolInfos.getValue();
+		ITool[] buildTools = h.buildTools;
+		Vector<String> buildVars = new Vector<>();
+		for (int i = 0; i < buildTools.length; i++) {
+			// Add the specified output build variables
+			IOutputType[] outTypes = buildTools[i].getOutputTypes();
+			if (outTypes != null && outTypes.length > 0) {
+				for (int j = 0; j < outTypes.length; j++) {
+					IOutputType outType = outTypes[j];
+					//  Is this one of the secondary outputs?
+					//  Look for an outputType with this ID, or one with a superclass with this id
+					thisType: for (int k = 0; k < secondaryOutputs.length; k++) {
+						IOutputType matchType = outType;
+						do {
+							if (matchType.getId().equals(secondaryOutputs[k].getId())) {
+								buildVars.add(outType.getBuildVariable());
+								break thisType;
+							}
+							matchType = matchType.getSuperClass();
+						} while (matchType != null);
+					}
+				}
+			}
+		}
+		return buildVars;
+	}
+
+	protected boolean isSecondaryOutputVar(ToolInfoHolder h, IOutputType[] secondaryOutputs, String varName) {
+		ITool[] buildTools = h.buildTools;
+		for (ITool buildTool : buildTools) {
+			// Add the specified output build variables
+			IOutputType[] outTypes = buildTool.getOutputTypes();
+			if (outTypes != null && outTypes.length > 0) {
+				for (IOutputType outType : outTypes) {
+					//  Is this one of the secondary outputs?
+					//  Look for an outputType with this ID, or one with a superclass with this id
+					for (IOutputType secondaryOutput : secondaryOutputs) {
+						IOutputType matchType = outType;
+						do {
+							if (matchType.getId().equals(secondaryOutput.getId())) {
+								if (outType.getBuildVariable().equals(varName)) {
+									return true;
+								}
+							}
+							matchType = matchType.getSuperClass();
+						} while (matchType != null);
+					}
+				}
+			}
+		}
+		return false;
+	}
+
+	/*************************************************************************
+	 *   S O U R C E S (sources.mk)   M A K E F I L E   M E T H O D S
+	 ************************************************************************/
+
+	private StringBuffer addSubdirectories() {
+		StringBuffer buffer = new StringBuffer();
+		// Add the comment
+		buffer.append(COMMENT_SYMBOL).append(WHITESPACE).append(ManagedMakeMessages.getResourceString(MOD_LIST))
+				.append(NEWLINE);
+
+		buffer.append("SUBDIRS := ").append(LINEBREAK); //$NON-NLS-1$
+
+		// Get all the module names
+		for (IResource container : getSubdirList()) {
+			updateMonitor(ManagedMakeMessages.getFormattedString("MakefileGenerator.message.adding.source.folder", //$NON-NLS-1$
+					container.getFullPath().toString()));
+			// Check the special case where the module is the project root
+			if (container.getFullPath() == project.getFullPath()) {
+				buffer.append(DOT).append(WHITESPACE).append(LINEBREAK);
+			} else {
+				IPath path = container.getProjectRelativePath();
+				buffer.append(escapeWhitespaces(path.toString())).append(WHITESPACE).append(LINEBREAK);
+			}
+		}
+
+		buffer.append(NEWLINE);
+		return buffer;
+	}
+
+	/*************************************************************************
+	 *   F R A G M E N T (subdir.mk)   M A K E F I L E   M E T H O D S
+	 ************************************************************************/
+
+	/**
+	 * Returns a <code>StringBuffer</code> containing the comment(s)
+	 * for a fragment makefile (subdir.mk).
+	 */
+	protected StringBuffer addFragmentMakefileHeader() {
+		return addDefaultHeader();
+	}
+
+	/**
+	 * Returns a <code>StringBuffer</code> containing makefile text for all of the sources
+	 * contributed by a container (project directory/subdirectory) to the fragement makefile
+	 *
+	 * @param module  project resource directory/subdirectory
+	 * @return StringBuffer  generated text for the fragement makefile
+	 */
+	protected StringBuffer addSources(IContainer module) throws CoreException {
+		// Calculate the new directory relative to the build output
+		IPath moduleRelativePath = module.getProjectRelativePath();
+		String relativePath = moduleRelativePath.toString();
+		relativePath += relativePath.length() == 0 ? "" : SEPARATOR; //$NON-NLS-1$
+
+		// For build macros in the configuration, create a map which will map them
+		// to a string which holds its list of sources.
+		LinkedHashMap<String, String> buildVarToRuleStringMap = new LinkedHashMap<>();
+
+		// Add statements that add the source files in this folder,
+		// and generated source files, and generated dependency files
+		// to the build macros
+		for (Entry<String, List<IPath>> entry : buildSrcVars.entrySet()) {
+			String macroName = entry.getKey();
+			addMacroAdditionPrefix(buildVarToRuleStringMap, macroName, null, false);
+
+		}
+		for (Entry<String, List<IPath>> entry : buildOutVars.entrySet()) {
+			String macroName = entry.getKey();
+			addMacroAdditionPrefix(buildVarToRuleStringMap, macroName, "./" + relativePath, false); //$NON-NLS-1$
+		}
+
+		// String buffers
+		StringBuffer buffer = new StringBuffer(); // Return buffer
+		StringBuffer ruleBuffer = new StringBuffer(
+				COMMENT_SYMBOL + WHITESPACE + ManagedMakeMessages.getResourceString(MOD_RULES) + NEWLINE);
+
+		// Visit the resources in this folder and add each one to a sources macro, and generate a build rule, if appropriate
+		IResource[] resources = module.members();
+
+		IResourceInfo rcInfo;
+		IFolder folder = project.getFolder(computeTopBuildDir(config.getName()));
+
+		for (IResource resource : resources) {
+			if (resource.getType() == IResource.FILE) {
+				// Check whether this resource is excluded from build
+				IPath rcProjRelPath = resource.getProjectRelativePath();
+				if (!isSource(rcProjRelPath))
+					continue;
+				rcInfo = config.getResourceInfo(rcProjRelPath, false);
+				//				if( (rcInfo.isExcluded()) )
+				//					continue;
+				addFragmentMakefileEntriesForSource(buildVarToRuleStringMap, ruleBuffer, folder, relativePath, resource,
+						getPathForResource(resource), rcInfo, null, false);
+			}
+		}
+
+		// Write out the macro addition entries to the buffer
+		buffer.append(writeAdditionMacros(buildVarToRuleStringMap));
+		return buffer.append(ruleBuffer).append(NEWLINE);
+	}
+
+	/* (non-Javadoc
+	 * Adds the entries for a particular source file to the fragment makefile
+	 *
+	 * @param buildVarToRuleStringMap  map of build variable names to the list of files assigned to the variable
+	 * @param ruleBuffer  buffer to add generated nmakefile text to
+	 * @param folder  the top level build output directory
+	 * @param relativePath  build output directory relative path of the current output directory
+	 * @param resource  the source file for this invocation of the tool - this may be null for a generated output
+	 * @param sourceLocation  the full path of the source
+	 * @param resConfig  the IResourceConfiguration associated with this file or null
+	 * @param varName  the build variable to add this invocation's outputs to
+	 *                   if <code>null</code>, use the file extension to find the name
+	 * @param generatedSource  if <code>true</code>, this file was generated by another tool in the tool-chain
+	 */
+	protected void addFragmentMakefileEntriesForSource(LinkedHashMap<String, String> buildVarToRuleStringMap,
+			StringBuffer ruleBuffer, IFolder folder, String relativePath, IResource resource, IPath sourceLocation,
+			IResourceInfo rcInfo, String varName, boolean generatedSource) {
+
+		//  Determine which tool, if any, builds files with this extension
+		String ext = sourceLocation.getFileExtension();
+		ITool tool = null;
+
+		//TODO: remove
+		//		IResourceConfiguration resConfig = null;
+		//		if(rcInfo instanceof IFileInfo){
+		//			resConfig = (IFileInfo)rcInfo;
+		//		}
+		//end remove
+
+		//  Use the tool from the resource configuration if there is one
+		if (rcInfo instanceof IFileInfo) {
+			IFileInfo fi = (IFileInfo) rcInfo;
+			ITool[] tools = fi.getToolsToInvoke();
+			if (tools != null && tools.length > 0) {
+				tool = tools[0];
+				//				if(!tool.getCustomBuildStep())
+				addToBuildVar(buildVarToRuleStringMap, ext, varName, relativePath, sourceLocation, generatedSource);
+			}
+		}
+
+		ToolInfoHolder h = getToolInfo(rcInfo.getPath());
+		ITool buildTools[] = h.buildTools;
+
+		//		if(tool == null){
+		//			for (int j=0; j<buildTools.length; j++) {
+		//				if (buildTools[j].buildsFileType(ext)) {
+		//					if (tool == null) {
+		//						tool = buildTools[j];
+		//					}
+		//					addToBuildVar(buildVarToRuleStringMap, ext, varName, relativePath, sourceLocation, generatedSource);
+		//					break;
+		//				}
+		//			}
+		//		}
+		//
+		//		if(tool == null && rcInfo.getPath().segmentCount() != 0){
+		if (tool == null) {
+			h = getToolInfo(Path.EMPTY);
+			buildTools = h.buildTools;
+
+			for (ITool buildTool : buildTools) {
+				if (buildTool.buildsFileType(ext)) {
+					tool = buildTool;
+					addToBuildVar(buildVarToRuleStringMap, ext, varName, relativePath, sourceLocation, generatedSource);
+					break;
+				}
+			}
+		}
+
+		if (tool != null) {
+			//  Generate the rule to build this source file
+			IInputType primaryInputType = tool.getPrimaryInputType();
+			IInputType inputType = tool.getInputType(ext);
+			if ((primaryInputType != null && !primaryInputType.getMultipleOfType())
+					|| (inputType == null && tool != config.calculateTargetTool())) {
+
+				// Try to add the rule for the file
+				Vector<IPath> generatedOutputs = new Vector<>(); //  IPath's - build directory relative
+				Vector<IPath> generatedDepFiles = new Vector<>(); //  IPath's - build directory relative or absolute
+				addRuleForSource(relativePath, ruleBuffer, resource, sourceLocation, rcInfo, generatedSource,
+						generatedDepFiles, generatedOutputs);
+
+				// If the rule generates a dependency file(s), add the file(s) to the variable
+				if (generatedDepFiles.size() > 0) {
+					for (int k = 0; k < generatedDepFiles.size(); k++) {
+						IPath generatedDepFile = generatedDepFiles.get(k);
+						addMacroAdditionFile(buildVarToRuleStringMap, getDepMacroName(ext).toString(),
+								(generatedDepFile.isAbsolute() ? "" : "./") + //$NON-NLS-1$ //$NON-NLS-2$
+										generatedDepFile.toString());
+					}
+				}
+
+				// If the generated outputs of this tool are input to another tool,
+				// 1. add the output to the appropriate macro
+				// 2. If the tool does not have multipleOfType input, generate the rule.
+
+				IOutputType outType = tool.getPrimaryOutputType();
+				String buildVariable = null;
+				if (outType != null) {
+					if (tool.getCustomBuildStep()) {
+						// TODO: This is somewhat of a hack since a custom build step
+						//       tool does not currently define a build variable
+						if (generatedOutputs.size() > 0) {
+							IPath firstOutput = generatedOutputs.get(0);
+							String firstExt = firstOutput.getFileExtension();
+							ToolInfoHolder tmpH = getFolderToolInfo(rcInfo.getPath());
+							ITool[] tmpBuildTools = tmpH.buildTools;
+							for (ITool tmpBuildTool : tmpBuildTools) {
+								if (tmpBuildTool.buildsFileType(firstExt)) {
+									String bV = tmpBuildTool.getPrimaryInputType().getBuildVariable();
+									if (bV.length() > 0) {
+										buildVariable = bV;
+										break;
+									}
+								}
+							}
+						}
+					} else {
+						buildVariable = outType.getBuildVariable();
+					}
+				} else {
+					// For support of pre-CDT 3.0 integrations.
+					buildVariable = OBJS_MACRO;
+				}
+
+				for (int k = 0; k < generatedOutputs.size(); k++) {
+					IPath generatedOutput;
+					IResource generateOutputResource;
+					if (generatedOutputs.get(k).isAbsolute()) {
+						// TODO:  Should we use relative paths when possible (e.g., see MbsMacroSupplier.calculateRelPath)
+						generatedOutput = generatedOutputs.get(k);
+						//  If this file has an absolute path, then the generateOutputResource will not be correct
+						//  because the file is not under the project.  We use this resource in the calls to the dependency generator
+						generateOutputResource = project.getFile(generatedOutput);
+					} else {
+						generatedOutput = getPathForResource(project).append(getBuildWorkingDir())
+								.append(generatedOutputs.get(k));
+						generateOutputResource = project.getFile(getBuildWorkingDir().append(generatedOutputs.get(k)));
+					}
+					IResourceInfo nextRcInfo;
+					if (rcInfo instanceof IFileInfo) {
+						nextRcInfo = config.getResourceInfo(rcInfo.getPath().removeLastSegments(1), false);
+					} else {
+						nextRcInfo = rcInfo;
+					}
+					addFragmentMakefileEntriesForSource(buildVarToRuleStringMap, ruleBuffer, folder, relativePath,
+							generateOutputResource, generatedOutput, nextRcInfo, buildVariable, true);
+				}
+			}
+		} else {
+			//  If this is a secondary input, add it to build vars
+			if (varName == null) {
+				for (ITool buildTool : buildTools) {
+					if (buildTool.isInputFileType(ext)) {
+						addToBuildVar(buildVarToRuleStringMap, ext, varName, relativePath, sourceLocation,
+								generatedSource);
+						break;
+					}
+				}
+			}
+			//  If this generated output is identified as a secondary output, add the file to the build variable
+			else {
+				IOutputType[] secondaryOutputs = config.getToolChain().getSecondaryOutputs();
+				if (secondaryOutputs.length > 0) {
+					if (isSecondaryOutputVar(h, secondaryOutputs, varName)) {
+						addMacroAdditionFile(buildVarToRuleStringMap, varName, relativePath, sourceLocation,
+								generatedSource);
+					}
+				}
+			}
+		}
+	}
+
+	/**
+	 * Gets a path for a resource by extracting the Path field from its
+	 * location URI.
+	 * @return IPath
+	 * @since 6.0
+	 */
+	protected IPath getPathForResource(IResource resource) {
+		return new Path(resource.getLocationURI().getPath());
+	}
+
+	/**
+	 * Adds the source file to the appropriate build variable
+	 *
+	 * @param buildVarToRuleStringMap  map of build variable names to the list of files assigned to the variable
+	 * @param ext  the file extension of the file
+	 * @param varName  the build variable to add this invocation's outputs to
+	 *                   if <code>null</code>, use the file extension to find the name
+	 * @param relativePath  build output directory relative path of the current output directory
+	 * @param sourceLocation  the full path of the source
+	 * @param generatedSource  if <code>true</code>, this file was generated by another tool in the tool-chain
+	 */
+	protected void addToBuildVar(LinkedHashMap<String, String> buildVarToRuleStringMap, String ext, String varName,
+			String relativePath, IPath sourceLocation, boolean generatedSource) {
+		List<IPath> varList = null;
+		if (varName == null) {
+			// Get the proper source build variable based upon the extension
+			varName = getSourceMacroName(ext).toString();
+			varList = buildSrcVars.get(varName);
+		} else {
+			varList = buildOutVars.get(varName);
+		}
+		//  Add the resource to the list of all resources associated with a variable.
+		//  Do not allow duplicates - there is no reason to and it can be 'bad' -
+		//  e.g., having the same object in the OBJS list can cause duplicate symbol errors from the linker
+		if ((varList != null) && !(varList.contains(sourceLocation))) {
+			//  Since we don't know how these files will be used, we store them using a "location"
+			//  path rather than a relative path
+			varList.add(sourceLocation);
+			if (!buildVarToRuleStringMap.containsKey(varName)) {
+				//  TODO - is this an error?
+			} else {
+				//  Add the resource name to the makefile line that adds resources to the build variable
+				addMacroAdditionFile(buildVarToRuleStringMap, varName, relativePath, sourceLocation, generatedSource);
+			}
+		}
+	}
+
+	private IManagedCommandLineInfo generateToolCommandLineInfo(ITool tool, String sourceExtension, String[] flags,
+			String outputFlag, String outputPrefix, String outputName, String[] inputResources, IPath inputLocation,
+			IPath outputLocation) {
+
+		String cmd = tool.getToolCommand();
+		//try to resolve the build macros in the tool command
+		try {
+			String resolvedCommand = null;
+
+			if ((inputLocation != null && inputLocation.toString().indexOf(" ") != -1) || //$NON-NLS-1$
+					(outputLocation != null && outputLocation.toString().indexOf(" ") != -1)) //$NON-NLS-1$
+			{
+				resolvedCommand = ManagedBuildManager.getBuildMacroProvider().resolveValue(cmd, "", //$NON-NLS-1$
+						" ", //$NON-NLS-1$
+						IBuildMacroProvider.CONTEXT_FILE,
+						new FileContextData(inputLocation, outputLocation, null, tool));
+			}
+
+			else {
+				resolvedCommand = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(cmd, "", //$NON-NLS-1$
+						" ", //$NON-NLS-1$
+						IBuildMacroProvider.CONTEXT_FILE,
+						new FileContextData(inputLocation, outputLocation, null, tool));
+			}
+			if ((resolvedCommand = resolvedCommand.trim()).length() > 0)
+				cmd = resolvedCommand;
+
+		} catch (BuildMacroException e) {
+		}
+
+		IManagedCommandLineGenerator gen = tool.getCommandLineGenerator();
+		return gen.generateCommandLineInfo(tool, cmd, flags, outputFlag, outputPrefix, outputName, inputResources,
+				tool.getCommandLinePattern());
+
+	}
+
+	/**
+	 * Create a rule for this source file.  We create a pattern rule if possible.
+	 *
+	 * This is an example of a pattern rule:
+	 *
+	 * <relative_path>/%.<outputExtension>: ../<relative_path>/%.<inputExtension>
+	 * 		@echo Building file: $<
+	 * 		@echo Invoking tool xxx
+	 * 		@echo <tool> <flags> <output_flag><output_prefix>$@ $<
+	 * 		@<tool> <flags> <output_flag><output_prefix>$@ $< && \
+	 * 		echo -n $(@:%.o=%.d) ' <relative_path>/' >> $(@:%.o=%.d) && \
+	 * 		<tool> -P -MM -MG <flags> $< >> $(@:%.o=%.d)
+	 * 		@echo Finished building: $<
+	 * 		@echo ' '
+	 *
+	 * Note that the macros all come from the build model and are
+	 * resolved to a real command before writing to the module
+	 * makefile, so a real command might look something like:
+	 * source1/%.o: ../source1/%.cpp
+	 * 		@echo Building file: $<
+	 * 		@echo Invoking tool xxx
+	 * 		@echo g++ -g -O2 -c -I/cygdrive/c/eclipse/workspace/Project/headers -o$@ $<
+	 *		@g++ -g -O2 -c -I/cygdrive/c/eclipse/workspace/Project/headers -o$@ $< && \
+	 * 		echo -n $(@:%.o=%.d) ' source1/' >> $(@:%.o=%.d) && \
+	 * 		g++ -P -MM -MG -g -O2 -c -I/cygdrive/c/eclipse/workspace/Project/headers $< >> $(@:%.o=%.d)
+	 * 		@echo Finished building: $<
+	 * 		@echo ' '
+	 *
+	 * @param relativePath  top build output directory relative path of the current output directory
+	 * @param buffer  buffer to populate with the build rule
+	 * @param resource  the source file for this invocation of the tool
+	 * @param sourceLocation  the full path of the source
+	 * @param rcInfo  the IResourceInfo associated with this file or null
+	 * @param generatedSource  <code>true</code> if the resource is a generated output
+	 * @param enumeratedOutputs  vector of the filenames that are the output of this rule
+	 */
+	protected void addRuleForSource(String relativePath, StringBuffer buffer, IResource resource, IPath sourceLocation,
+			IResourceInfo rcInfo, boolean generatedSource, Vector<IPath> generatedDepFiles,
+			Vector<IPath> enumeratedOutputs) {
+
+		String fileName = sourceLocation.removeFileExtension().lastSegment();
+		String inputExtension = sourceLocation.getFileExtension();
+		String outputExtension = null;
+
+		ITool tool = null;
+		if (rcInfo instanceof IFileInfo) {
+			IFileInfo fi = (IFileInfo) rcInfo;
+			ITool[] tools = fi.getToolsToInvoke();
+			if (tools != null && tools.length > 0) {
+				tool = tools[0];
+			}
+		} else {
+			IFolderInfo foInfo = (IFolderInfo) rcInfo;
+			tool = foInfo.getToolFromInputExtension(inputExtension);
+		}
+
+		ToolInfoHolder h = getToolInfo(rcInfo.getPath());
+
+		if (tool != null)
+			outputExtension = tool.getOutputExtension(inputExtension);
+		if (outputExtension == null)
+			outputExtension = EMPTY_STRING;
+
+		//  Get the dependency generator information for this tool and file extension
+		IManagedDependencyGenerator oldDepGen = null; //  This interface is deprecated but still supported
+		IManagedDependencyGenerator2 depGen = null; //  This is the recommended interface
+		IManagedDependencyInfo depInfo = null;
+		IManagedDependencyCommands depCommands = null;
+		IManagedDependencyPreBuild depPreBuild = null;
+		IPath[] depFiles = null;
+		boolean doDepGen = false;
+		{
+			IManagedDependencyGeneratorType t = null;
+			if (tool != null)
+				t = tool.getDependencyGeneratorForExtension(inputExtension);
+			if (t != null) {
+				int calcType = t.getCalculatorType();
+				if (calcType <= IManagedDependencyGeneratorType.TYPE_OLD_TYPE_LIMIT) {
+					oldDepGen = (IManagedDependencyGenerator) t;
+					doDepGen = (calcType == IManagedDependencyGeneratorType.TYPE_COMMAND);
+					if (doDepGen) {
+						IPath depFile = Path.fromOSString(relativePath + fileName + DOT + DEP_EXT);
+						getDependencyMakefiles(h).add(depFile);
+						generatedDepFiles.add(depFile);
+					}
+				} else {
+					depGen = (IManagedDependencyGenerator2) t;
+					doDepGen = (calcType == IManagedDependencyGeneratorType.TYPE_BUILD_COMMANDS);
+					IBuildObject buildContext = rcInfo;//(resConfig != null) ? (IBuildObject)resConfig : (IBuildObject)config;
+
+					depInfo = depGen.getDependencySourceInfo(resource.getProjectRelativePath(), resource, buildContext,
+							tool, getBuildWorkingDir());
+
+					if (calcType == IManagedDependencyGeneratorType.TYPE_BUILD_COMMANDS) {
+						depCommands = (IManagedDependencyCommands) depInfo;
+						depFiles = depCommands.getDependencyFiles();
+					} else if (calcType == IManagedDependencyGeneratorType.TYPE_PREBUILD_COMMANDS) {
+						depPreBuild = (IManagedDependencyPreBuild) depInfo;
+						depFiles = depPreBuild.getDependencyFiles();
+					}
+					if (depFiles != null) {
+						for (IPath depFile : depFiles) {
+							getDependencyMakefiles(h).add(depFile);
+							generatedDepFiles.add(depFile);
+						}
+					}
+				}
+			}
+		}
+
+		// Figure out the output paths
+		String optDotExt = EMPTY_STRING;
+		if (outputExtension.length() > 0)
+			optDotExt = DOT + outputExtension;
+
+		Vector<IPath> ruleOutputs = new Vector<>();
+		Vector<IPath> enumeratedPrimaryOutputs = new Vector<>(); // IPaths relative to the top build directory
+		Vector<IPath> enumeratedSecondaryOutputs = new Vector<>(); // IPaths relative to the top build directory
+		calculateOutputsForSource(tool, relativePath, resource, sourceLocation, ruleOutputs, enumeratedPrimaryOutputs,
+				enumeratedSecondaryOutputs);
+		enumeratedOutputs.addAll(enumeratedPrimaryOutputs);
+		enumeratedOutputs.addAll(enumeratedSecondaryOutputs);
+		String primaryOutputName = null;
+		if (enumeratedPrimaryOutputs.size() > 0) {
+			primaryOutputName = escapeWhitespaces(enumeratedPrimaryOutputs.get(0).toString());
+		} else {
+			primaryOutputName = escapeWhitespaces(relativePath + fileName + optDotExt);
+		}
+		String otherPrimaryOutputs = EMPTY_STRING;
+		for (int i = 1; i < enumeratedPrimaryOutputs.size(); i++) { // Starting with 1 is intentional
+			otherPrimaryOutputs += WHITESPACE + escapeWhitespaces(enumeratedPrimaryOutputs.get(i).toString());
+		}
+
+		// Output file location needed for the file-specific build macros
+		IPath outputLocation = Path.fromOSString(primaryOutputName);
+		if (!outputLocation.isAbsolute()) {
+			outputLocation = getPathForResource(project).append(getBuildWorkingDir()).append(primaryOutputName);
+		}
+
+		// A separate rule is needed for the resource in the case where explicit file-specific macros
+		// are referenced, or if the resource contains special characters in its path (e.g., whitespace)
+
+		/* fix for 137674
+		 *
+		 * We only need an explicit rule if one of the following is true:
+		 * - The resource is linked, and its full path to its real location contains special characters
+		 * - The resource is not linked, but its project relative path contains special characters
+		*/
+
+		boolean resourceNameRequiresExplicitRule = (resource.isLinked()
+				&& containsSpecialCharacters(sourceLocation.toString()))
+				|| (!resource.isLinked() && containsSpecialCharacters(resource.getProjectRelativePath().toString()));
+
+		boolean needExplicitRuleForFile = resourceNameRequiresExplicitRule
+				|| BuildMacroProvider.getReferencedExplitFileMacros(tool).length > 0
+				|| BuildMacroProvider.getReferencedExplitFileMacros(tool.getToolCommand(),
+						IBuildMacroProvider.CONTEXT_FILE,
+						new FileContextData(sourceLocation, outputLocation, null, tool)).length > 0;
+
+		// Get and resolve the command
+		String cmd = tool.getToolCommand();
+
+		try {
+			String resolvedCommand = null;
+			if (!needExplicitRuleForFile) {
+				resolvedCommand = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(cmd,
+						EMPTY_STRING, WHITESPACE, IBuildMacroProvider.CONTEXT_FILE,
+						new FileContextData(sourceLocation, outputLocation, null, tool));
+			} else {
+				// if we need an explicit rule then don't use any builder
+				// variables, resolve everything
+				// to explicit strings
+				resolvedCommand = ManagedBuildManager.getBuildMacroProvider().resolveValue(cmd, EMPTY_STRING,
+						WHITESPACE, IBuildMacroProvider.CONTEXT_FILE,
+						new FileContextData(sourceLocation, outputLocation, null, tool));
+			}
+
+			if ((resolvedCommand = resolvedCommand.trim()).length() > 0)
+				cmd = resolvedCommand;
+
+		} catch (BuildMacroException e) {
+		}
+
+		String defaultOutputName = EMPTY_STRING;
+		String primaryDependencyName = EMPTY_STRING;
+		String patternPrimaryDependencyName = EMPTY_STRING;
+		String home = (generatedSource) ? DOT : reachProjectRoot();
+		String resourcePath = null;
+		boolean patternRule = true;
+		boolean isItLinked = false;
+		if (resource.isLinked(IResource.CHECK_ANCESTORS)) {
+			// it IS linked, so use the actual location
+			isItLinked = true;
+			resourcePath = sourceLocation.toString();
+			// Need a hardcoded rule, not a pattern rule, as a linked file
+			// can reside in any path
+			defaultOutputName = escapeWhitespaces(relativePath + fileName + optDotExt);
+			primaryDependencyName = escapeWhitespaces(resourcePath);
+			patternRule = false;
+		} else {
+			// Use the relative path (not really needed to store per se but in the future someone may want this)
+			resourcePath = relativePath;
+			// The rule and command to add to the makefile
+			if (rcInfo instanceof IFileInfo || needExplicitRuleForFile) {
+				// Need a hardcoded rule, not a pattern rule
+				defaultOutputName = escapeWhitespaces(resourcePath + fileName + optDotExt);
+				patternRule = false;
+			} else {
+				defaultOutputName = relativePath + WILDCARD + optDotExt;
+			}
+			primaryDependencyName = escapeWhitespaces(
+					home + SEPARATOR + resourcePath + fileName + DOT + inputExtension);
+			patternPrimaryDependencyName = home + SEPARATOR + resourcePath + WILDCARD + DOT + inputExtension;
+		} // end fix for PR 70491
+
+		//  If the tool specifies a dependency calculator of TYPE_BUILD_COMMANDS, ask whether
+		//  the dependency commands are "generic" (i.e., we can use a pattern rule)
+		boolean needExplicitDependencyCommands = false;
+		if (depCommands != null) {
+			needExplicitDependencyCommands = !depCommands.areCommandsGeneric();
+		}
+
+		//  If we still think that we are using a pattern rule, check a few more things
+		if (patternRule) {
+			patternRule = false;
+			//  Make sure that at least one of the rule outputs contains a %.
+			for (int i = 0; i < ruleOutputs.size(); i++) {
+				String ruleOutput = ruleOutputs.get(i).toString();
+				if (ruleOutput.indexOf('%') >= 0) {
+					patternRule = true;
+					break;
+				}
+			}
+			if (patternRule) {
+				patternRule = !needExplicitDependencyCommands;
+			}
+		}
+
+		// Begin building the rule for this source file
+		String buildRule = EMPTY_STRING;
+
+		if (patternRule) {
+			if (ruleOutputs.size() == 0) {
+				buildRule += defaultOutputName;
+			} else {
+				boolean first = true;
+				for (int i = 0; i < ruleOutputs.size(); i++) {
+					String ruleOutput = ruleOutputs.get(i).toString();
+					if (ruleOutput.indexOf('%') >= 0) {
+						if (first) {
+							first = false;
+						} else {
+							buildRule += WHITESPACE;
+						}
+						buildRule += ruleOutput;
+					}
+				}
+			}
+		} else {
+			buildRule += primaryOutputName;
+		}
+
+		String buildRuleDependencies = primaryDependencyName;
+		String patternBuildRuleDependencies = patternPrimaryDependencyName;
+
+		// Other additional inputs
+		// Get any additional dependencies specified for the tool in other InputType elements and AdditionalInput elements
+		IPath[] addlDepPaths = tool.getAdditionalDependencies();
+		for (IPath addlDepPath : addlDepPaths) {
+			// Translate the path from project relative to build directory relative
+			IPath addlPath = addlDepPath;
+			if (!(addlPath.toString().startsWith("$("))) { //$NON-NLS-1$
+				if (!addlPath.isAbsolute()) {
+					IPath tempPath = project.getLocation().append(new Path(ensureUnquoted(addlPath.toString())));
+					if (tempPath != null) {
+						addlPath = ManagedBuildManager.calculateRelativePath(getTopBuildDir(), tempPath);
+					}
+				}
+			}
+			String suitablePath = ensurePathIsGNUMakeTargetRuleCompatibleSyntax(addlPath.toString());
+			buildRuleDependencies += WHITESPACE + suitablePath;
+			patternBuildRuleDependencies += WHITESPACE + suitablePath;
+		}
+
+		buildRule += COLON + WHITESPACE + (patternRule ? patternBuildRuleDependencies : buildRuleDependencies)
+				+ WHITESPACE + escapeWhitespaces(relativePath + MODFILE_NAME);
+
+		// No duplicates in a makefile.  If we already have this rule, don't add it or the commands to build the file
+		if (getRuleList().contains(buildRule)) {
+			//  TODO:  Should we assert that this is a pattern rule?
+		} else {
+			getRuleList().add(buildRule);
+
+			// Echo starting message
+			buffer.append(buildRule).append(NEWLINE);
+			buffer.append(TAB).append(AT).append(escapedEcho(MESSAGE_START_FILE + WHITESPACE + IN_MACRO));
+			buffer.append(TAB).append(AT).append(escapedEcho(tool.getAnnouncement()));
+
+			// If the tool specifies a dependency calculator of TYPE_BUILD_COMMANDS, ask whether
+			// there are any pre-tool commands.
+			if (depCommands != null) {
+				String[] preToolCommands = depCommands.getPreToolDependencyCommands();
+				if (preToolCommands != null && preToolCommands.length > 0) {
+					for (String preCmd : preToolCommands) {
+						try {
+							String resolvedCommand;
+							IBuildMacroProvider provider = ManagedBuildManager.getBuildMacroProvider();
+							if (!needExplicitRuleForFile) {
+								resolvedCommand = provider.resolveValueToMakefileFormat(preCmd, EMPTY_STRING,
+										WHITESPACE, IBuildMacroProvider.CONTEXT_FILE,
+										new FileContextData(sourceLocation, outputLocation, null, tool));
+							} else {
+								// if we need an explicit rule then don't use any builder
+								// variables, resolve everything to explicit strings
+								resolvedCommand = provider.resolveValue(preCmd, EMPTY_STRING, WHITESPACE,
+										IBuildMacroProvider.CONTEXT_FILE,
+										new FileContextData(sourceLocation, outputLocation, null, tool));
+							}
+							if (resolvedCommand != null)
+								buffer.append(resolvedCommand).append(NEWLINE);
+						} catch (BuildMacroException e) {
+						}
+					}
+				}
+			}
+
+			// Generate the command line
+
+			Vector<String> inputs = new Vector<>();
+			inputs.add(IN_MACRO);
+
+			// Other additional inputs
+			// Get any additional dependencies specified for the tool in other InputType elements and AdditionalInput elements
+			IPath[] addlInputPaths = getAdditionalResourcesForSource(tool);
+			for (IPath addlInputPath : addlInputPaths) {
+				// Translate the path from project relative to build directory relative
+				IPath addlPath = addlInputPath;
+				if (!(addlPath.toString().startsWith("$("))) { //$NON-NLS-1$
+					if (!addlPath.isAbsolute()) {
+						IPath tempPath = getPathForResource(project).append(addlPath);
+						if (tempPath != null) {
+							addlPath = ManagedBuildManager.calculateRelativePath(getTopBuildDir(), tempPath);
+						}
+					}
+				}
+				inputs.add(addlPath.toString());
+			}
+			String[] inputStrings = inputs.toArray(new String[inputs.size()]);
+
+			String[] flags = null;
+			// Get the tool command line options
+			try {
+				flags = tool.getToolCommandFlags(sourceLocation, outputLocation);
+			} catch (BuildException ex) {
+				// TODO add some routines to catch this
+				flags = EMPTY_STRING_ARRAY;
+			}
+
+			// If we have a TYPE_BUILD_COMMANDS dependency generator, determine if there are any options that
+			// it wants added to the command line
+			if (depCommands != null) {
+				flags = addDependencyOptions(depCommands, flags);
+			}
+
+			IManagedCommandLineInfo cmdLInfo = null;
+			String outflag = null;
+			String outputPrefix = null;
+
+			if (rcInfo instanceof IFileInfo || needExplicitRuleForFile || needExplicitDependencyCommands) {
+				outflag = tool.getOutputFlag();
+				outputPrefix = tool.getOutputPrefix();
+
+				// Call the command line generator
+				IManagedCommandLineGenerator cmdLGen = tool.getCommandLineGenerator();
+				cmdLInfo = cmdLGen.generateCommandLineInfo(tool, cmd, flags, outflag, outputPrefix,
+						OUT_MACRO + otherPrimaryOutputs, inputStrings, tool.getCommandLinePattern());
+
+			} else {
+				outflag = tool.getOutputFlag();//config.getOutputFlag(outputExtension);
+				outputPrefix = tool.getOutputPrefix();//config.getOutputPrefix(outputExtension);
+
+				// Call the command line generator
+				cmdLInfo = generateToolCommandLineInfo(tool, inputExtension, flags, outflag, outputPrefix,
+						OUT_MACRO + otherPrimaryOutputs, inputStrings, sourceLocation, outputLocation);
+			}
+
+			// The command to build
+			String buildCmd;
+			if (cmdLInfo != null) {
+				buildCmd = cmdLInfo.getCommandLine();
+			} else {
+				StringBuffer buildFlags = new StringBuffer();
+				for (String flag : flags) {
+					if (flag != null) {
+						buildFlags.append(flag).append(WHITESPACE);
+					}
+				}
+				buildCmd = cmd + WHITESPACE + buildFlags.toString().trim() + WHITESPACE + outflag + WHITESPACE
+						+ outputPrefix + OUT_MACRO + otherPrimaryOutputs + WHITESPACE + IN_MACRO;
+			}
+
+			// resolve any remaining macros in the command after it has been
+			// generated
+			try {
+				String resolvedCommand;
+				IBuildMacroProvider provider = ManagedBuildManager.getBuildMacroProvider();
+				if (!needExplicitRuleForFile) {
+					resolvedCommand = provider.resolveValueToMakefileFormat(buildCmd, EMPTY_STRING, WHITESPACE,
+							IBuildMacroProvider.CONTEXT_FILE,
+							new FileContextData(sourceLocation, outputLocation, null, tool));
+				} else {
+					// if we need an explicit rule then don't use any builder
+					// variables, resolve everything to explicit strings
+					resolvedCommand = provider.resolveValue(buildCmd, EMPTY_STRING, WHITESPACE,
+							IBuildMacroProvider.CONTEXT_FILE,
+							new FileContextData(sourceLocation, outputLocation, null, tool));
+				}
+
+				if ((resolvedCommand = resolvedCommand.trim()).length() > 0)
+					buildCmd = resolvedCommand;
+
+			} catch (BuildMacroException e) {
+			}
+
+			//buffer.append(TAB).append(AT).append(escapedEcho(buildCmd));
+			//buffer.append(TAB).append(AT).append(buildCmd);
+			buffer.append(TAB).append(buildCmd);
+
+			// Determine if there are any dependencies to calculate
+			if (doDepGen) {
+				// Get the dependency rule out of the generator
+				String[] depCmds = null;
+				if (oldDepGen != null) {
+					depCmds = new String[1];
+					depCmds[0] = oldDepGen.getDependencyCommand(resource, ManagedBuildManager.getBuildInfo(project));
+				} else {
+					if (depCommands != null) {
+						depCmds = depCommands.getPostToolDependencyCommands();
+					}
+				}
+
+				if (depCmds != null) {
+					for (String depCmd : depCmds) {
+						// Resolve any macros in the dep command after it has been generated.
+						// Note:  do not trim the result because it will strip out necessary tab characters.
+						buffer.append(WHITESPACE).append(LOGICAL_AND).append(WHITESPACE).append(LINEBREAK);
+						try {
+							if (!needExplicitRuleForFile) {
+								depCmd = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(
+										depCmd, EMPTY_STRING, WHITESPACE, IBuildMacroProvider.CONTEXT_FILE,
+										new FileContextData(sourceLocation, outputLocation, null, tool));
+							}
+
+							else {
+								depCmd = ManagedBuildManager.getBuildMacroProvider().resolveValue(depCmd, EMPTY_STRING,
+										WHITESPACE, IBuildMacroProvider.CONTEXT_FILE,
+										new FileContextData(sourceLocation, outputLocation, null, tool));
+							}
+
+						} catch (BuildMacroException e) {
+						}
+
+						buffer.append(depCmd);
+					}
+				}
+			}
+
+			// Echo finished message
+			buffer.append(NEWLINE);
+			buffer.append(TAB).append(AT).append(escapedEcho(MESSAGE_FINISH_FILE + WHITESPACE + IN_MACRO));
+			buffer.append(TAB).append(AT).append(ECHO_BLANK_LINE).append(NEWLINE);
+		}
+
+		// Determine if there are calculated dependencies
+		IPath[] addlDeps = null; // IPath's that are relative to the build directory
+		IPath[] addlTargets = null; // IPath's that are relative to the build directory
+		String calculatedDependencies = null;
+		boolean addedDepLines = false;
+		String depLine;
+		if (oldDepGen != null && oldDepGen.getCalculatorType() != IManagedDependencyGeneratorType.TYPE_COMMAND) {
+			addlDeps = oldCalculateDependenciesForSource(oldDepGen, tool, relativePath, resource);
+		} else {
+			if (depGen != null && depGen.getCalculatorType() == IManagedDependencyGeneratorType.TYPE_CUSTOM) {
+				if (depInfo instanceof IManagedDependencyCalculator) {
+					IManagedDependencyCalculator depCalculator = (IManagedDependencyCalculator) depInfo;
+					addlDeps = calculateDependenciesForSource(depCalculator);
+					addlTargets = depCalculator.getAdditionalTargets();
+				}
+			}
+		}
+
+		if (addlDeps != null && addlDeps.length > 0) {
+			calculatedDependencies = ""; //$NON-NLS-1$
+			for (IPath addlDep : addlDeps) {
+				calculatedDependencies += WHITESPACE + escapeWhitespaces(addlDep.toString());
+			}
+		}
+
+		if (calculatedDependencies != null) {
+			depLine = primaryOutputName + COLON + calculatedDependencies + NEWLINE;
+			if (!getDepLineList().contains(depLine)) {
+				getDepLineList().add(depLine);
+				addedDepLines = true;
+				buffer.append(depLine);
+			}
+		}
+
+		// Add any additional outputs here using dependency lines
+		Vector<IPath> addlOutputs = new Vector<>();
+		if (enumeratedPrimaryOutputs.size() > 1) {
+			// Starting with 1 is intentional in order to skip the primary output
+			for (int i = 1; i < enumeratedPrimaryOutputs.size(); i++)
+				addlOutputs.add(enumeratedPrimaryOutputs.get(i));
+		}
+		addlOutputs.addAll(enumeratedSecondaryOutputs);
+		if (addlTargets != null) {
+			for (IPath addlTarget : addlTargets)
+				addlOutputs.add(addlTarget);
+		}
+		for (int i = 0; i < addlOutputs.size(); i++) {
+			depLine = escapeWhitespaces(addlOutputs.get(i).toString()) + COLON + WHITESPACE + primaryOutputName;
+			if (calculatedDependencies != null)
+				depLine += calculatedDependencies;
+			depLine += NEWLINE;
+			if (!getDepLineList().contains(depLine)) {
+				getDepLineList().add(depLine);
+				addedDepLines = true;
+				buffer.append(depLine);
+			}
+		}
+		if (addedDepLines) {
+			buffer.append(NEWLINE);
+		}
+
+		//  If we are using a dependency calculator of type TYPE_PREBUILD_COMMANDS,
+		//  get the rule to build the dependency file
+		if (depPreBuild != null && depFiles != null) {
+			addedDepLines = false;
+			String[] preBuildCommands = depPreBuild.getDependencyCommands();
+			if (preBuildCommands != null) {
+				depLine = ""; //$NON-NLS-1$
+				//  Can we use a pattern rule?
+				patternRule = !isItLinked && !needExplicitRuleForFile && depPreBuild.areCommandsGeneric();
+				//  Begin building the rule
+				for (int i = 0; i < depFiles.length; i++) {
+					if (i > 0)
+						depLine += WHITESPACE;
+					if (patternRule) {
+						optDotExt = EMPTY_STRING;
+						String depExt = depFiles[i].getFileExtension();
+						if (depExt != null && depExt.length() > 0)
+							optDotExt = DOT + depExt;
+						depLine += escapeWhitespaces(relativePath + WILDCARD + optDotExt);
+					} else {
+						depLine += escapeWhitespaces((depFiles[i]).toString());
+					}
+				}
+				depLine += COLON + WHITESPACE + (patternRule ? patternBuildRuleDependencies : buildRuleDependencies)
+						+ WHITESPACE + escapeWhitespaces(relativePath + MODFILE_NAME);
+				if (!getDepRuleList().contains(depLine)) {
+					getDepRuleList().add(depLine);
+					addedDepLines = true;
+					buffer.append(depLine).append(NEWLINE);
+					buffer.append(TAB).append(AT)
+							.append(escapedEcho(MESSAGE_START_DEPENDENCY + WHITESPACE + OUT_MACRO));
+					for (String preBuildCommand : preBuildCommands) {
+						depLine = preBuildCommand;
+						// Resolve macros
+						try {
+							if (!needExplicitRuleForFile) {
+								depLine = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(
+										depLine, EMPTY_STRING, WHITESPACE, IBuildMacroProvider.CONTEXT_FILE,
+										new FileContextData(sourceLocation, outputLocation, null, tool));
+							}
+
+							else {
+								depLine = ManagedBuildManager.getBuildMacroProvider().resolveValue(depLine,
+										EMPTY_STRING, WHITESPACE, IBuildMacroProvider.CONTEXT_FILE,
+										new FileContextData(sourceLocation, outputLocation, null, tool));
+							}
+
+						} catch (BuildMacroException e) {
+						}
+						//buffer.append(TAB).append(AT).append(escapedEcho(depLine));
+						//buffer.append(TAB).append(AT).append(depLine).append(NEWLINE);
+						buffer.append(TAB).append(depLine).append(NEWLINE);
+					}
+				}
+				if (addedDepLines) {
+					buffer.append(TAB).append(AT).append(ECHO_BLANK_LINE).append(NEWLINE);
+				}
+			}
+		}
+	}
+
+	/*
+	 * Add any dependency calculator options to the tool options
+	 */
+	private String[] addDependencyOptions(IManagedDependencyCommands depCommands, String[] flags) {
+		String[] depOptions = depCommands.getDependencyCommandOptions();
+		if (depOptions != null && depOptions.length > 0) {
+			int flagsLen = flags.length;
+			String[] flagsCopy = new String[flags.length + depOptions.length];
+			for (int i = 0; i < flags.length; i++) {
+				flagsCopy[i] = flags[i];
+			}
+			for (int i = 0; i < depOptions.length; i++) {
+				flagsCopy[i + flagsLen] = depOptions[i];
+			}
+			flags = flagsCopy;
+		}
+		return flags;
+	}
+
+	/**
+	 * Returns any additional resources specified for the tool in other InputType elements and AdditionalInput elements
+	 */
+	protected IPath[] getAdditionalResourcesForSource(ITool tool) {
+		List<IPath> allRes = new ArrayList<>();
+		IInputType[] types = tool.getInputTypes();
+		for (IInputType type : types) {
+			//  Additional resources come from 2 places.
+			//  1.  From AdditionalInput childen
+			IPath[] res = type.getAdditionalResources();
+			for (IPath re : res) {
+				allRes.add(re);
+			}
+			//  2.  From InputTypes that other than the primary input type
+			if (!type.getPrimaryInput() && type != tool.getPrimaryInputType()) {
+				String var = type.getBuildVariable();
+				if (var != null && var.length() > 0) {
+					allRes.add(Path.fromOSString("$(" + type.getBuildVariable() + ")")); //$NON-NLS-1$ //$NON-NLS-2$
+				} else {
+					//  Use file extensions
+					String[] typeExts = type.getSourceExtensions(tool);
+					for (IResource projectResource : projectResources) {
+						if (projectResource.getType() == IResource.FILE) {
+							String fileExt = projectResource.getFileExtension();
+							if (fileExt == null) {
+								fileExt = ""; //$NON-NLS-1$
+							}
+							for (String typeExt : typeExts) {
+								if (fileExt.equals(typeExt)) {
+									allRes.add(projectResource.getProjectRelativePath());
+									break;
+								}
+							}
+						}
+					}
+				}
+
+				//  If an assignToOption has been specified, set the value of the option to the inputs
+				IOption assignToOption = tool.getOptionBySuperClassId(type.getAssignToOptionId());
+				IOption option = tool.getOptionBySuperClassId(type.getOptionId());
+				if (assignToOption != null && option == null) {
+					try {
+						int optType = assignToOption.getValueType();
+						IResourceInfo rcInfo = tool.getParentResourceInfo();
+						if (rcInfo != null) {
+							if (optType == IOption.STRING) {
+								String optVal = ""; //$NON-NLS-1$
+								for (int j = 0; j < allRes.size(); j++) {
+									if (j != 0) {
+										optVal += " "; //$NON-NLS-1$
+									}
+									String resPath = allRes.get(j).toString();
+									if (!resPath.startsWith("$(")) { //$NON-NLS-1$
+										IResource addlResource = project.getFile(resPath);
+										if (addlResource != null) {
+											IPath addlPath = addlResource.getLocation();
+											if (addlPath != null) {
+												resPath = ManagedBuildManager
+														.calculateRelativePath(getTopBuildDir(), addlPath).toString();
+											}
+										}
+									}
+									optVal += ManagedBuildManager
+											.calculateRelativePath(getTopBuildDir(), Path.fromOSString(resPath))
+											.toString();
+								}
+								ManagedBuildManager.setOption(rcInfo, tool, assignToOption, optVal);
+							} else if (optType == IOption.STRING_LIST || optType == IOption.LIBRARIES
+									|| optType == IOption.OBJECTS || optType == IOption.INCLUDE_FILES
+									|| optType == IOption.LIBRARY_PATHS || optType == IOption.LIBRARY_FILES
+									|| optType == IOption.MACRO_FILES) {
+								//TODO: do we need to do anything with undefs here?
+								//  Note that the path(s) must be translated from project relative
+								//  to top build directory relative
+								String[] paths = new String[allRes.size()];
+								for (int j = 0; j < allRes.size(); j++) {
+									paths[j] = allRes.get(j).toString();
+									if (!paths[j].startsWith("$(")) { //$NON-NLS-1$
+										IResource addlResource = project.getFile(paths[j]);
+										if (addlResource != null) {
+											IPath addlPath = addlResource.getLocation();
+											if (addlPath != null) {
+												paths[j] = ManagedBuildManager
+														.calculateRelativePath(getTopBuildDir(), addlPath).toString();
+											}
+										}
+									}
+								}
+								ManagedBuildManager.setOption(rcInfo, tool, assignToOption, paths);
+							} else if (optType == IOption.BOOLEAN) {
+								boolean b = false;
+								if (allRes.size() > 0)
+									b = true;
+								ManagedBuildManager.setOption(rcInfo, tool, assignToOption, b);
+							} else if (optType == IOption.ENUMERATED || optType == IOption.TREE) {
+								if (allRes.size() > 0) {
+									String s = allRes.get(0).toString();
+									ManagedBuildManager.setOption(rcInfo, tool, assignToOption, s);
+								}
+							}
+							allRes.clear();
+						}
+					} catch (BuildException ex) {
+					}
+				}
+			}
+		}
+		return allRes.toArray(new IPath[allRes.size()]);
+	}
+
+	/**
+	 * Returns the output <code>IPath</code>s for this invocation of the tool with the specified source file
+	 *
+	 * The priorities for determining the names of the outputs of a tool are:
+	 *  1.  If the tool is the build target and primary output, use artifact name & extension -
+	 *      This case does not apply here...
+	 *  2.  If an option is specified, use the value of the option
+	 *  3.  If a nameProvider is specified, call it
+	 *  4.  If outputNames is specified, use it
+	 *  5.  Use the name pattern to generate a transformation macro
+	 *      so that the source names can be transformed into the target names
+	 *      using the built-in string substitution functions of <code>make</code>.
+	 *
+	 *  @param relativePath  build output directory relative path of the current output directory
+	 *  @param ruleOutputs  Vector of rule IPaths that are relative to the build directory
+	 *  @param enumeratedPrimaryOutputs  Vector of IPaths of primary outputs
+	 *                            that are relative to the build directory
+	 *  @param enumeratedSecondaryOutputs  Vector of IPaths of secondary outputs
+	 *                            that are relative to the build directory
+	 */
+	protected void calculateOutputsForSource(ITool tool, String relativePath, IResource resource, IPath sourceLocation,
+			Vector<IPath> ruleOutputs, Vector<IPath> enumeratedPrimaryOutputs,
+			Vector<IPath> enumeratedSecondaryOutputs) {
+		String inExt = sourceLocation.getFileExtension();
+		String outExt = tool.getOutputExtension(inExt);
+		IResourceInfo rcInfo = tool.getParentResourceInfo();
+
+		IOutputType[] outTypes = tool.getOutputTypes();
+		if (outTypes != null && outTypes.length > 0) {
+			for (IOutputType type : outTypes) {
+				boolean primaryOutput = (type == tool.getPrimaryOutputType());
+				//if (primaryOutput && ignorePrimary) continue;
+				String outputPrefix = type.getOutputPrefix();
+
+				// Resolve any macros in the outputPrefix
+				// Note that we cannot use file macros because if we do a clean
+				// we need to know the actual name of the file to clean, and
+				// cannot use any builder variables such as $@. Hence we use the
+				// next best thing, i.e. configuration context.
+
+				// figure out the configuration we're using
+				//                IBuildObject toolParent = tool.getParent();
+				//                IConfiguration config = null;
+				// if the parent is a config then we're done
+				//                if (toolParent instanceof IConfiguration)
+				//                    config = (IConfiguration) toolParent;
+				//                else if (toolParent instanceof IToolChain) {
+				//                    // must be a toolchain
+				//                    config = (IConfiguration) ((IToolChain) toolParent)
+				//                            .getParent();
+				//                }
+				//
+				//                else if (toolParent instanceof IResourceConfiguration) {
+				//                    config = (IConfiguration) ((IResourceConfiguration) toolParent)
+				//                            .getParent();
+				//                }
+
+				//                else {
+				//                    // bad
+				//                    throw new AssertionError(
+				//                            "tool parent must be one of configuration, toolchain, or resource configuration");
+				//                }
+
+				//                if (config != null) {
+
+				try {
+
+					if (containsSpecialCharacters(sourceLocation.toString())) {
+						outputPrefix = ManagedBuildManager.getBuildMacroProvider().resolveValue(outputPrefix, "", //$NON-NLS-1$
+								" ", //$NON-NLS-1$
+								IBuildMacroProvider.CONTEXT_CONFIGURATION, config);
+					} else {
+						outputPrefix = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(
+								outputPrefix, "", //$NON-NLS-1$
+								" ", //$NON-NLS-1$
+								IBuildMacroProvider.CONTEXT_CONFIGURATION, config);
+					}
+				}
+
+				catch (BuildMacroException e) {
+				}
+
+				//                }
+
+				boolean multOfType = type.getMultipleOfType();
+				IOption option = tool.getOptionBySuperClassId(type.getOptionId());
+				IManagedOutputNameProvider nameProvider = type.getNameProvider();
+				String[] outputNames = type.getOutputNames();
+
+				//  1.  If the tool is the build target and this is the primary output,
+				//      use artifact name & extension
+				//      Not appropriate here...
+				//  2.  If an option is specified, use the value of the option
+				if (option != null) {
+					try {
+						List<String> outputList = new ArrayList<>();
+						int optType = option.getValueType();
+						if (optType == IOption.STRING) {
+							outputList.add(outputPrefix + option.getStringValue());
+						} else if (optType == IOption.STRING_LIST || optType == IOption.LIBRARIES
+								|| optType == IOption.OBJECTS || optType == IOption.INCLUDE_FILES
+								|| optType == IOption.LIBRARY_PATHS || optType == IOption.LIBRARY_FILES
+								|| optType == IOption.MACRO_FILES) {
+							@SuppressWarnings("unchecked")
+							List<String> value = (List<String>) option.getValue();
+							outputList = value;
+							((Tool) tool).filterValues(optType, outputList);
+							// Add outputPrefix to each if necessary
+							if (outputPrefix.length() > 0) {
+								for (int j = 0; j < outputList.size(); j++) {
+									outputList.set(j, outputPrefix + outputList.get(j));
+								}
+							}
+						}
+						for (int j = 0; j < outputList.size(); j++) {
+							String outputName = outputList.get(j);
+
+							// try to resolve the build macros in the output
+							// names
+							try {
+
+								String resolved = null;
+
+								if (containsSpecialCharacters(sourceLocation.toString())) {
+									resolved = ManagedBuildManager.getBuildMacroProvider().resolveValue(outputName, "", //$NON-NLS-1$
+											" ", //$NON-NLS-1$
+											IBuildMacroProvider.CONTEXT_FILE,
+											new FileContextData(sourceLocation, null, option, tool));
+								}
+
+								else {
+									resolved = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(
+											outputName, "", //$NON-NLS-1$
+											" ", //$NON-NLS-1$
+											IBuildMacroProvider.CONTEXT_FILE,
+											new FileContextData(sourceLocation, null, option, tool));
+								}
+
+								if ((resolved = resolved.trim()).length() > 0)
+									outputName = resolved;
+							} catch (BuildMacroException e) {
+							}
+
+							IPath outPath = Path.fromOSString(outputName);
+							//  If only a file name is specified, add the relative path of this output directory
+							if (outPath.segmentCount() == 1) {
+								outPath = Path.fromOSString(relativePath + outputList.get(j));
+							}
+							if (primaryOutput) {
+								ruleOutputs.add(j, outPath);
+								enumeratedPrimaryOutputs.add(j, resolvePercent(outPath, sourceLocation));
+							} else {
+								ruleOutputs.add(outPath);
+								enumeratedSecondaryOutputs.add(resolvePercent(outPath, sourceLocation));
+							}
+						}
+					} catch (BuildException ex) {
+					}
+				} else
+				//  3.  If a nameProvider is specified, call it
+				if (nameProvider != null) {
+					IPath[] inPaths = new IPath[1];
+					inPaths[0] = sourceLocation;
+					IPath[] outPaths = nameProvider.getOutputNames(tool, inPaths);
+					if (outPaths != null) {
+						for (int j = 0; j < outPaths.length; j++) {
+							IPath outPath = outPaths[j];
+							String outputName = outPaths[j].toString();
+
+							// try to resolve the build macros in the output names
+							try {
+
+								String resolved = null;
+
+								if (containsSpecialCharacters(sourceLocation.toString())) {
+									resolved = ManagedBuildManager.getBuildMacroProvider().resolveValue(outputName, "", //$NON-NLS-1$
+											" ", //$NON-NLS-1$
+											IBuildMacroProvider.CONTEXT_FILE,
+											new FileContextData(sourceLocation, null, option, tool));
+								}
+
+								else {
+									resolved = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(
+											outputName, "", //$NON-NLS-1$
+											" ", //$NON-NLS-1$
+											IBuildMacroProvider.CONTEXT_FILE,
+											new FileContextData(sourceLocation, null, option, tool));
+								}
+
+								if ((resolved = resolved.trim()).length() > 0)
+									outputName = resolved;
+							} catch (BuildMacroException e) {
+							}
+
+							//  If only a file name is specified, add the relative path of this output directory
+							if (outPath.segmentCount() == 1) {
+								outPath = Path.fromOSString(relativePath + outPath.toString());
+							}
+							if (primaryOutput) {
+								ruleOutputs.add(j, outPath);
+								enumeratedPrimaryOutputs.add(j, resolvePercent(outPath, sourceLocation));
+							} else {
+								ruleOutputs.add(outPath);
+								enumeratedSecondaryOutputs.add(resolvePercent(outPath, sourceLocation));
+							}
+						}
+					}
+				} else
+				//  4.  If outputNames is specified, use it
+				if (outputNames != null) {
+					for (int j = 0; j < outputNames.length; j++) {
+						String outputName = outputNames[j];
+						try {
+							//try to resolve the build macros in the output names
+							String resolved = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(
+									outputName, "", //$NON-NLS-1$
+									" ", //$NON-NLS-1$
+									IBuildMacroProvider.CONTEXT_FILE,
+									new FileContextData(sourceLocation, null, option, tool));
+							if ((resolved = resolved.trim()).length() > 0)
+								outputName = resolved;
+						} catch (BuildMacroException e) {
+						}
+
+						IPath outPath = Path.fromOSString(outputName);
+						//  If only a file name is specified, add the relative path of this output directory
+						if (outPath.segmentCount() == 1) {
+							outPath = Path.fromOSString(relativePath + outPath.toString());
+						}
+						if (primaryOutput) {
+							ruleOutputs.add(j, outPath);
+							enumeratedPrimaryOutputs.add(j, resolvePercent(outPath, sourceLocation));
+						} else {
+							ruleOutputs.add(outPath);
+							enumeratedSecondaryOutputs.add(resolvePercent(outPath, sourceLocation));
+						}
+					}
+				} else {
+					//  5.  Use the name pattern to generate a transformation macro
+					//      so that the source names can be transformed into the target names
+					//      using the built-in string substitution functions of <code>make</code>.
+					if (multOfType) {
+						// This case is not handled - a nameProvider or outputNames must be specified
+						// TODO - report error
+					} else {
+						String namePattern = type.getNamePattern();
+						IPath namePatternPath = null;
+						if (namePattern == null || namePattern.length() == 0) {
+							namePattern = relativePath + outputPrefix + IManagedBuilderMakefileGenerator.WILDCARD;
+							if (outExt != null && outExt.length() > 0) {
+								namePattern += DOT + outExt;
+							}
+							namePatternPath = Path.fromOSString(namePattern);
+						} else {
+							if (outputPrefix.length() > 0) {
+								namePattern = outputPrefix + namePattern;
+							}
+							namePatternPath = Path.fromOSString(namePattern);
+							//  If only a file name is specified, add the relative path of this output directory
+							if (namePatternPath.segmentCount() == 1) {
+								namePatternPath = Path.fromOSString(relativePath + namePatternPath.toString());
+							}
+						}
+
+						if (primaryOutput) {
+							ruleOutputs.add(0, namePatternPath);
+							enumeratedPrimaryOutputs.add(0, resolvePercent(namePatternPath, sourceLocation));
+						} else {
+							ruleOutputs.add(namePatternPath);
+							enumeratedSecondaryOutputs.add(resolvePercent(namePatternPath, sourceLocation));
+						}
+					}
+				}
+			}
+		} else {
+			// For support of pre-CDT 3.0 integrations.
+			// NOTE WELL:  This only supports the case of a single "target tool"
+			//     that consumes exactly all of the object files, $OBJS, produced
+			//     by other tools in the build and produces a single output.
+			//     In this case, the output file name is the input file name with
+			//     the output extension.
+
+			//if (!ignorePrimary) {
+			String outPrefix = tool.getOutputPrefix();
+			IPath outPath = Path.fromOSString(relativePath + outPrefix + WILDCARD);
+			outPath = outPath.addFileExtension(outExt);
+			ruleOutputs.add(0, outPath);
+			enumeratedPrimaryOutputs.add(0, resolvePercent(outPath, sourceLocation));
+			//}
+		}
+	}
+
+	/**
+	 * If the path contains a %, returns the path resolved using the resource name
+	 *
+	 */
+	protected IPath resolvePercent(IPath outPath, IPath sourceLocation) {
+		//  Get the input file name
+		String fileName = sourceLocation.removeFileExtension().lastSegment();
+		//  Replace the % with the file name
+		String outName = outPath.toOSString().replaceAll("%", fileName); //$NON-NLS-1$
+		IPath result = Path.fromOSString(outName);
+		return DOT_SLASH_PATH.isPrefixOf(outPath) ? DOT_SLASH_PATH.append(result) : result;
+	}
+
+	/**
+	 * Returns the dependency <code>IPath</code>s for this invocation of the tool with the specified source file
+	 *
+	 *  @param depGen  the dependency calculator
+	 *  @param tool  tool used to build the source file
+	 *  @param relativePath  build output directory relative path of the current output directory
+	 *  @param resource  source file to scan for dependencies
+	 *  @return Vector of IPaths that are relative to the build directory
+	 */
+	protected IPath[] oldCalculateDependenciesForSource(IManagedDependencyGenerator depGen, ITool tool,
+			String relativePath, IResource resource) {
+		Vector<IPath> deps = new Vector<>();
+		int type = depGen.getCalculatorType();
+
+		switch (type) {
+
+		case IManagedDependencyGeneratorType.TYPE_INDEXER:
+		case IManagedDependencyGeneratorType.TYPE_EXTERNAL:
+			IResource[] res = depGen.findDependencies(resource, project);
+			if (res != null) {
+				for (IResource re : res) {
+					IPath dep = null;
+					if (re != null) {
+						IPath addlPath = re.getLocation();
+						if (addlPath != null) {
+							dep = ManagedBuildManager.calculateRelativePath(getTopBuildDir(), addlPath);
+						}
+					}
+					if (dep != null) {
+						deps.add(dep);
+					}
+				}
+			}
+			break;
+
+		case IManagedDependencyGeneratorType.TYPE_NODEPS:
+		default:
+			break;
+		}
+		return deps.toArray(new IPath[deps.size()]);
+	}
+
+	/**
+	 * Returns the dependency <code>IPath</code>s relative to the build directory
+	 *
+	 *  @param depCalculator  the dependency calculator
+	 *  @return IPath[] that are relative to the build directory
+	 */
+	protected IPath[] calculateDependenciesForSource(IManagedDependencyCalculator depCalculator) {
+		IPath[] addlDeps = depCalculator.getDependencies();
+		if (addlDeps != null) {
+			for (int i = 0; i < addlDeps.length; i++) {
+				if (!addlDeps[i].isAbsolute()) {
+					// Convert from project relative to build directory relative
+					IPath absolutePath = project.getLocation().append(addlDeps[i]);
+					addlDeps[i] = ManagedBuildManager.calculateRelativePath(getTopBuildDir(), absolutePath);
+				}
+			}
+		}
+		return addlDeps;
+	}
+
+	/*************************************************************************
+	 *   M A K E F I L E   G E N E R A T I O N   C O M M O N   M E T H O D S
+	 ************************************************************************/
+
+	/**
+	 * Generates a source macro name from a file extension
+	 */
+	public StringBuffer getSourceMacroName(String extensionName) {
+		StringBuffer macroName = new StringBuffer();
+
+		// We need to handle case sensitivity in file extensions (e.g. .c vs .C), so if the
+		// extension was already upper case, tack on an "UPPER_" to the macro name.
+		// In theory this means there could be a conflict if you had for example,
+		// extensions .c_upper, and .C, but realistically speaking the chances of this are
+		// practically nil so it doesn't seem worth the hassle of generating a truly
+		// unique name.
+		if (extensionName.equals(extensionName.toUpperCase())) {
+			macroName.append(extensionName.toUpperCase()).append("_UPPER"); //$NON-NLS-1$
+		} else {
+			// lower case... no need for "UPPER_"
+			macroName.append(extensionName.toUpperCase());
+		}
+		macroName.append("_SRCS"); //$NON-NLS-1$
+		return macroName;
+	}
+
+	/**
+	 * Generates a generated dependency file macro name from a file extension
+	 */
+	public StringBuffer getDepMacroName(String extensionName) {
+		StringBuffer macroName = new StringBuffer();
+
+		// We need to handle case sensitivity in file extensions (e.g. .c vs .C), so if the
+		// extension was already upper case, tack on an "UPPER_" to the macro name.
+		// In theory this means there could be a conflict if you had for example,
+		// extensions .c_upper, and .C, but realistically speaking the chances of this are
+		// practically nil so it doesn't seem worth the hassle of generating a truly
+		// unique name.
+		if (extensionName.equals(extensionName.toUpperCase())) {
+			macroName.append(extensionName.toUpperCase()).append("_UPPER"); //$NON-NLS-1$
+		} else {
+			// lower case... no need for "UPPER_"
+			macroName.append(extensionName.toUpperCase());
+		}
+		macroName.append("_DEPS"); //$NON-NLS-1$
+		return macroName;
+	}
+
+	/**
+	 * Answers all of the output extensions that the target
+	 * of the build has tools defined to work on.
+	 *
+	 * @return a <code>Set</code> containing all of the output extensions
+	 */
+	public Set<String> getOutputExtensions(ToolInfoHolder h) {
+		if (h.outputExtensionsSet == null) {
+			// The set of output extensions which will be produced by this tool.
+			// It is presumed that this set is not very large (likely < 10) so
+			// a HashSet should provide good performance.
+			h.outputExtensionsSet = new HashSet<>();
+
+			// For each tool for the target, lookup the kinds of sources it outputs
+			// and add that to our list of output extensions.
+			for (ITool tool : h.buildTools) {
+				String[] outputs = tool.getAllOutputExtensions();
+				if (outputs != null) {
+					h.outputExtensionsSet.addAll(Arrays.asList(outputs));
+				}
+			}
+		}
+		return h.outputExtensionsSet;
+	}
+
+	/**
+	 * @deprecated Use {@link GnuMakefileGenerator#generateDummyTargets(IConfiguration, IFile, boolean)}
+	 */
+	@Deprecated
+	static public boolean populateDummyTargets(IConfiguration cfg, IFile makefile, boolean force)
+			throws CoreException, IOException {
+		return new GnuMakefileGenerator().generateDummyTargets(cfg, makefile, force);
+	}
+
+	/**
+	 *  This method postprocesses a .d file created by a build.
+	 *  It's main job is to add dummy targets for the header files dependencies.
+	 *  This prevents make from aborting the build if the header file does not exist.
+	 *
+	 *  A secondary job is to work in tandem with the "echo" command that is used
+	 *  by some tool-chains in order to get the "targets" part of the dependency rule
+	 *  correct.
+	 *
+	 *  This method adds a comment to the beginning of the dependency file which it
+	 *  checks for to determine if this dependency file has already been updated.
+	 *
+	 * @return a <code>true</code> if the dependency file is modified
+	 * @since 9.3
+	 */
+	public boolean generateDummyTargets(IConfiguration cfg, IFile makefile, boolean force)
+			throws CoreException, IOException {
+		return generateDummyTargets(cfg.getRootFolderInfo(), makefile, force);
+	}
+
+	/**
+	 * @deprecated Use {@link GnuMakefileGenerator#generateDummyTargets(IResourceInfo, IFile, boolean)}
+	 */
+	@Deprecated
+	static public boolean populateDummyTargets(IResourceInfo rcInfo, IFile makefile, boolean force)
+			throws CoreException, IOException {
+		return new GnuMakefileGenerator().generateDummyTargets(rcInfo, makefile, force);
+	}
+
+	/**
+	 * @since 9.3
+	 */
+	public boolean generateDummyTargets(IResourceInfo rcInfo, IFile makefile, boolean force)
+			throws CoreException, IOException {
+
+		if (makefile == null || !makefile.exists())
+			return false;
+
+		// Get the contents of the dependency file
+		StringBuffer inBuffer;
+		InputStream contentStream = makefile.getContents(false);
+		try (Reader in = new InputStreamReader(contentStream)) {
+			int chunkSize = contentStream.available();
+			inBuffer = new StringBuffer(chunkSize);
+			char[] readBuffer = new char[chunkSize];
+			int n = in.read(readBuffer);
+			while (n > 0) {
+				inBuffer.append(readBuffer);
+				n = in.read(readBuffer);
+			}
+		}
+
+		// The rest of this operation is equally expensive, so
+		// if we are doing an incremental build, only update the
+		// files that do not have a comment
+		String inBufferString = inBuffer.toString();
+		if (!force && inBufferString.startsWith(COMMENT_SYMBOL)) {
+			return false;
+		}
+
+		// Try to determine if this file already has dummy targets defined.
+		// If so, we will only add the comment.
+		String[] bufferLines = inBufferString.split("[\\r\\n]"); //$NON-NLS-1$
+		for (String bufferLine : bufferLines) {
+			if (bufferLine.endsWith(":")) { //$NON-NLS-1$
+				StringBuffer outBuffer = addDefaultHeader();
+				outBuffer.append(inBuffer);
+				save(outBuffer, makefile);
+				return true;
+			}
+		}
+
+		// Reconstruct the buffer tokens into useful chunks of dependency information
+		Vector<String> bufferTokens = new Vector<>(Arrays.asList(inBufferString.split("\\s"))); //$NON-NLS-1$
+		Vector<String> deps = new Vector<>(bufferTokens.size());
+		Iterator<String> tokenIter = bufferTokens.iterator();
+		while (tokenIter.hasNext()) {
+			String token = tokenIter.next();
+			if (token.lastIndexOf("\\") == token.length() - 1 && token.length() > 1) { //$NON-NLS-1$
+				// This is escaped so keep adding to the token until we find the end
+				while (tokenIter.hasNext()) {
+					String nextToken = tokenIter.next();
+					token += WHITESPACE + nextToken;
+					if (!nextToken.endsWith("\\")) { //$NON-NLS-1$
+						//$NON-NLS-1$
+						break;
+					}
+				}
+			}
+			deps.add(token);
+		}
+		deps.trimToSize();
+
+		// Now find the header file dependencies and make dummy targets for them
+		boolean save = false;
+		StringBuffer outBuffer = null;
+
+		// If we are doing an incremental build, only update the files that do not have a comment
+		String firstToken;
+		try {
+			firstToken = deps.get(0);
+		} catch (ArrayIndexOutOfBoundsException e) {
+			// This makes no sense so bail
+			return false;
+		}
+
+		// Put the generated comments in the output buffer
+		if (!firstToken.startsWith(COMMENT_SYMBOL)) {
+			outBuffer = addDefaultHeader();
+		} else {
+			outBuffer = new StringBuffer();
+		}
+
+		// Some echo implementations misbehave and put the -n and newline in the output
+		if (firstToken.startsWith("-n")) { //$NON-NLS-1$
+
+			// Now let's parse:
+			// Win32 outputs -n '<path>/<file>.d <path>/'
+			// POSIX outputs -n <path>/<file>.d <path>/
+			// Get the dep file name
+			String secondToken;
+			try {
+				secondToken = deps.get(1);
+			} catch (ArrayIndexOutOfBoundsException e) {
+				secondToken = ""; //$NON-NLS-1$
+			}
+			if (secondToken.startsWith("'")) { //$NON-NLS-1$
+				// This is the Win32 implementation of echo (MinGW without MSYS)
+				outBuffer.append(secondToken.substring(1)).append(WHITESPACE);
+			} else {
+				outBuffer.append(secondToken).append(WHITESPACE);
+			}
+
+			// The relative path to the build goal comes next
+			String thirdToken;
+			try {
+				thirdToken = deps.get(2);
+			} catch (ArrayIndexOutOfBoundsException e) {
+				thirdToken = ""; //$NON-NLS-1$
+			}
+			int lastIndex = thirdToken.lastIndexOf("'"); //$NON-NLS-1$
+			if (lastIndex != -1) {
+				if (lastIndex == 0) {
+					outBuffer.append(WHITESPACE);
+				} else {
+					outBuffer.append(thirdToken.substring(0, lastIndex - 1));
+				}
+			} else {
+				outBuffer.append(thirdToken);
+			}
+
+			// Followed by the target output by the compiler plus ':'
+			// If we see any empty tokens here, assume they are the result of
+			// a line feed output by "echo" and skip them
+			String fourthToken;
+			int nToken = 3;
+			try {
+				do {
+					fourthToken = deps.get(nToken++);
+				} while (fourthToken.length() == 0);
+
+			} catch (ArrayIndexOutOfBoundsException e) {
+				fourthToken = ""; //$NON-NLS-1$
+			}
+			outBuffer.append(fourthToken).append(WHITESPACE);
+
+			// Followed by the actual dependencies
+			try {
+				for (String nextElement : deps) {
+					if (nextElement.endsWith("\\")) { //$NON-NLS-1$
+						outBuffer.append(nextElement).append(NEWLINE).append(WHITESPACE);
+					} else {
+						outBuffer.append(nextElement).append(WHITESPACE);
+					}
+				}
+			} catch (IndexOutOfBoundsException e) {
+			}
+
+		} else {
+			outBuffer.append(inBuffer);
+		}
+
+		outBuffer.append(NEWLINE);
+		save = true;
+
+		IFolderInfo fo = null;
+		if (rcInfo instanceof IFolderInfo) {
+			fo = (IFolderInfo) rcInfo;
+		} else {
+			IConfiguration c = rcInfo.getParent();
+			fo = (IFolderInfo) c.getResourceInfo(rcInfo.getPath().removeLastSegments(1), false);
+		}
+		// Dummy targets to add to the makefile
+		for (String dummy : deps) {
+			IPath dep = new Path(dummy);
+			String extension = dep.getFileExtension();
+			if (fo.isHeaderFile(extension)) {
+				/*
+				 * The formatting here is
+				 * <dummy_target>:
+				 */
+				outBuffer.append(dummy).append(COLON).append(NEWLINE).append(NEWLINE);
+			}
+		}
+
+		// Write them out to the makefile
+		if (save) {
+			save(outBuffer, makefile);
+			return true;
+		}
+
+		return false;
+	}
+
+	/**
+	 * prepend all instanced of '\' or '"' with a backslash
+	 *
+	 * @return resulting string
+	 */
+	static public String escapedEcho(String string) {
+		String escapedString = string.replaceAll("'", "'\"'\"'"); //$NON-NLS-1$ //$NON-NLS-2$
+		return ECHO + WHITESPACE + SINGLE_QUOTE + escapedString + SINGLE_QUOTE + NEWLINE;
+	}
+
+	static public String ECHO_BLANK_LINE = ECHO + WHITESPACE + SINGLE_QUOTE + WHITESPACE + SINGLE_QUOTE + NEWLINE;
+
+	/**
+	 * @deprecated Use {@link GnuMakefileGenerator#addGenericHeader()}
+	 */
+	@Deprecated
+	static protected StringBuffer addDefaultHeader() {
+		return new GnuMakefileGenerator().addGenericHeader();
+	}
+
+	/**
+	 * Outputs a comment formatted as follows:
+	 * ##### ....... #####
+	 * # <Comment message>
+	 * ##### ....... #####
+	 * @since 9.3
+	 */
+	protected StringBuffer addGenericHeader() {
+		StringBuffer buffer = new StringBuffer();
+		outputCommentLine(buffer);
+		buffer.append(COMMENT_SYMBOL).append(WHITESPACE).append(ManagedMakeMessages.getResourceString(HEADER))
+				.append(NEWLINE);
+		addCustomHeader(buffer);
+		outputCommentLine(buffer);
+		buffer.append(NEWLINE);
+		return buffer;
+	}
+
+	/**
+	 * @since 9.3
+	 */
+	protected void addCustomHeader(StringBuffer buffer) {
+	}
+
+	/**
+	 * Put COLS_PER_LINE comment charaters in the argument.
+	 */
+	static protected void outputCommentLine(StringBuffer buffer) {
+		for (int i = 0; i < COLS_PER_LINE; i++) {
+			buffer.append(COMMENT_SYMBOL);
+		}
+		buffer.append(NEWLINE);
+	}
+
+	static public boolean containsSpecialCharacters(String path) {
+		return path.matches(".*(\\s|[\\{\\}\\(\\)\\$\\@%=;]).*"); //$NON-NLS-1$
+	}
+
+	/**
+	 * Answers the argument with all whitespaces replaced with an escape sequence.
+	 */
+	static public String escapeWhitespaces(String path) {
+		// Escape the spaces in the path/filename if it has any
+		String[] segments = path.split("\\s"); //$NON-NLS-1$
+		if (segments.length > 1) {
+			StringBuffer escapedPath = new StringBuffer();
+			for (int index = 0; index < segments.length; ++index) {
+				escapedPath.append(segments[index]);
+				if (index + 1 < segments.length) {
+					escapedPath.append("\\ "); //$NON-NLS-1$
+				}
+			}
+			return escapedPath.toString().trim();
+		} else {
+			return path;
+		}
+	}
+
+	/**
+	 * Adds a macro addition prefix to a map of macro names to entries.
+	 * Entry prefixes look like:
+	 * 	C_SRCS += \
+	 * 	${addprefix $(ROOT)/, \
+	 */
+	// TODO fix comment
+	protected void addMacroAdditionPrefix(LinkedHashMap<String, String> map, String macroName, String relativePath,
+			boolean addPrefix) {
+		// there is no entry in the map, so create a buffer for this macro
+		StringBuffer tempBuffer = new StringBuffer();
+		tempBuffer.append(macroName).append(WHITESPACE).append(MACRO_ADDITION_PREFIX_SUFFIX);
+		if (addPrefix) {
+			tempBuffer.append(MACRO_ADDITION_ADDPREFIX_HEADER).append(relativePath)
+					.append(MACRO_ADDITION_ADDPREFIX_SUFFIX);
+		}
+
+		// have to store the buffer in String form as StringBuffer is not a sublcass of Object
+		map.put(macroName, tempBuffer.toString());
+	}
+
+	/**
+	 * Adds a file to an entry in a map of macro names to entries.
+	 * File additions look like:
+	 * 	example.c, \
+	 */
+	protected void addMacroAdditionFile(HashMap<String, String> map, String macroName, String filename) {
+		StringBuffer buffer = new StringBuffer();
+		buffer.append(map.get(macroName));
+
+		// escape whitespace in the filename
+		filename = escapeWhitespaces(filename);
+
+		buffer.append(filename).append(WHITESPACE).append(LINEBREAK);
+		// re-insert string in the map
+		map.put(macroName, buffer.toString());
+	}
+
+	/**
+	 * Adds a file to an entry in a map of macro names to entries.
+	 * File additions look like:
+	 * 	example.c, \
+	 */
+	protected void addMacroAdditionFile(HashMap<String, String> map, String macroName, String relativePath,
+			IPath sourceLocation, boolean generatedSource) {
+		//  Add the source file path to the makefile line that adds source files to the build variable
+		String srcName;
+		IPath projectLocation = getPathForResource(project);
+		IPath dirLocation = projectLocation;
+		if (generatedSource) {
+			dirLocation = dirLocation.append(getBuildWorkingDir());
+		}
+		if (dirLocation.isPrefixOf(sourceLocation)) {
+			IPath srcPath = sourceLocation.removeFirstSegments(dirLocation.segmentCount()).setDevice(null);
+			if (generatedSource) {
+				srcName = "./" + srcPath.toString(); //$NON-NLS-1$
+			} else {
+				srcName = reachProjectRoot() + SEPARATOR + srcPath.toString();
+			}
+		} else {
+			if (generatedSource && !sourceLocation.isAbsolute()) {
+				srcName = "./" + relativePath + sourceLocation.lastSegment().toString(); //$NON-NLS-1$
+			} else {
+				// TODO:  Should we use relative paths when possible (e.g., see MbsMacroSupplier.calculateRelPath)
+				srcName = sourceLocation.toString();
+			}
+		}
+		addMacroAdditionFile(map, macroName, srcName);
+	}
+
+	/**
+	 * Adds file(s) to an entry in a map of macro names to entries.
+	 * File additions look like:
+	 * 	example.c, \
+	 */
+	public void addMacroAdditionFiles(HashMap<String, String> map, String macroName, Vector<String> filenames) {
+		StringBuffer buffer = new StringBuffer();
+		buffer.append(map.get(macroName));
+		for (int i = 0; i < filenames.size(); i++) {
+			String filename = filenames.get(i);
+			if (filename.length() > 0) {
+
+				// Bug 417288, ilg@livius.net & freidin.alex@gmail.com
+				filename = ensurePathIsGNUMakeTargetRuleCompatibleSyntax(filename);
+
+				buffer.append(filename).append(WHITESPACE).append(LINEBREAK);
+			}
+		}
+		// re-insert string in the map
+		map.put(macroName, buffer.toString());
+	}
+
+	/**
+	 * Write all macro addition entries in a map to the buffer
+	 */
+	protected StringBuffer writeAdditionMacros(LinkedHashMap<String, String> map) {
+		StringBuffer buffer = new StringBuffer();
+		// Add the comment
+		buffer.append(COMMENT_SYMBOL).append(WHITESPACE).append(ManagedMakeMessages.getResourceString(MOD_VARS))
+				.append(NEWLINE);
+
+		for (String macroString : map.values()) {
+			// Check if we added any files to the rule
+			// Currently, we do this by comparing the end of the rule buffer to MACRO_ADDITION_PREFIX_SUFFIX
+			if (!(macroString.endsWith(MACRO_ADDITION_PREFIX_SUFFIX))) {
+				StringBuffer currentBuffer = new StringBuffer();
+
+				// Remove the final "/"
+				if (macroString.endsWith(LINEBREAK)) {
+					macroString = macroString.substring(0, (macroString.length() - 2)) + NEWLINE;
+				}
+				currentBuffer.append(macroString);
+
+				currentBuffer.append(NEWLINE);
+
+				// append the contents of the buffer to the master buffer for
+				// the whole file
+				buffer.append(currentBuffer);
+			}
+		}
+		return buffer.append(NEWLINE);
+	}
+
+	/**
+	 * Write all macro addition entries in a map to the buffer
+	 */
+	protected StringBuffer writeTopAdditionMacros(List<String> varList, HashMap<String, String> varMap) {
+		StringBuffer buffer = new StringBuffer();
+		// Add the comment
+		buffer.append(COMMENT_SYMBOL).append(WHITESPACE).append(ManagedMakeMessages.getResourceString(MOD_VARS))
+				.append(NEWLINE);
+
+		for (int i = 0; i < varList.size(); i++) {
+			String addition = varMap.get(varList.get(i));
+			StringBuffer currentBuffer = new StringBuffer();
+			currentBuffer.append(addition);
+			currentBuffer.append(NEWLINE);
+
+			// append the contents of the buffer to the master buffer for the whole file
+			buffer.append(currentBuffer);
+		}
+		return buffer.append(NEWLINE);
+	}
+
+	/**
+	 * Calculates the inputs and outputs for tools that will be generated in the top makefile.
+	 * This information is used by the top level makefile generation methods.
+	 */
+	protected void calculateToolInputsOutputs() {
+
+		toolInfos.accept(new IPathSettingsContainerVisitor() {
+			@Override
+			public boolean visit(PathSettingsContainer container) {
+				ToolInfoHolder h = (ToolInfoHolder) container.getValue();
+				ITool[] buildTools = h.buildTools;
+				ManagedBuildGnuToolInfo[] gnuToolInfos = h.gnuToolInfos;
+				//  We are "done" when the information for all tools has been calculated,
+				//  or we are not making any progress
+				boolean done = false;
+				boolean lastChance = false;
+				int[] doneState = new int[buildTools.length];
+
+				// Identify the target tool
+				ITool targetTool = config.calculateTargetTool();
+				//		if (targetTool == null) {
+				//			targetTool = info.getToolFromOutputExtension(buildTargetExt);
+				//		}
+
+				//  Initialize the tool info array and the done state
+
+				if (buildTools.length != 0 && buildTools[0].getCustomBuildStep())
+					return true;
+
+				for (int i = 0; i < buildTools.length; i++) {
+					if ((buildTools[i] == targetTool)) {
+						String ext = config.getArtifactExtension();
+						//try to resolve the build macros in the artifact extension
+						try {
+							ext = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(ext, "", //$NON-NLS-1$
+									" ", //$NON-NLS-1$
+									IBuildMacroProvider.CONTEXT_CONFIGURATION, config);
+						} catch (BuildMacroException e) {
+						}
+
+						String name = config.getArtifactName();
+						//try to resolve the build macros in the artifact name
+						try {
+							String resolved = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(
+									name, "", //$NON-NLS-1$
+									" ", //$NON-NLS-1$
+									IBuildMacroProvider.CONTEXT_CONFIGURATION, config);
+							if ((resolved = resolved.trim()).length() > 0)
+								name = resolved;
+						} catch (BuildMacroException e) {
+						}
+
+						gnuToolInfos[i] = new ManagedBuildGnuToolInfo(project, buildTools[i], true, name, ext);
+					} else {
+						gnuToolInfos[i] = new ManagedBuildGnuToolInfo(project, buildTools[i], false, null, null);
+					}
+					doneState[i] = 0;
+				}
+
+				//  Initialize the build output variable to file additions map
+				LinkedHashMap<String, String> map = getTopBuildOutputVars();
+				Set<Entry<String, List<IPath>>> set = buildOutVars.entrySet();
+				for (Entry<String, List<IPath>> entry : set) {
+					String macroName = entry.getKey();
+
+					// for projects with specific setting on folders/files do
+					// not clear the macro value on subsequent passes
+					if (!map.containsKey(macroName)) {
+						addMacroAdditionPrefix(map, macroName, "", false); //$NON-NLS-1$
+					}
+				}
+
+				// Set of input extensions for which macros have been created so far
+				HashSet<String> handledDepsInputExtensions = new HashSet<>();
+				HashSet<String> handledOutsInputExtensions = new HashSet<>();
+
+				while (!done) {
+					int[] testState = new int[doneState.length];
+					for (int i = 0; i < testState.length; i++)
+						testState[i] = 0;
+
+					//  Calculate inputs
+					for (int i = 0; i < gnuToolInfos.length; i++) {
+						if (gnuToolInfos[i].areInputsCalculated()) {
+							testState[i]++;
+						} else {
+							if (gnuToolInfos[i].calculateInputs(GnuMakefileGenerator.this, config, projectResources, h,
+									lastChance)) {
+								testState[i]++;
+							}
+						}
+					}
+					//  Calculate dependencies
+					for (int i = 0; i < gnuToolInfos.length; i++) {
+						if (gnuToolInfos[i].areDependenciesCalculated()) {
+							testState[i]++;
+						} else {
+							if (gnuToolInfos[i].calculateDependencies(GnuMakefileGenerator.this, config,
+									handledDepsInputExtensions, h, lastChance)) {
+								testState[i]++;
+							}
+						}
+					}
+					//  Calculate outputs
+					for (int i = 0; i < gnuToolInfos.length; i++) {
+						if (gnuToolInfos[i].areOutputsCalculated()) {
+							testState[i]++;
+						} else {
+							if (gnuToolInfos[i].calculateOutputs(GnuMakefileGenerator.this, config,
+									handledOutsInputExtensions, lastChance)) {
+								testState[i]++;
+							}
+						}
+					}
+					//  Are all calculated?  If so, done.
+					done = true;
+					for (int element : testState) {
+						if (element != 3) {
+							done = false;
+							break;
+						}
+					}
+
+					//  Test our "done" state vs. the previous "done" state.
+					//  If we have made no progress, give it a "last chance" and then quit
+					if (!done) {
+						done = true;
+						for (int i = 0; i < testState.length; i++) {
+							if (testState[i] != doneState[i]) {
+								done = false;
+								break;
+							}
+						}
+					}
+					if (done) {
+						if (!lastChance) {
+							lastChance = true;
+							done = false;
+						}
+					}
+					if (!done) {
+						doneState = testState;
+					}
+				}
+				return true;
+			}
+		});
+	}
+
+	/**
+	 * Returns the (String) list of files associated with the build variable
+	 *
+	 * @param variable  the variable name
+	 * @param locationType  the format in which we want the filenames returned
+	 * @param directory  project relative directory path used with locationType == DIRECTORY_RELATIVE
+	 * @param getAll  only return the list if all tools that are going to contrubute to this
+	 *                variable have done so.
+	 * @return List
+	 */
+	public List<String> getBuildVariableList(ToolInfoHolder h, String variable, int locationType, IPath directory,
+			boolean getAll) {
+		ManagedBuildGnuToolInfo[] gnuToolInfos = h.gnuToolInfos;
+		boolean done = true;
+		for (int i = 0; i < gnuToolInfos.length; i++) {
+			if (!gnuToolInfos[i].areOutputVariablesCalculated()) {
+				done = false;
+			}
+		}
+		if (!done && getAll)
+			return null;
+		List<IPath> list = buildSrcVars.get(variable);
+		if (list == null) {
+			list = buildOutVars.get(variable);
+		}
+
+		List<String> fileList = null;
+		if (list != null) {
+			//  Convert the items in the list to the location-type wanted by the caller,
+			//  and to a string list
+			IPath dirLocation = null;
+			if (locationType != ABSOLUTE) {
+				dirLocation = project.getLocation();
+				if (locationType == PROJECT_SUBDIR_RELATIVE) {
+					dirLocation = dirLocation.append(directory);
+				}
+			}
+			for (int i = 0; i < list.size(); i++) {
+				IPath path = list.get(i);
+				if (locationType != ABSOLUTE) {
+					if (dirLocation != null && dirLocation.isPrefixOf(path)) {
+						path = path.removeFirstSegments(dirLocation.segmentCount()).setDevice(null);
+					}
+				}
+				if (fileList == null) {
+					fileList = new Vector<>();
+				}
+				fileList.add(path.toString());
+			}
+		}
+
+		return fileList;
+	}
+
+	/**
+	 * Returns the map of build variables to list of files
+	 *
+	 * @return HashMap
+	 */
+	public HashMap<String, List<IPath>> getBuildOutputVars() {
+		return buildOutVars;
+	}
+
+	/**
+	 * Returns the map of build variables used in the top makefile to list of files
+	 *
+	 * @return HashMap
+	 */
+	public LinkedHashMap<String, String> getTopBuildOutputVars() {
+		return topBuildOutVars;
+	}
+
+	/**
+	 * Returns the list of known build rules. This keeps me from generating duplicate
+	 * rules for known file extensions.
+	 *
+	 * @return List
+	 */
+	protected Vector<String> getRuleList() {
+		if (ruleList == null) {
+			ruleList = new Vector<>();
+		}
+		return ruleList;
+	}
+
+	/**
+	 * Returns the list of known dependency lines. This keeps me from generating duplicate
+	 * lines.
+	 *
+	 * @return List
+	 */
+	protected Vector<String> getDepLineList() {
+		if (depLineList == null) {
+			depLineList = new Vector<>();
+		}
+		return depLineList;
+	}
+
+	/**
+	 * Returns the list of known dependency file generation lines. This keeps me from
+	 * generating duplicate lines.
+	 *
+	 * @return List
+	 */
+	protected Vector<String> getDepRuleList() {
+		if (depRuleList == null) {
+			depRuleList = new Vector<>();
+		}
+		return depRuleList;
+	}
+
+	/*************************************************************************
+	 *   R E S O U R C E   V I S I T O R   M E T H O D S
+	 ************************************************************************/
+
+	/**
+	 * 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 resource is not generated as part of the build.
+	 */
+	protected void appendBuildSubdirectory(IResource resource) {
+		IContainer container = resource.getParent();
+		// Only add the container once
+		if (!getSubdirList().contains(container))
+			getSubdirList().add(container);
+	}
+
+	/**
+	 * Adds the container of the argument to a list of subdirectories that are to be
+	 * deleted. As a result, the directories that are generated for the output
+	 * should be removed as well.
+	 */
+	protected void appendDeletedSubdirectory(IContainer container) {
+		// No point in adding a folder if the parent is already there
+		IContainer parent = container.getParent();
+		if (!getDeletedDirList().contains(container) && !getDeletedDirList().contains(parent)) {
+			getDeletedDirList().add(container);
+		}
+	}
+
+	/**
+	 * If a file is removed from a source folder (either because of a delete
+	 * or move action on the part of the user), the makefilegenerator has to
+	 * remove the dependency makefile along with the old build goal
+	 */
+	protected void appendDeletedFile(IResource resource) {
+		// Cache this for now
+		getDeletedFileList().add(resource);
+	}
+
+	/**
+	 * 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.
+	 */
+	protected void appendModifiedSubdirectory(IResource resource) {
+		IContainer container = resource.getParent();
+
+		if (!getModifiedList().contains(container)) {
+			getModifiedList().add(container);
+		}
+	}
+
+	/*************************************************************************
+	 *   O T H E R   M E T H O D S
+	 ************************************************************************/
+
+	protected void cancel(String message) {
+		if (monitor != null && !monitor.isCanceled()) {
+			throw new OperationCanceledException(message);
+		}
+	}
+
+	/**
+	 * 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()
+	 */
+	protected void checkCancel() {
+		if (monitor != null && monitor.isCanceled()) {
+			throw new OperationCanceledException();
+		}
+	}
+
+	/**
+	 * Return or create the folder needed for the build output. If we are
+	 * creating the folder, set the derived bit to true so the CM system
+	 * ignores the contents. If the resource exists, respect the existing
+	 * derived setting.
+	 */
+	private IPath createDirectory(String dirName) throws CoreException {
+		// Create or get the handle for the build directory
+		IFolder folder = project.getFolder(dirName);
+		if (!folder.exists()) {
+			// Make sure that parent folders exist
+			IPath parentPath = (new Path(dirName)).removeLastSegments(1);
+			// Assume that the parent exists if the path is empty
+			if (!parentPath.isEmpty()) {
+				IFolder parent = project.getFolder(parentPath);
+				if (!parent.exists()) {
+					createDirectory(parentPath.toString());
+				}
+			}
+
+			// Now make the requested folder
+			try {
+				folder.create(true, true, null);
+			} catch (CoreException e) {
+				if (e.getStatus().getCode() == IResourceStatus.PATH_OCCUPIED)
+					folder.refreshLocal(IResource.DEPTH_ZERO, null);
+				else
+					throw e;
+			}
+
+			// Make sure the folder is marked as derived so it is not added to CM
+			if (!folder.isDerived()) {
+				folder.setDerived(true, null);
+			}
+		}
+
+		return folder.getFullPath();
+	}
+
+	/**
+	 * Return or create the makefile needed for the build. If we are creating
+	 * the resource, set the derived bit to true so the CM system ignores
+	 * the contents. If the resource exists, respect the existing derived
+	 * setting.
+	 */
+	private IFile createFile(IPath makefilePath) throws CoreException {
+		// Create or get the handle for the makefile
+		IWorkspaceRoot root = CCorePlugin.getWorkspace().getRoot();
+		IFile newFile = root.getFileForLocation(makefilePath);
+		if (newFile == null) {
+			newFile = root.getFile(makefilePath);
+		}
+		// Create the file if it does not exist
+		ByteArrayInputStream contents = new ByteArrayInputStream(new byte[0]);
+		try {
+			newFile.create(contents, false, new SubProgressMonitor(monitor, 1));
+			// Make sure the new file is marked as derived
+			if (!newFile.isDerived()) {
+				newFile.setDerived(true, null);
+			}
+
+		} catch (CoreException e) {
+			// If the file already existed locally, just refresh to get contents
+			if (e.getStatus().getCode() == IResourceStatus.PATH_OCCUPIED)
+				newFile.refreshLocal(IResource.DEPTH_ZERO, null);
+			else
+				throw e;
+		}
+
+		return newFile;
+	}
+
+	private void deleteBuildTarget(IResource deletedFile) {
+		// Get the project relative path of the file
+		String fileName = getFileName(deletedFile);
+		String srcExtension = deletedFile.getFileExtension();
+		IPath folderPath = inFullPathFromOutFullPath(deletedFile.getFullPath().removeLastSegments(1));
+		if (folderPath != null) {
+			folderPath = folderPath.removeFirstSegments(1);
+		} else {
+			folderPath = new Path(""); //$NON-NLS-1$
+		}
+		IResourceInfo rcInfo = config.getResourceInfo(folderPath, false);
+		if (rcInfo instanceof IFileInfo) {
+			rcInfo = config.getResourceInfo(folderPath.removeLastSegments(1), false);
+		}
+		String targetExtension = ((IFolderInfo) rcInfo).getOutputExtension(srcExtension);
+		if (!targetExtension.isEmpty())
+			fileName += DOT + targetExtension;
+		IPath projectRelativePath = deletedFile.getProjectRelativePath().removeLastSegments(1);
+		IPath targetFilePath = getBuildWorkingDir().append(projectRelativePath).append(fileName);
+		IResource depFile = project.findMember(targetFilePath);
+		if (depFile != null && depFile.exists()) {
+			try {
+				depFile.delete(true, new SubProgressMonitor(monitor, 1));
+			} catch (CoreException e) {
+				// This had better be allowed during a build
+
+			}
+		}
+	}
+
+	private IPath inFullPathFromOutFullPath(IPath path) {
+		IPath inPath = null;
+		if (topBuildDir.isPrefixOf(path)) {
+			inPath = path.removeFirstSegments(topBuildDir.segmentCount());
+			inPath = project.getFullPath().append(path);
+		}
+		return inPath;
+	}
+
+	private void deleteDepFile(IResource deletedFile) {
+		// Calculate the top build directory relative paths of the dependency files
+		IPath[] depFilePaths = null;
+		ITool tool = null;
+		IManagedDependencyGeneratorType depType = null;
+		String sourceExtension = deletedFile.getFileExtension();
+		IPath folderPath = inFullPathFromOutFullPath(deletedFile.getFullPath().removeLastSegments(1));
+		if (folderPath != null) {
+			folderPath = folderPath.removeFirstSegments(1);
+		} else {
+			folderPath = new Path(""); //$NON-NLS-1$
+		}
+		ToolInfoHolder h = getToolInfo(folderPath);
+		ITool[] tools = h.buildTools;
+		for (int index = 0; index < tools.length; ++index) {
+			if (tools[index].buildsFileType(sourceExtension)) {
+				tool = tools[index];
+				depType = tool.getDependencyGeneratorForExtension(sourceExtension);
+				break;
+			}
+		}
+		if (depType != null) {
+			int calcType = depType.getCalculatorType();
+			if (calcType == IManagedDependencyGeneratorType.TYPE_COMMAND) {
+				depFilePaths = new IPath[1];
+				IPath absolutePath = deletedFile.getLocation();
+				depFilePaths[0] = ManagedBuildManager.calculateRelativePath(getTopBuildDir(), absolutePath);
+				depFilePaths[0] = depFilePaths[0].removeFileExtension().addFileExtension(DEP_EXT);
+			} else if (calcType == IManagedDependencyGeneratorType.TYPE_BUILD_COMMANDS
+					|| calcType == IManagedDependencyGeneratorType.TYPE_PREBUILD_COMMANDS) {
+				IManagedDependencyGenerator2 depGen = (IManagedDependencyGenerator2) depType;
+				IManagedDependencyInfo depInfo = depGen.getDependencySourceInfo(deletedFile.getProjectRelativePath(),
+						deletedFile, config, tool, getBuildWorkingDir());
+				if (depInfo != null) {
+					if (calcType == IManagedDependencyGeneratorType.TYPE_BUILD_COMMANDS) {
+						IManagedDependencyCommands depCommands = (IManagedDependencyCommands) depInfo;
+						depFilePaths = depCommands.getDependencyFiles();
+					} else if (calcType == IManagedDependencyGeneratorType.TYPE_PREBUILD_COMMANDS) {
+						IManagedDependencyPreBuild depPreBuild = (IManagedDependencyPreBuild) depInfo;
+						depFilePaths = depPreBuild.getDependencyFiles();
+					}
+				}
+			}
+		}
+
+		// Delete the files if they exist
+		if (depFilePaths != null) {
+			for (IPath dfp : depFilePaths) {
+				IPath depFilePath = getBuildWorkingDir().append(dfp);
+				IResource depFile = project.findMember(depFilePath);
+				if (depFile != null && depFile.exists()) {
+					try {
+						depFile.delete(true, new SubProgressMonitor(monitor, 1));
+					} catch (CoreException e) {
+						// This had better be allowed during a build
+					}
+				}
+			}
+		}
+	}
+
+	/**
+	 * Returns the current build configuration.
+	 *
+	 * @return String
+	 * @since 8.0
+	 */
+	protected IConfiguration getConfig() {
+		return config;
+	}
+
+	/**
+	 * Returns the build target extension.
+	 *
+	 * @return String
+	 * @since 8.0
+	 */
+	protected String getBuildTargetExt() {
+		return buildTargetExt;
+	}
+
+	/**
+	 * Returns the build target name.
+	 *
+	 * @return String
+	 * @since 8.0
+	 */
+	protected String getBuildTargetName() {
+		return buildTargetName;
+	}
+
+	/**
+	 * @return Returns the deletedDirList.
+	 */
+	private Vector<IResource> getDeletedDirList() {
+		if (deletedDirList == null) {
+			deletedDirList = new Vector<>();
+		}
+		return deletedDirList;
+	}
+
+	private Vector<IResource> getDeletedFileList() {
+		if (deletedFileList == null) {
+			deletedFileList = new Vector<>();
+		}
+		return deletedFileList;
+	}
+
+	private List<IPath> getDependencyMakefiles(ToolInfoHolder h) {
+		if (h.dependencyMakefiles == null) {
+			h.dependencyMakefiles = new ArrayList<>();
+		}
+		return h.dependencyMakefiles;
+	}
+
+	/**
+	 * Strips off the file extension from the argument and returns
+	 * the name component in a <code>String</code>
+	 */
+	private String getFileName(IResource file) {
+		String answer = ""; //$NON-NLS-1$
+		String lastSegment = file.getName();
+		int extensionSeparator = lastSegment.lastIndexOf(DOT);
+		if (extensionSeparator != -1) {
+			answer = lastSegment.substring(0, extensionSeparator);
+		}
+		return answer;
+	}
+
+	/**
+	 * Answers a Vector containing a list of directories that are invalid for the
+	 * build for some reason. At the moment, the only reason a directory would
+	 * not be considered for the build is if it contains a space in the relative
+	 * path from the project root.
+	 *
+	 * @return a a list of directories that are invalid for the build
+	 */
+	private Vector<IResource> getInvalidDirList() {
+		if (invalidDirList == null) {
+			invalidDirList = new Vector<>();
+		}
+		return invalidDirList;
+	}
+
+	/**
+	 * @return Collection of Containers which contain modified source files
+	 */
+	private Collection<IContainer> getModifiedList() {
+		if (modifiedList == null)
+			modifiedList = new LinkedHashSet<>();
+		return modifiedList;
+	}
+
+	/**
+	 * @return Collection of subdirectories (IContainers) contributing source code to the build
+	 */
+	private Collection<IContainer> getSubdirList() {
+		if (subdirList == null)
+			subdirList = new LinkedHashSet<>();
+		return subdirList;
+	}
+
+	private void removeGeneratedDirectory(IContainer subDir) {
+		try {
+			// The source directory isn't empty
+			if (subDir.exists() && subDir.members().length > 0)
+				return;
+		} catch (CoreException e) {
+			// The resource doesn't exist so we should delete the output folder
+		}
+
+		// Figure out what the generated directory name is and delete it
+		IPath moduleRelativePath = subDir.getProjectRelativePath();
+		IPath buildRoot = getBuildWorkingDir();
+		if (buildRoot == null) {
+			return;
+		}
+		IPath moduleOutputPath = buildRoot.append(moduleRelativePath);
+		IFolder folder = project.getFolder(moduleOutputPath);
+		if (folder.exists()) {
+			try {
+				folder.delete(true, new SubProgressMonitor(monitor, 1));
+			} catch (CoreException e) {
+				// TODO Log this
+			}
+		}
+	}
+
+	protected void updateMonitor(String msg) {
+		if (monitor != null && !monitor.isCanceled()) {
+			monitor.subTask(msg);
+			monitor.worked(1);
+		}
+	}
+
+	/**
+	 * Return the configuration's top build directory as an absolute path
+	 */
+	public IPath getTopBuildDir() {
+		return getPathForResource(project).append(getBuildWorkingDir());
+	}
+
+	/**
+	 * Process a String denoting a filepath in a way compatible for GNU Make rules, handling
+	 * windows drive letters and whitespace appropriately.
+	 * <p><p>
+	 * The context these paths appear in is on the right hand side of a rule header. i.e.
+	 * <p><p>
+	 * target : dep1 dep2 dep3
+	 * <p>
+	 * @param path the String denoting the path to process
+	 * @throws NullPointerException is path is null
+	 * @return a suitable Make rule compatible path
+	 */
+	/* see https://bugs.eclipse.org/bugs/show_bug.cgi?id=129782 */
+	public String ensurePathIsGNUMakeTargetRuleCompatibleSyntax(String path) {
+		boolean isQuotedOption = false;
+		if (path.startsWith("-")) { //$NON-NLS-1$
+			isQuotedOption = checkIfQuotedOption(path);
+		}
+		if (!isQuotedOption)
+			return escapeWhitespaces(ensureUnquoted(path));
+		return path;
+	}
+
+	private boolean checkIfQuotedOption(String path) {
+		Matcher m1 = doubleQuotedOption.matcher(path);
+		if (m1.matches())
+			return true;
+		Matcher m2 = singleQuotedOption.matcher(path);
+		if (m2.matches())
+			return true;
+		return false;
+	}
+
+	/**
+	 * Strips outermost quotes of Strings of the form "a" and 'a' or returns the original
+	 * string if the input is not of this form.
+	 *
+	 * @throws NullPointerException if path is null
+	 * @return a String without the outermost quotes (if the input has them)
+	 */
+	public static String ensureUnquoted(String path) {
+		boolean doubleQuoted = path.startsWith("\"") && path.endsWith("\""); //$NON-NLS-1$ //$NON-NLS-2$
+		boolean singleQuoted = path.startsWith("'") && path.endsWith("'"); //$NON-NLS-1$ //$NON-NLS-2$
+		return doubleQuoted || singleQuoted ? path.substring(1, path.length() - 1) : path;
+	}
+
+	@Override
+	public void initialize(int buildKind, IConfiguration cfg, IBuilder builder, IProgressMonitor monitor) {
+		// Save the project so we can get path and member information
+		this.project = cfg.getOwner().getProject();
+		if (builder == null) {
+			builder = cfg.getEditableBuilder();
+		}
+		try {
+			projectResources = project.members();
+		} catch (CoreException e) {
+			projectResources = null;
+		}
+		// Save the monitor reference for reporting back to the user
+		this.monitor = monitor;
+		// Get the build info for the project
+		//		this.info = info;
+		// Get the name of the build target
+		buildTargetName = cfg.getArtifactName();
+		// Get its extension
+		buildTargetExt = cfg.getArtifactExtension();
+
+		try {
+			//try to resolve the build macros in the target extension
+			buildTargetExt = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(buildTargetExt,
+					"", //$NON-NLS-1$
+					" ", //$NON-NLS-1$
+					IBuildMacroProvider.CONTEXT_CONFIGURATION, builder);
+		} catch (BuildMacroException e) {
+		}
+
+		try {
+			//try to resolve the build macros in the target name
+			String resolved = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(buildTargetName,
+					"", //$NON-NLS-1$
+					" ", //$NON-NLS-1$
+					IBuildMacroProvider.CONTEXT_CONFIGURATION, builder);
+			if (resolved != null) {
+				resolved = resolved.trim();
+				if (resolved.length() > 0)
+					buildTargetName = resolved;
+			}
+		} catch (BuildMacroException e) {
+		}
+
+		if (buildTargetExt == null) {
+			buildTargetExt = ""; //$NON-NLS-1$
+		}
+		// Cache the build tools
+		config = cfg;
+		this.builder = builder;
+
+		initToolInfos();
+		//set the top build dir path
+		initializeTopBuildDir(cfg.getName());
+
+		srcEntries = config.getSourceEntries();
+		if (srcEntries.length == 0) {
+			srcEntries = new ICSourceEntry[] {
+					new CSourceEntry(Path.EMPTY, null, ICSettingEntry.RESOLVED | ICSettingEntry.VALUE_WORKSPACE_PATH) };
+		} else {
+			ICConfigurationDescription cfgDes = ManagedBuildManager.getDescriptionForConfiguration(config);
+			srcEntries = CDataUtil.resolveEntries(srcEntries, cfgDes);
+		}
+	}
+
+	private void initToolInfos() {
+		toolInfos = PathSettingsContainer.createRootContainer();
+
+		IResourceInfo rcInfos[] = config.getResourceInfos();
+		for (IResourceInfo rcInfo : rcInfos) {
+			if (rcInfo.isExcluded() /*&& !((ResourceInfo)rcInfo).isRoot()*/)
+				continue;
+
+			ToolInfoHolder h = getToolInfo(rcInfo.getPath(), true);
+			if (rcInfo instanceof IFolderInfo) {
+				IFolderInfo fo = (IFolderInfo) rcInfo;
+				h.buildTools = fo.getFilteredTools();
+				h.buildToolsUsed = new boolean[h.buildTools.length];
+				h.gnuToolInfos = new ManagedBuildGnuToolInfo[h.buildTools.length];
+			} else {
+				IFileInfo fi = (IFileInfo) rcInfo;
+				h.buildTools = fi.getToolsToInvoke();
+				h.buildToolsUsed = new boolean[h.buildTools.length];
+				h.gnuToolInfos = new ManagedBuildGnuToolInfo[h.buildTools.length];
+			}
+		}
+	}
+
+	private ToolInfoHolder getToolInfo(IPath path) {
+		return getToolInfo(path, false);
+	}
+
+	private ToolInfoHolder getFolderToolInfo(IPath path) {
+		IResourceInfo rcInfo = config.getResourceInfo(path, false);
+		while (rcInfo instanceof IFileInfo) {
+			path = path.removeLastSegments(1);
+			rcInfo = config.getResourceInfo(path, false);
+		}
+		return getToolInfo(path, false);
+	}
+
+	private ToolInfoHolder getToolInfo(IPath path, boolean create) {
+		PathSettingsContainer child = toolInfos.getChildContainer(path, create, create);
+		ToolInfoHolder h = null;
+		if (child != null) {
+			h = (ToolInfoHolder) child.getValue();
+			if (h == null && create) {
+				h = new ToolInfoHolder();
+				child.setValue(h);
+			}
+		}
+		return h;
+	}
+
+	private void ensureTopBuildDir() throws CoreException {
+		IPath buildWorkingDir = getBuildWorkingDir();
+		if (buildWorkingDir != null) {
+			createDirectory(buildWorkingDir.toString());
+		}
+	}
+
+	private void initializeTopBuildDir(String configName) {
+		topBuildDir = project.getFolder(computeTopBuildDir(configName)).getFullPath();
+	}
+
+	/**
+	 * Can be overwritten by a subclass to specify the top build directory to be
+	 * used. Default implementation simply returns configuration name.
+	 * <p>
+	 * <strong>Note</strong>: be careful by overriding this method - all places in the custom code and related
+	 * scripts using or referencing top build directory must also be changed to use same logic.
+	 *
+	 * @param configName name of the configuration
+	 * @return project relative path for top build directory
+	 * @since 8.7
+	 */
+	protected IPath computeTopBuildDir(String configName) {
+		return new Path(configName);
+	}
+
+	/**
+	 * @return As many ".." as required to get from getBuildWorkingDir() to the project root.
+	 *
+	 *         E.g. If getBuildWorkingDir() is "Debug", then the function returns "..". If
+	 *         getBuildWorkingDir() returns "x86/Debug" then "../.." is returned.
+	 *
+	 * @since 8.7
+	 */
+	public String reachProjectRoot() {
+		IPath buildWorkingDir = getBuildWorkingDir();
+		if (buildWorkingDir == null) {
+			return ROOT;
+		}
+		String root = ROOT;
+		int segCnt = buildWorkingDir.segmentCount();
+		for (int i = 1; i < segCnt; i++) {
+			root += SEPARATOR + ROOT;
+		}
+		return root;
+	}
+
+}
diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/makegen/gnu2/IManagedBuildGnuToolInfo.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/makegen/gnu2/IManagedBuildGnuToolInfo.java
new file mode 100644
index 00000000000..f95f7a6ef40
--- /dev/null
+++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/makegen/gnu2/IManagedBuildGnuToolInfo.java
@@ -0,0 +1,128 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2010 Intel Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Intel Corporation - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.managedbuilder.makegen.gnu2;
+
+import java.util.Vector;
+
+/**
+ * This interface returns information about a Tool's inputs
+ * and outputs while a Gnu makefile is being generated.
+ *
+ * @noextend This class is not intended to be subclassed by clients.
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IManagedBuildGnuToolInfo {
+	public final String DOT = "."; //$NON-NLS-1$
+
+	/**
+	 * Returns <code>true</code> if the tool's inputs have been calculated,
+	 * else <code>false</code>.
+	 *
+	 * @return boolean
+	 */
+	public boolean areInputsCalculated();
+
+	/**
+	 * Returns the tool's inputs in command line format.  This will use
+	 * variables rather than actual file names as appropriate.
+	 *
+	 *  @return Vector
+	 */
+	public Vector<String> getCommandInputs();
+
+	/**
+	 * Returns the raw list of tool's input file names.
+	 *
+	 *  @return Vector
+	 */
+	public Vector<String> getEnumeratedInputs();
+
+	/**
+	 * Returns <code>true</code> if the tool's outputs have been calculated,
+	 * else <code>false</code>.
+	 *
+	 * @return boolean
+	 */
+	public boolean areOutputsCalculated();
+
+	/**
+	 * Returns the tool's outputs in command line format.  This will use
+	 * variables rather than actual file names as appropriate.
+	 *
+	 *  @return Vector
+	 */
+	public Vector<String> getCommandOutputs();
+
+	/**
+	 * Returns the raw list of tool's primary output file names.
+	 *
+	 *  @return Vector
+	 */
+	public Vector<String> getEnumeratedPrimaryOutputs();
+
+	/**
+	 * Returns the raw list of tool's secondary output file names.
+	 *
+	 *  @return Vector
+	 */
+	public Vector<String> getEnumeratedSecondaryOutputs();
+
+	/**
+	 * Returns the raw list of tool's output variable names.
+	 *
+	 *  @return Vector
+	 */
+	public Vector<String> getOutputVariables();
+
+	/**
+	 * Returns <code>true</code> if the tool's dependencies have been calculated,
+	 * else <code>false</code>.
+	 *
+	 * @return boolean
+	 */
+	public boolean areDependenciesCalculated();
+
+	/**
+	 * Returns the tool's dependencies in command line format.  This will use
+	 * variables rather than actual file names as appropriate.
+	 * Dependencies are top build directory relative.
+	 *
+	 *  @return Vector
+	 */
+	public Vector<String> getCommandDependencies();
+
+	/**
+	 * Returns the tool's additional targets as determined by the
+	 * dependency calculator.
+	 * Additional targets are top build directory relative
+	 *
+	 *  @return Vector
+	 */
+	public Vector<String> getAdditionalTargets();
+
+	/**
+	 * Returns the raw list of tool's input dependencies.
+	 *
+	 *  @return Vector
+	 */
+	//public Vector<String> getEnumeratedDependencies();
+
+	/**
+	 * Returns <code>true</code> if this is the target tool
+	 * else <code>false</code>.
+	 *
+	 * @return boolean
+	 */
+	public boolean isTargetTool();
+}
diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/makegen/gnu2/ManagedBuildGnuToolInfo.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/makegen/gnu2/ManagedBuildGnuToolInfo.java
new file mode 100644
index 00000000000..30c6bfd06bb
--- /dev/null
+++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/makegen/gnu2/ManagedBuildGnuToolInfo.java
@@ -0,0 +1,1004 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2016 Intel Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Intel Corporation - Initial API and implementation
+ * IBM Corporation
+ *******************************************************************************/
+package org.eclipse.cdt.managedbuilder.makegen.gnu2;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.Vector;
+
+import org.eclipse.cdt.managedbuilder.core.BuildException;
+import org.eclipse.cdt.managedbuilder.core.IAdditionalInput;
+import org.eclipse.cdt.managedbuilder.core.IConfiguration;
+import org.eclipse.cdt.managedbuilder.core.IInputType;
+import org.eclipse.cdt.managedbuilder.core.IManagedOutputNameProvider;
+import org.eclipse.cdt.managedbuilder.core.IOption;
+import org.eclipse.cdt.managedbuilder.core.IOutputType;
+import org.eclipse.cdt.managedbuilder.core.ITool;
+import org.eclipse.cdt.managedbuilder.core.ManagedBuildManager;
+import org.eclipse.cdt.managedbuilder.internal.core.ManagedMakeMessages;
+import org.eclipse.cdt.managedbuilder.internal.core.Tool;
+import org.eclipse.cdt.managedbuilder.internal.macros.OptionContextData;
+import org.eclipse.cdt.managedbuilder.macros.BuildMacroException;
+import org.eclipse.cdt.managedbuilder.macros.IBuildMacroProvider;
+import org.eclipse.cdt.managedbuilder.makegen.IManagedBuilderMakefileGenerator;
+import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyCalculator;
+import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyGenerator;
+import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyGenerator2;
+import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyGeneratorType;
+import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyInfo;
+import org.eclipse.cdt.managedbuilder.makegen.gnu2.GnuMakefileGenerator.ToolInfoHolder;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+
+/**
+ * This class represents information about a Tool's inputs
+ * and outputs while a Gnu makefile is being generated.
+ *
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+public class ManagedBuildGnuToolInfo implements IManagedBuildGnuToolInfo {
+
+	/*
+	 * Members
+	 */
+	private IProject project;
+	private Tool tool;
+	private boolean bIsTargetTool;
+	private String targetName;
+	private String targetExt;
+	private boolean inputsCalculated = false;
+	private boolean outputsCalculated = false;
+	private boolean outputVariablesCalculated = false;
+	private boolean dependenciesCalculated = false;
+	private Vector<String> commandInputs = new Vector<>();
+	private Vector<String> enumeratedInputs = new Vector<>();
+	private Vector<String> commandOutputs = new Vector<>();
+	private Vector<String> enumeratedPrimaryOutputs = new Vector<>();
+	private Vector<String> enumeratedSecondaryOutputs = new Vector<>();
+	private Vector<String> outputVariables = new Vector<>();
+	private Vector<String> commandDependencies = new Vector<>();
+	private Vector<String> additionalTargets = new Vector<>();
+	//private Vector enumeratedDependencies = new Vector();
+	// Map of macro names (String) to values (List)
+
+	/*
+	 * Constructor
+	 */
+	public ManagedBuildGnuToolInfo(IProject project, ITool tool, boolean targetTool, String name, String ext) {
+		this.project = project;
+		this.tool = (Tool) tool;
+		bIsTargetTool = targetTool;
+		if (bIsTargetTool) {
+			targetName = name;
+			targetExt = ext;
+		}
+	}
+
+	/*
+	 * IManagedBuildGnuToolInfo Methods
+	 */
+	@Override
+	public boolean areInputsCalculated() {
+		return inputsCalculated;
+	}
+
+	//  Command inputs are top build directory relative
+	@Override
+	public Vector<String> getCommandInputs() {
+		return commandInputs;
+	}
+
+	//  Enumerated inputs are project relative
+	@Override
+	public Vector<String> getEnumeratedInputs() {
+		return enumeratedInputs;
+	}
+
+	@Override
+	public boolean areOutputsCalculated() {
+		return outputsCalculated;
+	}
+
+	//  Command outputs are top build directory relative
+	@Override
+	public Vector<String> getCommandOutputs() {
+		return commandOutputs;
+	}
+
+	@Override
+	public Vector<String> getEnumeratedPrimaryOutputs() {
+		return enumeratedPrimaryOutputs;
+	}
+
+	@Override
+	public Vector<String> getEnumeratedSecondaryOutputs() {
+		return enumeratedSecondaryOutputs;
+	}
+
+	@Override
+	public Vector<String> getOutputVariables() {
+		return outputVariables;
+	}
+
+	public boolean areOutputVariablesCalculated() {
+		return outputVariablesCalculated;
+	}
+
+	@Override
+	public boolean areDependenciesCalculated() {
+		return dependenciesCalculated;
+	}
+
+	//  Command dependencies are top build directory relative
+	@Override
+	public Vector<String> getCommandDependencies() {
+		return commandDependencies;
+	}
+
+	//  Additional targets are top build directory relative
+	@Override
+	public Vector<String> getAdditionalTargets() {
+		return additionalTargets;
+	}
+
+	//public Vector getEnumeratedDependencies() {
+	//	return enumeratedDependencies;
+	//}
+
+	@Override
+	public boolean isTargetTool() {
+		return bIsTargetTool;
+	}
+
+	/*
+	 * Other Methods
+	 */
+
+	public boolean calculateInputs(GnuMakefileGenerator makeGen, IConfiguration config, IResource[] projResources,
+			ToolInfoHolder h, boolean lastChance) {
+		// Get the inputs for this tool invocation
+		// Note that command inputs that are also dependencies are also added to the command dependencies list
+
+		/* The priorities for determining the names of the inputs of a tool are:
+		 *  1.  If an option is specified, use the value of the option.
+		 *  2.  If a build variable is specified, use the files that have been added to the build variable as
+		 *      the output(s) of other build steps.
+		 *  3.  Use the file extensions and the resources in the project
+		 */
+		boolean done = true;
+		Vector<String> myCommandInputs = new Vector<>(); // Inputs for the tool command line
+		Vector<String> myCommandDependencies = new Vector<>(); // Dependencies for the make rule
+		Vector<String> myEnumeratedInputs = new Vector<>(); // Complete list of individual inputs
+
+		IInputType[] inTypes = tool.getInputTypes();
+		if (inTypes != null && inTypes.length > 0) {
+			for (IInputType type : inTypes) {
+				Vector<String> itCommandInputs = new Vector<>(); // Inputs for the tool command line for this input-type
+				Vector<String> itCommandDependencies = new Vector<>(); // Dependencies for the make rule for this input-type
+				Vector<String> itEnumeratedInputs = new Vector<>(); // Complete list of individual inputs for this input-type
+				String variable = type.getBuildVariable();
+				boolean primaryInput = type.getPrimaryInput();
+				boolean useFileExts = false;
+				IOption option = tool.getOptionBySuperClassId(type.getOptionId());
+				IOption assignToOption = tool.getOptionBySuperClassId(type.getAssignToOptionId());
+
+				//  Option?
+				if (option != null) {
+					try {
+						List<String> inputs = new ArrayList<>();
+						int optType = option.getValueType();
+						if (optType == IOption.STRING) {
+							inputs.add(option.getStringValue());
+						} else if (optType == IOption.STRING_LIST || optType == IOption.LIBRARIES
+								|| optType == IOption.OBJECTS || optType == IOption.INCLUDE_FILES
+								|| optType == IOption.LIBRARY_PATHS || optType == IOption.LIBRARY_FILES
+								|| optType == IOption.MACRO_FILES) {
+							@SuppressWarnings("unchecked")
+							List<String> valueList = (List<String>) option.getValue();
+							inputs = valueList;
+							tool.filterValues(optType, inputs);
+							tool.filterValues(optType, inputs);
+						}
+						for (int j = 0; j < inputs.size(); j++) {
+							String inputName = inputs.get(j);
+
+							try {
+								// try to resolve the build macros in the output
+								// names
+
+								String resolved = null;
+
+								// does the input name contain spaces?
+								// TODO: support other special characters
+								if (inputName.indexOf(" ") != -1) //$NON-NLS-1$
+								{
+									// resolve to string
+									resolved = ManagedBuildManager.getBuildMacroProvider().resolveValue(inputName, "", //$NON-NLS-1$
+											" ", //$NON-NLS-1$
+											IBuildMacroProvider.CONTEXT_OPTION, new OptionContextData(option, tool));
+								} else {
+
+									// resolve to makefile variable format
+									resolved = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(
+											inputName, "", //$NON-NLS-1$
+											" ", //$NON-NLS-1$
+											IBuildMacroProvider.CONTEXT_OPTION, new OptionContextData(option, tool));
+								}
+
+								if ((resolved = resolved.trim()).length() > 0)
+									inputName = resolved;
+							} catch (BuildMacroException e) {
+							}
+
+							if (primaryInput) {
+								itCommandDependencies.add(j, inputName);
+							} else {
+								itCommandDependencies.add(inputName);
+							}
+							// NO - itCommandInputs.add(inputName);
+							// NO - itEnumeratedInputs.add(inputName);
+						}
+					} catch (BuildException ex) {
+					}
+
+				} else {
+
+					//  Build Variable?
+					if (variable.length() > 0) {
+						String cmdVariable = variable = "$(" + variable + ")"; //$NON-NLS-1$	//$NON-NLS-2$
+						itCommandInputs.add(cmdVariable);
+						if (primaryInput) {
+							itCommandDependencies.add(0, cmdVariable);
+						} else {
+							itCommandDependencies.add(cmdVariable);
+						}
+						// If there is an output variable with the same name, get
+						// the files associated with it.
+						List<String> outMacroList = makeGen.getBuildVariableList(h, variable,
+								GnuMakefileGenerator.PROJECT_RELATIVE, null, true);
+						if (outMacroList != null) {
+							itEnumeratedInputs.addAll(outMacroList);
+						} else {
+							// If "last chance", then calculate using file extensions below
+							if (lastChance) {
+								useFileExts = true;
+							} else {
+								done = false;
+								break;
+							}
+						}
+					}
+
+					//  Use file extensions
+					if (variable.length() == 0 || useFileExts) {
+						//if (type.getMultipleOfType()) {
+						// Calculate EnumeratedInputs using the file extensions and the resources in the project
+						// Note:  This is only correct for tools with multipleOfType == true, but for other tools
+						//        it gives us an input resource for generating default names
+						// Determine the set of source input macros to use
+						HashSet<String> handledInputExtensions = new HashSet<>();
+						String[] exts = type.getSourceExtensions(tool);
+						if (projResources != null) {
+							for (IResource rc : projResources) {
+								if (rc.getType() == IResource.FILE) {
+									String fileExt = rc.getFileExtension();
+
+									// fix for NPE, bugzilla 99483
+									if (fileExt == null) {
+										fileExt = ""; //$NON-NLS-1$
+									}
+
+									for (int k = 0; k < exts.length; k++) {
+										if (fileExt.equals(exts[k])) {
+											if (!useFileExts) {
+												if (!handledInputExtensions.contains(fileExt)) {
+													handledInputExtensions.add(fileExt);
+													String buildMacro = "$(" //$NON-NLS-1$
+															+ makeGen.getSourceMacroName(fileExt).toString() + ")"; //$NON-NLS-1$
+													itCommandInputs.add(buildMacro);
+													if (primaryInput) {
+														itCommandDependencies.add(0, buildMacro);
+													} else {
+														itCommandDependencies.add(buildMacro);
+													}
+												}
+											}
+											if (type.getMultipleOfType() || itEnumeratedInputs.size() == 0) {
+												//  Add a path that is relative to the project directory
+												itEnumeratedInputs.add(rc.getProjectRelativePath().toString());
+											}
+											break;
+										}
+									}
+								}
+							}
+						}
+						//}
+					}
+				}
+
+				// Get any additional inputs specified in the manifest file or the project file
+				IAdditionalInput[] addlInputs = type.getAdditionalInputs();
+				if (addlInputs != null) {
+					for (int j = 0; j < addlInputs.length; j++) {
+						IAdditionalInput addlInput = addlInputs[j];
+						int kind = addlInput.getKind();
+						if (kind == IAdditionalInput.KIND_ADDITIONAL_INPUT
+								|| kind == IAdditionalInput.KIND_ADDITIONAL_INPUT_DEPENDENCY) {
+							String[] paths = addlInput.getPaths();
+							if (paths != null) {
+								for (int k = 0; k < paths.length; k++) {
+									String path = paths[k];
+									itEnumeratedInputs.add(path);
+									// Translate the path from project relative to build directory relative
+									if (!(path.startsWith("$("))) { //$NON-NLS-1$
+										IResource addlResource = project.getFile(path);
+										if (addlResource != null) {
+											IPath addlPath = addlResource.getLocation();
+											if (addlPath != null) {
+												path = ManagedBuildManager
+														.calculateRelativePath(makeGen.getTopBuildDir(), addlPath)
+														.toString();
+											}
+										}
+									}
+									itCommandInputs.add(path);
+								}
+							}
+						}
+					}
+				}
+
+				//  If the assignToOption attribute is specified, set the input(s) as the value of that option
+				if (assignToOption != null && option == null) {
+					try {
+						int optType = assignToOption.getValueType();
+						if (optType == IOption.STRING) {
+							String optVal = ""; //$NON-NLS-1$
+							for (int j = 0; j < itCommandInputs.size(); j++) {
+								if (j != 0) {
+									optVal += " "; //$NON-NLS-1$
+								}
+								optVal += itCommandInputs.get(j);
+							}
+							ManagedBuildManager.setOption(config, tool, assignToOption, optVal);
+						} else if (optType == IOption.STRING_LIST || optType == IOption.LIBRARIES
+								|| optType == IOption.OBJECTS || optType == IOption.INCLUDE_FILES
+								|| optType == IOption.LIBRARY_PATHS || optType == IOption.LIBRARY_FILES
+								|| optType == IOption.MACRO_FILES) {
+							//TODO: do we need to do anything with undefs here?
+							//  Mote that when using the enumerated inputs, the path(s) must be translated from project relative
+							//  to top build directory relative
+							String[] paths = new String[itEnumeratedInputs.size()];
+							for (int j = 0; j < itEnumeratedInputs.size(); j++) {
+								paths[j] = itEnumeratedInputs.get(j);
+								IResource enumResource = project.getFile(paths[j]);
+								if (enumResource != null) {
+									IPath enumPath = enumResource.getLocation();
+									if (enumPath != null) {
+										paths[j] = ManagedBuildManager
+												.calculateRelativePath(makeGen.getTopBuildDir(), enumPath).toString();
+									}
+								}
+							}
+							ManagedBuildManager.setOption(config, tool, assignToOption, paths);
+						} else if (optType == IOption.BOOLEAN) {
+							if (itEnumeratedInputs.size() > 0) {
+								ManagedBuildManager.setOption(config, tool, assignToOption, true);
+							} else {
+								ManagedBuildManager.setOption(config, tool, assignToOption, false);
+							}
+						} else if (optType == IOption.ENUMERATED || optType == IOption.TREE) {
+							if (itCommandInputs.size() > 0) {
+								ManagedBuildManager.setOption(config, tool, assignToOption,
+										itCommandInputs.firstElement());
+							}
+						}
+						itCommandInputs.removeAllElements();
+						//itEnumeratedInputs.removeAllElements();
+					} catch (BuildException ex) {
+					}
+				}
+
+				myCommandInputs.addAll(itCommandInputs);
+				myCommandDependencies.addAll(itCommandDependencies);
+				myEnumeratedInputs.addAll(itEnumeratedInputs);
+			}
+		} else {
+			// For support of pre-CDT 3.0 integrations.
+			if (bIsTargetTool) {
+				// NOTE WELL:  This only supports the case of a single "target tool"
+				//      with the following characteristics:
+				// 1.  The tool consumes exactly all of the object files produced
+				//     by other tools in the build and produces a single output
+				// 2.  The target name comes from the configuration artifact name
+				// The rule looks like:
+				//    <targ_prefix><target>.<extension>: $(OBJS) <refd_project_1 ... refd_project_n>
+				myCommandInputs.add("$(OBJS)"); //$NON-NLS-1$
+				myCommandInputs.add("$(USER_OBJS)"); //$NON-NLS-1$
+				myCommandInputs.add("$(LIBS)"); //$NON-NLS-1$
+			} else {
+				// Rule will be generated by addRuleForSource
+			}
+		}
+
+		if (done) {
+			commandInputs.addAll(myCommandInputs);
+			commandDependencies.addAll(0, myCommandDependencies);
+			enumeratedInputs.addAll(myEnumeratedInputs);
+			inputsCalculated = true;
+			return true;
+		}
+
+		return false;
+	}
+
+	/*
+	* The priorities for determining the names of the outputs of a tool are:
+	*  1.  If the tool is the build target and primary output, use artifact name & extension
+	*  2.  If an option is specified, use the value of the option
+	*  3.  If a nameProvider is specified, call it
+	*  4.  If outputNames is specified, use it
+	*  5.  Use the name pattern to generate a transformation macro
+	*      so that the source names can be transformed into the target names
+	*      using the built-in string substitution functions of <code>make</code>.
+	*
+	* NOTE: If an option is not specified and this is not the primary output type, the outputs
+	*       from the type are not added to the command line
+	*/
+	public boolean calculateOutputs(GnuMakefileGenerator makeGen, IConfiguration config,
+			HashSet<String> handledInputExtensions, boolean lastChance) {
+
+		boolean done = true;
+		Vector<String> myCommandOutputs = new Vector<>();
+		Vector<String> myEnumeratedPrimaryOutputs = new Vector<>();
+		Vector<String> myEnumeratedSecondaryOutputs = new Vector<>();
+		HashMap<String, List<IPath>> myOutputMacros = new HashMap<>();
+		//  The next two fields are used together
+		Vector<String> myBuildVars = new Vector<>();
+		Vector<Vector<String>> myBuildVarsValues = new Vector<>();
+
+		// Get the outputs for this tool invocation
+		IOutputType[] outTypes = tool.getOutputTypes();
+		if (outTypes != null && outTypes.length > 0) {
+			for (int i = 0; i < outTypes.length; i++) {
+				Vector<String> typeEnumeratedOutputs = new Vector<>();
+				IOutputType type = outTypes[i];
+				String outputPrefix = type.getOutputPrefix();
+
+				// Resolve any macros in the outputPrefix
+				// Note that we cannot use file macros because if we do a clean
+				// we need to know the actual name of the file to clean, and
+				// cannot use any builder variables such as $@. Hence we use the
+				// next best thing, i.e. configuration context.
+
+				if (config != null) {
+
+					try {
+						outputPrefix = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(
+								outputPrefix, "", //$NON-NLS-1$
+								" ", //$NON-NLS-1$
+								IBuildMacroProvider.CONTEXT_CONFIGURATION, config);
+					}
+
+					catch (BuildMacroException e) {
+					}
+				}
+
+				String variable = type.getBuildVariable();
+				boolean multOfType = type.getMultipleOfType();
+				boolean primaryOutput = (type == tool.getPrimaryOutputType());
+				IOption option = tool.getOptionBySuperClassId(type.getOptionId());
+				IManagedOutputNameProvider nameProvider = type.getNameProvider();
+				String[] outputNames = type.getOutputNames();
+
+				//  1.  If the tool is the build target and this is the primary output,
+				//      use artifact name & extension
+				if (bIsTargetTool && primaryOutput) {
+					String outputName = outputPrefix + targetName;
+					if (targetExt.length() > 0) {
+						outputName += (DOT + targetExt);
+					}
+					myCommandOutputs.add(outputName);
+					typeEnumeratedOutputs.add(outputName);
+					//  But this doesn't use any output macro...
+				} else
+				//  2.  If an option is specified, use the value of the option
+				if (option != null) {
+					try {
+						List<String> outputs = new ArrayList<>();
+						int optType = option.getValueType();
+						if (optType == IOption.STRING) {
+							outputs.add(outputPrefix + option.getStringValue());
+						} else if (optType == IOption.STRING_LIST || optType == IOption.LIBRARIES
+								|| optType == IOption.OBJECTS || optType == IOption.INCLUDE_FILES
+								|| optType == IOption.LIBRARY_PATHS || optType == IOption.LIBRARY_FILES
+								|| optType == IOption.MACRO_FILES) {
+							@SuppressWarnings("unchecked")
+							List<String> value = (List<String>) option.getValue();
+							outputs = value;
+							tool.filterValues(optType, outputs);
+							// Add outputPrefix to each if necessary
+							if (outputPrefix.length() > 0) {
+								for (int j = 0; j < outputs.size(); j++) {
+									outputs.set(j, outputPrefix + outputs.get(j));
+								}
+							}
+						}
+						for (int j = 0; j < outputs.size(); j++) {
+							String outputName = outputs.get(j);
+							try {
+								//try to resolve the build macros in the output names
+								String resolved = ManagedBuildManager.getBuildMacroProvider()
+										.resolveValueToMakefileFormat(outputName, "", //$NON-NLS-1$
+												" ", //$NON-NLS-1$
+												IBuildMacroProvider.CONTEXT_OPTION,
+												new OptionContextData(option, tool));
+								if ((resolved = resolved.trim()).length() > 0)
+									outputs.set(j, resolved);
+							} catch (BuildMacroException e) {
+							}
+						}
+
+						// NO - myCommandOutputs.addAll(outputs);
+						typeEnumeratedOutputs.addAll(outputs);
+						if (variable.length() > 0) {
+							List<IPath> outputPaths = new ArrayList<>();
+							for (int j = 0; j < outputs.size(); j++) {
+								outputPaths.add(Path.fromOSString(outputs.get(j)));
+							}
+							if (myOutputMacros.containsKey(variable)) {
+								List<IPath> currList = myOutputMacros.get(variable);
+								currList.addAll(outputPaths);
+								myOutputMacros.put(variable, currList);
+							} else {
+								myOutputMacros.put(variable, outputPaths);
+							}
+						}
+					} catch (BuildException ex) {
+					}
+				} else
+				//  3.  If a nameProvider is specified, call it
+				if (nameProvider != null) {
+					// The inputs must have been calculated before we can do this
+					IPath[] outNames = null;
+					if (!inputsCalculated) {
+						done = false;
+					} else {
+						Vector<String> inputs = getEnumeratedInputs();
+						IPath[] inputPaths = new IPath[inputs.size()];
+						for (int j = 0; j < inputPaths.length; j++) {
+							inputPaths[j] = Path.fromOSString(inputs.get(j));
+						}
+						outNames = nameProvider.getOutputNames(tool, inputPaths);
+						if (outNames != null) {
+							for (int j = 0; j < outNames.length; j++) {
+								String outputName = outNames[j].toString();
+								try {
+									//try to resolve the build macros in the output names
+									String resolved = ManagedBuildManager.getBuildMacroProvider()
+											.resolveValueToMakefileFormat(outputName, "", //$NON-NLS-1$
+													" ", //$NON-NLS-1$
+													IBuildMacroProvider.CONTEXT_CONFIGURATION, config);
+									if ((resolved = resolved.trim()).length() > 0) {
+										outputName = resolved;
+										outNames[j] = Path.fromOSString(resolved);
+									}
+								} catch (BuildMacroException e) {
+								}
+
+								if (primaryOutput) {
+									myCommandOutputs.add(outputName);
+								}
+								typeEnumeratedOutputs.add(outputName);
+							}
+						}
+					}
+					if (variable.length() > 0 && outNames != null) {
+						if (myOutputMacros.containsKey(variable)) {
+							List<IPath> currList = myOutputMacros.get(variable);
+							currList.addAll(Arrays.asList(outNames));
+							myOutputMacros.put(variable, currList);
+						} else {
+							myOutputMacros.put(variable, new ArrayList<>(Arrays.asList(outNames)));
+						}
+					}
+				} else
+				//  4.  If outputNames is specified, use it
+				if (outputNames != null) {
+					if (outputNames.length > 0) {
+						for (int j = 0; j < outputNames.length; j++) {
+							String outputName = outputNames[j];
+							try {
+								//try to resolve the build macros in the output names
+								String resolved = ManagedBuildManager.getBuildMacroProvider()
+										.resolveValueToMakefileFormat(outputName, "", //$NON-NLS-1$
+												" ", //$NON-NLS-1$
+												IBuildMacroProvider.CONTEXT_OPTION,
+												new OptionContextData(option, tool));
+								if ((resolved = resolved.trim()).length() > 0)
+									outputNames[j] = resolved;
+							} catch (BuildMacroException e) {
+							}
+						}
+						List<String> namesList = Arrays.asList(outputNames);
+						if (primaryOutput) {
+							myCommandOutputs.addAll(namesList);
+						}
+						typeEnumeratedOutputs.addAll(namesList);
+						if (variable.length() > 0) {
+							List<IPath> outputPaths = new ArrayList<>();
+							for (int j = 0; j < namesList.size(); j++) {
+								outputPaths.add(Path.fromOSString(namesList.get(j)));
+							}
+							if (myOutputMacros.containsKey(variable)) {
+								List<IPath> currList = myOutputMacros.get(variable);
+								currList.addAll(outputPaths);
+								myOutputMacros.put(variable, currList);
+							} else {
+								myOutputMacros.put(variable, outputPaths);
+							}
+						}
+					}
+				} else {
+					//  5.  Use the name pattern to generate a transformation macro
+					//      so that the source names can be transformed into the target names
+					//      using the built-in string substitution functions of <code>make</code>.
+					if (multOfType) {
+						// This case is not handled - a nameProvider or outputNames must be specified
+						List<String> errList = new ArrayList<>();
+						errList.add(ManagedMakeMessages.getResourceString("MakefileGenerator.error.no.nameprovider")); //$NON-NLS-1$
+						myCommandOutputs.addAll(errList);
+					} else {
+						String namePattern = type.getNamePattern();
+						if (namePattern == null || namePattern.length() == 0) {
+							namePattern = outputPrefix + IManagedBuilderMakefileGenerator.WILDCARD;
+							String outExt = (type.getOutputExtensions(tool))[0];
+							if (outExt != null && outExt.length() > 0) {
+								namePattern += DOT + outExt;
+							}
+						} else if (outputPrefix.length() > 0) {
+							namePattern = outputPrefix + namePattern;
+						}
+
+						// Calculate the output name
+						// The inputs must have been calculated before we can do this
+						if (!inputsCalculated) {
+							done = false;
+						} else {
+							Vector<String> inputs = getEnumeratedInputs();
+							String fileName;
+							if (inputs.size() > 0) {
+								//  Get the input file name
+								fileName = (Path.fromOSString(inputs.get(0))).removeFileExtension().lastSegment();
+								//  Check if this is a build macro.  If so, use the raw macro name.
+								if (fileName.startsWith("$(") && fileName.endsWith(")")) { //$NON-NLS-1$ //$NON-NLS-2$
+									fileName = fileName.substring(2, fileName.length() - 1);
+								}
+							} else {
+								fileName = "default"; //$NON-NLS-1$
+							}
+							//  Replace the % with the file name
+							if (primaryOutput) {
+								myCommandOutputs.add(namePattern.replaceAll("%", fileName)); //$NON-NLS-1$
+							}
+							typeEnumeratedOutputs.add(namePattern.replaceAll("%", fileName)); //$NON-NLS-1$
+							if (variable.length() > 0) {
+								List<IPath> outputs = new ArrayList<>();
+								outputs.add(Path.fromOSString(fileName));
+								if (myOutputMacros.containsKey(variable)) {
+									List<IPath> currList = myOutputMacros.get(variable);
+									currList.addAll(outputs);
+									myOutputMacros.put(variable, currList);
+								} else {
+									myOutputMacros.put(variable, outputs);
+								}
+							}
+						}
+					}
+				}
+				if (variable.length() > 0) {
+					myBuildVars.add(variable);
+					myBuildVarsValues.add(typeEnumeratedOutputs);
+				}
+				if (primaryOutput) {
+					myEnumeratedPrimaryOutputs.addAll(typeEnumeratedOutputs);
+				} else {
+					myEnumeratedSecondaryOutputs.addAll(typeEnumeratedOutputs);
+				}
+			}
+		} else {
+			if (bIsTargetTool) {
+				String outputPrefix = tool.getOutputPrefix();
+				String outputName = outputPrefix + targetName;
+				if (targetExt.length() > 0) {
+					outputName += (DOT + targetExt);
+				}
+				myCommandOutputs.add(outputName);
+				myEnumeratedPrimaryOutputs.add(outputName);
+			} else {
+				// For support of pre-CDT 3.0 integrations.
+				// NOTE WELL:  This only supports the case of a single "target tool"
+				//     that consumes exactly all of the object files, $OBJS, produced
+				//     by other tools in the build and produces a single output
+			}
+		}
+
+		//  Add the output macros of this tool to the buildOutVars map
+		Set<Entry<String, List<IPath>>> entrySet = myOutputMacros.entrySet();
+		for (Entry<String, List<IPath>> entry : entrySet) {
+			String macroName = entry.getKey();
+			List<IPath> newMacroValue = entry.getValue();
+			HashMap<String, List<IPath>> map = makeGen.getBuildOutputVars();
+			if (map.containsKey(macroName)) {
+				List<IPath> macroValue = map.get(macroName);
+				macroValue.addAll(newMacroValue);
+				map.put(macroName, macroValue);
+			} else {
+				map.put(macroName, newMacroValue);
+			}
+		}
+		outputVariablesCalculated = true;
+
+		if (done) {
+			commandOutputs.addAll(myCommandOutputs);
+			enumeratedPrimaryOutputs.addAll(myEnumeratedPrimaryOutputs);
+			enumeratedSecondaryOutputs.addAll(myEnumeratedSecondaryOutputs);
+			outputVariables.addAll(myOutputMacros.keySet());
+			outputsCalculated = true;
+			for (int i = 0; i < myBuildVars.size(); i++) {
+				makeGen.addMacroAdditionFiles(makeGen.getTopBuildOutputVars(), myBuildVars.get(i),
+						myBuildVarsValues.get(i));
+			}
+			return true;
+		}
+
+		return false;
+	}
+
+	private boolean callDependencyCalculator(GnuMakefileGenerator makeGen, IConfiguration config,
+			HashSet<String> handledInputExtensions, IManagedDependencyGeneratorType depGen, String[] extensionsList,
+			Vector<String> myCommandDependencies, HashMap<String, List<IPath>> myOutputMacros,
+			Vector<String> myAdditionalTargets, ToolInfoHolder h, boolean done) {
+
+		int calcType = depGen.getCalculatorType();
+		switch (calcType) {
+		case IManagedDependencyGeneratorType.TYPE_COMMAND:
+		case IManagedDependencyGeneratorType.TYPE_BUILD_COMMANDS:
+			// iterate over all extensions that the tool knows how to handle
+			for (int i = 0; i < extensionsList.length; i++) {
+				String extensionName = extensionsList[i];
+
+				// Generated files should not appear in the list.
+				if (!makeGen.getOutputExtensions(h).contains(extensionName)
+						&& !handledInputExtensions.contains(extensionName)) {
+					handledInputExtensions.add(extensionName);
+					String depExt = IManagedBuilderMakefileGenerator.DEP_EXT;
+					if (calcType == IManagedDependencyGeneratorType.TYPE_BUILD_COMMANDS) {
+						IManagedDependencyGenerator2 depGen2 = (IManagedDependencyGenerator2) depGen;
+						String xt = depGen2.getDependencyFileExtension(config, tool);
+						if (xt != null && xt.length() > 0)
+							depExt = xt;
+					}
+					String depsMacroEntry = calculateSourceMacro(makeGen, extensionName, depExt,
+							IManagedBuilderMakefileGenerator.WILDCARD);
+
+					List<IPath> depsList = new ArrayList<>();
+					depsList.add(Path.fromOSString(depsMacroEntry));
+					String depsMacro = makeGen.getDepMacroName(extensionName).toString();
+					if (myOutputMacros.containsKey(depsMacro)) {
+						List<IPath> currList = myOutputMacros.get(depsMacro);
+						currList.addAll(depsList);
+						myOutputMacros.put(depsMacro, currList);
+					} else {
+						myOutputMacros.put(depsMacro, depsList);
+					}
+				}
+			}
+			break;
+
+		case IManagedDependencyGeneratorType.TYPE_INDEXER:
+		case IManagedDependencyGeneratorType.TYPE_EXTERNAL:
+		case IManagedDependencyGeneratorType.TYPE_CUSTOM:
+			// The inputs must have been calculated before we can do this
+			if (!inputsCalculated) {
+				done = false;
+			} else {
+				Vector<String> inputs = getEnumeratedInputs();
+
+				if (calcType == IManagedDependencyGeneratorType.TYPE_CUSTOM) {
+					IManagedDependencyGenerator2 depGen2 = (IManagedDependencyGenerator2) depGen;
+					IManagedDependencyInfo depInfo = null;
+					for (int i = 0; i < inputs.size(); i++) {
+
+						depInfo = depGen2.getDependencySourceInfo(Path.fromOSString(inputs.get(i)), config, tool,
+								makeGen.getBuildWorkingDir());
+
+						if (depInfo instanceof IManagedDependencyCalculator) {
+							IManagedDependencyCalculator depCalc = (IManagedDependencyCalculator) depInfo;
+							IPath[] depPaths = depCalc.getDependencies();
+							if (depPaths != null) {
+								for (int j = 0; j < depPaths.length; j++) {
+									if (!depPaths[j].isAbsolute()) {
+										//  Convert from project relative to build directory relative
+										IPath absolutePath = project.getLocation().append(depPaths[j]);
+										depPaths[j] = ManagedBuildManager
+												.calculateRelativePath(makeGen.getTopBuildDir(), absolutePath);
+									}
+									myCommandDependencies.add(depPaths[j].toString());
+								}
+							}
+							IPath[] targetPaths = depCalc.getAdditionalTargets();
+							if (targetPaths != null) {
+								for (int j = 0; j < targetPaths.length; j++) {
+									myAdditionalTargets.add(targetPaths[j].toString());
+								}
+							}
+						}
+					}
+				} else {
+					IManagedDependencyGenerator oldDepGen = (IManagedDependencyGenerator) depGen;
+					for (String input : inputs) {
+						IResource[] outNames = oldDepGen.findDependencies(project.getFile(input), project);
+						if (outNames != null) {
+							for (IResource outName : outNames) {
+								myCommandDependencies.add(outName.toString());
+							}
+						}
+					}
+				}
+			}
+			break;
+
+		default:
+			break;
+		}
+
+		return done;
+	}
+
+	public boolean calculateDependencies(GnuMakefileGenerator makeGen, IConfiguration config,
+			HashSet<String> handledInputExtensions, ToolInfoHolder h, boolean lastChance) {
+		// Get the dependencies for this tool invocation
+		boolean done = true;
+		Vector<String> myCommandDependencies = new Vector<>();
+		Vector<String> myAdditionalTargets = new Vector<>();
+		//Vector myEnumeratedDependencies = new Vector();
+		HashMap<String, List<IPath>> myOutputMacros = new HashMap<>();
+
+		IInputType[] inTypes = tool.getInputTypes();
+		if (inTypes != null && inTypes.length > 0) {
+			for (int i = 0; i < inTypes.length; i++) {
+				IInputType type = inTypes[i];
+
+				// Handle dependencies from the dependencyCalculator
+				IManagedDependencyGeneratorType depGen = type.getDependencyGenerator();
+				String[] extensionsList = type.getSourceExtensions(tool);
+				if (depGen != null) {
+					done = callDependencyCalculator(makeGen, config, handledInputExtensions, depGen, extensionsList,
+							myCommandDependencies, myOutputMacros, myAdditionalTargets, h, done);
+				}
+
+				// Add additional dependencies specified in AdditionalInput elements
+				IAdditionalInput[] addlInputs = type.getAdditionalInputs();
+				if (addlInputs != null && addlInputs.length > 0) {
+					for (int j = 0; j < addlInputs.length; j++) {
+						IAdditionalInput addlInput = addlInputs[j];
+						int kind = addlInput.getKind();
+						if (kind == IAdditionalInput.KIND_ADDITIONAL_DEPENDENCY
+								|| kind == IAdditionalInput.KIND_ADDITIONAL_INPUT_DEPENDENCY) {
+							String[] paths = addlInput.getPaths();
+							if (paths != null) {
+								for (int k = 0; k < paths.length; k++) {
+									// Translate the path from project relative to
+									// build directory relative
+									String path = paths[k];
+									if (!(path.startsWith("$("))) { //$NON-NLS-1$
+										IResource addlResource = project.getFile(path);
+										if (addlResource != null) {
+											IPath addlPath = addlResource.getLocation();
+											if (addlPath != null) {
+												path = ManagedBuildManager
+														.calculateRelativePath(makeGen.getTopBuildDir(), addlPath)
+														.toString();
+											}
+										}
+									}
+									myCommandDependencies.add(path);
+									//myEnumeratedInputs.add(path);
+								}
+							}
+						}
+					}
+				}
+			}
+		} else {
+			if (bIsTargetTool) {
+				// For support of pre-CDT 3.0 integrations.
+				// NOTE WELL:  This only supports the case of a single "target tool"
+				//      with the following characteristics:
+				// 1.  The tool consumes exactly all of the object files produced
+				//     by other tools in the build and produces a single output
+				// 2.  The target name comes from the configuration artifact name
+				// The rule looks like:
+				//    <targ_prefix><target>.<extension>: $(OBJS) <refd_project_1 ... refd_project_n>
+				myCommandDependencies.add("$(OBJS)"); //$NON-NLS-1$
+				myCommandDependencies.add("$(USER_OBJS)"); //$NON-NLS-1$
+			} else {
+				// Handle dependencies from the dependencyCalculator
+				IManagedDependencyGeneratorType depGen = tool.getDependencyGenerator();
+				String[] extensionsList = tool.getAllInputExtensions();
+				if (depGen != null) {
+					done = callDependencyCalculator(makeGen, config, handledInputExtensions, depGen, extensionsList,
+							myCommandDependencies, myOutputMacros, myAdditionalTargets, h, done);
+				}
+
+			}
+		}
+
+		//  Add the output macros of this tool to the buildOutVars map
+		Set<Entry<String, List<IPath>>> entrySet = myOutputMacros.entrySet();
+		for (Entry<String, List<IPath>> entry : entrySet) {
+			String macroName = entry.getKey();
+			List<IPath> newMacroValue = entry.getValue();
+			HashMap<String, List<IPath>> map = makeGen.getBuildOutputVars();
+			if (map.containsKey(macroName)) {
+				List<IPath> macroValue = map.get(macroName);
+				macroValue.addAll(newMacroValue);
+				map.put(macroName, macroValue);
+			} else {
+				map.put(macroName, newMacroValue);
+			}
+		}
+
+		if (done) {
+			commandDependencies.addAll(myCommandDependencies);
+			additionalTargets.addAll(myAdditionalTargets);
+			//enumeratedDependencies.addAll(myEnumeratedDependencies);
+			dependenciesCalculated = true;
+			return true;
+		}
+
+		return false;
+	}
+
+	/*
+	 * Calculate the source macro for the given extension
+	 */
+	protected String calculateSourceMacro(GnuMakefileGenerator makeGen, String srcExtensionName,
+			String outExtensionName, String wildcard) {
+		StringBuffer macroName = makeGen.getSourceMacroName(srcExtensionName);
+		String OptDotExt = ""; //$NON-NLS-1$
+		if (outExtensionName != null) {
+			OptDotExt = DOT + outExtensionName;
+		} else if (!tool.getOutputExtension(srcExtensionName).isEmpty())
+			OptDotExt = DOT + tool.getOutputExtension(srcExtensionName);
+
+		// create rule of the form
+		// OBJS = $(macroName1: ../%.input1=%.output1) ... $(macroNameN: ../%.inputN=%.outputN)
+		return IManagedBuilderMakefileGenerator.WHITESPACE + "$(" + macroName + //$NON-NLS-1$
+				IManagedBuilderMakefileGenerator.COLON + makeGen.reachProjectRoot()
+				+ IManagedBuilderMakefileGenerator.SEPARATOR + IManagedBuilderMakefileGenerator.WILDCARD + DOT
+				+ srcExtensionName + "=" + wildcard + OptDotExt + ")"; //$NON-NLS-1$ //$NON-NLS-2$
+	}
+
+}
diff --git a/build/org.eclipse.cdt.managedbuilder.gnu.ui/META-INF/MANIFEST.MF b/build/org.eclipse.cdt.managedbuilder.gnu.ui/META-INF/MANIFEST.MF
index 68d3b38d8d5..3f24da3ce7b 100644
--- a/build/org.eclipse.cdt.managedbuilder.gnu.ui/META-INF/MANIFEST.MF
+++ b/build/org.eclipse.cdt.managedbuilder.gnu.ui/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
 Bundle-ManifestVersion: 2
 Bundle-Name: %pluginName
 Bundle-SymbolicName: org.eclipse.cdt.managedbuilder.gnu.ui; singleton:=true
-Bundle-Version: 8.4.100.qualifier
+Bundle-Version: 8.4.200.qualifier
 Bundle-Activator: org.eclipse.cdt.managedbuilder.gnu.ui.GnuUIPlugin
 Bundle-Vendor: %providerName
 Bundle-Localization: plugin
diff --git a/build/org.eclipse.cdt.managedbuilder.gnu.ui/plugin.xml b/build/org.eclipse.cdt.managedbuilder.gnu.ui/plugin.xml
index 3b4273dad01..06a8414c4e9 100644
--- a/build/org.eclipse.cdt.managedbuilder.gnu.ui/plugin.xml
+++ b/build/org.eclipse.cdt.managedbuilder.gnu.ui/plugin.xml
@@ -2168,7 +2168,7 @@
           variableFormat="${=}"
           isVariableCaseSensitive="true"
           reservedMacroNames="ROOT,DEPS,OBJS,.*_SRCS,EXECUTABLES,SUBDIRS,LIBS,USER_OBJS,.*_INPUTS,.*_OUTPUTS"
-          buildfileGenerator="org.eclipse.cdt.managedbuilder.makegen.gnu.GnuMakefileGenerator"
+          buildfileGenerator="org.eclipse.cdt.managedbuilder.makegen.gnu2.GnuMakefileGenerator"
           macroInputFileNameValue="$(notdir $&lt;)"
           macroInputFileExtValue="$(suffix $(notdir $&lt;))"
           macroInputFileBaseNameValue="$(basename $(notdir $&lt;))"
diff --git a/doc/org.eclipse.cdt.doc.isv/guide/deprecated_API_removals.html b/doc/org.eclipse.cdt.doc.isv/guide/deprecated_API_removals.html
index b6fd67dbd20..5b9d5e6d62b 100644
--- a/doc/org.eclipse.cdt.doc.isv/guide/deprecated_API_removals.html
+++ b/doc/org.eclipse.cdt.doc.isv/guide/deprecated_API_removals.html
@@ -63,6 +63,12 @@
     <li><a href="#GnuMakefileGenerator.addRuleForTool">Removed unneded boolean from function</a></li>
     <li><a href="#GnuMakefileGenerator.addDefaultHeader">Changed methods from static to non-static</a></li>
   </ol>
+  <p>
+    Planned Removals after December 2023
+  </p>
+  <ol>
+    <li><a href="#GnuMakefileGeneratorAPI">GnuMakefileGenerator is no longer part of API</a></li>
+  </ol>
 
   <p>
     API Changes prior to CDT 10.0 / 2020-09.
@@ -488,6 +494,22 @@
   <p>
     See <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=573722" target="_blank">Bug 573722</a>.
   </p>
+
+
+  <h3>API Removals after December 2023</h3>
+
+  <h3>1. <a name="GnuMakefileGeneratorAPI">GnuMakefileGenerator is no longer part of API</a></h3>
+  <p>
+    The following classes have been removed from the API.
+  </p>
+  <ul>
+    <li>org.eclipse.cdt.managedbuilder.makegen.gnu.GnuMakefileGenerator</li>
+    <li>org.eclipse.cdt.managedbuilder.makegen.gnu.IManagedBuildGnuToolInfo</li>
+    <li>org.eclipse.cdt.managedbuilder.makegen.gnu.ManagedBuildGnuToolInfo</li>
+  </ul>
+  <p>
+    See <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=505882" target="_blank">Bug 505882</a>.
+  </p>
 </body>
 
 </html>