Major change to new build arch to give configs more power.

Creates a single central CBuilder builder which find the C Build
Config and delegates the builds to it. That give configs full control
over the builds. Qt and CMake build configs are adapted to this new
structure.

More features are added to the default super class for configs.

Change-Id: I5ecfc7a4e9b909da6749189a059cdcd4a208fddd
diff --git a/build/org.eclipse.cdt.build.gcc.core/src/org/eclipse/cdt/build/gcc/core/GCCToolChain.java b/build/org.eclipse.cdt.build.gcc.core/src/org/eclipse/cdt/build/gcc/core/GCCToolChain.java
index 8d16e94..5d7c521 100644
--- a/build/org.eclipse.cdt.build.gcc.core/src/org/eclipse/cdt/build/gcc/core/GCCToolChain.java
+++ b/build/org.eclipse.cdt.build.gcc.core/src/org/eclipse/cdt/build/gcc/core/GCCToolChain.java
@@ -11,9 +11,12 @@
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStreamReader;
+import java.net.URI;
 import java.nio.file.Files;
 import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -31,6 +34,7 @@
 import org.eclipse.core.resources.IBuildConfiguration;
 import org.eclipse.core.resources.IFile;
 import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IWorkspaceRoot;
 import org.eclipse.core.resources.ResourcesPlugin;
 import org.eclipse.core.runtime.IPath;
 import org.eclipse.core.runtime.Platform;
@@ -47,6 +51,7 @@
 
 	private final IToolChainType type;
 	private final String name;
+	private final String command;
 	private String version;
 	private String target;
 	private Path path;
@@ -55,6 +60,7 @@
 
 	public GCCToolChain(IToolChainType type, Path path, String command) {
 		this.type = type;
+		this.command = command;
 		getVersion(path.resolve(command).toString());
 		this.name = command + '-' + version;
 		this.path = path;
@@ -64,9 +70,10 @@
 		envVars = new IEnvironmentVariable[] { pathVar };
 	}
 
-	protected GCCToolChain(IToolChainType type, String name) {
+	protected GCCToolChain(IToolChainType type, String name, String command) {
 		this.type = type;
 		this.name = name;
+		this.command = command;
 		// TODO need to pull the other info out of preferences
 	}
 
@@ -119,6 +126,10 @@
 		}
 	}
 
+	public String getTarget() {
+		return target;
+	}
+	
 	protected void addDiscoveryOptions(List<String> command) {
 		command.add("-E"); //$NON-NLS-1$
 		command.add("-P"); //$NON-NLS-1$
@@ -127,9 +138,11 @@
 	}
 
 	@Override
-	public IExtendedScannerInfo getScannerInfo(IBuildConfiguration buildConfig, Path command, List<String> args,
-			List<String> includePaths, IResource resource, Path buildDirectory) {
+	public IExtendedScannerInfo getScannerInfo(IBuildConfiguration buildConfig, Path command, String[] args,
+			IExtendedScannerInfo baseScannerInfo, IResource resource, URI buildDirectoryURI) {
 		try {
+			Path buildDirectory = Paths.get(buildDirectoryURI);
+			
 			List<String> commandLine = new ArrayList<>();
 			if (command.isAbsolute()) {
 				commandLine.add(command.toString());
@@ -137,12 +150,14 @@
 				commandLine.add(path.resolve(command).toString());
 			}
 
-			for (String includePath : includePaths) {
-				commandLine.add("-I" + includePath); //$NON-NLS-1$
+			if (baseScannerInfo != null && baseScannerInfo.getIncludePaths() != null) {
+				for (String includePath : baseScannerInfo.getIncludePaths()) {
+					commandLine.add("-I" + includePath); //$NON-NLS-1$
+				}
 			}
 
 			addDiscoveryOptions(commandLine);
-			commandLine.addAll(args);
+			commandLine.addAll(Arrays.asList(args));
 
 			// Change output to stdout
 			for (int i = 0; i < commandLine.size() - 1; ++i) {
@@ -259,5 +274,42 @@
 	public Path getCommandPath(String command) {
 		return path.resolve(command);
 	}
-	
+
+	@Override
+	public IResource[] getResourcesFromCommand(String[] cmd, URI buildDirectoryURI) {
+		// Make sure this is our command
+		boolean found = false;
+		for (String arg : cmd) {
+			if (arg.startsWith("-")) { //$NON-NLS-1$
+				break;
+			}
+			Path cmdPath = Paths.get(arg);
+			if (cmdPath.getFileName().toString().equals(command)) {
+				found = true;
+				break;
+			}
+		}
+		
+		if (!found) {
+			// not our command
+			return null;
+		}
+		
+		// Start at the back looking for arguments
+		List<IResource> resources = new ArrayList<>();
+		IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
+		for (int i = cmd.length - 1; i >= 0; --i) {
+			String arg = cmd[i];
+			if (arg.startsWith("-")) { //$NON-NLS-1$
+				// ran into an option, we're done.
+				break;
+			}
+			for (IFile resource : root.findFilesForLocationURI(buildDirectoryURI.resolve(arg))) {
+				resources.add(resource);
+			}
+		}
+		
+		return resources.toArray(new IResource[resources.size()]);
+	}
+
 }
diff --git a/build/org.eclipse.cdt.cmake.core/plugin.xml b/build/org.eclipse.cdt.cmake.core/plugin.xml
index 335c10f..7b159d8 100644
--- a/build/org.eclipse.cdt.cmake.core/plugin.xml
+++ b/build/org.eclipse.cdt.cmake.core/plugin.xml
@@ -69,16 +69,6 @@
       </launchConfigurationType>
    </extension>
    <extension
-         point="org.eclipse.core.runtime.adapters">
-      <factory
-            adaptableType="org.eclipse.core.resources.IBuildConfiguration"
-            class="org.eclipse.cdt.cmake.core.internal.CMakeBuildConfigurationFactory">
-         <adapter
-               type="org.eclipse.cdt.cmake.core.internal.CMakeBuildConfiguration">
-         </adapter>
-      </factory>
-   </extension>
-   <extension
          point="org.eclipse.cdt.core.ScannerInfoProvider2">
       <provider
             builder="org.eclipse.cdt.cmake.core.cmakeBuilder"
diff --git a/build/org.eclipse.cdt.cmake.core/src/org/eclipse/cdt/cmake/core/CMakeNature.java b/build/org.eclipse.cdt.cmake.core/src/org/eclipse/cdt/cmake/core/CMakeNature.java
index 0e774d5..215d369 100644
--- a/build/org.eclipse.cdt.cmake.core/src/org/eclipse/cdt/cmake/core/CMakeNature.java
+++ b/build/org.eclipse.cdt.cmake.core/src/org/eclipse/cdt/cmake/core/CMakeNature.java
@@ -8,9 +8,13 @@
 package org.eclipse.cdt.cmake.core;
 
 import org.eclipse.cdt.cmake.core.internal.Activator;
+import org.eclipse.cdt.core.build.CBuilder;
+import org.eclipse.core.resources.ICommand;
 import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IProjectDescription;
 import org.eclipse.core.resources.IProjectNature;
 import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.NullProgressMonitor;
 
 public class CMakeNature implements IProjectNature {
 
@@ -18,17 +22,17 @@
 
 	private IProject project;
 
-	public static boolean hasNature(IProject project) {
-		try {
-			return project.hasNature(ID);
-		} catch (CoreException e) {
-			Activator.log(e);
-			return false;
-		}
+	public static void setupBuilder(IProjectDescription projDesc) throws CoreException {
+		ICommand command = projDesc.newCommand();
+		CBuilder.setupBuilder(command);
+		projDesc.setBuildSpec(new ICommand[] { command });
 	}
-
+	
 	@Override
 	public void configure() throws CoreException {
+		IProjectDescription projDesc = project.getDescription();
+		setupBuilder(projDesc);
+		project.setDescription(projDesc, new NullProgressMonitor());
 	}
 
 	@Override
diff --git a/build/org.eclipse.cdt.cmake.core/src/org/eclipse/cdt/cmake/core/CMakeProjectGenerator.java b/build/org.eclipse.cdt.cmake.core/src/org/eclipse/cdt/cmake/core/CMakeProjectGenerator.java
index 8ce37d6..c0ae251 100644
--- a/build/org.eclipse.cdt.cmake.core/src/org/eclipse/cdt/cmake/core/CMakeProjectGenerator.java
+++ b/build/org.eclipse.cdt.cmake.core/src/org/eclipse/cdt/cmake/core/CMakeProjectGenerator.java
@@ -10,18 +10,15 @@
 import java.util.HashMap;
 import java.util.Map;
 
-import org.eclipse.cdt.cmake.core.internal.CMakeBuilder;
 import org.eclipse.cdt.cmake.core.internal.CMakeTemplateGenerator;
 import org.eclipse.cdt.core.CCProjectNature;
 import org.eclipse.cdt.core.CProjectNature;
 import org.eclipse.cdt.core.model.CoreModel;
 import org.eclipse.cdt.core.model.IPathEntry;
-import org.eclipse.core.resources.ICommand;
 import org.eclipse.core.resources.IFile;
 import org.eclipse.core.resources.IFolder;
 import org.eclipse.core.resources.IProject;
 import org.eclipse.core.resources.IProjectDescription;
-import org.eclipse.core.resources.IncrementalProjectBuilder;
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IProgressMonitor;
 
@@ -59,11 +56,6 @@
 		newIds[newIds.length - 1] = CMakeNature.ID;
 		projDesc.setNatureIds(newIds);
 
-		ICommand command = projDesc.newCommand();
-		command.setBuilderName(CMakeBuilder.ID);
-		command.setBuilding(IncrementalProjectBuilder.AUTO_BUILD, false);
-		projDesc.setBuildSpec(new ICommand[] { command });
-
 		project.setDescription(projDesc, monitor);
 
 		IPathEntry[] entries = new IPathEntry[] { CoreModel.newOutputEntry(sourceFolder.getFullPath()) };
diff --git a/build/org.eclipse.cdt.cmake.core/src/org/eclipse/cdt/cmake/core/internal/CMakeBuildConfiguration.java b/build/org.eclipse.cdt.cmake.core/src/org/eclipse/cdt/cmake/core/internal/CMakeBuildConfiguration.java
index f8ccd69..f1cf77f 100644
--- a/build/org.eclipse.cdt.cmake.core/src/org/eclipse/cdt/cmake/core/internal/CMakeBuildConfiguration.java
+++ b/build/org.eclipse.cdt.cmake.core/src/org/eclipse/cdt/cmake/core/internal/CMakeBuildConfiguration.java
@@ -7,18 +7,86 @@
  *******************************************************************************/
 package org.eclipse.cdt.cmake.core.internal;
 
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.cdt.core.ConsoleOutputStream;
+import org.eclipse.cdt.core.IConsoleParser;
 import org.eclipse.cdt.core.build.CBuildConfiguration;
 import org.eclipse.cdt.core.build.IToolChain;
+import org.eclipse.cdt.core.model.ICModelMarker;
+import org.eclipse.cdt.core.parser.IScannerInfo;
+import org.eclipse.cdt.core.resources.IConsole;
 import org.eclipse.core.resources.IBuildConfiguration;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
 
 public class CMakeBuildConfiguration extends CBuildConfiguration {
 
-	public CMakeBuildConfiguration(IBuildConfiguration config) {
-		super(config);
+	public CMakeBuildConfiguration(IBuildConfiguration config, String name) {
+		super(config, name);
 	}
 
-	public CMakeBuildConfiguration(IBuildConfiguration config, IToolChain toolChain) {
-		super(config, toolChain);
+	public CMakeBuildConfiguration(IBuildConfiguration config, String name, IToolChain toolChain) {
+		super(config, name, toolChain);
 	}
 
+	@Override
+	public IProject[] build(int kind, Map<String, String> args, IConsole console, IProgressMonitor monitor)
+			throws CoreException {
+		IProject project = getProject();
+		try {
+			project.deleteMarkers(ICModelMarker.C_MODEL_PROBLEM_MARKER, false,  IResource.DEPTH_INFINITE);
+
+			ConsoleOutputStream outStream = console.getOutputStream();
+			
+			Path buildDir = getBuildDirectory();
+
+			if (!Files.exists(buildDir.resolve("Makefile"))) { //$NON-NLS-1$
+				// TODO assuming cmake is in the path here, probably need a
+				// preference in case it isn't.
+				List<String> command = Arrays.asList("cmake", //$NON-NLS-1$
+						"-DCMAKE_EXPORT_COMPILE_COMMANDS=ON", new File(project.getLocationURI()).getAbsolutePath());
+				ProcessBuilder processBuilder = new ProcessBuilder(command).directory(buildDir.toFile());
+				Process process = processBuilder.start();
+				outStream.write(String.join(" ", command) + '\n'); //$NON-NLS-1$
+				watchProcess(process, new IConsoleParser[0], console);
+			}
+
+			// TODO need to figure out which builder to call. Hardcoding to make
+			// for now.
+			List<String> command = Arrays.asList("make");
+			ProcessBuilder processBuilder = new ProcessBuilder(command).directory(buildDir.toFile()); // $NON-NLS-1$
+			Process process = processBuilder.start();
+			outStream.write(String.join(" ", command) + '\n'); //$NON-NLS-1$
+			
+			// TODO error parsers
+			watchProcess(process, new IConsoleParser[0], console);
+
+			project.refreshLocal(IResource.DEPTH_INFINITE, monitor);
+			return new IProject[] { project };
+		} catch (IOException e) {
+			throw new CoreException(Activator.errorStatus("Building " + project.getName(), e));
+		}
+	}
+	
+	@Override
+	public void clean(IConsole console, IProgressMonitor monitor) throws CoreException {
+		// TODO Auto-generated method stub
+		
+	}
+
+	@Override
+	public IScannerInfo getScannerInformation(IResource resource) {
+		// TODO Auto-generated method stub
+		return null;
+	}
+	
 }
diff --git a/build/org.eclipse.cdt.cmake.core/src/org/eclipse/cdt/cmake/core/internal/CMakeBuildConfigurationFactory.java b/build/org.eclipse.cdt.cmake.core/src/org/eclipse/cdt/cmake/core/internal/CMakeBuildConfigurationFactory.java
deleted file mode 100644
index 8a1e35e..0000000
--- a/build/org.eclipse.cdt.cmake.core/src/org/eclipse/cdt/cmake/core/internal/CMakeBuildConfigurationFactory.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2015 QNX Software Systems and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *******************************************************************************/
-package org.eclipse.cdt.cmake.core.internal;
-
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-
-import org.eclipse.cdt.core.build.IToolChain;
-import org.eclipse.cdt.core.build.IToolChainManager;
-import org.eclipse.core.resources.IBuildConfiguration;
-import org.eclipse.core.runtime.IAdapterFactory;
-import org.eclipse.core.runtime.Platform;
-
-public class CMakeBuildConfigurationFactory implements IAdapterFactory {
-
-	private static IToolChainManager toolChainManager = Activator.getService(IToolChainManager.class);
-	private static Map<IBuildConfiguration, CMakeBuildConfiguration> cache = new HashMap<>();
-
-	@Override
-	public Class<?>[] getAdapterList() {
-		return new Class<?>[] { CMakeBuildConfiguration.class };
-	}
-
-	@SuppressWarnings("unchecked")
-	@Override
-	public <T> T getAdapter(Object adaptableObject, Class<T> adapterType) {
-		if (adapterType.equals(CMakeBuildConfiguration.class) && adaptableObject instanceof IBuildConfiguration) {
-			IBuildConfiguration config = (IBuildConfiguration) adaptableObject;
-			synchronized (cache) {
-				CMakeBuildConfiguration cmakeConfig = cache.get(config);
-				if (cmakeConfig == null) {
-					if (!config.getName().equals(IBuildConfiguration.DEFAULT_CONFIG_NAME)) {
-						cmakeConfig = new CMakeBuildConfiguration(config);
-						cache.put(config, cmakeConfig);
-						return (T) cmakeConfig;
-					} else {
-						// Default to local toolchain
-						Map<String, String> properties = new HashMap<>();
-						properties.put(IToolChain.ATTR_OS, Platform.getOS());
-						properties.put(IToolChain.ATTR_ARCH, Platform.getOSArch());
-						Collection<IToolChain> toolChains = toolChainManager.getToolChainsMatching(properties);
-						if (!toolChains.isEmpty()) {
-							// TODO propery handle when we have more than one
-							cmakeConfig = new CMakeBuildConfiguration(config, toolChains.iterator().next());
-							cache.put(config, cmakeConfig);
-							return (T) cmakeConfig;
-						}
-
-						// Use the first toolchain we can find
-						toolChains = toolChainManager.getToolChainsMatching(new HashMap<>());
-						if (!toolChains.isEmpty()) {
-							// TODO propery handle when we have more
-							// than one
-							cmakeConfig = new CMakeBuildConfiguration(config, toolChains.iterator().next());
-							cache.put(config, cmakeConfig);
-							return (T) cmakeConfig;
-						}
-					}
-				} else {
-					return (T) cmakeConfig;
-				}
-			}
-		}
-		return null;
-	}
-
-}
diff --git a/build/org.eclipse.cdt.cmake.core/src/org/eclipse/cdt/cmake/core/internal/CMakeBuilder.java b/build/org.eclipse.cdt.cmake.core/src/org/eclipse/cdt/cmake/core/internal/CMakeBuilder.java
deleted file mode 100644
index 3be278e..0000000
--- a/build/org.eclipse.cdt.cmake.core/src/org/eclipse/cdt/cmake/core/internal/CMakeBuilder.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2015 QNX Software Systems and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *******************************************************************************/
-package org.eclipse.cdt.cmake.core.internal;
-
-import java.io.File;
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-
-import org.eclipse.cdt.core.CCorePlugin;
-import org.eclipse.cdt.core.ConsoleOutputStream;
-import org.eclipse.cdt.core.resources.IConsole;
-import org.eclipse.core.resources.IProject;
-import org.eclipse.core.resources.IResource;
-import org.eclipse.core.resources.IncrementalProjectBuilder;
-import org.eclipse.core.runtime.CoreException;
-import org.eclipse.core.runtime.IProgressMonitor;
-
-public class CMakeBuilder extends IncrementalProjectBuilder {
-
-	public static final String ID = Activator.getId() + ".cmakeBuilder"; //$NON-NLS-1$
-
-	@Override
-	protected IProject[] build(int kind, Map<String, String> args, IProgressMonitor monitor) throws CoreException {
-		IProject project = getProject();
-		try {
-			IConsole console = CCorePlugin.getDefault().getConsole();
-			ConsoleOutputStream outStream = console.getOutputStream();
-			
-			CMakeBuildConfiguration cmakeConfig = project.getActiveBuildConfig()
-					.getAdapter(CMakeBuildConfiguration.class);
-			Path buildDir = cmakeConfig.getBuildDirectory();
-
-			if (!Files.exists(buildDir.resolve("Makefile"))) { //$NON-NLS-1$
-				// TODO assuming cmake is in the path here, probably need a
-				// preference in case it isn't.
-				List<String> command = Arrays.asList("cmake", //$NON-NLS-1$
-						"-DCMAKE_EXPORT_COMPILE_COMMANDS=ON", new File(project.getLocationURI()).getAbsolutePath());
-				ProcessBuilder processBuilder = new ProcessBuilder(command).directory(buildDir.toFile());
-				Process process = processBuilder.start();
-				outStream.write(String.join(" ", command) + '\n'); //$NON-NLS-1$
-				//console.monitor(process, null, buildDir);
-			}
-
-			// TODO need to figure out which builder to call. Hardcoding to make
-			// for now.
-			List<String> command = Arrays.asList("make");
-			ProcessBuilder processBuilder = new ProcessBuilder(command).directory(buildDir.toFile()); // $NON-NLS-1$
-			Process process = processBuilder.start();
-			outStream.write(String.join(" ", command) + '\n'); //$NON-NLS-1$
-			//console.monitor(process, null, buildDir);
-
-			project.refreshLocal(IResource.DEPTH_INFINITE, monitor);
-			return new IProject[] { project };
-		} catch (IOException e) {
-			throw new CoreException(Activator.errorStatus("Building " + project.getName(), e));
-		}
-	}
-
-}
diff --git a/build/org.eclipse.cdt.cmake.core/src/org/eclipse/cdt/cmake/core/internal/CMakeLaunchDescriptorType.java b/build/org.eclipse.cdt.cmake.core/src/org/eclipse/cdt/cmake/core/internal/CMakeLaunchDescriptorType.java
index 4a66f37..9440843 100644
--- a/build/org.eclipse.cdt.cmake.core/src/org/eclipse/cdt/cmake/core/internal/CMakeLaunchDescriptorType.java
+++ b/build/org.eclipse.cdt.cmake.core/src/org/eclipse/cdt/cmake/core/internal/CMakeLaunchDescriptorType.java
@@ -24,7 +24,7 @@
 	public ILaunchDescriptor getDescriptor(Object launchObject) throws CoreException {
 		if (launchObject instanceof IProject) {
 			IProject project = (IProject) launchObject;
-			if (CMakeNature.hasNature(project)) {
+			if (project.hasNature(CMakeNature.ID)) {
 				CMakeLaunchDescriptor desc = descriptors.get(project);
 				if (desc == null) {
 					desc = new CMakeLaunchDescriptor(this, project);
diff --git a/build/org.eclipse.cdt.cmake.core/src/org/eclipse/cdt/cmake/core/internal/CMakeScannerInfoProvider.java b/build/org.eclipse.cdt.cmake.core/src/org/eclipse/cdt/cmake/core/internal/CMakeScannerInfoProvider.java
deleted file mode 100644
index c5fd8d2..0000000
--- a/build/org.eclipse.cdt.cmake.core/src/org/eclipse/cdt/cmake/core/internal/CMakeScannerInfoProvider.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2015 QNX Software Systems and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *******************************************************************************/
-package org.eclipse.cdt.cmake.core.internal;
-
-import org.eclipse.cdt.core.parser.IScannerInfo;
-import org.eclipse.cdt.core.parser.IScannerInfoChangeListener;
-import org.eclipse.cdt.core.parser.IScannerInfoProvider;
-import org.eclipse.core.resources.IBuildConfiguration;
-import org.eclipse.core.resources.IProject;
-import org.eclipse.core.resources.IResource;
-import org.eclipse.core.runtime.CoreException;
-
-public class CMakeScannerInfoProvider implements IScannerInfoProvider {
-
-	@Override
-	public IScannerInfo getScannerInformation(IResource resource) {
-		try {
-			IProject project = resource.getProject();
-			IBuildConfiguration config = project.getActiveBuildConfig();
-			CMakeBuildConfiguration cmakeConfig = config.getAdapter(CMakeBuildConfiguration.class);
-			if (cmakeConfig != null) {
-				return null; // TODO obviously
-			}
-		} catch (CoreException e) {
-			Activator.log(e);
-		}
-		return null;
-	}
-
-	@Override
-	public void subscribe(IResource resource, IScannerInfoChangeListener listener) {
-	}
-
-	@Override
-	public void unsubscribe(IResource resource, IScannerInfoChangeListener listener) {
-	}
-
-}
diff --git a/core/org.eclipse.cdt.core/plugin.xml b/core/org.eclipse.cdt.core/plugin.xml
index b8fe65b..7591899 100644
--- a/core/org.eclipse.cdt.core/plugin.xml
+++ b/core/org.eclipse.cdt.core/plugin.xml
@@ -869,5 +869,17 @@
          </adapter>
       </factory>
    </extension>
+   <extension
+         id="cBuilder"
+         point="org.eclipse.core.resources.builders">
+      <builder
+            callOnEmptyDelta="true"
+            isConfigurable="true"
+            supportsConfigurations="true">
+         <run
+               class="org.eclipse.cdt.core.build.CBuilder">
+         </run>
+      </builder>
+   </extension>
 
 </plugin>
diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ConsoleOutputStream.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ConsoleOutputStream.java
index 134ba15..bdff4c0 100644
--- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ConsoleOutputStream.java
+++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ConsoleOutputStream.java
@@ -40,7 +40,7 @@
 		ascii[0] = (byte) c;
 		fBuffer.append(new String(ascii));
 	}
-	    
+
     @Override
 	public synchronized void write(byte[] b, int off, int len) throws IOException {
         fBuffer.append(new String(b, off, len));
diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/build/BuildCommandRunner.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/build/BuildCommandRunner.java
deleted file mode 100644
index 3a02030..0000000
--- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/build/BuildCommandRunner.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*******************************************************************************

- * Copyright (c) 2016 QNX Software Systems and others.

- * All rights reserved. This program and the accompanying materials

- * are made available under the terms of the Eclipse Public License v1.0

- * which accompanies this distribution, and is available at

- * http://www.eclipse.org/legal/epl-v10.html

- *******************************************************************************/

-package org.eclipse.cdt.core.build;

-

-import java.io.BufferedReader;

-import java.io.IOException;

-import java.io.InputStream;

-import java.io.InputStreamReader;

-

-import org.eclipse.cdt.core.CCorePlugin;

-import org.eclipse.cdt.core.ErrorParserManager;

-import org.eclipse.cdt.core.resources.IConsole;

-import org.eclipse.core.resources.IProject;

-import org.eclipse.core.runtime.CoreException;

-

-/**

- * Utility to process the output of a build command, feeding it to an error

- * parser monitor and then off to the build console.

- * 

- * @since 6.0

- */

-public class BuildCommandRunner {

-

-	private final IProject project;

-	private final IConsole console;

-	private final ErrorParserManager epm;

-

-	public BuildCommandRunner(IProject project, IConsole console, ErrorParserManager epm) {

-		this.project = project;

-		this.console = console;

-		this.epm = epm;

-	}

-

-	public int monitor(Process process) throws CoreException {

-		console.start(project);

-		epm.setOutputStream(console.getOutputStream());

-		new ReaderThread(process.getInputStream()).start();

-		new ReaderThread(process.getErrorStream()).start();

-

-		try {

-			return process.waitFor();

-		} catch (InterruptedException e) {

-			return -1;

-		}

-	}

-

-	private class ReaderThread extends Thread {

-		private final BufferedReader in;

-

-		public ReaderThread(InputStream in) {

-			this.in = new BufferedReader(new InputStreamReader(in));

-		}

-

-		@Override

-		public void run() {

-			try {

-				for (String line = in.readLine(); line != null; line = in.readLine()) {

-					// Synchronize to avoid interleaving of lines

-					synchronized (BuildCommandRunner.this) {

-						epm.processLine(line);

-					}

-				}

-			} catch (IOException e) {

-				CCorePlugin.log(e);

-			}

-		}

-	}

-

-}

diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/build/CBuildConfiguration.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/build/CBuildConfiguration.java
index ce5f1c3..376d3d7 100644
--- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/build/CBuildConfiguration.java
+++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/build/CBuildConfiguration.java
@@ -7,19 +7,48 @@
  *******************************************************************************/
 package org.eclipse.cdt.core.build;
 
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.net.URI;
+import java.nio.file.Files;
 import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
 
 import org.eclipse.cdt.core.CCorePlugin;
+import org.eclipse.cdt.core.IConsoleParser;
+import org.eclipse.cdt.core.IMarkerGenerator;
+import org.eclipse.cdt.core.ProblemMarkerInfo;
+import org.eclipse.cdt.core.envvar.IEnvironmentVariable;
+import org.eclipse.cdt.core.model.CoreModel;
+import org.eclipse.cdt.core.model.ICModelMarker;
+import org.eclipse.cdt.core.parser.IExtendedScannerInfo;
+import org.eclipse.cdt.core.parser.IScannerInfo;
+import org.eclipse.cdt.core.parser.IScannerInfoChangeListener;
+import org.eclipse.cdt.core.resources.IConsole;
+import org.eclipse.core.filesystem.URIUtil;
 import org.eclipse.core.resources.IBuildConfiguration;
+import org.eclipse.core.resources.IContainer;
 import org.eclipse.core.resources.IFolder;
+import org.eclipse.core.resources.IMarker;
 import org.eclipse.core.resources.IProject;
 import org.eclipse.core.resources.IProjectDescription;
 import org.eclipse.core.resources.IResource;
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.Platform;
 import org.eclipse.core.runtime.PlatformObject;
 import org.eclipse.core.runtime.preferences.InstanceScope;
+import org.eclipse.osgi.util.NLS;
 import org.osgi.service.prefs.BackingStoreException;
 import org.osgi.service.prefs.Preferences;
 
@@ -28,8 +57,10 @@
  * settings for subclasses.
  * 
  * @since 6.0
+ * @noextend This class is provisional and should be subclassed with caution.
  */
-public abstract class CBuildConfiguration extends PlatformObject {
+public abstract class CBuildConfiguration extends PlatformObject
+		implements ICBuildConfiguration, IMarkerGenerator, IConsoleParser {
 
 	private static final String TOOLCHAIN_TYPE = "cdt.toolChain.type"; //$NON-NLS-1$
 	private static final String TOOLCHAIN_NAME = "cdt.toolChain.name"; //$NON-NLS-1$
@@ -38,14 +69,9 @@
 	private final IBuildConfiguration config;
 	private final IToolChain toolChain;
 
-	protected CBuildConfiguration(IBuildConfiguration config) {
+	protected CBuildConfiguration(IBuildConfiguration config, String name) {
 		this.config = config;
-		String[] split = config.getName().split("/");
-		if (split.length == 2) {
-			name = split[1];
-		} else {
-			name = config.getName();
-		}
+		this.name = name;
 
 		// Load toolchain from prefs
 		Preferences settings = getSettings();
@@ -53,20 +79,15 @@
 		String id = settings.get(TOOLCHAIN_NAME, ""); //$NON-NLS-1$
 		IToolChainManager toolChainManager = CCorePlugin.getService(IToolChainManager.class);
 		toolChain = !id.isEmpty() ? toolChainManager.getToolChain(typeId, id) : null;
-		
+
 		if (toolChain == null) {
 			CCorePlugin.log(String.format("Toolchain missing for config: %s", config.getName()));
 		}
 	}
 
-	protected CBuildConfiguration(IBuildConfiguration config, IToolChain toolChain) {
+	protected CBuildConfiguration(IBuildConfiguration config, String name, IToolChain toolChain) {
 		this.config = config;
-		String[] split = config.getName().split("/");
-		if (split.length == 2) {
-			name = split[1];
-		} else {
-			name = config.getName();
-		}
+		this.name = name;
 
 		this.toolChain = toolChain;
 		Preferences settings = getSettings();
@@ -79,6 +100,7 @@
 		}
 	}
 
+	@Override
 	public IBuildConfiguration getBuildConfiguration() {
 		return config;
 	}
@@ -91,28 +113,31 @@
 		return config.getProject();
 	}
 
-	public IFolder getBuildFolder() {
-		try {
-			// TODO should really be passing a monitor in here or create this in
-			// a better spot. should also throw the core exception
-			// TODO make the name of this folder a project property
-			IFolder buildRootFolder = getProject().getFolder("build"); //$NON-NLS-1$
-			if (!buildRootFolder.exists()) {
-				buildRootFolder.create(IResource.FORCE | IResource.DERIVED, true, new NullProgressMonitor());
-			}
-			IFolder buildFolder = buildRootFolder.getFolder(name);
-			if (!buildFolder.exists()) {
-				buildFolder.create(true, true, new NullProgressMonitor());
-			}
-			return buildFolder;
-		} catch (CoreException e) {
-			CCorePlugin.log(e);
+	public IContainer getBuildContainer() throws CoreException {
+		// TODO should really be passing a monitor in here or create this in
+		// a better spot. should also throw the core exception
+		// TODO make the name of this folder a project property
+		IFolder buildRootFolder = getProject().getFolder("build"); //$NON-NLS-1$
+		if (!buildRootFolder.exists()) {
+			buildRootFolder.create(IResource.FORCE | IResource.DERIVED, true, new NullProgressMonitor());
 		}
-		return null;
+		IFolder buildFolder = buildRootFolder.getFolder(name);
+		if (!buildFolder.exists()) {
+			buildFolder.create(true, true, new NullProgressMonitor());
+		}
+		return buildFolder;
 	}
 
-	public Path getBuildDirectory() {
-		return getBuildFolder().getLocation().toFile().toPath();
+	public URI getBuildDirectoryURI() throws CoreException {
+		return getBuildContainer().getLocationURI();
+	}
+
+	public Path getBuildDirectory() throws CoreException {
+		return Paths.get(getBuildDirectoryURI());
+	}
+
+	protected void setBuildEnvironment(Map<String, String> env) {
+		CCorePlugin.getDefault().getBuildEnvironmentManager().setEnvironment(env, config, true);
 	}
 
 	public void setActive(IProgressMonitor monitor) throws CoreException {
@@ -132,8 +157,247 @@
 				.node(getProject().getName()).node(config.getName());
 	}
 
+	@Override
 	public IToolChain getToolChain() {
 		return toolChain;
 	}
 
+	@Override
+	public IEnvironmentVariable getVariable(String name) {
+		// By default, none
+		return null;
+	}
+
+	@Override
+	public IEnvironmentVariable[] getVariables() {
+		// by default, none
+		return null;
+	}
+
+	@Override
+	public void addMarker(IResource file, int lineNumber, String errorDesc, int severity, String errorVar) {
+		addMarker(new ProblemMarkerInfo(file, lineNumber, errorDesc, severity, errorVar, null));
+	}
+
+	@Override
+	public void addMarker(ProblemMarkerInfo problemMarkerInfo) {
+		try {
+			IProject project = config.getProject();
+			IResource markerResource = problemMarkerInfo.file;
+			if (markerResource == null) {
+				markerResource = project;
+			}
+			String externalLocation = null;
+			if (problemMarkerInfo.externalPath != null && !problemMarkerInfo.externalPath.isEmpty()) {
+				externalLocation = problemMarkerInfo.externalPath.toOSString();
+			}
+
+			// Try to find matching markers and don't put in duplicates
+			IMarker[] markers = markerResource.findMarkers(ICModelMarker.C_MODEL_PROBLEM_MARKER, true,
+					IResource.DEPTH_ONE);
+			for (IMarker m : markers) {
+				int line = m.getAttribute(IMarker.LINE_NUMBER, -1);
+				int sev = m.getAttribute(IMarker.SEVERITY, -1);
+				String msg = (String) m.getAttribute(IMarker.MESSAGE);
+				if (line == problemMarkerInfo.lineNumber
+						&& sev == mapMarkerSeverity(problemMarkerInfo.severity)
+						&& msg.equals(problemMarkerInfo.description)) {
+					String extloc = (String) m.getAttribute(ICModelMarker.C_MODEL_MARKER_EXTERNAL_LOCATION);
+					if (extloc == externalLocation || (extloc != null && extloc.equals(externalLocation))) {
+						if (project == null || project.equals(markerResource.getProject())) {
+							return;
+						}
+						String source = (String) m.getAttribute(IMarker.SOURCE_ID);
+						if (project.getName().equals(source)) {
+							return;
+						}
+					}
+				}
+			}
+
+			String type = problemMarkerInfo.getType();
+			if (type == null) {
+				type = ICModelMarker.C_MODEL_PROBLEM_MARKER;
+			}
+
+			IMarker marker = markerResource.createMarker(type);
+			marker.setAttribute(IMarker.MESSAGE, problemMarkerInfo.description);
+			marker.setAttribute(IMarker.SEVERITY, mapMarkerSeverity(problemMarkerInfo.severity));
+			marker.setAttribute(IMarker.LINE_NUMBER, problemMarkerInfo.lineNumber);
+			marker.setAttribute(IMarker.CHAR_START, problemMarkerInfo.startChar);
+			marker.setAttribute(IMarker.CHAR_END, problemMarkerInfo.endChar);
+			if (problemMarkerInfo.variableName != null) {
+				marker.setAttribute(ICModelMarker.C_MODEL_MARKER_VARIABLE, problemMarkerInfo.variableName);
+			}
+			if (externalLocation != null) {
+				URI uri = URIUtil.toURI(externalLocation);
+				if (uri.getScheme() != null) {
+					marker.setAttribute(ICModelMarker.C_MODEL_MARKER_EXTERNAL_LOCATION, externalLocation);
+					String locationText = NLS.bind(
+							CCorePlugin.getResourceString("ACBuilder.ProblemsView.Location"), //$NON-NLS-1$
+							problemMarkerInfo.lineNumber, externalLocation);
+					marker.setAttribute(IMarker.LOCATION, locationText);
+				}
+			} else if (problemMarkerInfo.lineNumber == 0) {
+				marker.setAttribute(IMarker.LOCATION, " "); //$NON-NLS-1$
+			}
+			// Set source attribute only if the marker is being set to a file
+			// from different project
+			if (project != null && !project.equals(markerResource.getProject())) {
+				marker.setAttribute(IMarker.SOURCE_ID, project.getName());
+			}
+
+			// Add all other client defined attributes.
+			Map<String, String> attributes = problemMarkerInfo.getAttributes();
+			if (attributes != null) {
+				for (Entry<String, String> entry : attributes.entrySet()) {
+					marker.setAttribute(entry.getKey(), entry.getValue());
+				}
+			}
+		} catch (CoreException e) {
+			CCorePlugin.log(e.getStatus());
+		}
+	}
+
+	private int mapMarkerSeverity(int severity) {
+		switch (severity) {
+		case SEVERITY_ERROR_BUILD:
+		case SEVERITY_ERROR_RESOURCE:
+			return IMarker.SEVERITY_ERROR;
+		case SEVERITY_INFO:
+			return IMarker.SEVERITY_INFO;
+		case SEVERITY_WARNING:
+			return IMarker.SEVERITY_WARNING;
+		}
+		return IMarker.SEVERITY_ERROR;
+	}
+
+	protected Path findCommand(String command) {
+		if (Platform.getOS().equals(Platform.OS_WIN32) && !command.endsWith(".exe")) { //$NON-NLS-1$
+			command += ".exe"; //$NON-NLS-1$
+		}
+
+		Path cmdPath = Paths.get(command);
+		if (cmdPath.isAbsolute()) {
+			return cmdPath;
+		}
+
+		Map<String, String> env = new HashMap<>(System.getenv());
+		setBuildEnvironment(env);
+
+		String[] path = env.get("PATH").split(File.pathSeparator); //$NON-NLS-1$
+		for (String dir : path) {
+			Path commandPath = Paths.get(dir, command);
+			if (Files.exists(commandPath)) {
+				return commandPath;
+			}
+		}
+		return null;
+	}
+
+	protected int watchProcess(Process process, IConsoleParser[] consoleParsers, IConsole console)
+			throws CoreException {
+		new ReaderThread(process.getInputStream(), consoleParsers, console.getOutputStream()).start();
+		new ReaderThread(process.getErrorStream(), consoleParsers, console.getErrorStream()).start();
+		try {
+			return process.waitFor();
+		} catch (InterruptedException e) {
+			CCorePlugin.log(e);
+			return -1;
+		}
+	}
+
+	private static class ReaderThread extends Thread {
+
+		private final BufferedReader in;
+		private final PrintStream out;
+		private final IConsoleParser[] consoleParsers;
+
+		public ReaderThread(InputStream in, IConsoleParser[] consoleParsers, OutputStream out) {
+			this.in = new BufferedReader(new InputStreamReader(in));
+			this.consoleParsers = consoleParsers;
+			this.out = new PrintStream(out);
+		}
+
+		@Override
+		public void run() {
+			try {
+				for (String line = in.readLine(); line != null; line = in.readLine()) {
+					for (IConsoleParser consoleParser : consoleParsers) {
+						// Synchronize to avoid interleaving of lines
+						synchronized (consoleParser) {
+							consoleParser.processLine(line);
+						}
+					}
+					out.println(line);
+				}
+			} catch (IOException e) {
+				CCorePlugin.log(e);
+			}
+		}
+
+	}
+
+	private Map<IResource, IExtendedScannerInfo> cheaterInfo;
+	private boolean infoChanged = false;
+
+	private void initScannerInfo() {
+		if (cheaterInfo == null) {
+			cheaterInfo = new HashMap<>();
+		}
+	}
+	
+	@Override
+	public IScannerInfo getScannerInformation(IResource resource) {
+		initScannerInfo();
+		return cheaterInfo.get(resource);
+	}
+
+	@Override
+	public boolean processLine(String line) {
+		// TODO smarter line parsing to deal with quoted arguments
+		String[] command = line.split("\\s+"); //$NON-NLS-1$
+
+		try {
+			IResource[] resources = getToolChain().getResourcesFromCommand(command, getBuildDirectoryURI());
+			if (resources != null) {
+				for (IResource resource : resources) {
+					initScannerInfo();
+					cheaterInfo.put(resource,
+							getToolChain().getScannerInfo(getBuildConfiguration(), findCommand(command[0]),
+									Arrays.copyOfRange(command, 1, command.length), null, resource,
+									getBuildDirectoryURI()));
+					infoChanged = true;
+				}
+				return true;
+			} else {
+				return false;
+			}
+		} catch (CoreException e) {
+			CCorePlugin.log(e);
+			return false;
+		}
+	}
+
+	@Override
+	public void shutdown() {
+		// TODO persist changes
+
+		// Trigger a reindex if anything changed
+		if (infoChanged) {
+			CCorePlugin.getIndexManager().reindex(CoreModel.getDefault().create(getProject()));
+			infoChanged = false;
+		}
+	}
+
+	@Override
+	public void subscribe(IResource resource, IScannerInfoChangeListener listener) {
+		// TODO for IScannerInfoProvider
+	}
+
+	@Override
+	public void unsubscribe(IResource resource, IScannerInfoChangeListener listener) {
+		// TODO for IScannerInfoProvider
+	}
+
 }
diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/build/CBuilder.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/build/CBuilder.java
new file mode 100644
index 0000000..47f2eef
--- /dev/null
+++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/build/CBuilder.java
@@ -0,0 +1,75 @@
+package org.eclipse.cdt.core.build;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.eclipse.cdt.core.CCorePlugin;
+import org.eclipse.cdt.core.resources.IConsole;
+import org.eclipse.core.resources.ICommand;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IncrementalProjectBuilder;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+
+/**
+ * @since 6.0
+ */
+public class CBuilder extends IncrementalProjectBuilder {
+
+	private static final String ID = CCorePlugin.PLUGIN_ID + ".cBuilder"; //$NON-NLS-1$
+	
+	public static void setupBuilder(ICommand command) {
+		command.setBuilderName(CBuilder.ID);
+		command.setBuilding(IncrementalProjectBuilder.AUTO_BUILD, false);
+	}
+	
+	@Override
+	protected IProject[] build(int kind, Map<String, String> args, IProgressMonitor monitor)
+			throws CoreException {
+		try {
+			IProject project = getProject();
+
+			// Set up console
+			IConsole console = CCorePlugin.getDefault().getConsole();
+			console.start(project);
+
+			// Get the build configuration
+			ICBuildConfiguration config = getBuildConfig().getAdapter(ICBuildConfiguration.class);
+			if (config == null) {
+				console.getErrorStream().write("Build not configured correctly\n");
+				return null;
+			}
+
+			return config.build(kind, args, console, monitor);
+		} catch (IOException e) {
+			throw new CoreException(
+					new Status(IStatus.ERROR, CCorePlugin.PLUGIN_ID, "Exception while building", e));
+		}
+	}
+
+	@Override
+	protected void clean(IProgressMonitor monitor) throws CoreException {
+		try {
+			IProject project = getProject();
+
+			// Set up console
+			IConsole console = CCorePlugin.getDefault().getConsole();
+			console.start(project);
+
+			// Get the build configuration
+			ICBuildConfiguration config = getBuildConfig().getAdapter(ICBuildConfiguration.class);
+			if (config == null) {
+				console.getErrorStream().write("Build not configured correctly\n");
+				return;
+			}
+
+			config.clean(console, monitor);
+		} catch (IOException e) {
+			throw new CoreException(
+					new Status(IStatus.ERROR, CCorePlugin.PLUGIN_ID, "Exception while building", e));
+		}
+	}
+
+}
diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/build/ICBuildConfiguration.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/build/ICBuildConfiguration.java
index 807bd99..0bbeaff 100644
--- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/build/ICBuildConfiguration.java
+++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/build/ICBuildConfiguration.java
@@ -7,10 +7,16 @@
  *******************************************************************************/
 package org.eclipse.cdt.core.build;
 
+import java.util.Map;
+
 import org.eclipse.cdt.core.envvar.IEnvironmentVariable;
 import org.eclipse.cdt.core.parser.IScannerInfoProvider;
+import org.eclipse.cdt.core.resources.IConsole;
 import org.eclipse.core.resources.IBuildConfiguration;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IProgressMonitor;
 
 /**
  * This is the root interface for "new style" CDT build configurations. Adapting
@@ -41,4 +47,8 @@
 
 	IEnvironmentVariable[] getVariables();
 
+	IProject[] build(int kind, Map<String, String> args, IConsole console, IProgressMonitor monitor) throws CoreException;
+
+	void clean(IConsole console, IProgressMonitor monitor) throws CoreException;
+	
 }
diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/build/ICBuildConfigurationManager.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/build/ICBuildConfigurationManager.java
index 181702e..6a70b43 100644
--- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/build/ICBuildConfigurationManager.java
+++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/build/ICBuildConfigurationManager.java
@@ -54,6 +54,6 @@
 	 */

 	ICBuildConfiguration getBuildConfiguration(IBuildConfiguration buildConfig);

 

-	ICBuildConfiguration getDefaultBuildConfiguration(IProject project);

+	ICBuildConfiguration getDefaultBuildConfiguration(IProject project) throws CoreException;

 

 }

diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/build/ICBuildConfigurationProvider.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/build/ICBuildConfigurationProvider.java
index 961eb6d..40aa5dd 100644
--- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/build/ICBuildConfigurationProvider.java
+++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/build/ICBuildConfigurationProvider.java
@@ -9,6 +9,7 @@
 
 import org.eclipse.core.resources.IBuildConfiguration;
 import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.CoreException;
 
 /**
  * A CBuildConfigurationProvider provides C build configurations.
@@ -30,7 +31,7 @@
 	 * @param config
 	 * @return CDT build configuration for the Platform build configuration
 	 */
-	ICBuildConfiguration getCBuildConfiguration(IBuildConfiguration config);
+	ICBuildConfiguration getCBuildConfiguration(IBuildConfiguration config, String name);
 
 	/**
 	 * Returns a default C build configuration for a given project if any.
@@ -38,6 +39,6 @@
 	 * @param project
 	 * @return default C build configuration for the project
 	 */
-	ICBuildConfiguration getDefaultCBuildConfiguration(IProject project);
+	ICBuildConfiguration getDefaultCBuildConfiguration(IProject project) throws CoreException;
 
 }
diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/build/IToolChain.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/build/IToolChain.java
index 93801ea..6510be9 100644
--- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/build/IToolChain.java
+++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/build/IToolChain.java
@@ -7,8 +7,8 @@
  *******************************************************************************/

 package org.eclipse.cdt.core.build;

 

+import java.net.URI;

 import java.nio.file.Path;

-import java.util.List;

 

 import org.eclipse.cdt.core.envvar.IEnvironmentVariable;

 import org.eclipse.cdt.core.parser.IExtendedScannerInfo;

@@ -47,11 +47,13 @@
 

 	IEnvironmentVariable[] getVariables();

 

-	IExtendedScannerInfo getScannerInfo(IBuildConfiguration buildConfig, Path command, List<String> args,

-			List<String> includePaths, IResource resource, Path buildDirectory);

+	IExtendedScannerInfo getScannerInfo(IBuildConfiguration buildConfig, Path command, String[] args,

+			IExtendedScannerInfo baseScannerInfo, IResource resource, URI buildDirectoryURI);

 

 	String[] getErrorParserIds();

 

 	Path getCommandPath(String command);

 

+	IResource[] getResourcesFromCommand(String[] command, URI buildDirectoryURI);

+	

 }

diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/build/CBuildConfigurationManager.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/build/CBuildConfigurationManager.java
index 5883b49..94a3dbe 100644
--- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/build/CBuildConfigurationManager.java
+++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/build/CBuildConfigurationManager.java
@@ -140,16 +140,18 @@
 

 	@Override

 	public ICBuildConfiguration getBuildConfiguration(IBuildConfiguration buildConfig) {

+		initProviders();

 		synchronized (configs) {

 			ICBuildConfiguration config = configs.get(buildConfig);

 			if (config == null) {

 				String[] segments = buildConfig.getName().split("/"); //$NON-NLS-1$

 				if (segments.length == 2) {

 					String providerId = segments[0];

+					String configName = segments[1];

 

 					Provider provider = getProviderDelegate(providerId);

 					if (provider != null && provider.supports(buildConfig.getProject())) {

-						config = provider.getProvider().getCBuildConfiguration(buildConfig);

+						config = provider.getProvider().getCBuildConfiguration(buildConfig, configName);

 						configs.put(buildConfig, config);

 					}

 				}

@@ -159,7 +161,7 @@
 	}

 

 	@Override

-	public ICBuildConfiguration getDefaultBuildConfiguration(IProject project) {

+	public ICBuildConfiguration getDefaultBuildConfiguration(IProject project) throws CoreException {

 		initProviders();

 		for (Provider provider : providers.values()) {

 			if (provider.supports(project)) {

diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/BuildOutputStream.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/BuildOutputStream.java
index 703712d..25bd5cb 100644
--- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/BuildOutputStream.java
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/BuildOutputStream.java
@@ -59,7 +59,11 @@
 	@Override
 	public void write(String s, ProblemMarkerInfo marker) throws IOException {
 		fPartitioner.appendToDocument(s, fStream, marker);
-
 	}
 
+	@Override
+	public synchronized void write(String msg) throws IOException {
+		fPartitioner.appendToDocument(msg, fStream, null);
+	}
+	
 }
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/MultiBuildConsoleAdapter.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/MultiBuildConsoleAdapter.java
index bfaa62d..e290768 100644
--- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/MultiBuildConsoleAdapter.java
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/MultiBuildConsoleAdapter.java
@@ -56,6 +56,12 @@
 			two.write(b, off, len);
 	    }
 
+	    @Override
+	    public synchronized void write(String msg) throws IOException {
+	    	one.write(msg);
+	    	two.write(msg);
+	    }
+	    
 		@Override
 		public void write(String s, ProblemMarkerInfo marker) throws IOException {
 			one.write(s, marker);
@@ -63,6 +69,12 @@
 		}
 
 		@Override
+		public void flush() throws IOException {
+			one.flush();
+			two.flush();
+		}
+		
+		@Override
 		public void close() throws IOException {
 			one.flush();
 			two.flush();
diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/QtNature.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/QtNature.java
index e98c3ce..03ae8ee 100644
--- a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/QtNature.java
+++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/QtNature.java
@@ -13,18 +13,17 @@
 import java.util.Arrays;
 
 import org.eclipse.cdt.core.CCorePlugin;
+import org.eclipse.cdt.core.build.CBuilder;
 import org.eclipse.cdt.core.dom.ILinkage;
 import org.eclipse.cdt.core.index.IIndex;
 import org.eclipse.cdt.core.index.IIndexLinkage;
 import org.eclipse.cdt.core.model.ICProject;
 import org.eclipse.cdt.internal.core.index.CIndex;
 import org.eclipse.cdt.internal.core.index.IIndexFragment;
-import org.eclipse.cdt.internal.qt.core.build.QtBuilder;
 import org.eclipse.core.resources.ICommand;
 import org.eclipse.core.resources.IProject;
 import org.eclipse.core.resources.IProjectDescription;
 import org.eclipse.core.resources.IProjectNature;
-import org.eclipse.core.resources.IncrementalProjectBuilder;
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.IStatus;
@@ -59,13 +58,16 @@
 		}
 	}
 
+	public static void setupBuilder(IProjectDescription projDesc) {
+		ICommand command = projDesc.newCommand();
+		CBuilder.setupBuilder(command);
+		projDesc.setBuildSpec(new ICommand[] { command });
+	}
+
 	@Override
 	public void configure() throws CoreException {
 		IProjectDescription projDesc = project.getDescription();
-		ICommand command = projDesc.newCommand();
-		command.setBuilderName(QtBuilder.ID);
-		command.setBuilding(IncrementalProjectBuilder.AUTO_BUILD, false);
-		projDesc.setBuildSpec(new ICommand[] { command });
+		setupBuilder(projDesc);
 		project.setDescription(projDesc, new NullProgressMonitor());
 	}
 
diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/build/QtBuildConfiguration.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/build/QtBuildConfiguration.java
index 93722eb..2c53c5a 100644
--- a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/build/QtBuildConfiguration.java
+++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/build/QtBuildConfiguration.java
@@ -19,12 +19,18 @@
 import java.util.List;
 import java.util.Map;
 
+import org.eclipse.cdt.core.ConsoleOutputStream;
+import org.eclipse.cdt.core.ErrorParserManager;
+import org.eclipse.cdt.core.IConsoleParser;
 import org.eclipse.cdt.core.build.CBuildConfiguration;
 import org.eclipse.cdt.core.build.ICBuildConfiguration;
 import org.eclipse.cdt.core.build.IToolChain;
 import org.eclipse.cdt.core.envvar.IEnvironmentVariable;
+import org.eclipse.cdt.core.model.ICModelMarker;
+import org.eclipse.cdt.core.parser.ExtendedScannerInfo;
+import org.eclipse.cdt.core.parser.IExtendedScannerInfo;
 import org.eclipse.cdt.core.parser.IScannerInfo;
-import org.eclipse.cdt.core.parser.IScannerInfoChangeListener;
+import org.eclipse.cdt.core.resources.IConsole;
 import org.eclipse.cdt.internal.qt.core.Activator;
 import org.eclipse.cdt.qt.core.IQtBuildConfiguration;
 import org.eclipse.cdt.qt.core.IQtInstall;
@@ -34,7 +40,10 @@
 import org.eclipse.core.resources.IProject;
 import org.eclipse.core.resources.IResource;
 import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
 import org.osgi.service.prefs.BackingStoreException;
 import org.osgi.service.prefs.Preferences;
 
@@ -47,8 +56,8 @@
 	private final String launchMode;
 	private Map<String, String> properties;
 
-	public QtBuildConfiguration(IBuildConfiguration config) {
-		super(config);
+	public QtBuildConfiguration(IBuildConfiguration config, String name) {
+		super(config, name);
 
 		Preferences settings = getSettings();
 		String installName = settings.get(QTINSTALL_NAME, ""); //$NON-NLS-1$
@@ -62,9 +71,10 @@
 		launchMode = settings.get(LAUNCH_MODE, ""); //$NON-NLS-1$
 	}
 
-	QtBuildConfiguration(IBuildConfiguration config, IToolChain toolChain, IQtInstall qtInstall, String launchMode)
+	QtBuildConfiguration(IBuildConfiguration config, String name, IToolChain toolChain, IQtInstall qtInstall,
+			String launchMode)
 			throws CoreException {
-		super(config, toolChain);
+		super(config, name, toolChain);
 		this.qtInstall = qtInstall;
 		this.launchMode = launchMode;
 
@@ -122,7 +132,7 @@
 	}
 
 	@Override
-	public Path getProgramPath() {
+	public Path getProgramPath() throws CoreException {
 		String projectName = getProject().getName();
 		switch (Platform.getOS()) {
 		case Platform.OS_MACOSX:
@@ -158,8 +168,10 @@
 			cmd.add(getProjectFile().toString());
 
 			try {
-				ProcessBuilder procBuilder = new ProcessBuilder(cmd).directory(getProjectFile().getParent().toFile());
-				Process proc = procBuilder.start();
+				ProcessBuilder processBuilder = new ProcessBuilder(cmd)
+						.directory(getProjectFile().getParent().toFile());
+				setBuildEnvironment(processBuilder.environment());
+				Process proc = processBuilder.start();
 				try (BufferedReader reader = new BufferedReader(new InputStreamReader(proc.getInputStream()))) {
 					properties = new HashMap<>();
 					for (String line = reader.readLine(); line != null; line = reader.readLine()) {
@@ -226,21 +238,128 @@
 		for (int i = 0; i < includePaths.length; ++i) {
 			Path path = Paths.get(includePaths[i]);
 			if (!path.isAbsolute()) {
-				includePaths[i] = getBuildDirectory().resolve(path).toString();
+				try {
+					includePaths[i] = getBuildDirectory().resolve(path).toString();
+				} catch (CoreException e) {
+					Activator.log(e);
+				}
 			}
 		}
 
-		Path dir = Paths.get(project.getLocationURI());
-		return getToolChain().getScannerInfo(getBuildConfiguration(), command, args, Arrays.asList(includePaths),
-				resource, dir);
+		IExtendedScannerInfo baseScannerInfo = new ExtendedScannerInfo(null, includePaths);
+		try {
+			return getToolChain().getScannerInfo(getBuildConfiguration(), command,
+					args.toArray(new String[args.size()]), baseScannerInfo, resource,
+					getBuildContainer().getLocationURI());
+		} catch (CoreException e) {
+			Activator.log(e);
+			return null;
+		}
 	}
 
 	@Override
-	public void subscribe(IResource resource, IScannerInfoChangeListener listener) {
+	public IProject[] build(int kind, Map<String, String> args, IConsole console, IProgressMonitor monitor)
+			throws CoreException {
+		IProject project = getProject();
+		try {
+			project.deleteMarkers(ICModelMarker.C_MODEL_PROBLEM_MARKER, false, IResource.DEPTH_INFINITE);
+
+			ConsoleOutputStream errStream = console.getErrorStream();
+			ConsoleOutputStream outStream = console.getOutputStream();
+
+			Path makeCommand = getMakeCommand();
+			if (makeCommand == null) {
+				errStream.write("'make' not found.\n");
+				return null;
+			}
+
+			try (ErrorParserManager epm = new ErrorParserManager(project, getBuildDirectoryURI(), this,
+					getToolChain().getErrorParserIds())) {
+				Path buildDir = getBuildDirectory();
+				if (!buildDir.resolve("Makefile").toFile().exists()) { //$NON-NLS-1$
+					// Need to run qmake
+					List<String> command = new ArrayList<>();
+					command.add(getQmakeCommand().toString());
+
+					String config = getQmakeConfig();
+					if (config != null) {
+						command.add(config);
+					}
+
+					IFile projectFile = project.getFile(project.getName() + ".pro"); //$NON-NLS-1$
+					command.add(projectFile.getLocation().toOSString());
+
+					ProcessBuilder processBuilder = new ProcessBuilder(command)
+							.directory(getBuildDirectory().toFile());
+					setBuildEnvironment(processBuilder.environment());
+					Process process = processBuilder.start();
+
+					StringBuffer msg = new StringBuffer();
+					for (String arg : command) {
+						msg.append(arg).append(' ');
+					}
+					msg.append('\n');
+					outStream.write(msg.toString());
+
+					// TODO qmake error parser
+					watchProcess(process, new IConsoleParser[0], console);
+				}
+
+				// run make
+				ProcessBuilder processBuilder = new ProcessBuilder(makeCommand.toString()).directory(buildDir.toFile());
+				setBuildEnvironment(processBuilder.environment());
+				Process process = processBuilder.start();
+				outStream.write(makeCommand.toString() + '\n');
+				watchProcess(process, new IConsoleParser[] { epm }, console);
+			}
+
+			getProject().refreshLocal(IResource.DEPTH_INFINITE, monitor);
+			return new IProject[] { project };
+		} catch (IOException e) {
+			throw new CoreException(new Status(IStatus.ERROR, Activator.ID, "Building " + project.getName(), e)); //$NON-NLS-1$
+		}
 	}
 
 	@Override
-	public void unsubscribe(IResource resource, IScannerInfoChangeListener listener) {
+	public void clean(IConsole console, IProgressMonitor monitor) throws CoreException {
+		IProject project = getProject();
+		try {
+			project.deleteMarkers(ICModelMarker.C_MODEL_PROBLEM_MARKER, false, IResource.DEPTH_INFINITE);
+
+			ConsoleOutputStream errStream = console.getErrorStream();
+			ConsoleOutputStream outStream = console.getOutputStream();
+
+			Path makeCommand = getMakeCommand();
+			if (makeCommand == null) {
+				errStream.write("'make' not found.\n");
+				return;
+			}
+
+			Path buildDir = getBuildDirectory();
+
+			try (ErrorParserManager epm = new ErrorParserManager(project, getBuildDirectoryURI(), this,
+					getToolChain().getErrorParserIds())) {
+				// run make
+				ProcessBuilder processBuilder = new ProcessBuilder(makeCommand.toString(), "clean") //$NON-NLS-1$
+						.directory(buildDir.toFile());
+				setBuildEnvironment(processBuilder.environment());
+				Process process = processBuilder.start();
+				outStream.write(makeCommand.toString() + "clean\n"); //$NON-NLS-1$
+				watchProcess(process, new IConsoleParser[] { epm }, console);
+			}
+
+			project.refreshLocal(IResource.DEPTH_INFINITE, monitor);
+		} catch (IOException e) {
+			throw new CoreException(new Status(IStatus.ERROR, Activator.ID, "Cleaning " + project.getName(), e)); //$NON-NLS-1$
+		}
+	}
+
+	public Path getMakeCommand() {
+		Path makeCommand = findCommand("make"); //$NON-NLS-1$
+		if (makeCommand == null) {
+			makeCommand = findCommand("mingw32-make"); //$NON-NLS-1$
+		}
+		return makeCommand;
 	}
 
 }
diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/build/QtBuildConfigurationProvider.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/build/QtBuildConfigurationProvider.java
index f0bbed8..f97e3ef 100644
--- a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/build/QtBuildConfigurationProvider.java
+++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/build/QtBuildConfigurationProvider.java
@@ -26,7 +26,6 @@
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.NullProgressMonitor;
 import org.eclipse.core.runtime.Platform;
-import org.eclipse.launchbar.core.target.ILaunchTarget;
 
 public class QtBuildConfigurationProvider implements ICBuildConfigurationProvider {
 
@@ -42,18 +41,14 @@
 	}
 
 	@Override
-	public ICBuildConfiguration getCBuildConfiguration(IBuildConfiguration config) {
+	public ICBuildConfiguration getCBuildConfiguration(IBuildConfiguration config, String name) {
 		try {
 			// Double check to make sure this config is ours
-			if (!config.getName().startsWith(getId() + '/')) {
-				return null;
-			}
-
 			if (!config.getProject().hasNature(QtNature.ID)) {
 				return null;
 			}
 
-			return new QtBuildConfiguration(config);
+			return new QtBuildConfiguration(config, name);
 		} catch (CoreException e) {
 			Activator.log(e);
 		}
@@ -120,7 +115,7 @@
 				String configName = "qt." + qtInstall.getSpec() + "." + launchMode; //$NON-NLS-1$ //$NON-NLS-2$
 				IBuildConfiguration config = configManager.createBuildConfiguration(this, project, configName,
 						monitor);
-				QtBuildConfiguration qtConfig = new QtBuildConfiguration(config, toolChain, qtInstall,
+				QtBuildConfiguration qtConfig = new QtBuildConfiguration(config, configName, toolChain, qtInstall,
 						launchMode);
 				configManager.addBuildConfiguration(config, qtConfig);
 				return qtConfig;
@@ -130,35 +125,4 @@
 		return null;
 	}
 
-	public QtBuildConfiguration createConfiguration(IProject project, ILaunchTarget target, String launchMode,
-			IProgressMonitor monitor) throws CoreException {
-		// Find the toolchains
-		Map<String, String> properties = new HashMap<>();
-		String os = target.getAttribute(ILaunchTarget.ATTR_OS, null);
-		if (os != null) {
-			properties.put(IToolChain.ATTR_OS, os);
-		}
-		String arch = target.getAttribute(ILaunchTarget.ATTR_ARCH, null);
-		if (arch != null) {
-			properties.put(IToolChain.ATTR_ARCH, arch);
-		}
-
-		for (IToolChain toolChain : toolChainManager.getToolChainsMatching(properties)) {
-			for (IQtInstall qtInstall : qtInstallManager.getInstalls()) {
-				if (qtInstallManager.supports(qtInstall, toolChain)) {
-					// TODO what if multiple matches
-					String configName = "qt." + qtInstall.getSpec() + "." + launchMode; //$NON-NLS-1$ //$NON-NLS-2$
-					IBuildConfiguration config = configManager.createBuildConfiguration(this, project, configName,
-							monitor);
-					QtBuildConfiguration qtConfig = new QtBuildConfiguration(config, toolChain, qtInstall,
-							launchMode);
-					configManager.addBuildConfiguration(config, qtConfig);
-					return qtConfig;
-				}
-			}
-		}
-
-		return null;
-	}
-
 }
diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/build/QtBuilder.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/build/QtBuilder.java
deleted file mode 100644
index b5a21c5..0000000
--- a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/build/QtBuilder.java
+++ /dev/null
@@ -1,207 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2015, 2016 QNX Software Systems and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *******************************************************************************/
-package org.eclipse.cdt.internal.qt.core.build;
-
-import java.io.File;
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.eclipse.cdt.core.CCorePlugin;
-import org.eclipse.cdt.core.ConsoleOutputStream;
-import org.eclipse.cdt.core.ErrorParserManager;
-import org.eclipse.cdt.core.build.BuildCommandRunner;
-import org.eclipse.cdt.core.build.ICBuildConfiguration;
-import org.eclipse.cdt.core.model.ICModelMarker;
-import org.eclipse.cdt.core.resources.ACBuilder;
-import org.eclipse.cdt.core.resources.IConsole;
-import org.eclipse.cdt.internal.qt.core.Activator;
-import org.eclipse.cdt.internal.qt.core.Messages;
-import org.eclipse.cdt.qt.core.IQtBuildConfiguration;
-import org.eclipse.core.resources.IBuildConfiguration;
-import org.eclipse.core.resources.IFile;
-import org.eclipse.core.resources.IProject;
-import org.eclipse.core.resources.IResource;
-import org.eclipse.core.runtime.CoreException;
-import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.core.runtime.IStatus;
-import org.eclipse.core.runtime.Platform;
-import org.eclipse.core.runtime.Status;
-
-public class QtBuilder extends ACBuilder {
-
-	public static final String ID = Activator.ID + ".qtBuilder"; //$NON-NLS-1$
-
-	@Override
-	protected IProject[] build(int kind, Map<String, String> args, IProgressMonitor monitor) throws CoreException {
-		IProject project = getProject();
-		try {
-			project.deleteMarkers(ICModelMarker.C_MODEL_PROBLEM_MARKER, false,  IResource.DEPTH_INFINITE);
-
-			IConsole console = CCorePlugin.getDefault().getConsole();
-			console.start(project);
-			ConsoleOutputStream errStream = console.getErrorStream();
-			ConsoleOutputStream outStream = console.getOutputStream();
-
-			ICBuildConfiguration cconfig = getBuildConfig().getAdapter(ICBuildConfiguration.class);
-			IQtBuildConfiguration qtConfig = cconfig.getAdapter(QtBuildConfiguration.class);
-			if (qtConfig == null) {
-				// Qt hasn't been configured yet print a message and bale
-				errStream.write(Messages.QtBuilder_0);
-				return null;
-			}
-
-			Path makeCommand = getMakeCommand(getBuildConfig());
-			if (makeCommand == null) {
-				errStream.write("'make' not found.\n");
-				return null;
-			}
-
-			try (ErrorParserManager epm = new ErrorParserManager(project, qtConfig.getBuildDirectory().toUri(), this,
-					qtConfig.getToolChain().getErrorParserIds())) {
-				BuildCommandRunner runner = new BuildCommandRunner(project, console, epm);
-
-				Path buildDir = qtConfig.getBuildDirectory();
-				if (!buildDir.resolve("Makefile").toFile().exists()) { //$NON-NLS-1$
-					// Need to run qmake
-					List<String> command = new ArrayList<>();
-					command.add(qtConfig.getQmakeCommand().toString());
-
-					String config = qtConfig.getQmakeConfig();
-					if (config != null) {
-						command.add(config);
-					}
-
-					IFile projectFile = qtConfig.getBuildConfiguration().getProject()
-							.getFile(project.getName() + ".pro"); //$NON-NLS-1$
-					command.add(projectFile.getLocation().toOSString());
-
-					ProcessBuilder processBuilder = new ProcessBuilder(command)
-							.directory(qtConfig.getBuildDirectory().toFile());
-					CCorePlugin.getDefault().getBuildEnvironmentManager().setEnvironment(processBuilder.environment(),
-							getBuildConfig(), true);
-					Process process = processBuilder.start();
-
-					StringBuilder msg = new StringBuilder();
-					for (String arg : command) {
-						msg.append(arg).append(' ');
-					}
-					msg.append('\n');
-					outStream.write(msg.toString());
-
-					runner.monitor(process);
-				}
-
-				// run make
-				ProcessBuilder procBuilder = new ProcessBuilder(makeCommand.toString()).directory(buildDir.toFile());
-				CCorePlugin.getDefault().getBuildEnvironmentManager().setEnvironment(procBuilder.environment(),
-						getBuildConfig(), true);
-				Process process = procBuilder.start();
-				outStream.write(makeCommand.toString() + '\n');
-				runner.monitor(process);
-			}
-
-			project.refreshLocal(IResource.DEPTH_INFINITE, monitor);
-
-			// clear the scanner info cache
-			// TODO be more surgical about what to clear based on what was
-			// built.
-			// qtConfig.clearScannerInfoCache();
-
-			outStream.write("Complete.\n");
-			return new IProject[] { project };
-		} catch (IOException e) {
-			throw new CoreException(new Status(IStatus.ERROR, Activator.ID, "Building " + project.getName(), e)); //$NON-NLS-1$
-		}
-	}
-
-	@Override
-	protected void clean(IProgressMonitor monitor) throws CoreException {
-		IProject project = getProject();
-		try {
-			project.deleteMarkers(ICModelMarker.C_MODEL_PROBLEM_MARKER, false,  IResource.DEPTH_INFINITE);
-
-			IConsole console = CCorePlugin.getDefault().getConsole();
-			console.start(getProject());
-			ConsoleOutputStream errStream = console.getErrorStream();
-			ConsoleOutputStream outStream = console.getOutputStream();
-
-			ICBuildConfiguration cconfig = getBuildConfig().getAdapter(ICBuildConfiguration.class);
-			IQtBuildConfiguration qtConfig = cconfig.getAdapter(QtBuildConfiguration.class);
-			if (qtConfig == null) {
-				// Qt hasn't been configured yet print a message and bale
-				errStream.write(Messages.QtBuilder_0);
-				return;
-			}
-
-			Path makeCommand = getMakeCommand(getBuildConfig());
-			if (makeCommand == null) {
-				errStream.write("'make' not found.\n");
-				return;
-			}
-
-			Path buildDir = qtConfig.getBuildDirectory();
-
-			try (ErrorParserManager epm = new ErrorParserManager(project, qtConfig.getBuildDirectory().toUri(), this,
-					qtConfig.getToolChain().getErrorParserIds())) {
-				BuildCommandRunner runner = new BuildCommandRunner(project, console, epm);
-				// run make
-				ProcessBuilder procBuilder = new ProcessBuilder(makeCommand.toString(), "clean") //$NON-NLS-1$
-						.directory(buildDir.toFile());
-				CCorePlugin.getDefault().getBuildEnvironmentManager().setEnvironment(procBuilder.environment(),
-						getBuildConfig(), true);
-				Process process = procBuilder.start();
-				outStream.write(makeCommand.toString() + "clean\n"); //$NON-NLS-1$
-				runner.monitor(process);
-			}
-
-			project.refreshLocal(IResource.DEPTH_INFINITE, monitor);
-
-			// clear the scanner info cache
-			// TODO be more surgical about what to clear based on what was
-			// built.
-			// qtConfig.clearScannerInfoCache();
-
-			outStream.write("Complete.\n");
-			// TODO Auto-generated method stub
-			super.clean(monitor);
-		} catch (IOException e) {
-			throw new CoreException(new Status(IStatus.ERROR, Activator.ID, "Cleaning " + project.getName(), e)); //$NON-NLS-1$
-		}
-	}
-
-	public Path getMakeCommand(IBuildConfiguration config) {
-		Path makeCommand = findCommand(getBuildConfig(), "make"); //$NON-NLS-1$
-		if (makeCommand == null) {
-			makeCommand = findCommand(getBuildConfig(), "mingw32-make"); //$NON-NLS-1$
-		}
-		return makeCommand;
-	}
-
-	public Path findCommand(IBuildConfiguration config, String command) {
-		if (Platform.getOS().equals(Platform.OS_WIN32)) {
-			command += ".exe"; //$NON-NLS-1$
-		}
-		Map<String, String> env = new HashMap<>(System.getenv());
-		CCorePlugin.getDefault().getBuildEnvironmentManager().setEnvironment(env, config, true);
-		String[] path = env.get("PATH").split(File.pathSeparator); //$NON-NLS-1$
-		for (String dir : path) {
-			Path commandPath = Paths.get(dir, command);
-			if (Files.exists(commandPath)) {
-				return commandPath;
-			}
-		}
-		return null;
-	}
-
-}
diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/project/QtProjectGenerator.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/project/QtProjectGenerator.java
index 2cbd95f..ac870cc 100644
--- a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/project/QtProjectGenerator.java
+++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/project/QtProjectGenerator.java
@@ -17,35 +17,31 @@
 import org.eclipse.cdt.core.model.IPathEntry;
 import org.eclipse.cdt.internal.qt.core.Activator;
 import org.eclipse.cdt.internal.qt.core.QtNature;
-import org.eclipse.cdt.internal.qt.core.build.QtBuilder;
-import org.eclipse.core.resources.ICommand;
 import org.eclipse.core.resources.IFolder;
 import org.eclipse.core.resources.IProject;
 import org.eclipse.core.resources.IProjectDescription;
-import org.eclipse.core.resources.IncrementalProjectBuilder;
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.tools.templates.freemarker.FMProjectGenerator;
 import org.eclipse.tools.templates.freemarker.SourceRoot;
+import org.osgi.framework.Bundle;
 
 public class QtProjectGenerator extends FMProjectGenerator {
 
 	@Override
 	protected void initProjectDescription(IProjectDescription description) {
-		// Natures
 		description
 				.setNatureIds(new String[] { CProjectNature.C_NATURE_ID, CCProjectNature.CC_NATURE_ID, QtNature.ID });
-
-		// Builders
-		ICommand command = description.newCommand();
-		command.setBuilderName(QtBuilder.ID);
-		command.setBuilding(IncrementalProjectBuilder.AUTO_BUILD, false);
-		description.setBuildSpec(new ICommand[] { command });
+		QtNature.setupBuilder(description);
 	}
 
 	@Override
+	public Bundle getSourceBundle() {
+		return Activator.getDefault().getBundle();
+	}
+	
+	@Override
 	public void generate(Map<String, Object> model, IProgressMonitor monitor) throws CoreException {
-		setBundle(Activator.getDefault().getBundle());
 		super.generate(model, monitor);
 
 		// Create the sourcefolders
diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/IQtBuildConfiguration.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/IQtBuildConfiguration.java
index 08abf17..1e8dcf1 100644
--- a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/IQtBuildConfiguration.java
+++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/IQtBuildConfiguration.java
@@ -10,16 +10,17 @@
 import java.nio.file.Path;

 

 import org.eclipse.cdt.core.build.ICBuildConfiguration;

+import org.eclipse.core.runtime.CoreException;

 

 public interface IQtBuildConfiguration extends ICBuildConfiguration {

 

-	Path getBuildDirectory();

-

+	Path getBuildDirectory() throws CoreException;

+	

 	Path getQmakeCommand();

 

 	String getQmakeConfig();

 

-	Path getProgramPath();

+	Path getProgramPath() throws CoreException;

 

 	String getLaunchMode();

 

diff --git a/qt/org.eclipse.cdt.qt.ui/src/org/eclipse/cdt/internal/qt/ui/wizards/HelloWorldWizard.java b/qt/org.eclipse.cdt.qt.ui/src/org/eclipse/cdt/internal/qt/ui/wizards/HelloWorldWizard.java
index 2a0297d..8b3f2a2 100644
--- a/qt/org.eclipse.cdt.qt.ui/src/org/eclipse/cdt/internal/qt/ui/wizards/HelloWorldWizard.java
+++ b/qt/org.eclipse.cdt.qt.ui/src/org/eclipse/cdt/internal/qt/ui/wizards/HelloWorldWizard.java
@@ -17,9 +17,7 @@
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.jobs.ISchedulingRule;
 import org.eclipse.jface.dialogs.Dialog;
-import org.eclipse.jface.viewers.IStructuredSelection;
 import org.eclipse.swt.widgets.Composite;
-import org.eclipse.ui.IWorkbench;
 import org.eclipse.ui.actions.WorkspaceModifyOperation;
 import org.eclipse.ui.dialogs.WizardNewProjectCreationPage;
 import org.eclipse.ui.wizards.newresource.BasicNewResourceWizard;
@@ -80,9 +78,4 @@
 		return true;
 	}
 
-	@Override
-	public void init(IWorkbench theWorkbench, IStructuredSelection currentSelection) {
-		super.init(theWorkbench, currentSelection);
-	}
-
 }