Cherry picking changes from the CDT 9 branch for Qt and Arduino.

Change-Id: I85eca2b8bb0447d4dd703030c41d90c1f9bcdf89
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 f2117a1..9ffdc42 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
@@ -55,6 +55,7 @@
 	private final String prefix;
 	private final IEnvironmentVariable pathVar;
 	private final IEnvironmentVariable[] envVars;
+	private final Map<String, String> properties = new HashMap<>();
 
 	protected String[] compileCommands;
 
@@ -113,17 +114,28 @@
 
 	@Override
 	public String getProperty(String key) {
-		// this class represents a local toolchain
+		String value = properties.get(key);
+		if (value != null) {
+			return value;
+		}
+		
+		// By default, we're a local GCC
 		switch (key) {
 		case ATTR_OS:
 			return Platform.getOS();
 		case ATTR_ARCH:
 			return Platform.getOSArch();
 		}
+		
 		return null;
 	}
 
 	@Override
+	public void setProperty(String key, String value) {
+		properties.put(key, value);
+	}
+	
+	@Override
 	public String getBinaryParserId() {
 		// Assume local builds
 		// TODO be smarter and use the id which should be the target
diff --git a/build/org.eclipse.cdt.build.gcc.core/src/org/eclipse/cdt/build/gcc/core/internal/GCCPathToolChainProvider.java b/build/org.eclipse.cdt.build.gcc.core/src/org/eclipse/cdt/build/gcc/core/internal/GCCPathToolChainProvider.java
index 28905b0..61a0b69 100644
--- a/build/org.eclipse.cdt.build.gcc.core/src/org/eclipse/cdt/build/gcc/core/internal/GCCPathToolChainProvider.java
+++ b/build/org.eclipse.cdt.build.gcc.core/src/org/eclipse/cdt/build/gcc/core/internal/GCCPathToolChainProvider.java
@@ -18,8 +18,10 @@
 import java.util.regex.Pattern;
 
 import org.eclipse.cdt.build.gcc.core.GCCToolChain;
+import org.eclipse.cdt.core.build.IToolChain;
 import org.eclipse.cdt.core.build.IToolChainManager;
 import org.eclipse.cdt.core.build.IToolChainProvider;
+import org.eclipse.core.runtime.Platform;
 
 /**
  * Finds gcc and clang on the path.
@@ -74,8 +76,32 @@
 								String name = target + " - " + version; //$NON-NLS-1$
 								if (!names.contains(name)) {
 									names.add(name);
-									manager.addToolChain(new GCCToolChain(this, target, version,
-											new Path[] { dir.toPath() }, prefix));
+									GCCToolChain toolChain = new GCCToolChain(this, target, version,
+											new Path[] { dir.toPath() }, prefix);
+									String[] tuple = target.split("-"); //$NON-NLS-1$
+									if (tuple.length > 2) {
+										// Arch
+										if ("x86_64".equals(tuple[0])) {
+											toolChain.setProperty(IToolChain.ATTR_ARCH, tuple[0]);
+										} else {
+											toolChain.setProperty(IToolChain.ATTR_ARCH, "x86"); // default
+										}
+										
+										// OS
+										switch (tuple[1]) {
+										case "w64":
+											toolChain.setProperty(IToolChain.ATTR_OS, Platform.OS_WIN32);
+											break;
+										case "linux":
+											toolChain.setProperty(IToolChain.ATTR_OS, Platform.OS_LINUX);
+											break;
+										case "apple":
+											toolChain.setProperty(IToolChain.ATTR_OS, Platform.OS_MACOSX);
+											break;
+										}
+									}
+									toolChain.setProperty(IToolChain.ATTR_PACKAGE, "system");
+									manager.addToolChain(toolChain);
 								}
 							}
 						} catch (IOException e) {
diff --git a/build/org.eclipse.cdt.build.gcc.core/src/org/eclipse/cdt/build/gcc/core/internal/Msys2ToolChainProvider.java b/build/org.eclipse.cdt.build.gcc.core/src/org/eclipse/cdt/build/gcc/core/internal/Msys2ToolChainProvider.java
index aa22cd0..7e62455 100644
--- a/build/org.eclipse.cdt.build.gcc.core/src/org/eclipse/cdt/build/gcc/core/internal/Msys2ToolChainProvider.java
+++ b/build/org.eclipse.cdt.build.gcc.core/src/org/eclipse/cdt/build/gcc/core/internal/Msys2ToolChainProvider.java
@@ -11,6 +11,7 @@
 import java.nio.file.Paths;

 

 import org.eclipse.cdt.build.gcc.core.GCCToolChain;

+import org.eclipse.cdt.core.build.IToolChain;

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

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

 import org.eclipse.cdt.utils.WindowsRegistry;

@@ -65,8 +66,10 @@
 		Path msysPath = Paths.get(installLocation);

 		Path gccPath = msysPath.resolve("mingw64\\bin\\gcc.exe"); //$NON-NLS-1$

 		if (Files.exists(gccPath)) {

-			manager.addToolChain(new GCCToolChain(this, "x86_64-w64-mingw32", "msys2.x86_64", new Path[] { //$NON-NLS-1$ //$NON-NLS-2$

-					gccPath.getParent(), msysPath.resolve("bin"), msysPath.resolve("usr\\bin") })); //$NON-NLS-1$ //$NON-NLS-2$

+			GCCToolChain toolChain = new GCCToolChain(this, "x86_64-w64-mingw32", "msys2.x86_64", new Path[] { //$NON-NLS-1$ //$NON-NLS-2$

+					gccPath.getParent(), msysPath.resolve("bin"), msysPath.resolve("usr\\bin") }); //$NON-NLS-1$ //$NON-NLS-2$

+			toolChain.setProperty(IToolChain.ATTR_PACKAGE, "msys2"); //$NON-NLS-1$

+			manager.addToolChain(toolChain);

 			return true;

 		} else {

 			return addToolChain32(manager, registry, key);

@@ -78,8 +81,10 @@
 		Path msysPath = Paths.get(installLocation);

 		Path gccPath = msysPath.resolve("mingw32\\bin\\gcc.exe"); //$NON-NLS-1$

 		if (Files.exists(gccPath)) {

-			manager.addToolChain(new GCCToolChain(this, "i686-w64-mingw32", "msys2.i686", new Path[] { //$NON-NLS-1$ //$NON-NLS-2$

-					gccPath.getParent(), msysPath.resolve("bin"), msysPath.resolve("usr\\bin") })); //$NON-NLS-1$ //$NON-NLS-2$

+			GCCToolChain toolChain = new GCCToolChain(this, "i686-w64-mingw32", "msys2.i686", new Path[] { //$NON-NLS-1$ //$NON-NLS-2$

+					gccPath.getParent(), msysPath.resolve("bin"), msysPath.resolve("usr\\bin") }); //$NON-NLS-1$ //$NON-NLS-2$

+			toolChain.setProperty(IToolChain.ATTR_PACKAGE, "msys2"); //$NON-NLS-1$

+			manager.addToolChain(toolChain);

 			return true;

 		} else {

 			return false;

diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/CModelManager.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/CModelManager.java
index b9e110c..e3c90e9 100644
--- a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/CModelManager.java
+++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/CModelManager.java
@@ -611,11 +611,9 @@
 				// Check for new style build configs first
 				Set<String> parserIds = new HashSet<>();
 				for (IBuildConfiguration config : project.getBuildConfigs()) {
-					if (!IBuildConfiguration.DEFAULT_CONFIG_NAME.equals(config.getName())) {
-						ICBuildConfiguration cconfig = config.getAdapter(ICBuildConfiguration.class);
-						if (cconfig != null) {
-							parserIds.add(cconfig.getBinaryParserId());
-						}
+					ICBuildConfiguration cconfig = config.getAdapter(ICBuildConfiguration.class);
+					if (cconfig != null) {
+						parserIds.add(cconfig.getBinaryParserId());
 					}
 				}
 				if (!parserIds.isEmpty()) {
diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/CCorePlugin.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/CCorePlugin.java
index 1078303..5bde705 100644
--- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/CCorePlugin.java
+++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/CCorePlugin.java
@@ -1147,10 +1147,7 @@
 			
 			// If we are new style build configurations, get the provider there
 			IBuildConfiguration activeConfig = project.getActiveBuildConfig();
-			ICBuildConfiguration cconfig = buildConfigManager.getBuildConfiguration(activeConfig);
-			if (cconfig == null) {
-				cconfig = buildConfigManager.getDefaultBuildConfiguration(project);
-			}
+			ICBuildConfiguration cconfig = activeConfig.getAdapter(ICBuildConfiguration.class);
 			if (cconfig != null) {
 				return cconfig;
 			}
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 e4b644e..a8b89aa 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
@@ -101,8 +101,8 @@
 
 		toolChain = tc;
 	}
-
-	public CBuildConfiguration(IBuildConfiguration config, String name, IToolChain toolChain) {
+	
+	protected CBuildConfiguration(IBuildConfiguration config, String name, IToolChain toolChain) {
 		this.config = config;
 		this.name = name;
 		this.toolChain = toolChain;
@@ -118,6 +118,10 @@
 		}
 	}
 
+	protected CBuildConfiguration(IBuildConfiguration config, IToolChain toolChain) {
+		this(config, DEFAULT_NAME, toolChain);
+	}
+	
 	@Override
 	public IBuildConfiguration getBuildConfiguration() {
 		return config;
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 2b4c46e..59b8a87 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
@@ -29,6 +29,12 @@
 public interface ICBuildConfiguration extends IAdaptable, IScannerInfoProvider {
 
 	/**
+	 * CDT doesn't like that the Platform default config name is an empty string.
+	 * It needs a real name for the name of the build directory, for example.
+	 */
+	public static String DEFAULT_NAME = "default";
+	
+	/**
 	 * Returns the resources build configuration that this CDT build
 	 * configuration is associated with.
 	 * 
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 b2f1cef..b0f5d1d 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
@@ -20,6 +20,12 @@
  */

 public interface ICBuildConfigurationManager {

 

+	/**

+	 * Return the build configuration provider with the given id.

+	 * 

+	 * @param id

+	 * @return build configuration provider

+	 */

 	ICBuildConfigurationProvider getProvider(String id);

 

 	/**

@@ -35,8 +41,6 @@
 	IBuildConfiguration createBuildConfiguration(ICBuildConfigurationProvider provider, IProject project,

 			String configName, IProgressMonitor monitor) throws CoreException;

 

-	IBuildConfiguration getBuildConfiguration(ICBuildConfigurationProvider provider, IProject project, String configName) throws CoreException;

-

 	/**

 	 * Called by providers to add new build configurations as they are created.

 	 * 

@@ -56,6 +60,4 @@
 	 */

 	ICBuildConfiguration getBuildConfiguration(IBuildConfiguration buildConfig) throws CoreException;

 	

-	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 7885bf0..40bf781 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
@@ -8,7 +8,6 @@
 package org.eclipse.cdt.core.build;
 
 import org.eclipse.core.resources.IBuildConfiguration;
-import org.eclipse.core.resources.IProject;
 import org.eclipse.core.runtime.CoreException;
 
 /**
@@ -33,12 +32,4 @@
 	 */
 	ICBuildConfiguration getCBuildConfiguration(IBuildConfiguration config, String name) throws CoreException;
 
-	/**
-	 * Returns a default C build configuration for a given project if any.
-	 * 
-	 * @param project
-	 * @return default C build configuration for the 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 2d341e2..66dee54 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
@@ -27,11 +27,12 @@
 	// Standard attributes

 	static final String ATTR_OS = "os"; //$NON-NLS-1$

 	static final String ATTR_ARCH = "arch"; //$NON-NLS-1$

+	static final String ATTR_PACKAGE = "package"; //$NON-NLS-1$

 

 	IToolChainProvider getProvider();

 

 	String getId();

-	

+

 	String getVersion();

 

 	String getName();

@@ -47,6 +48,8 @@
 	 */

 	String getProperty(String key);

 

+	void setProperty(String key, String value);

+

 	IEnvironmentVariable getVariable(String name);

 

 	IEnvironmentVariable[] getVariables();

@@ -63,5 +66,5 @@
 	IResource[] getResourcesFromCommand(String[] command, URI buildDirectoryURI);

 

 	String getBinaryParserId();

-	

+

 }

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 065afe9..84991ef 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
@@ -72,16 +72,19 @@
 

 		public boolean supports(IProject project) {

 			try {

-				return project.hasNature(natureId);

+				if (natureId != null) {

+					return project.hasNature(natureId);

+				}

 			} catch (CoreException e) {

 				CCorePlugin.log(e.getStatus());

-				return false;

 			}

+			return false;

 		}

 	}

 

 	private Map<String, Provider> providers;

 	private Map<IBuildConfiguration, ICBuildConfiguration> configs = new HashMap<>();

+	private Set<IBuildConfiguration> noConfigs = new HashSet<>();

 

 	public CBuildConfigurationManager() {

 		ResourcesPlugin.getWorkspace().addResourceChangeListener(this);

@@ -105,13 +108,33 @@
 	}

 

 	private Provider getProviderDelegate(String id) {

-		initProviders();

 		return providers.get(id);

 	}

 

 	@Override

 	public ICBuildConfigurationProvider getProvider(String id) {

-		return getProviderDelegate(id).getProvider();

+		initProviders();

+		Provider provider = providers.get(id);

+		return provider != null ? provider.getProvider() : null;

+	}

+	

+	public ICBuildConfigurationProvider getProvider(String id, IProject project) {

+		initProviders();

+		Provider provider = getProviderDelegate(id);

+		if (provider != null && provider.supports(project)) {

+			return provider.getProvider();

+		}

+		return null;

+	}

+

+	public ICBuildConfigurationProvider getProvider(IProject project) throws CoreException {

+		initProviders();

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

+			if (provider.supports(project)) {

+				return provider.getProvider();

+			}

+		}

+		return null;

 	}

 

 	@Override

@@ -143,47 +166,51 @@
 	public ICBuildConfiguration getBuildConfiguration(IBuildConfiguration buildConfig) throws CoreException {

 		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, configName);

-						configs.put(buildConfig, config);

-

-						// Also make sure we reset the binary parser cache for the new config

-						CModelManager.getDefault().resetBinaryParser(buildConfig.getProject());

-					}

-				}

-			}

-			return config;

-		}

-	}

-

-	@Override

-	public IBuildConfiguration getBuildConfiguration(ICBuildConfigurationProvider provider, IProject project,

-			String configName) throws CoreException {

-		String name = provider.getId() + '/' + configName;

-		return project.getBuildConfig(name);

-	}

-

-	@Override

-	public ICBuildConfiguration getDefaultBuildConfiguration(IProject project) throws CoreException {

-		initProviders();

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

-			if (provider.supports(project)) {

-				ICBuildConfiguration config = provider.getProvider().getDefaultCBuildConfiguration(project);

+			if (noConfigs.contains(buildConfig)) {

+				return null;

+			} else {

+				ICBuildConfiguration config = configs.get(buildConfig);

 				if (config != null) {

-					configs.put(config.getBuildConfiguration(), config);

 					return config;

+				} else {

+					String configName;

+					ICBuildConfigurationProvider provider;

+					if (IBuildConfiguration.DEFAULT_CONFIG_NAME.equals(buildConfig.getName())) {

+						configName = ICBuildConfiguration.DEFAULT_NAME;

+						provider = getProvider(buildConfig.getProject());

+					} else {

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

+						if (segments.length == 2) {

+							String providerId = segments[0];

+							configName = segments[1];

+							Provider delegate = getProviderDelegate(providerId);

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

+								provider = delegate.getProvider();

+							} else {

+								return null;

+							}

+						} else {

+							// Not ours

+							return null;

+						}

+					}

+

+					if (provider != null) {

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

+						if (config != null) {

+							configs.put(buildConfig, config);

+

+							// Also make sure we reset the binary parser cache for the new config

+							CModelManager.getDefault().resetBinaryParser(buildConfig.getProject());

+							return config;

+						}

+					}

+

+					noConfigs.add(buildConfig);

+					return null;

 				}

 			}

 		}

-		return null;

 	}

 

 	@Override

diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/build/ToolChainManager.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/build/ToolChainManager.java
index ed83798..b6fa1aa 100644
--- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/build/ToolChainManager.java
+++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/build/ToolChainManager.java
@@ -133,6 +133,15 @@
 				tcs.add(toolChain);
 			}
 		}
+		
+		// Allow 32-bit compilers on 64-bit machines
+		// TODO is there a cleaner way to do this?
+		if ("x86_64".equals(properties.get(IToolChain.ATTR_ARCH))) { //$NON-NLS-1$
+			Map<String, String> properties32 = new HashMap<>(properties);
+			properties32.put(IToolChain.ATTR_ARCH, "x86"); //$NON-NLS-1$
+			tcs.addAll(getToolChainsMatching(properties32));
+		}
+
 		return tcs;
 	}
 
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/launching/GdbLaunch.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/launching/GdbLaunch.java
index 721546d..a76718a 100644
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/launching/GdbLaunch.java
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/launching/GdbLaunch.java
@@ -32,6 +32,7 @@
 import org.eclipse.cdt.core.CCorePlugin;
 import org.eclipse.cdt.core.cdtvariables.CdtVariableException;
 import org.eclipse.cdt.core.cdtvariables.ICdtVariable;
+import org.eclipse.cdt.core.cdtvariables.ICdtVariableManager;
 import org.eclipse.cdt.core.envvar.IEnvironmentVariable;
 import org.eclipse.cdt.core.model.CoreModel;
 import org.eclipse.cdt.core.model.ICProject;
@@ -660,19 +661,17 @@
 			}
 
 			// Add variables from build info
-			ICdtVariable[] buildVars = CCorePlugin.getDefault().getCdtVariableManager().getVariables(cfg);
+			ICdtVariableManager manager = CCorePlugin.getDefault().getCdtVariableManager();
+			ICdtVariable[] buildVars = manager.getVariables(cfg);
 			for (ICdtVariable var : buildVars) {
 				try {
 					// The project_classpath variable contributed by JDT is
-					// useless
-					// for running C/C++
-					// binaries, but it can be lethal if it has a very large
-					// value
-					// that exceeds shell
-					// limit. See
+					// useless for running C/C++ binaries, but it can be lethal
+					// if it has a very large value that exceeds shell limit. See
 					// http://bugs.eclipse.org/bugs/show_bug.cgi?id=408522
 					if (!"project_classpath".equals(var.getName())) {//$NON-NLS-1$
-						envMap.put(var.getName(), var.getStringValue());
+						String value = manager.resolveValue(var.getStringValue(), "", File.pathSeparator, cfg); //$NON-NLS-1$
+						envMap.put(var.getName(), value);
 					}
 				} catch (CdtVariableException e) {
 					// Some Eclipse dynamic variables can't be resolved
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/launching/GdbLaunchDelegate.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/launching/GdbLaunchDelegate.java
index 7534f18..12b987b 100644
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/launching/GdbLaunchDelegate.java
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/launching/GdbLaunchDelegate.java
@@ -139,7 +139,7 @@
     	
         monitor.worked(1);
 
-        String gdbVersion = getGDBVersion(config);
+        String gdbVersion = launch.getGDBVersion();
         
         // First make sure non-stop is supported, if the user want to use this mode
         if (LaunchUtils.getIsNonStopMode(config) && !isNonStopSupportedInGdbVersion(gdbVersion)) {
diff --git a/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/internal/LocalRunLaunchDelegate.java b/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/internal/LocalRunLaunchDelegate.java
index 7b85457..e0e48bc 100644
--- a/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/internal/LocalRunLaunchDelegate.java
+++ b/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/internal/LocalRunLaunchDelegate.java
@@ -18,9 +18,19 @@
 import java.util.Arrays;
 import java.util.Date;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
+import java.util.Map.Entry;
 
+import org.eclipse.cdt.core.CCorePlugin;
+import org.eclipse.cdt.core.cdtvariables.CdtVariableException;
+import org.eclipse.cdt.core.cdtvariables.ICdtVariable;
+import org.eclipse.cdt.core.cdtvariables.ICdtVariableManager;
+import org.eclipse.cdt.core.envvar.IEnvironmentVariable;
+import org.eclipse.cdt.core.model.CoreModel;
 import org.eclipse.cdt.core.model.ICProject;
+import org.eclipse.cdt.core.settings.model.ICConfigurationDescription;
+import org.eclipse.cdt.core.settings.model.ICProjectDescription;
 import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants;
 import org.eclipse.cdt.launch.AbstractCLaunchDelegate2;
 import org.eclipse.cdt.launch.internal.ui.LaunchMessages;
@@ -28,6 +38,9 @@
 import org.eclipse.cdt.utils.CommandLineUtil;
 import org.eclipse.cdt.utils.pty.PTY;
 import org.eclipse.cdt.utils.spawner.ProcessFactory;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.ResourcesPlugin;
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IPath;
 import org.eclipse.core.runtime.IProgressMonitor;
@@ -44,28 +57,29 @@
 /**
  * The launch delegate for Run mode.
  */
-public class LocalRunLaunchDelegate extends AbstractCLaunchDelegate2
-{
+public class LocalRunLaunchDelegate extends AbstractCLaunchDelegate2 {
 	public LocalRunLaunchDelegate() {
 		// We support project-less run
 		super(false);
 	}
-	
+
 	@Override
-	public void launch( ILaunchConfiguration config, String mode, ILaunch launch, IProgressMonitor monitor ) throws CoreException {
+	public void launch(ILaunchConfiguration config, String mode, ILaunch launch, IProgressMonitor monitor)
+			throws CoreException {
 		// This delegate is only for Run mode
 		assert mode.equals(ILaunchManager.RUN_MODE);
-		
-		if ( monitor == null ) {
+
+		if (monitor == null) {
 			monitor = new NullProgressMonitor();
 		}
-		if ( mode.equals(ILaunchManager.RUN_MODE ) ) {
-			runLocalApplication( config, launch, monitor );
+		if (mode.equals(ILaunchManager.RUN_MODE)) {
+			runLocalApplication(config, launch, monitor);
 		}
 	}
 
-	private void runLocalApplication(ILaunchConfiguration config, ILaunch launch, IProgressMonitor monitor) throws CoreException {
-		monitor.beginTask(LaunchMessages.LocalCDILaunchDelegate_0, 10); 
+	private void runLocalApplication(ILaunchConfiguration config, ILaunch launch, IProgressMonitor monitor)
+			throws CoreException {
+		monitor.beginTask(LaunchMessages.LocalCDILaunchDelegate_0, 10);
 		if (monitor.isCanceled()) {
 			return;
 		}
@@ -77,50 +91,173 @@
 			if (wd == null) {
 				wd = new File(System.getProperty("user.home", ".")); //$NON-NLS-1$ //$NON-NLS-2$
 			}
-			
+
 			String args = config.getAttribute(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_ARGUMENTS, ""); //$NON-NLS-1$
 			if (args.length() != 0) {
 				args = VariablesPlugin.getDefault().getStringVariableManager().performStringSubstitution(args);
 			}
-			
+
 			String[] arguments = CommandLineUtil.argumentsToArray(args);
 			ArrayList<String> command = new ArrayList<>(1 + arguments.length);
 			command.add(exePath.toOSString());
 			command.addAll(Arrays.asList(arguments));
 			monitor.worked(2);
-			
+
 			String[] commandArray = command.toArray(new String[command.size()]);
-			String[] environment = DebugPlugin.getDefault().getLaunchManager().getEnvironment(config);
+			String[] environment = getLaunchEnvironment(config);
 			Process process = exec(commandArray, environment, wd);
 			monitor.worked(6);
 
 			String timestamp = DateFormat.getInstance().format(new Date(System.currentTimeMillis()));
 			String processLabel = String.format("%s (%s)", commandArray[0], timestamp); //$NON-NLS-1$
-			
+
 			DebugPlugin.newProcess(launch, process, processLabel, createProcessAttributes());
 		} finally {
 			monitor.done();
-		}		
+		}
+	}
+
+	/**
+	 * Gets the CDT environment from the CDT project's configuration referenced
+	 * by the launch
+	 */
+	protected String[] getLaunchEnvironment(ILaunchConfiguration config) throws CoreException {
+		// Get the project
+		String projectName = config.getAttribute(ICDTLaunchConfigurationConstants.ATTR_PROJECT_NAME, (String) null);
+		IProject project = null;
+		if (projectName == null) {
+			IResource[] resources = config.getMappedResources();
+			if (resources != null && resources.length > 0 && resources[0] instanceof IProject) {
+				project = (IProject) resources[0];
+			}
+		} else {
+			projectName = projectName.trim();
+			if (projectName.length() == 0) {
+				return null;
+			}
+			project = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName);
+		}
+
+		HashMap<String, String> envMap = new HashMap<String, String>();
+
+		// Add in from the config
+		String[] debugEnv = DebugPlugin.getDefault().getLaunchManager().getEnvironment(config);
+		if (debugEnv != null) {
+			for (String env : debugEnv) {
+				String[] parts = env.split("=", 2); //$NON-NLS-1$
+				if (parts.length == 2) {
+					envMap.put(parts[0], parts[1]);
+				}
+			}
+		}
+
+		if (project != null && project.isAccessible()) {
+			ICProjectDescription projDesc = CoreModel.getDefault().getProjectDescription(project, false);
+			if (projDesc != null) {
+				String buildConfigID = config
+						.getAttribute(ICDTLaunchConfigurationConstants.ATTR_PROJECT_BUILD_CONFIG_ID, ""); //$NON-NLS-1$
+				ICConfigurationDescription cfg = null;
+				if (buildConfigID.length() != 0) {
+					cfg = projDesc.getConfigurationById(buildConfigID);
+				}
+
+				// if configuration is null fall-back to active
+				if (cfg == null) {
+					cfg = projDesc.getActiveConfiguration();
+				}
+
+				// Environment variables and inherited vars
+				IEnvironmentVariable[] vars = CCorePlugin.getDefault().getBuildEnvironmentManager().getVariables(cfg,
+						true);
+				for (IEnvironmentVariable var : vars) {
+					String value;
+					switch (var.getOperation()) {
+					case IEnvironmentVariable.ENVVAR_REPLACE:
+						value = var.getValue();
+						break;
+					case IEnvironmentVariable.ENVVAR_APPEND:
+						value = envMap.get(var.getName());
+						if (value != null) {
+							value += var.getDelimiter() + var.getValue();
+						} else {
+							value = var.getValue();
+						}
+						break;
+					case IEnvironmentVariable.ENVVAR_PREPEND:
+						value = envMap.get(var.getName());
+						if (value != null) {
+							value = var.getValue() + var.getDelimiter() + value;
+						} else {
+							value = var.getValue();
+						}
+						break;
+					case IEnvironmentVariable.ENVVAR_REMOVE:
+						envMap.remove(var.getName());
+						value = null;
+						break;
+					default:
+						value = null;
+					}
+
+					if (value != null) {
+						envMap.put(var.getName(), value);
+					}
+				}
+
+				// Add variables from build info
+				ICdtVariableManager manager = CCorePlugin.getDefault().getCdtVariableManager();
+				ICdtVariable[] buildVars = manager.getVariables(cfg);
+				for (ICdtVariable var : buildVars) {
+					try {
+						// The project_classpath variable contributed by JDT is
+						// useless for running C/C++ binaries, but it can be
+						// lethal if it has a very large value that exceeds
+						// shell limit. See
+						// http://bugs.eclipse.org/bugs/show_bug.cgi?id=408522
+						if (!"project_classpath".equals(var.getName())) {//$NON-NLS-1$
+							String value = manager.resolveValue(var.getStringValue(), "", File.pathSeparator, cfg); //$NON-NLS-1$
+							envMap.put(var.getName(), value);
+						}
+					} catch (CdtVariableException e) {
+						// Some Eclipse dynamic variables can't be resolved
+						// dynamically... we don't care.
+					}
+				}
+			}
+		}
+
+		// Turn it into an envp format
+		List<String> strings = new ArrayList<String>(envMap.size());
+		for (Entry<String, String> entry : envMap.entrySet()) {
+			StringBuilder buffer = new StringBuilder(entry.getKey());
+			buffer.append('=').append(entry.getValue());
+			strings.add(buffer.toString());
+		}
+
+		return strings.toArray(new String[strings.size()]);
 	}
 
 	protected Map<String, String> createProcessAttributes() {
 		Map<String, String> attributes = new HashMap<>();
-		
-		// Specify that the process factory (GdbProcessFactory) should use InferiorRuntimeProcess to wrap
+
+		// Specify that the process factory (GdbProcessFactory) should use
+		// InferiorRuntimeProcess to wrap
 		// the process that we are about to run.
-		// Note that GdbProcessFactory is only used for launches created using DSF-GDB not CDI
-	    attributes.put("org.eclipse.cdt.dsf.gdb.createProcessType" /* IGdbDebugConstants.PROCESS_TYPE_CREATION_ATTR */, //$NON-NLS-1$
-    		    	   "org.eclipse.cdt.dsf.gdb.inferiorProcess" /* IGdbDebugConstants.INFERIOR_PROCESS_CREATION_VALUE */);  //$NON-NLS-1$
-	    
-	    // Show the exit code of the process in the console title once it has terminated
-	    attributes.put("org.eclipse.cdt.dsf.gdb.inferiorExited" /* IGdbDebugConstants.INFERIOR_EXITED_ATTR */,  //$NON-NLS-1$
-	    		       "");  //$NON-NLS-1$
+		// Note that GdbProcessFactory is only used for launches created using
+		// DSF-GDB not CDI
+		attributes.put("org.eclipse.cdt.dsf.gdb.createProcessType" /* IGdbDebugConstants.PROCESS_TYPE_CREATION_ATTR */, //$NON-NLS-1$
+				"org.eclipse.cdt.dsf.gdb.inferiorProcess" /* IGdbDebugConstants.INFERIOR_PROCESS_CREATION_VALUE */); //$NON-NLS-1$
+
+		// Show the exit code of the process in the console title once it has
+		// terminated
+		attributes.put("org.eclipse.cdt.dsf.gdb.inferiorExited" /* IGdbDebugConstants.INFERIOR_EXITED_ATTR */, //$NON-NLS-1$
+				""); //$NON-NLS-1$
 		return attributes;
 	}
 
 	/**
-	 * Method used to check that the project and program are correct.
-	 * Can be overridden to avoid checking certain things.
+	 * Method used to check that the project and program are correct. Can be
+	 * overridden to avoid checking certain things.
 	 */
 	protected IPath checkBinaryDetails(final ILaunchConfiguration config) throws CoreException {
 		// First verify we are dealing with a proper project.
@@ -139,7 +276,8 @@
 	 * @param environ
 	 * @param workingDirectory
 	 *            the working directory, or <code>null</code>
-	 * @return the resulting process or <code>null</code> if the exec is cancelled
+	 * @return the resulting process or <code>null</code> if the exec is
+	 *         cancelled
 	 * @see Runtime
 	 * @since 4.7
 	 */
@@ -151,38 +289,40 @@
 				return ProcessFactory.getFactory().exec(cmdLine, environ, workingDirectory);
 			}
 		} catch (IOException e) {
-			abort(LaunchMessages.LocalCDILaunchDelegate_8, e, ICDTLaunchConfigurationConstants.ERR_INTERNAL_ERROR); 
+			abort(LaunchMessages.LocalCDILaunchDelegate_8, e, ICDTLaunchConfigurationConstants.ERR_INTERNAL_ERROR);
 		}
 		return null;
 	}
 
-
 	@Override
-    public boolean preLaunchCheck(ILaunchConfiguration config, String mode, IProgressMonitor monitor) throws CoreException {
-    	// Setup default Process Factory
+	public boolean preLaunchCheck(ILaunchConfiguration config, String mode, IProgressMonitor monitor)
+			throws CoreException {
+		// Setup default Process Factory
 		setDefaultProcessFactory(config);
 
 		return super.preLaunchCheck(config, mode, monitor);
 	}
 
-    /**
-     * Modify the ILaunchConfiguration to set the DebugPlugin.ATTR_PROCESS_FACTORY_ID attribute,
-     * so as to specify the process factory to use.
-     * 
-     * This attribute should only be set if it is not part of the configuration already, to allow
-     * other code to set it to something else.
+	/**
+	 * Modify the ILaunchConfiguration to set the
+	 * DebugPlugin.ATTR_PROCESS_FACTORY_ID attribute, so as to specify the
+	 * process factory to use.
+	 * 
+	 * This attribute should only be set if it is not part of the configuration
+	 * already, to allow other code to set it to something else.
 	 */
-    protected void setDefaultProcessFactory(ILaunchConfiguration config) throws CoreException {
-        if (!config.hasAttribute(DebugPlugin.ATTR_PROCESS_FACTORY_ID)) {
-            ILaunchConfigurationWorkingCopy wc = config.getWorkingCopy();
-            // Use the debug process factory as it provides extra features for the program
-            // that is being debugged or in this case run.
-            // Effectively, we want to use InferiorRuntimeProcess when doing this Run launch.
-            wc.setAttribute(DebugPlugin.ATTR_PROCESS_FACTORY_ID,
-            				"org.eclipse.cdt.dsf.gdb.GdbProcessFactory"); //$NON-NLS-1$
-            wc.doSave();
-        }
-    }
+	protected void setDefaultProcessFactory(ILaunchConfiguration config) throws CoreException {
+		if (!config.hasAttribute(DebugPlugin.ATTR_PROCESS_FACTORY_ID)) {
+			ILaunchConfigurationWorkingCopy wc = config.getWorkingCopy();
+			// Use the debug process factory as it provides extra features for
+			// the program
+			// that is being debugged or in this case run.
+			// Effectively, we want to use InferiorRuntimeProcess when doing
+			// this Run launch.
+			wc.setAttribute(DebugPlugin.ATTR_PROCESS_FACTORY_ID, "org.eclipse.cdt.dsf.gdb.GdbProcessFactory"); //$NON-NLS-1$
+			wc.doSave();
+		}
+	}
 
 	@Override
 	protected String getPluginID() {
diff --git a/qt/org.eclipse.cdt.qt-feature/feature.xml b/qt/org.eclipse.cdt.qt-feature/feature.xml
index 1840a9d..5883efe 100644
--- a/qt/org.eclipse.cdt.qt-feature/feature.xml
+++ b/qt/org.eclipse.cdt.qt-feature/feature.xml
@@ -1,36 +1,40 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<feature
-      id="org.eclipse.cdt.qt"
-      label="%featureName"
-      version="9.0.0.qualifier"
-      provider-name="%providerName"
-      license-feature="org.eclipse.license"
-      license-feature-version="0.0.0">
-
-   <description>
-      %description
-   </description>
-
-   <copyright>
-      %copyright
-   </copyright>
-
-   <license url="%licenseURL">
-      %license
-   </license>
-
-   <plugin
-         id="org.eclipse.cdt.qt.core"
-         download-size="0"
-         install-size="0"
-         version="0.0.0"
-         unpack="false"/>
-
-   <plugin
-         id="org.eclipse.cdt.qt.ui"
-         download-size="0"
-         install-size="0"
-         version="0.0.0"
-         unpack="false"/>
-
-</feature>
+<?xml version="1.0" encoding="UTF-8"?>

+<feature

+      id="org.eclipse.cdt.qt"

+      label="%featureName"

+      version="9.0.0.qualifier"

+      provider-name="%providerName"

+      license-feature="org.eclipse.license"

+      license-feature-version="0.0.0">

+

+   <description>

+      %description

+   </description>

+

+   <copyright>

+      %copyright

+   </copyright>

+

+   <license url="%licenseURL">

+      %license

+   </license>

+

+   <requires>

+      <import feature="org.eclipse.launchbar" version="2.0.0" match="compatible"/>

+   </requires>

+

+   <plugin

+         id="org.eclipse.cdt.qt.core"

+         download-size="0"

+         install-size="0"

+         version="0.0.0"

+         unpack="false"/>

+

+   <plugin

+         id="org.eclipse.cdt.qt.ui"

+         download-size="0"

+         install-size="0"

+         version="0.0.0"

+         unpack="false"/>

+

+</feature>

diff --git a/qt/org.eclipse.cdt.qt.core/plugin.xml b/qt/org.eclipse.cdt.qt.core/plugin.xml
index 56757c6..56a4eb9 100644
--- a/qt/org.eclipse.cdt.qt.core/plugin.xml
+++ b/qt/org.eclipse.cdt.qt.core/plugin.xml
@@ -185,6 +185,9 @@
        <provider
              class="org.eclipse.cdt.internal.qt.core.provider.QtInstallProvider">
        </provider>
+       <provider
+             class="org.eclipse.cdt.internal.qt.core.provider.LinuxQtInstallProvider">
+       </provider>
     </extension>
     <extension
           point="org.eclipse.cdt.qt.core.qtToolChainMapper">
@@ -210,5 +213,16 @@
                 value="x86_64">
           </property>
        </mapping>
+       <mapping
+             spec="linux-g++-64">
+          <property
+                key="os"
+                value="linux">
+          </property>
+          <property
+                key="arch"
+                value="x86_64">
+          </property>
+       </mapping>
     </extension>
 </plugin>
diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/QtInstall.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/QtInstall.java
index c3e8c42..47ab4d4 100644
--- a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/QtInstall.java
+++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/QtInstall.java
@@ -10,7 +10,11 @@
 import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStreamReader;
+import java.nio.file.Files;
 import java.nio.file.Path;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
 
 import org.eclipse.cdt.qt.core.IQtInstall;
 
@@ -18,6 +22,7 @@
 
 	private final Path qmakePath;
 	private String spec;
+	private Map<String, String> properties = new HashMap<>();
 
 	public QtInstall(Path qmakePath) {
 		this.qmakePath = qmakePath;
@@ -38,14 +43,16 @@
 		return qmakePath.resolve("../../qml"); //$NON-NLS-1$
 	}
 
-	public static String getSpec(String qmakePath) throws IOException {
-		Process proc = new ProcessBuilder(qmakePath, "-query", "QMAKE_XSPEC").start(); //$NON-NLS-1$ //$NON-NLS-2$
+	public static String getSpec(Path qmakePath) throws IOException {
+		if (Files.exists(qmakePath)) {
+		Process proc = new ProcessBuilder(qmakePath.toString(), "-query", "QMAKE_XSPEC").start(); //$NON-NLS-1$ //$NON-NLS-2$
 		try (BufferedReader reader = new BufferedReader(new InputStreamReader(proc.getInputStream()))) {
 			String line = reader.readLine();
 			if (line != null) {
 				return line.trim();
 			}
 		}
+		}
 		return null;
 	}
 
@@ -53,7 +60,7 @@
 	public String getSpec() {
 		if (spec == null) {
 			try {
-				spec = getSpec(getQmakePath().toString());
+				spec = getSpec(getQmakePath());
 			} catch (IOException e) {
 				Activator.log(e);
 			}
@@ -61,4 +68,14 @@
 		return spec;
 	}
 
+	@Override
+	public void setProperty(String key, String value) {
+		properties.put(key, value);
+	}
+
+	@Override
+	public Map<String, String> getProperties() {
+		return Collections.unmodifiableMap(properties);
+	}
+	
 }
diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/QtInstallManager.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/QtInstallManager.java
index ce8e6cb..2e9e11f 100644
--- a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/QtInstallManager.java
+++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/QtInstallManager.java
@@ -13,6 +13,7 @@
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Map.Entry;
 
 import org.eclipse.cdt.core.build.IToolChain;
 import org.eclipse.cdt.qt.core.IQtInstall;
@@ -78,7 +79,7 @@
 			for (Path path : installs.keySet()) {
 				String key = path.toString();
 				if (prefs.get(key, null) == null) {
-					prefs.put(key, installs.get(key).getQmakePath().toString());
+					prefs.put(key, installs.get(path).getQmakePath().toString());
 				}
 			}
 
@@ -135,6 +136,13 @@
 					return false;
 				}
 			}
+			
+			for (Entry<String, String> property : install.getProperties().entrySet()) {
+				if (!property.getValue().equals(toolChain.getProperty(property.getKey()))) {
+					return false;
+				}
+			}
+
 			return true;
 		} else {
 			// Don't know so returning false
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 571a76d..f66e451 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
@@ -68,19 +68,20 @@
 			qtInstall = null;
 		}
 
-		launchMode = settings.get(LAUNCH_MODE, ""); //$NON-NLS-1$
+		launchMode = settings.get(LAUNCH_MODE, null); // $NON-NLS-1$
 	}
 
 	QtBuildConfiguration(IBuildConfiguration config, String name, IToolChain toolChain, IQtInstall qtInstall,
-			String launchMode)
-			throws CoreException {
+			String launchMode) throws CoreException {
 		super(config, name, toolChain);
 		this.qtInstall = qtInstall;
 		this.launchMode = launchMode;
 
 		Preferences settings = getSettings();
 		settings.put(QTINSTALL_NAME, qtInstall.getQmakePath().toString());
-		settings.put(LAUNCH_MODE, launchMode);
+		if (launchMode != null) {
+			settings.put(LAUNCH_MODE, launchMode);
+		}
 		try {
 			settings.flush();
 		} catch (BackingStoreException e) {
@@ -108,16 +109,18 @@
 	}
 
 	@Override
-	public String getQmakeConfig() {
-		switch (launchMode) {
-		case "run": //$NON-NLS-1$
-			return "CONFIG+=release"; //$NON-NLS-1$
-		case "debug": //$NON-NLS-1$
-			return "CONFIG+=debug"; //$NON-NLS-1$
-		default:
-			// TODO probably need an extension point for guidance
-			return null;
+	public String[] getQmakeConfig() {
+		if (launchMode != null) {
+			switch (launchMode) {
+			case "run": //$NON-NLS-1$
+				return new String[] { "CONFIG-=debug_and_release", "CONFIG+=release" }; //$NON-NLS-1$ //$NON-NLS-2$
+			case "debug": //$NON-NLS-1$
+				return new String[] { "CONFIG-=debug_and_release", "CONFIG+=debug" }; //$NON-NLS-1$ //$NON-NLS-2$
+			default:
+				return new String[] { "CONFIG-=debug_and_release", "CONFIG+=launch_mode_" + launchMode }; //$NON-NLS-1$ //$NON-NLS-2$
+			}
 		}
+		return new String[] { "CONFIG+=debug_and_release", "CONFIG+=launch_modeall" }; //$NON-NLS-1$ //$NON-NLS-2$
 	}
 
 	public Path getProjectFile() {
@@ -133,21 +136,18 @@
 
 	@Override
 	public Path getProgramPath() throws CoreException {
+		// TODO get the app name from the .pro file.
 		String projectName = getProject().getName();
 		switch (Platform.getOS()) {
 		case Platform.OS_MACOSX:
-			// TODO this is mac local specific and really should be
-			// in the config
-			// TODO also need to pull the app name out of the pro
-			// file name
 			Path appFolder = getBuildDirectory().resolve(projectName + ".app"); //$NON-NLS-1$
 			Path contentsFolder = appFolder.resolve("Contents"); //$NON-NLS-1$
 			Path macosFolder = contentsFolder.resolve("MacOS"); //$NON-NLS-1$
 			return macosFolder.resolve(projectName);
-		case Platform.OS_WIN32: {
-			String subdir = "run".equals(launchMode) ? "release" : "debug"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
-			return getBuildDirectory().resolve(subdir).resolve(projectName + ".exe"); //$NON-NLS-1$
-		}
+		case Platform.OS_WIN32:
+			return getBuildDirectory().resolve(projectName + ".exe"); //$NON-NLS-1$
+		case Platform.OS_LINUX:
+			return getBuildDirectory().resolve(projectName); //$NON-NLS-1$
 		default:
 			Path releaseFolder = getBuildDirectory().resolve("release"); //$NON-NLS-1$
 			return releaseFolder.resolve(projectName);
@@ -160,9 +160,11 @@
 			cmd.add(getQmakeCommand().toString());
 			cmd.add("-E"); //$NON-NLS-1$
 
-			String config = getQmakeConfig();
+			String[] config = getQmakeConfig();
 			if (config != null) {
-				cmd.add(config);
+				for (String str : config) {
+					cmd.add(str);
+				}
 			}
 
 			cmd.add(getProjectFile().toString());
@@ -280,16 +282,17 @@
 					List<String> command = new ArrayList<>();
 					command.add(getQmakeCommand().toString());
 
-					String config = getQmakeConfig();
+					String[] config = getQmakeConfig();
 					if (config != null) {
-						command.add(config);
+						for (String str : config) {
+							command.add(str);
+						}
 					}
 
 					IFile projectFile = project.getFile(project.getName() + ".pro"); //$NON-NLS-1$
 					command.add(projectFile.getLocation().toOSString());
 
-					ProcessBuilder processBuilder = new ProcessBuilder(command)
-							.directory(getBuildDirectory().toFile());
+					ProcessBuilder processBuilder = new ProcessBuilder(command).directory(getBuildDirectory().toFile());
 					setBuildEnvironment(processBuilder.environment());
 					Process process = processBuilder.start();
 
@@ -305,7 +308,7 @@
 				}
 
 				// run make
-				ProcessBuilder processBuilder = new ProcessBuilder(makeCommand.toString()).directory(buildDir.toFile());
+				ProcessBuilder processBuilder = new ProcessBuilder(makeCommand.toString(), "all").directory(buildDir.toFile());
 				setBuildEnvironment(processBuilder.environment());
 				Process process = processBuilder.start();
 				outStream.write(makeCommand.toString() + '\n');
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 ae3c784..019c1c2 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
@@ -7,6 +7,7 @@
  *******************************************************************************/
 package org.eclipse.cdt.internal.qt.core.build;
 
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -16,15 +17,14 @@
 import org.eclipse.cdt.core.build.IToolChain;
 import org.eclipse.cdt.core.build.IToolChainManager;
 import org.eclipse.cdt.internal.qt.core.Activator;
-import org.eclipse.cdt.internal.qt.core.QtNature;
 import org.eclipse.cdt.qt.core.IQtBuildConfiguration;
 import org.eclipse.cdt.qt.core.IQtInstall;
 import org.eclipse.cdt.qt.core.IQtInstallManager;
+import org.eclipse.cdt.qt.core.QtMinGWToolChainProvider;
 import org.eclipse.core.resources.IBuildConfiguration;
 import org.eclipse.core.resources.IProject;
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.core.runtime.NullProgressMonitor;
 import org.eclipse.core.runtime.Platform;
 
 public class QtBuildConfigurationProvider implements ICBuildConfigurationProvider {
@@ -43,83 +43,71 @@
 	@Override
 	public ICBuildConfiguration getCBuildConfiguration(IBuildConfiguration config, String name) {
 		try {
-			// Double check to make sure this config is ours
-			if (!config.getProject().hasNature(QtNature.ID)) {
-				return null;
-			}
+			if (config.getName().equals(IBuildConfiguration.DEFAULT_CONFIG_NAME)) {
+				// try the toolchain for the local target
+				Map<String, String> properties = new HashMap<>();
+				properties.put(IToolChain.ATTR_OS, Platform.getOS());
+				properties.put(IToolChain.ATTR_ARCH, Platform.getOSArch());
+				for (IToolChain toolChain : toolChainManager.getToolChainsMatching(properties)) {
+					for (IQtInstall qtInstall : qtInstallManager.getInstalls()) {
+						if (qtInstallManager.supports(qtInstall, toolChain)) {
+							return new QtBuildConfiguration(config, name, toolChain, qtInstall, null);
+						}
+					}
+				}
 
-			return new QtBuildConfiguration(config, name);
+				// local didn't work, try and find one that does
+				for (IToolChain toolChain : toolChainManager.getToolChainsMatching(new HashMap<>())) {
+					for (IQtInstall qtInstall : qtInstallManager.getInstalls()) {
+						if (qtInstallManager.supports(qtInstall, toolChain)) {
+							return new QtBuildConfiguration(config, name, toolChain, qtInstall, null);
+						}
+					}
+				}
+
+				// No valid combinations
+				return null;
+			} else {
+				return new QtBuildConfiguration(config, name);
+			}
 		} catch (CoreException e) {
-			// Failed to create the build config. Return null so it gets recreated.
+			// Failed to create the build config. Return null so it gets
+			// recreated.
 			Activator.log(e);
 			return null;
 		}
 	}
 
-	@Override
-	public ICBuildConfiguration getDefaultCBuildConfiguration(IProject project) {
-		try {
-			if (!project.hasNature(QtNature.ID)) {
-				return null;
-			}
-
-			// try the local target as the default
-			Map<String, String> properties = new HashMap<>();
-			properties.put(IToolChain.ATTR_OS, Platform.getOS());
-			properties.put(IToolChain.ATTR_ARCH, Platform.getOSArch());
-			for (IToolChain toolChain : toolChainManager.getToolChainsMatching(properties)) {
-				IQtBuildConfiguration qtConfig = getConfiguration(project, toolChain, "run", new NullProgressMonitor()); //$NON-NLS-1$
-				if (qtConfig == null) {
-					qtConfig = createConfiguration(project, toolChain, "run", new NullProgressMonitor()); //$NON-NLS-1$
-					if (qtConfig != null) {
-						return qtConfig;
-					}
-				}
-			}
-
-			// local didn't work, try and find one that does
-			for (IToolChain toolChain : toolChainManager.getToolChainsMatching(new HashMap<>())) {
-				IQtBuildConfiguration qtConfig = getConfiguration(project, toolChain, "run", new NullProgressMonitor()); //$NON-NLS-1$
-				if (qtConfig == null) {
-					qtConfig = createConfiguration(project, toolChain, "run", new NullProgressMonitor()); //$NON-NLS-1$
-					if (qtConfig != null) {
-						return qtConfig;
-					}
-				}
-			}
-		} catch (CoreException e) {
-			Activator.log(e);
-		}
-		return null;
-	}
-
-	public IQtBuildConfiguration getConfiguration(IProject project, IToolChain toolChain, String launchMode,
+	public IQtBuildConfiguration getConfiguration(IProject project, Map<String, String> properties, String launchMode,
 			IProgressMonitor monitor) throws CoreException {
+		Collection<IToolChain> toolChains = toolChainManager.getToolChainsMatching(properties);
 		for (IBuildConfiguration config : project.getBuildConfigs()) {
 			ICBuildConfiguration cconfig = config.getAdapter(ICBuildConfiguration.class);
 			if (cconfig != null) {
 				IQtBuildConfiguration qtConfig = cconfig.getAdapter(IQtBuildConfiguration.class);
-				if (qtConfig != null && qtConfig.getLaunchMode().equals(launchMode)
-						&& qtConfig.getToolChain().equals(toolChain)) {
-					return qtConfig;
+				if (qtConfig != null && launchMode.equals(qtConfig.getLaunchMode())) {
+					for (IToolChain toolChain : toolChains) {
+						if (qtConfig.getToolChain().equals(toolChain)) {
+							return qtConfig;
+						}
+					}
 				}
 			}
 		}
-		return null;
-	}
 
-	public QtBuildConfiguration createConfiguration(IProject project, IToolChain toolChain, String launchMode,
-			IProgressMonitor monitor) throws CoreException {
-		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, configName, toolChain, qtInstall,
-						launchMode);
-				configManager.addBuildConfiguration(config, qtConfig);
-				return qtConfig;
+		// Not found, create one
+		for (IToolChain toolChain : toolChains) {
+			for (IQtInstall qtInstall : qtInstallManager.getInstalls()) {
+				if (qtInstallManager.supports(qtInstall, toolChain)) {
+					// TODO what if multiple matches, this returns first match
+					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, configName, toolChain, qtInstall,
+							launchMode);
+					configManager.addBuildConfiguration(config, qtConfig);
+					return qtConfig;
+				}
 			}
 		}
 
diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/provider/LinuxQtInstallProvider.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/provider/LinuxQtInstallProvider.java
new file mode 100644
index 0000000..afd6a54
--- /dev/null
+++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/provider/LinuxQtInstallProvider.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * 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.internal.qt.core.provider;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+
+import org.eclipse.cdt.core.build.IToolChain;
+import org.eclipse.cdt.internal.qt.core.QtInstall;
+import org.eclipse.cdt.qt.core.IQtInstall;
+import org.eclipse.cdt.qt.core.IQtInstallProvider;
+import org.eclipse.core.runtime.Platform;
+
+/**
+ * Qt install provider that looks for qmake on /usr/bin
+ */
+public class LinuxQtInstallProvider implements IQtInstallProvider {
+
+	@Override
+	public Collection<IQtInstall> getInstalls() {
+		if (Platform.getOS().equals(Platform.OS_LINUX)) {
+			Path qmakePath = Paths.get("/usr/bin/qmake"); //$NON-NLS-1$
+			if (Files.exists(qmakePath)) {
+				QtInstall install = new QtInstall(qmakePath);
+				install.setProperty(IToolChain.ATTR_PACKAGE, "system");
+				return Arrays.asList(install);
+			}
+		}
+		return Collections.emptyList();
+	}
+
+}
diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/provider/Msys2QtInstallProvider.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/provider/Msys2QtInstallProvider.java
index 7f0b1a5..d3270a2 100644
--- a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/provider/Msys2QtInstallProvider.java
+++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/provider/Msys2QtInstallProvider.java
@@ -14,6 +14,7 @@
 import java.util.Collections;
 import java.util.List;
 
+import org.eclipse.cdt.core.build.IToolChain;
 import org.eclipse.cdt.internal.qt.core.QtInstall;
 import org.eclipse.cdt.qt.core.IQtInstall;
 import org.eclipse.cdt.qt.core.IQtInstallProvider;
@@ -40,7 +41,9 @@
 				if ("MSYS2 64bit".equals(displayName)) { //$NON-NLS-1$
 					String installLocation = registry.getCurrentUserValue(compKey, "InstallLocation"); //$NON-NLS-1$
 					Path qmakePath = Paths.get(installLocation + "\\mingw64\\bin\\qmake.exe"); //$NON-NLS-1$
-					installs.add(new QtInstall(qmakePath));
+					QtInstall install = new QtInstall(qmakePath);
+					install.setProperty(IToolChain.ATTR_PACKAGE, "msys2"); //$NON-NLS-1$
+					installs.add(install);
 				}
 			}
 			return installs;
diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/provider/QtInstallProvider.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/provider/QtInstallProvider.java
index 1ebfe46..144eb89 100644
--- a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/provider/QtInstallProvider.java
+++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/provider/QtInstallProvider.java
@@ -16,6 +16,7 @@
 import java.util.stream.Collectors;
 
 import org.eclipse.cdt.codan.core.cxx.Activator;
+import org.eclipse.cdt.core.build.IToolChain;
 import org.eclipse.cdt.internal.qt.core.QtInstall;
 import org.eclipse.cdt.qt.core.IQtInstall;
 import org.eclipse.cdt.qt.core.IQtInstallProvider;
@@ -27,14 +28,22 @@
  */
 public class QtInstallProvider implements IQtInstallProvider {
 
+	private static boolean isWin32 = Platform.getOS().equals(Platform.OS_WIN32);
+
 	@Override
 	public Collection<IQtInstall> getInstalls() {
 		Path root = getQtRoot();
-		Path qmake = Paths.get(Platform.getOS().equals(Platform.OS_WIN32) ? "bin/qmake.exe" : "bin/qmake"); //$NON-NLS-1$ //$NON-NLS-2$
-		if (root != null) {
+		Path qmake = Paths.get(isWin32 ? "bin/qmake.exe" : "bin/qmake"); //$NON-NLS-1$ //$NON-NLS-2$
+		if (root != null && Files.exists(root)) {
 			try {
 				return Files.walk(root, 2).filter((path) -> Files.exists(path.resolve(qmake)))
-						.map((path) -> new QtInstall(path.resolve(qmake))).collect(Collectors.toList());
+						.map((path) -> {
+							QtInstall install = new QtInstall(path.resolve(qmake));
+							if (isWin32 && "win32-g++".equals(install.getSpec())) { //$NON-NLS-1$
+								install.setProperty(IToolChain.ATTR_PACKAGE, "qt"); //$NON-NLS-1$ //$NON-NLS-2$
+							}
+							return install;
+						}).collect(Collectors.toList());
 			} catch (IOException e) {
 				Activator.log(e);
 			}
@@ -43,14 +52,13 @@
 	}
 
 	private Path getQtRoot() {
-		if (Platform.getOS().equals(Platform.OS_WIN32)) {
+		if (isWin32) {
 			WindowsRegistry registry = WindowsRegistry.getRegistry();
 			String uninstallKey = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall"; //$NON-NLS-1$
 			String subkey;
 			for (int i = 0; (subkey = registry.getCurrentUserKeyName(uninstallKey, i)) != null; i++) {
 				String compKey = uninstallKey + '\\' + subkey;
 				String displayName = registry.getCurrentUserValue(compKey, "DisplayName"); //$NON-NLS-1$
-				// On Windows, look for MSYS2, MinGW 64/32 locations
 				if ("Qt".equals(displayName)) { //$NON-NLS-1$
 					String installLocation = registry.getCurrentUserValue(compKey, "InstallLocation"); //$NON-NLS-1$
 					return Paths.get(installLocation);
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 1e8dcf1..ee55522 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
@@ -18,7 +18,7 @@
 	

 	Path getQmakeCommand();

 

-	String getQmakeConfig();

+	String[] getQmakeConfig();

 

 	Path getProgramPath() throws CoreException;

 

diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/IQtInstall.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/IQtInstall.java
index c55fd1a..03cefb8 100644
--- a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/IQtInstall.java
+++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/IQtInstall.java
@@ -8,6 +8,7 @@
 package org.eclipse.cdt.qt.core;
 
 import java.nio.file.Path;
+import java.util.Map;
 
 /**
  * Represents an installation of the Qt SDK. Qt installs are defined by the path
@@ -25,4 +26,8 @@
 
 	Path getQmlPath();
 
+	void setProperty(String key, String value);
+
+	Map<String, String> getProperties();
+
 }
diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/QtLaunchConfigurationDelegate.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/QtLaunchConfigurationDelegate.java
index d3e952c..9985462 100644
--- a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/QtLaunchConfigurationDelegate.java
+++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/QtLaunchConfigurationDelegate.java
@@ -12,7 +12,6 @@
 
 import org.eclipse.cdt.core.build.ICBuildConfigurationManager;
 import org.eclipse.cdt.core.build.IToolChain;
-import org.eclipse.cdt.core.build.IToolChainManager;
 import org.eclipse.cdt.internal.qt.core.Activator;
 import org.eclipse.cdt.internal.qt.core.build.QtBuildConfigurationProvider;
 import org.eclipse.core.resources.IProject;
@@ -71,19 +70,12 @@
 				.getProvider(QtBuildConfigurationProvider.ID);
 		IProject project = configuration.getMappedResources()[0].getProject();
 
-		// Find the toolchains that support this target
 		Map<String, String> properties = new HashMap<>();
 		populateToolChainProperties(target, properties);
 
-		IToolChainManager toolChainManager = Activator.getService(IToolChainManager.class);
-		for (IToolChain toolChain : toolChainManager.getToolChainsMatching(properties)) {
-			IQtBuildConfiguration qtConfig = provider.getConfiguration(project, toolChain, mode, monitor);
-			if (qtConfig == null) {
-				qtConfig = provider.createConfiguration(project, toolChain, mode, monitor);
-			}
-			if (qtConfig != null) {
-				return qtConfig;
-			}
+		IQtBuildConfiguration qtConfig = provider.getConfiguration(project, properties, mode, monitor);
+		if (qtConfig != null) {
+			return qtConfig;
 		}
 
 		// Couldn't find any
diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/QtMinGWToolChainProvider.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/QtMinGWToolChainProvider.java
index d6918cc..c50572f 100644
--- a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/QtMinGWToolChainProvider.java
+++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/QtMinGWToolChainProvider.java
@@ -13,6 +13,7 @@
 import java.nio.file.Paths;
 
 import org.eclipse.cdt.build.gcc.core.GCCToolChain;
+import org.eclipse.cdt.core.build.IToolChain;
 import org.eclipse.cdt.core.build.IToolChainManager;
 import org.eclipse.cdt.core.build.IToolChainProvider;
 import org.eclipse.cdt.internal.qt.core.Activator;
@@ -22,7 +23,8 @@
 
 public class QtMinGWToolChainProvider implements IToolChainProvider {
 
-	private static final String ID = "org.eclipse.cdt.qt.core.qtMinGWProvider"; //$NON-NLS-1$
+	public static final String ID = "org.eclipse.cdt.qt.core.qtMinGWProvider"; //$NON-NLS-1$
+	public static final String TOOLCHAIN_ID = "qt.mingw"; //$NON-NLS-1$
 
 	@Override
 	public String getId() {
@@ -39,15 +41,20 @@
 				String compKey = uninstallKey + '\\' + subkey;
 				String displayName = registry.getCurrentUserValue(compKey, "DisplayName"); //$NON-NLS-1$
 				if ("Qt".equals(displayName)) { //$NON-NLS-1$
-					String installLocation = registry.getCurrentUserValue(compKey, "InstallLocation"); //$NON-NLS-1$
-					Path gcc = Paths.get("\\bin\\gcc.exe"); //$NON-NLS-1$
-					try {
-						Files.walk(Paths.get(installLocation).resolve("Tools"), 1) //$NON-NLS-1$
-								.filter((path) -> Files.exists(path.resolve(gcc)))
-								.map((path) -> new GCCToolChain(this, "qt.mingw", "", new Path[] { path.resolve("bin") })) //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
-								.forEach(toolChain -> manager.addToolChain(toolChain));
-					} catch (IOException e) {
-						Activator.log(e);
+					Path installLocation = Paths.get(registry.getCurrentUserValue(compKey, "InstallLocation")); //$NON-NLS-1$
+					if (Files.exists(installLocation)) {
+						Path gcc = Paths.get("bin\\gcc.exe"); //$NON-NLS-1$
+						try {
+							Files.walk(installLocation.resolve("Tools"), 1) //$NON-NLS-1$
+									.filter(path -> Files.exists(path.resolve(gcc))).map(path -> {
+										GCCToolChain toolChain = new GCCToolChain(this, TOOLCHAIN_ID, "", //$NON-NLS-1$
+												new Path[] { path.resolve("bin") }); //$NON-NLS-1$
+										toolChain.setProperty(IToolChain.ATTR_PACKAGE, "qt"); //$NON-NLS-1$
+										return toolChain;
+									}).forEach(toolChain -> manager.addToolChain(toolChain));
+						} catch (IOException e) {
+							Activator.log(e);
+						}
 					}
 				}
 			}
diff --git a/qt/org.eclipse.cdt.qt.core/templates/project2/appProject/main.pro b/qt/org.eclipse.cdt.qt.core/templates/project2/appProject/main.pro
index 9684769..f80ccb3 100644
--- a/qt/org.eclipse.cdt.qt.core/templates/project2/appProject/main.pro
+++ b/qt/org.eclipse.cdt.qt.core/templates/project2/appProject/main.pro
@@ -6,3 +6,11 @@
 RESOURCES += ${projectName}.qrc
 
 qml.files = src/${projectName}.qml
+
+launch_modeall {
+	CONFIG(debug, debug|release) {
+	    DESTDIR = debug
+	} else {
+	    DESTDIR = release
+	}
+}
diff --git a/qt/org.eclipse.cdt.qt.ui/src/org/eclipse/cdt/internal/qt/ui/preferences/NewQtInstallWizardPage.java b/qt/org.eclipse.cdt.qt.ui/src/org/eclipse/cdt/internal/qt/ui/preferences/NewQtInstallWizardPage.java
index a870caf..1096583 100644
--- a/qt/org.eclipse.cdt.qt.ui/src/org/eclipse/cdt/internal/qt/ui/preferences/NewQtInstallWizardPage.java
+++ b/qt/org.eclipse.cdt.qt.ui/src/org/eclipse/cdt/internal/qt/ui/preferences/NewQtInstallWizardPage.java
@@ -81,7 +81,7 @@
 					@Override
 					protected IStatus run(IProgressMonitor monitor) {
 						try {
-							String spec = QtInstall.getSpec(selected);
+							String spec = QtInstall.getSpec(Paths.get(selected));
 							getControl().getDisplay().asyncExec(() -> {
 								specText.setText(spec);
 							});
diff --git a/toolchains/arduino/org.eclipse.cdt.arduino-feature/feature.xml b/toolchains/arduino/org.eclipse.cdt.arduino-feature/feature.xml
index cd655da..a01625e 100644
--- a/toolchains/arduino/org.eclipse.cdt.arduino-feature/feature.xml
+++ b/toolchains/arduino/org.eclipse.cdt.arduino-feature/feature.xml
@@ -1,46 +1,46 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<feature
-      id="org.eclipse.cdt.arduino"
-      label="%featureName"
-      version="9.0.0.qualifier"
-      provider-name="%providerName"
-      plugin="org.eclipse.cdt.arduino.ui"
-      license-feature="org.eclipse.license"
-      license-feature-version="0.0.0">
-
-   <description>
-      %description
-   </description>
-
-   <copyright>
-      %copyright
-   </copyright>
-
-   <license url="%licenseURL">
-      %license
-   </license>
-
-   <requires>
-      <import feature="org.eclipse.launchbar" version="1.0.0"/>
-      <import feature="org.eclipse.remote.serial" version="1.0.0"/>
-      <import feature="org.eclipse.remote" version="2.0.0"/>
-      <import feature="org.eclipse.remote.console" version="2.0.0"/>
-      <import feature="org.eclipse.cdt" version="9.0.0"/>
-      <import feature="org.eclipse.launchbar.remote" version="1.0.0.qualifier"/>
-   </requires>
-
-   <plugin
-         id="org.eclipse.cdt.arduino.core"
-         download-size="0"
-         install-size="0"
-         version="0.0.0"
-         unpack="false"/>
-
-   <plugin
-         id="org.eclipse.cdt.arduino.ui"
-         download-size="0"
-         install-size="0"
-         version="0.0.0"
-         unpack="false"/>
-
-</feature>
+<?xml version="1.0" encoding="UTF-8"?>

+<feature

+      id="org.eclipse.cdt.arduino"

+      label="%featureName"

+      version="9.0.0.qualifier"

+      provider-name="%providerName"

+      plugin="org.eclipse.cdt.arduino.ui"

+      license-feature="org.eclipse.license"

+      license-feature-version="0.0.0">

+

+   <description>

+      %description

+   </description>

+

+   <copyright>

+      %copyright

+   </copyright>

+

+   <license url="%licenseURL">

+      %license

+   </license>

+

+   <requires>

+      <import feature="org.eclipse.launchbar" version="1.0.0"/>

+      <import feature="org.eclipse.remote.serial" version="1.0.0"/>

+      <import feature="org.eclipse.remote" version="2.0.0"/>

+      <import feature="org.eclipse.remote.console" version="2.0.0"/>

+      <import feature="org.eclipse.cdt" version="9.0.0"/>

+      <import feature="org.eclipse.launchbar.remote" version="1.0.0"/>

+   </requires>

+

+   <plugin

+         id="org.eclipse.cdt.arduino.core"

+         download-size="0"

+         install-size="0"

+         version="0.0.0"

+         unpack="false"/>

+

+   <plugin

+         id="org.eclipse.cdt.arduino.ui"

+         download-size="0"

+         install-size="0"

+         version="0.0.0"

+         unpack="false"/>

+

+</feature>

diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.core.tests/src/org/eclipse/cdt/arduino/core/tests/FullIntegration.java b/toolchains/arduino/org.eclipse.cdt.arduino.core.tests/src/org/eclipse/cdt/arduino/core/tests/FullIntegration.java
new file mode 100644
index 0000000..f70e5bd
--- /dev/null
+++ b/toolchains/arduino/org.eclipse.cdt.arduino.core.tests/src/org/eclipse/cdt/arduino/core/tests/FullIntegration.java
@@ -0,0 +1,205 @@
+/*******************************************************************************
+ * 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.arduino.core.tests;
+
+import java.net.URL;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.eclipse.cdt.arduino.core.internal.Activator;
+import org.eclipse.cdt.arduino.core.internal.ArduinoPreferences;
+import org.eclipse.cdt.arduino.core.internal.ArduinoProjectGenerator;
+import org.eclipse.cdt.arduino.core.internal.board.ArduinoBoard;
+import org.eclipse.cdt.arduino.core.internal.board.ArduinoManager;
+import org.eclipse.cdt.arduino.core.internal.board.ArduinoPlatform;
+import org.eclipse.cdt.arduino.core.internal.build.ArduinoBuildConfiguration;
+import org.eclipse.cdt.arduino.core.internal.build.ArduinoBuildConfigurationProvider;
+import org.eclipse.cdt.arduino.core.internal.remote.ArduinoRemoteConnection;
+import org.eclipse.cdt.core.build.ICBuildConfigurationManager;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IWorkspaceRoot;
+import org.eclipse.core.resources.ResourcesPlugin;
+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.eclipse.core.runtime.jobs.Job;
+import org.eclipse.remote.core.IRemoteConnection;
+import org.eclipse.remote.core.IRemoteConnectionType;
+import org.eclipse.remote.core.IRemoteConnectionWorkingCopy;
+import org.eclipse.remote.core.IRemoteServicesManager;
+import org.junit.Test;
+
+@SuppressWarnings("nls")
+public class FullIntegration {
+
+	private static final ArduinoManager arduinoManager = Activator.getService(ArduinoManager.class);
+	private static final IRemoteServicesManager remoteManager = Activator.getService(IRemoteServicesManager.class);
+	private static final ICBuildConfigurationManager buildConfigManager = Activator
+			.getService(ICBuildConfigurationManager.class);
+
+	private void setBoardUrls() throws Exception {
+		URL[] urls = new URL[] { new URL("http://downloads.arduino.cc/packages/package_index.json"),
+				new URL("https://adafruit.github.io/arduino-board-index/package_adafruit_index.json") };
+		ArduinoPreferences.setBoardUrlList(urls);
+	}
+
+	private Set<ArduinoBoard> getSkipBuild() throws Exception {
+		Set<ArduinoBoard> boards = new HashSet<>();
+
+		// Fails in arduino too
+		boards.add(arduinoManager.getBoard("arduino", "avr", "robotControl"));
+		boards.add(arduinoManager.getBoard("arduino", "avr", "robotMotor"));
+		boards.add(arduinoManager.getBoard("adafruit", "avr", "adafruit32u4"));
+
+		// TODO Need to add support for menu specific build properties
+		boards.add(arduinoManager.getBoard("arduino", "avr", "mini"));
+		boards.add(arduinoManager.getBoard("arduino", "avr", "lilypad"));
+		boards.add(arduinoManager.getBoard("arduino", "avr", "diecimila"));
+		boards.add(arduinoManager.getBoard("arduino", "avr", "pro"));
+		boards.add(arduinoManager.getBoard("arduino", "avr", "atmegang"));
+		boards.add(arduinoManager.getBoard("arduino", "avr", "bt"));
+		boards.add(arduinoManager.getBoard("arduino", "avr", "mega"));
+		boards.add(arduinoManager.getBoard("arduino", "avr", "nano"));
+		boards.add(arduinoManager.getBoard("TeeOnArdu", "avr", "CirPlayTeensyCore"));
+		boards.add(arduinoManager.getBoard("TeeOnArdu", "avr", "FloraTeensyCore"));
+		boards.add(arduinoManager.getBoard("TeeOnArdu", "avr", "TeeOnArdu"));
+
+		// TODO build.system.path missing
+		boards.add(arduinoManager.getBoard("arduino", "sam", "arduino_due_x"));
+		boards.add(arduinoManager.getBoard("arduino", "sam", "arduino_due_x_dbg"));
+		boards.add(arduinoManager.getBoard("Intel", "arc32", "arduino_101"));
+
+		if (Platform.getOS().equals(Platform.OS_WIN32)) {
+			// i586/i686 link missing
+			boards.add(arduinoManager.getBoard("Intel", "i586", "izmir_fd"));
+			boards.add(arduinoManager.getBoard("Intel", "i586", "izmir_fg"));
+			boards.add(arduinoManager.getBoard("Intel", "i686", "izmir_ec"));
+		}
+		return boards;
+	}
+
+	private Set<ArduinoBoard> getSkipUpload() throws Exception {
+		Set<ArduinoBoard> boards = new HashSet<>();
+		
+		// missing upload.protocol
+		boards.add(arduinoManager.getBoard("arduino", "avr", "gemma"));
+		boards.add(arduinoManager.getBoard("adafruit", "avr", "gemma"));
+		boards.add(arduinoManager.getBoard("adafruit", "avr", "trinket5"));
+		boards.add(arduinoManager.getBoard("adafruit", "avr", "trinket3"));
+		
+		// usbtiny missing
+		boards.add(arduinoManager.getBoard("adafruit", "avr", "protrinket3"));
+		boards.add(arduinoManager.getBoard("adafruit", "avr", "protrinket5"));
+		
+		return boards;
+	}
+
+	@Test
+	public void runTest() throws Exception {
+		IProgressMonitor monitor = new SysoutProgressMonitor();
+
+		setArduinoHome();
+		setBoardUrls();
+		loadPlatforms(monitor);
+
+		Set<ArduinoBoard> skipBuild = getSkipBuild();
+		Set<ArduinoBoard> skipUpload = getSkipUpload();
+		IProject project = createProject(monitor);
+		for (ArduinoBoard board : arduinoManager.getInstalledBoards()) {
+			if (!skipBuild.contains(board)) {
+				buildBoard(project, board, !skipUpload.contains(board), monitor);
+			}
+		}
+	}
+
+	private void setArduinoHome() throws Exception {
+		Path workspace = Paths.get(ResourcesPlugin.getWorkspace().getRoot().getLocationURI());
+		ArduinoPreferences.setArduinoHome(workspace.resolve(".arduinocdt"));
+	}
+
+	private void loadPlatforms(IProgressMonitor monitor) throws Exception {
+		Collection<ArduinoPlatform> plats = arduinoManager.getAvailablePlatforms(monitor);
+		arduinoManager.installPlatforms(plats, monitor);
+	}
+
+	private IProject createProject(IProgressMonitor monitor) throws Exception {
+		IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
+		String projectName = "ArduinoTest";
+		ArduinoProjectGenerator generator = new ArduinoProjectGenerator("templates/cppsketch/manifest.xml"); //$NON-NLS-1$
+
+		Job job = new Job("Create") {
+			@Override
+			protected IStatus run(IProgressMonitor monitor) {
+				try {
+					IProject project = root.getProject(projectName);
+					if (project.exists()) {
+						project.delete(true, monitor);
+					}
+
+					generator.setProjectName(projectName);
+					generator.generate(new HashMap<String, Object>(), monitor);
+					return Status.OK_STATUS;
+				} catch (CoreException e) {
+					return e.getStatus();
+				}
+			}
+		};
+		job.setRule(root);
+		job.schedule();
+		job.join();
+
+		return generator.getProject();
+	}
+
+	private void buildBoard(IProject project, ArduinoBoard board, boolean upload, IProgressMonitor monitor) throws Exception {
+		ArduinoRemoteConnection arduinoTarget = createTarget(board);
+		ArduinoBuildConfigurationProvider provider = (ArduinoBuildConfigurationProvider) buildConfigManager
+				.getProvider(ArduinoBuildConfigurationProvider.ID);
+		ArduinoBuildConfiguration config = provider.createConfiguration(project, arduinoTarget, "run", monitor);
+
+		System.out.println(String.format("Building board: %s\n    %s - %s", board.getName(), board.getId(),
+				board.getPlatform().getInstallPath()));
+
+		config.generateMakeFile(monitor);
+		ProcessBuilder processBuilder = new ProcessBuilder().command(config.getBuildCommand())
+				.directory(config.getBuildDirectory().toFile()).inheritIO();
+		config.setBuildEnvironment(processBuilder.environment());
+		Process process = processBuilder.start();
+		int rc = process.waitFor();
+		if (rc != 0) {
+			throw new Exception("Build failed");
+		}
+
+		// Test to make sure we can get the upload command cleanly
+		if (upload) {
+			System.out.println(String.join(" ", config.getUploadCommand("port1")));
+		}
+	}
+
+	private ArduinoRemoteConnection createTarget(ArduinoBoard board) throws Exception {
+		IRemoteConnectionType type = remoteManager.getConnectionType(ArduinoRemoteConnection.TYPE_ID);
+		IRemoteConnection connection = type.getConnection(board.getName());
+		if (connection != null) {
+			type.removeConnection(connection);
+		}
+
+		IRemoteConnectionWorkingCopy workingCopy = type.newConnection(board.getName());
+		ArduinoRemoteConnection.setBoardId(workingCopy, board);
+		ArduinoRemoteConnection.setPortName(workingCopy, "port1");
+		connection = workingCopy.save();
+
+		return connection.getService(ArduinoRemoteConnection.class);
+	}
+
+}
diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.core.tests/src/org/eclipse/cdt/arduino/core/tests/SysoutProgressMonitor.java b/toolchains/arduino/org.eclipse.cdt.arduino.core.tests/src/org/eclipse/cdt/arduino/core/tests/SysoutProgressMonitor.java
new file mode 100644
index 0000000..deb16eb
--- /dev/null
+++ b/toolchains/arduino/org.eclipse.cdt.arduino.core.tests/src/org/eclipse/cdt/arduino/core/tests/SysoutProgressMonitor.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * 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.arduino.core.tests;
+
+import org.eclipse.core.runtime.NullProgressMonitor;
+
+public class SysoutProgressMonitor extends NullProgressMonitor {
+	
+	@Override
+	public void beginTask(String name, int totalWork) {
+		if (name.length() > 0) {
+			System.out.println(name);
+			System.out.flush();
+		}
+	}
+	
+	@Override
+	public void subTask(String name) {
+		if (name.length() > 0) {
+			System.out.println(name);
+			System.out.flush();
+		}
+	}
+
+	@Override
+	public void setTaskName(String name) {
+		if (name.length() > 0) {
+			System.out.println(name);
+			System.out.flush();
+		}
+	}
+	
+}
diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/ArduinoPreferences.java b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/ArduinoPreferences.java
index c8ac61c5..988ef26 100644
--- a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/ArduinoPreferences.java
+++ b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/ArduinoPreferences.java
@@ -38,11 +38,15 @@
 		return Paths.get(getPrefs().get(ARDUINO_HOME, defaultHome));
 	}
 
+	public static void setArduinoHome(Path home) {
+		getPrefs().put(ARDUINO_HOME, home.toString());
+	}
+	
 	public static String getBoardUrls() {
 		return getPrefs().get(BOARD_URLS, defaultBoardUrls);
 	}
 
-	public static Collection<URL> getBoardUrlList() throws CoreException {
+	public static URL[] getBoardUrlList() throws CoreException {
 		List<URL> urlList = new ArrayList<>();
 		for (String url : getBoardUrls().split("\n")) { //$NON-NLS-1$
 			try {
@@ -51,7 +55,7 @@
 				throw Activator.coreException(e);
 			}
 		}
-		return urlList;
+		return urlList.toArray(new URL[urlList.size()]);
 	}
 	
 	public static void setBoardUrls(String boardUrls) {
@@ -64,6 +68,22 @@
 		}
 	}
 
+	public static void setBoardUrlList(URL[] urls) {
+		StringBuilder str = new StringBuilder();
+		for (int i = 0; i < urls.length - 1; ++i) {
+			str.append(urls[i].toString());
+			str.append('\n');
+		}
+		if (urls.length > 0) {
+			str.append(urls[urls.length - 1].toString());
+		}
+		setBoardUrls(str.toString());
+	}
+
+	public static String getDefaultArduinoHome() {
+		return defaultHome;
+	}
+
 	public static String getDefaultBoardUrls() {
 		return defaultBoardUrls;
 	}
diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/ArduinoBoard.java b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/ArduinoBoard.java
index bad4694..0bb2b8d 100644
--- a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/ArduinoBoard.java
+++ b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/ArduinoBoard.java
@@ -13,8 +13,6 @@
 
 public class ArduinoBoard {
 
-	public static final String MENU_QUALIFIER = "menu_"; //$NON-NLS-1$
-
 	private String name;
 
 	private String id;
diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/ArduinoManager.java b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/ArduinoManager.java
index 556c800..d894855 100644
--- a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/ArduinoManager.java
+++ b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/ArduinoManager.java
@@ -90,7 +90,7 @@
 		return ArduinoPreferences.getArduinoHome().resolve(".version"); //$NON-NLS-1$
 	}
 
-	private void init() throws CoreException {
+	private synchronized void init() throws CoreException {
 		if (props == null) {
 			if (!Files.exists(ArduinoPreferences.getArduinoHome())) {
 				try {
@@ -219,12 +219,12 @@
 		return pkg != null ? pkg.getInstalledPlatform(architecture) : null;
 	}
 
-	public Collection<ArduinoPlatform> getAvailablePlatforms(IProgressMonitor monitor) throws CoreException {
+	public synchronized Collection<ArduinoPlatform> getAvailablePlatforms(IProgressMonitor monitor) throws CoreException {
 		List<ArduinoPlatform> platforms = new ArrayList<>();
-		Collection<URL> urls = ArduinoPreferences.getBoardUrlList();
-		SubMonitor sub = SubMonitor.convert(monitor, urls.size() + 1);
+		URL[] urls = ArduinoPreferences.getBoardUrlList();
+		SubMonitor sub = SubMonitor.convert(monitor, urls.length + 1);
 
-		sub.beginTask("Downloading package descriptions", urls.size()); //$NON-NLS-1$
+		sub.beginTask("Downloading package descriptions", urls.length); //$NON-NLS-1$
 		for (URL url : urls) {
 			Path packagePath = ArduinoPreferences.getArduinoHome()
 					.resolve(Paths.get(url.getPath()).getFileName());
@@ -252,7 +252,7 @@
 	public void installPlatforms(Collection<ArduinoPlatform> platforms, IProgressMonitor monitor) throws CoreException {
 		SubMonitor sub = SubMonitor.convert(monitor, platforms.size());
 		for (ArduinoPlatform platform : platforms) {
-			sub.setTaskName(String.format("Installing %s", platform.getName())); //$NON-NLS-1$
+			sub.setTaskName(String.format("Installing %s %s", platform.getName(), platform.getVersion())); //$NON-NLS-1$
 			platform.install(sub);
 			sub.worked(1);
 		}
@@ -292,7 +292,7 @@
 		return result;
 	}
 
-	private void initPackages() throws CoreException {
+	private synchronized void initPackages() throws CoreException {
 		if (packages == null) {
 			init();
 			packages = new HashMap<>();
@@ -326,7 +326,7 @@
 		packages = null;
 	}
 
-	private ArduinoPackage getPackage(String packageName) throws CoreException {
+	public ArduinoPackage getPackage(String packageName) throws CoreException {
 		if (packageName == null) {
 			return null;
 		} else {
diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/ArduinoPackage.java b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/ArduinoPackage.java
index 3aba4a8..19a9fff 100644
--- a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/ArduinoPackage.java
+++ b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/ArduinoPackage.java
@@ -92,24 +92,27 @@
 			if (Files.isDirectory(getInstallPath())) {
 				Path platformTxt = Paths.get("platform.txt"); //$NON-NLS-1$
 				try {
-					Files.find(getInstallPath().resolve("hardware"), 2, //$NON-NLS-1$
-							(path, attrs) -> path.getFileName().equals(platformTxt))
-							.forEach(path -> {
-								try (FileReader reader = new FileReader(path.toFile())) {
-									Properties platformProperties = new Properties();
-									platformProperties.load(reader);
-									String arch = path.getName(path.getNameCount() - 2).toString();
-									String version = platformProperties.getProperty("version"); //$NON-NLS-1$
+					Path hardware = getInstallPath().resolve("hardware");
+					if (Files.exists(hardware)) {
+						Files.find(hardware, 2, // $NON-NLS-1$
+								(path, attrs) -> path.getFileName().equals(platformTxt)).forEach(path -> {
+									try (FileReader reader = new FileReader(path.toFile())) {
+										Properties platformProperties = new Properties();
+										platformProperties.load(reader);
+										String arch = path.getName(path.getNameCount() - 2).toString();
+										String version = platformProperties.getProperty("version"); //$NON-NLS-1$
 
-									ArduinoPlatform platform = getPlatform(arch, version);
-									if (platform != null) {
-										platform.setPlatformProperties(platformProperties);
-										installedPlatforms.put(arch, platform);
-									} // TODO manually add it if was removed from index
-								} catch (IOException e) {
-									throw new RuntimeException(e);
-								}
-							});
+										ArduinoPlatform platform = getPlatform(arch, version);
+										if (platform != null) {
+											platform.setPlatformProperties(platformProperties);
+											installedPlatforms.put(arch, platform);
+										} // TODO manually add it if was removed
+											// from index
+									} catch (IOException e) {
+										throw new RuntimeException(e);
+									}
+								});
+					}
 				} catch (IOException e) {
 					throw Activator.coreException(e);
 				}
@@ -166,6 +169,18 @@
 		return null;
 	}
 
+	public ArduinoTool getLatestTool(String toolName) {
+		ArduinoTool latest = null;
+		for (ArduinoTool tool : tools) {
+			if (tool.getName().equals(toolName) && tool.isInstalled()) {
+				if (latest == null || ArduinoManager.compareVersions(tool.getVersion(), latest.getVersion()) > 0) {
+					latest = tool;
+				}
+			}
+		}
+		return latest;
+	}
+
 	@Override
 	public boolean equals(Object obj) {
 		if (obj instanceof ArduinoPackage) {
diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/ArduinoPlatform.java b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/ArduinoPlatform.java
index 3e85fa1..26110ac 100644
--- a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/ArduinoPlatform.java
+++ b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/ArduinoPlatform.java
@@ -20,7 +20,6 @@
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
@@ -31,7 +30,6 @@
 import org.eclipse.cdt.arduino.core.internal.ArduinoPreferences;
 import org.eclipse.cdt.arduino.core.internal.HierarchicalProperties;
 import org.eclipse.cdt.arduino.core.internal.Messages;
-import org.eclipse.cdt.arduino.core.internal.build.ArduinoBuildConfiguration;
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.IStatus;
@@ -209,39 +207,6 @@
 		return getPackage().getInstallPath().resolve("hardware").resolve(architecture); //$NON-NLS-1$
 	}
 
-	public List<Path> getIncludePath() {
-		Path installPath = getInstallPath();
-		return Arrays.asList(installPath.resolve("cores/{build.core}"), //$NON-NLS-1$
-				installPath.resolve("variants/{build.variant}")); //$NON-NLS-1$
-	}
-
-	private void getSources(Collection<String> sources, Path dir, boolean recurse) {
-		for (File file : dir.toFile().listFiles()) {
-			if (file.isDirectory()) {
-				if (recurse) {
-					getSources(sources, file.toPath(), recurse);
-				}
-			} else {
-				if (ArduinoBuildConfiguration.isSource(file.getName())) {
-					sources.add(ArduinoBuildConfiguration.pathString(file.toPath()));
-				}
-			}
-		}
-	}
-
-	public Collection<String> getSources(String core, String variant) {
-		List<String> sources = new ArrayList<>();
-		Path srcPath = getInstallPath().resolve("cores").resolve(core); //$NON-NLS-1$
-		if (srcPath.toFile().isDirectory()) {
-			getSources(sources, srcPath, true);
-		}
-		Path variantPath = getInstallPath().resolve("variants").resolve(variant); //$NON-NLS-1$
-		if (variantPath.toFile().isDirectory()) {
-			getSources(sources, variantPath, true);
-		}
-		return sources;
-	}
-
 	private void initLibraries() throws CoreException {
 		if (libraries == null) {
 			libraries = new HashMap<>();
diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/ArduinoTool.java b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/ArduinoTool.java
index c3a9bf4..2561cbc 100644
--- a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/ArduinoTool.java
+++ b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/ArduinoTool.java
@@ -87,6 +87,7 @@
 		for (ArduinoToolSystem system : systems) {
 			if (system.isApplicable()) {
 				system.install(monitor);
+				return;
 			}
 		}
 
diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/build/ArduinoBuildConfiguration.java b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/build/ArduinoBuildConfiguration.java
index 39af24d..877be21 100644
--- a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/build/ArduinoBuildConfiguration.java
+++ b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/build/ArduinoBuildConfiguration.java
@@ -23,8 +23,10 @@
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashMap;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Map.Entry;
 import java.util.Properties;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -38,6 +40,7 @@
 import org.eclipse.cdt.arduino.core.internal.board.ArduinoManager;
 import org.eclipse.cdt.arduino.core.internal.board.ArduinoPackage;
 import org.eclipse.cdt.arduino.core.internal.board.ArduinoPlatform;
+import org.eclipse.cdt.arduino.core.internal.board.ArduinoTool;
 import org.eclipse.cdt.arduino.core.internal.board.ToolDependency;
 import org.eclipse.cdt.arduino.core.internal.remote.ArduinoRemoteConnection;
 import org.eclipse.cdt.core.CCorePlugin;
@@ -79,6 +82,7 @@
 	private static final String PACKAGE_NAME = "packageName"; //$NON-NLS-1$
 	private static final String PLATFORM_NAME = "platformName"; //$NON-NLS-1$
 	private static final String BOARD_NAME = "boardName"; //$NON-NLS-1$
+	private static final String MENU_QUALIFIER = "menu_"; //$NON-NLS-1$
 
 	private static ArduinoManager manager = Activator.getService(ArduinoManager.class);
 
@@ -117,8 +121,7 @@
 	}
 
 	ArduinoBuildConfiguration(IBuildConfiguration config, String name, ArduinoBoard board, String launchMode,
-			IToolChain toolChain)
-			throws CoreException {
+			IToolChain toolChain) throws CoreException {
 		super(config, name, toolChain);
 		this.board = board;
 		this.launchMode = launchMode;
@@ -148,10 +151,9 @@
 		if (menus != null) {
 			Preferences settings = getSettings();
 			for (String id : menus.getChildren().keySet()) {
-				String key = ArduinoBoard.MENU_QUALIFIER + id;
-				String value = target.getRemoteConnection().getAttribute(key);
+				String value = target.getMenuValue(id);
 				if (value != null) {
-					settings.put(key, value);
+					settings.put(MENU_QUALIFIER + id, value);
 				}
 			}
 
@@ -164,7 +166,9 @@
 	}
 
 	static String generateName(ArduinoBoard board, String launchMode) {
-		return "arduino." + board.getId() + '.' + launchMode; //$NON-NLS-1$
+		ArduinoPlatform platform = board.getPlatform();
+		ArduinoPackage pkg = platform.getPackage();
+		return pkg.getName() + '.' + platform.getArchitecture() + '.' + board.getId() + '.' + launchMode;
 	}
 
 	@SuppressWarnings("unchecked")
@@ -190,8 +194,7 @@
 		HierarchicalProperties menus = board.getMenus();
 		if (menus != null) {
 			for (String id : menus.getChildren().keySet()) {
-				String key = ArduinoBoard.MENU_QUALIFIER + id;
-				if (!settings.get(key, "").equals(target.getRemoteConnection().getAttribute(key))) { //$NON-NLS-1$
+				if (!settings.get(MENU_QUALIFIER + id, "").equals(target.getMenuValue(id))) { //$NON-NLS-1$
 					return false;
 				}
 			}
@@ -211,19 +214,43 @@
 			// IDE generated properties
 			properties = new Properties();
 			properties.put("runtime.platform.path", platform.getInstallPath().toString()); //$NON-NLS-1$
-			properties.put("runtime.ide.version", "10607"); //$NON-NLS-1$ //$NON-NLS-2$
+			properties.put("runtime.ide.version", "10608"); //$NON-NLS-1$ //$NON-NLS-2$
 			properties.put("software", "ARDUINO"); //$NON-NLS-1$ //$NON-NLS-2$
 			properties.put("build.arch", platform.getArchitecture().toUpperCase()); //$NON-NLS-1$
 			String configName = getBuildConfiguration().getName();
 			if (configName.equals(IBuildConfiguration.DEFAULT_CONFIG_NAME)) {
 				configName = "default"; //$NON-NLS-1$
 			}
-			properties.put("build.path", configName); //$NON-NLS-1$
+			properties.put("build.path", "."); //$NON-NLS-1$ //$NON-NLS-2$
 			properties.put("build.variant.path", //$NON-NLS-1$
 					platform.getInstallPath().resolve("variants").resolve("{build.variant}").toString()); //$NON-NLS-1$ //$NON-NLS-2$
 
+			// Everyone seems to want to use the avr-gcc and avrdude tools
+			ArduinoPackage arduinoPackage = manager.getPackage("arduino"); //$NON-NLS-1$
+			ArduinoTool avrgcc = arduinoPackage.getLatestTool("avr-gcc"); //$NON-NLS-1$
+			if (avrgcc != null) {
+				properties.put("runtime.tools.avr-gcc.path", avrgcc.getInstallPath().toString()); //$NON-NLS-1$
+			}
+			ArduinoTool avrdude = arduinoPackage.getLatestTool("avrdude"); //$NON-NLS-1$
+			if (avrdude != null) {
+				properties.put("runtime.tools.avrdude.path", avrdude.getInstallPath().toString()); //$NON-NLS-1$
+			}
+
+			// Super Platform
+			String core = board.getBoardProperties().getProperty("build.core"); //$NON-NLS-1$
+			if (core.contains(":")) { //$NON-NLS-1$
+				String[] segments = core.split(":"); //$NON-NLS-1$
+				if (segments.length == 2) {
+					ArduinoPlatform superPlatform = manager.getInstalledPlatform(segments[0],
+							platform.getArchitecture());
+					if (superPlatform != null) {
+						properties.putAll(superPlatform.getPlatformProperties());
+					}
+				}
+			}
+
 			// Platform
-			properties.putAll(board.getPlatform().getPlatformProperties());
+			properties.putAll(platform.getPlatformProperties());
 
 			// Tools
 			for (ToolDependency toolDep : platform.getToolsDependencies()) {
@@ -238,10 +265,18 @@
 			Preferences settings = getSettings();
 			HierarchicalProperties menus = board.getMenus();
 			if (menus != null) {
-				for (String menuId : menus.getChildren().keySet()) {
-					String value = settings.get(ArduinoBoard.MENU_QUALIFIER + menuId, ""); //$NON-NLS-1$
+				for (Entry<String, HierarchicalProperties> menuEntry : menus.getChildren().entrySet()) {
+					String key = menuEntry.getKey();
+					String defaultValue;
+					Iterator<HierarchicalProperties> i = menuEntry.getValue().getChildren().values().iterator();
+					if (i.hasNext()) {
+						defaultValue = i.next().getValue();
+					} else {
+						defaultValue = ""; //$NON-NLS-1$
+					}
+					String value = settings.get(MENU_QUALIFIER + key, defaultValue);
 					if (!value.isEmpty()) {
-						properties.putAll(board.getMenuProperties(menuId, value));
+						properties.putAll(board.getMenuProperties(key, value));
 					}
 				}
 			}
@@ -252,13 +287,6 @@
 		return properties;
 	}
 
-	public IFile getMakeFile() throws CoreException {
-		IFolder buildFolder = (IFolder) getBuildContainer();
-		ArduinoBoard board = getBoard();
-		String makeFileName = board.getId() + ".mk"; //$NON-NLS-1$
-		return buildFolder.getFile(makeFileName);
-	}
-
 	public Map<String, Object> getBuildModel() throws CoreException {
 		IProject project = getProject();
 		ArduinoBoard board = getBoard();
@@ -301,7 +329,7 @@
 		buildModel.put("project_name", project.getName()); //$NON-NLS-1$
 
 		String includes = null;
-		for (Path include : platform.getIncludePath()) {
+		for (Path include : getIncludePath(platform, properties)) {
 			if (includes == null) {
 				includes = "-I"; //$NON-NLS-1$
 			} else {
@@ -316,10 +344,35 @@
 		}
 		properties.put("includes", includes); //$NON-NLS-1$
 
-		Path platformPath = platform.getInstallPath();
-		buildModel.put("platform_path", pathString(platformPath).replace("+", "\\+")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
-		buildModel.put("platform_srcs", //$NON-NLS-1$
-				platform.getSources(properties.getProperty("build.core"), properties.getProperty("build.variant"))); //$NON-NLS-1$ //$NON-NLS-2$
+		ArduinoPlatform corePlatform = platform;
+		String core = properties.getProperty("build.core"); //$NON-NLS-1$
+		if (core.contains(":")) { //$NON-NLS-1$
+			String[] segments = core.split(":"); //$NON-NLS-1$
+			if (segments.length == 2) {
+				corePlatform = manager.getInstalledPlatform(segments[0], platform.getArchitecture());
+				core = segments[1];
+			}
+		}
+		Path corePath = corePlatform.getInstallPath().resolve("cores").resolve(core); //$NON-NLS-1$
+		buildModel.put("platform_core_path", pathString(corePath)); //$NON-NLS-1$
+		List<String> coreSources = new ArrayList<>();
+		getSources(coreSources, corePath, true);
+		buildModel.put("platform_core_srcs", coreSources); //$NON-NLS-1$
+
+		ArduinoPlatform variantPlatform = platform;
+		String variant = properties.getProperty("build.variant"); //$NON-NLS-1$
+		if (variant.contains(":")) { //$NON-NLS-1$
+			String[] segments = variant.split(":"); //$NON-NLS-1$
+			if (segments.length == 2) {
+				variantPlatform = manager.getInstalledPlatform(segments[0], platform.getArchitecture());
+				variant = segments[1];
+			}
+		}
+		Path variantPath = variantPlatform.getInstallPath().resolve("variants").resolve(variant); //$NON-NLS-1$
+		buildModel.put("platform_variant_path", pathString(variantPath)); //$NON-NLS-1$
+		List<String> variantSources = new ArrayList<>();
+		getSources(variantSources, variantPath, true);
+		buildModel.put("platform_variant_srcs", variantSources); //$NON-NLS-1$
 
 		properties.put("object_file", "$@"); //$NON-NLS-1$ //$NON-NLS-2$
 		properties.put("source_file", "$<"); //$NON-NLS-1$ //$NON-NLS-2$
@@ -340,13 +393,27 @@
 		return buildModel;
 	}
 
+	private static void getSources(Collection<String> sources, Path dir, boolean recurse) {
+		for (File file : dir.toFile().listFiles()) {
+			if (file.isDirectory()) {
+				if (recurse) {
+					getSources(sources, file.toPath(), recurse);
+				}
+			} else {
+				if (ArduinoBuildConfiguration.isSource(file.getName())) {
+					sources.add(ArduinoBuildConfiguration.pathString(file.toPath()));
+				}
+			}
+		}
+	}
+
 	public IFile generateMakeFile(IProgressMonitor monitor) throws CoreException {
 		IFolder buildFolder = (IFolder) getBuildContainer();
 		if (!buildFolder.exists()) {
 			buildFolder.create(true, true, monitor);
 		}
 
-		IFile makefile = getMakeFile();
+		IFile makefile = buildFolder.getFile("Makefile"); //$NON-NLS-1$
 
 		Map<String, Object> buildModel = getBuildModel();
 
@@ -402,28 +469,35 @@
 		}
 	}
 
-	private String resolvePropertyValue(String value, Properties dict) {
+	private String resolvePropertyValue(String value, Properties dict) throws CoreException {
 		String last;
 		do {
 			last = value;
 			for (int i = value.indexOf('{'); i >= 0; i = value.indexOf('{', i)) {
 				i++;
+				if (value.charAt(i) == '{') {
+					i++;
+					continue;
+				}
+
 				int n = value.indexOf('}', i);
 				if (n >= 0) {
 					String p2 = value.substring(i, n);
 					String r2 = dict.getProperty(p2);
 					if (r2 != null) {
 						value = value.replace('{' + p2 + '}', r2);
+					} else {
+						throw Activator.coreException(String.format("Undefined key %s", p2), null);
 					}
 				}
 				i = n;
 			}
 		} while (!value.equals(last));
 
-		return value;
+		return value.replace("}}", "}").replace("{{", "{"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
 	}
 
-	private String resolveProperty(String property, Properties dict) {
+	private String resolveProperty(String property, Properties dict) throws CoreException {
 		String value = dict.getProperty(property);
 		return value != null ? resolvePropertyValue(value, dict) : null;
 	}
@@ -433,17 +507,17 @@
 	}
 
 	public String[] getBuildCommand() throws CoreException {
-		return new String[] { getMakeCommand(), "-f", getMakeFile().getName() }; //$NON-NLS-1$
+		return new String[] { getMakeCommand() };
 	}
 
 	public String[] getCleanCommand() throws CoreException {
-		return new String[] { getMakeCommand(), "-f", getMakeFile().getName(), "clean" }; //$NON-NLS-1$ //$NON-NLS-2$
+		return new String[] { getMakeCommand(), "clean" }; //$NON-NLS-1$
 	}
 
 	public String[] getSizeCommand() throws CoreException {
 		// TODO this shouldn't be in the makefile
 		// should be like the upload command
-		return new String[] { getMakeCommand(), "-f", getMakeFile().getName(), "size" }; //$NON-NLS-1$ //$NON-NLS-2$
+		return new String[] { getMakeCommand(), "size" }; //$NON-NLS-1$
 	}
 
 	public String getCodeSizeRegex() throws CoreException {
@@ -466,8 +540,21 @@
 
 	public String[] getUploadCommand(String serialPort) throws CoreException {
 		String toolName = getProperties().getProperty("upload.tool"); //$NON-NLS-1$
+		ArduinoPlatform platform = getBoard().getPlatform();
+		if (toolName.contains(":")) { //$NON-NLS-1$
+			String[] segments = toolName.split(":"); //$NON-NLS-1$
+			if (segments.length == 2) {
+				platform = manager.getInstalledPlatform(segments[0], platform.getArchitecture());
+				toolName = segments[1];
+			}
+		}
 
 		Properties properties = getProperties();
+		
+		ArduinoTool uploadTool = platform.getPackage().getLatestTool(toolName);
+		if (uploadTool != null) {
+			properties.putAll(uploadTool.getToolProperties());
+		}
 
 		properties.put("serial.port", serialPort); //$NON-NLS-1$
 		// Little bit of weirdness needed for the bossac tool
@@ -482,7 +569,7 @@
 		properties.put("config.path", "{tools." + toolName + ".config.path}"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
 
 		// properties for the tool flattened
-		HierarchicalProperties toolsProps = new HierarchicalProperties(getBoard().getPlatform().getPlatformProperties())
+		HierarchicalProperties toolsProps = new HierarchicalProperties(platform.getPlatformProperties())
 				.getChild("tools"); //$NON-NLS-1$
 		if (toolsProps != null) {
 			HierarchicalProperties toolProps = toolsProps.getChild(toolName);
@@ -493,13 +580,14 @@
 
 		// TODO make this a preference
 		properties.put("upload.verbose", properties.getProperty("upload.params.verbose", "")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		properties.put("upload.verify", properties.getProperty("upload.params.verify", "")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
 
 		// TODO needed this for esptool
 		properties.put("upload.resetmethod", "ck"); //$NON-NLS-1$ //$NON-NLS-2$
 
 		String command = resolveProperty("upload.pattern", properties); //$NON-NLS-1$
 		if (command == null) {
-			return new String[] { "command not specified" }; //$NON-NLS-1$
+			throw Activator.coreException("Upload command not specified", null);
 		}
 		if (isWindows) {
 			return splitCommand(command);
@@ -508,6 +596,31 @@
 		}
 	}
 
+	private Collection<Path> getIncludePath(ArduinoPlatform platform, Properties properties) throws CoreException {
+		ArduinoPlatform corePlatform = platform;
+		String core = properties.getProperty("build.core"); //$NON-NLS-1$
+		if (core.contains(":")) { //$NON-NLS-1$
+			String[] segments = core.split(":"); //$NON-NLS-1$
+			if (segments.length == 2) {
+				corePlatform = manager.getInstalledPlatform(segments[0], platform.getArchitecture());
+				core = segments[1];
+			}
+		}
+
+		ArduinoPlatform variantPlatform = platform;
+		String variant = properties.getProperty("build.variant"); //$NON-NLS-1$
+		if (variant.contains(":")) { //$NON-NLS-1$
+			String[] segments = variant.split(":"); //$NON-NLS-1$
+			if (segments.length == 2) {
+				variantPlatform = manager.getInstalledPlatform(segments[0], platform.getArchitecture());
+				variant = segments[1];
+			}
+		}
+
+		return Arrays.asList(corePlatform.getInstallPath().resolve("cores").resolve(core), //$NON-NLS-1$
+				variantPlatform.getInstallPath().resolve("variants").resolve(variant)); //$NON-NLS-1$
+	}
+
 	// Scanner Info Cache
 	private String[] cachedIncludePath;
 	private String cachedInfoCommand;
@@ -537,14 +650,27 @@
 			String commandString = resolveProperty(recipe, properties);
 
 			List<Path> includePath = new ArrayList<>();
-			includePath.addAll(platform.getIncludePath());
+			includePath.addAll(getIncludePath(platform, properties));
 			Collection<ArduinoLibrary> libs = manager.getLibraries(getProject());
 			for (ArduinoLibrary lib : libs) {
 				includePath.addAll(lib.getIncludePath());
 			}
-			String[] includes = includePath.stream()
-					.map(path -> resolvePropertyValue(path.toString(), properties)).collect(Collectors.toList())
-					.toArray(new String[includePath.size()]);
+			String[] includes = null;
+			try {
+				includes = includePath.stream().map(path -> {
+					try {
+						return resolvePropertyValue(path.toString(), properties);
+					} catch (CoreException e) {
+						throw new RuntimeException(e);
+					}
+				}).collect(Collectors.toList()).toArray(new String[includePath.size()]);
+			} catch (RuntimeException e) {
+				if (e.getCause() != null && e.getCause() instanceof CoreException) {
+					throw (CoreException) e.getCause();
+				} else {
+					throw e;
+				}
+			}
 
 			// Use cache if we can
 			if (cachedScannerInfo != null && cachedInfoCommand.equals(commandString)
diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/build/ArduinoBuildConfigurationProvider.java b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/build/ArduinoBuildConfigurationProvider.java
index 0dfda45..7b4f6ad 100644
--- a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/build/ArduinoBuildConfigurationProvider.java
+++ b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/build/ArduinoBuildConfigurationProvider.java
@@ -39,49 +39,28 @@
 
 	@Override
 	public ICBuildConfiguration getCBuildConfiguration(IBuildConfiguration config, String name) throws CoreException {
-		return new ArduinoBuildConfiguration(config, name);
-	}
-
-	@Override
-	public ICBuildConfiguration getDefaultCBuildConfiguration(IProject project) throws CoreException {
-		ArduinoBoard board = arduinoManager.getBoard("arduino", "avr", "Arduino/Genuino Uno"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
-		if (board == null) {
-			Collection<ArduinoBoard> boards = arduinoManager.getInstalledBoards();
-			if (!boards.isEmpty()) {
-				board = boards.iterator().next();
-			}
-		}
-		if (board != null) {
-			String launchMode = "run"; //$NON-NLS-1$
-			for (IBuildConfiguration config : project.getBuildConfigs()) {
-				ICBuildConfiguration cconfig = config.getAdapter(ICBuildConfiguration.class);
-				if (cconfig != null) {
-					ArduinoBuildConfiguration arduinoConfig = cconfig.getAdapter(ArduinoBuildConfiguration.class);
-					if (arduinoConfig != null && arduinoConfig.getLaunchMode().equals(launchMode)
-							&& arduinoConfig.getBoard().equals(board)) {
-						return arduinoConfig;
-					}
+		if (config.getName().equals(IBuildConfiguration.DEFAULT_CONFIG_NAME)) {
+			// Use the good ol' Uno as the default
+			ArduinoBoard board = arduinoManager.getBoard("arduino", "avr", "uno"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+			if (board == null) {
+				Collection<ArduinoBoard> boards = arduinoManager.getInstalledBoards();
+				if (!boards.isEmpty()) {
+					board = boards.iterator().next();
 				}
 			}
+			if (board != null) {
+				// Create the toolChain
+				IToolChainManager toolChainManager = Activator.getService(IToolChainManager.class);
+				IToolChainProvider provider = toolChainManager.getProvider(ArduinoToolChainProvider.ID);
+				IToolChain toolChain = new ArduinoToolChain(provider, config);
+				toolChainManager.addToolChain(toolChain);
 
-			// not found, create one
-			String configName = ArduinoBuildConfiguration.generateName(board, launchMode);
-			IBuildConfiguration config = configManager.createBuildConfiguration(this, project, configName,
-					null);
-
-			// Create the toolChain
-			IToolChainManager toolChainManager = Activator.getService(IToolChainManager.class);
-			IToolChainProvider provider = toolChainManager.getProvider(ArduinoToolChainProvider.ID);
-			IToolChain toolChain = new ArduinoToolChain(provider, config);
-			toolChainManager.addToolChain(toolChain);
-
-			ArduinoBuildConfiguration arduinoConfig = new ArduinoBuildConfiguration(config, configName, board,
-					launchMode, toolChain);
-			arduinoConfig.setActive(null);
-			configManager.addBuildConfiguration(config, arduinoConfig);
-			return arduinoConfig;
+				return new ArduinoBuildConfiguration(config, name, board, "run", toolChain); //$NON-NLS-1$
+			}
+			return null;
+		} else {
+			return new ArduinoBuildConfiguration(config, name);
 		}
-		return null;
 	}
 
 	public ArduinoBuildConfiguration getConfiguration(IProject project, ArduinoRemoteConnection target,
diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/remote/ArduinoRemoteConnection.java b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/remote/ArduinoRemoteConnection.java
index 380ec26..30d3ca8 100644
--- a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/remote/ArduinoRemoteConnection.java
+++ b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/remote/ArduinoRemoteConnection.java
@@ -17,12 +17,15 @@
 import org.eclipse.cdt.arduino.core.internal.Activator;
 import org.eclipse.cdt.arduino.core.internal.board.ArduinoBoard;
 import org.eclipse.cdt.arduino.core.internal.board.ArduinoManager;
+import org.eclipse.cdt.arduino.core.internal.board.ArduinoPackage;
+import org.eclipse.cdt.arduino.core.internal.board.ArduinoPlatform;
 import org.eclipse.cdt.serial.SerialPort;
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.remote.core.IRemoteCommandShellService;
 import org.eclipse.remote.core.IRemoteConnection;
 import org.eclipse.remote.core.IRemoteConnectionChangeListener;
 import org.eclipse.remote.core.IRemoteConnectionPropertyService;
+import org.eclipse.remote.core.IRemoteConnectionWorkingCopy;
 import org.eclipse.remote.core.IRemoteProcess;
 import org.eclipse.remote.core.RemoteConnectionChangeEvent;
 import org.eclipse.remote.serial.core.SerialPortCommandShell;
@@ -31,10 +34,12 @@
 		implements IRemoteConnectionPropertyService, IRemoteCommandShellService, IRemoteConnectionChangeListener {
 
 	public static final String TYPE_ID = "org.eclipse.cdt.arduino.core.connectionType"; //$NON-NLS-1$
-	public static final String PORT_NAME = "arduinoPortName"; //$NON-NLS-1$
-	public static final String PACKAGE_NAME = "arduinoPackageName"; //$NON-NLS-1$
-	public static final String PLATFORM_NAME = "arduinoPlatformName"; //$NON-NLS-1$
-	public static final String BOARD_NAME = "arduinoBoardName"; //$NON-NLS-1$
+
+	private static final String PORT_NAME = "arduinoPortName"; //$NON-NLS-1$
+	private static final String PACKAGE_NAME = "arduinoPackageName"; //$NON-NLS-1$
+	private static final String PLATFORM_NAME = "arduinoPlatformName"; //$NON-NLS-1$
+	private static final String BOARD_NAME = "arduinoBoardName"; //$NON-NLS-1$
+	private static final String MENU_QUALIFIER = "menu_"; //$NON-NLS-1$
 
 	private final IRemoteConnection remoteConnection;
 	private SerialPort serialPort;
@@ -47,6 +52,28 @@
 		remoteConnection.addConnectionChangeListener(this);
 	}
 
+	public static void setBoardId(IRemoteConnectionWorkingCopy workingCopy, ArduinoBoard board) {
+		workingCopy.setAttribute(BOARD_NAME, board.getId());
+
+		ArduinoPlatform platform = board.getPlatform();
+		workingCopy.setAttribute(PLATFORM_NAME, platform.getArchitecture());
+
+		ArduinoPackage pkg = platform.getPackage();
+		workingCopy.setAttribute(PACKAGE_NAME, pkg.getName());
+	}
+	
+	public static void setPortName(IRemoteConnectionWorkingCopy workingCopy, String portName) {
+		workingCopy.setAttribute(PORT_NAME, portName);
+	}
+	
+	public static void setMenuValue(IRemoteConnectionWorkingCopy workingCopy, String key, String value) {
+		workingCopy.setAttribute(MENU_QUALIFIER + key, value);
+	}
+	
+	public String getMenuValue(String key) {
+		return remoteConnection.getAttribute(MENU_QUALIFIER + key);
+	}
+
 	@Override
 	public void connectionChanged(RemoteConnectionChangeEvent event) {
 		if (event.getType() == RemoteConnectionChangeEvent.CONNECTION_REMOVED) {
diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.core/templates/Makefile b/toolchains/arduino/org.eclipse.cdt.arduino.core/templates/Makefile
index 4888852..82ec947 100644
--- a/toolchains/arduino/org.eclipse.cdt.arduino.core/templates/Makefile
+++ b/toolchains/arduino/org.eclipse.cdt.arduino.core/templates/Makefile
@@ -15,19 +15,35 @@
 </#if>
 </#list>
 
-PLATFORM_OBJS = \
-<#list platform_srcs as file>
-<#assign cpp = file?matches("${platform_path}/(.*)\\.cpp")>
+PLATFORM_CORE_OBJS = \
+<#list platform_core_srcs as file>
+<#assign cpp = file?matches("${platform_core_path}/(.*)\\.cpp")>
 <#if cpp>
-	${build_path}/platform/${cpp?groups[1]}.cpp.o \
+	${build_path}/core/${cpp?groups[1]}.cpp.o \
 </#if>
-<#assign c = file?matches("${platform_path}/(.*)\\.c")>
+<#assign c = file?matches("${platform_core_path}/(.*)\\.c")>
 <#if c>
-	${build_path}/platform/${c?groups[1]}.c.o \
+	${build_path}/core/${c?groups[1]}.c.o \
 </#if>
-<#assign S = file?matches("${platform_path}/(.*)\\.S")>
+<#assign S = file?matches("${platform_core_path}/(.*)\\.S")>
 <#if S>
-	${build_path}/platform/${S?groups[1]}.S.o \
+	${build_path}/core/${S?groups[1]}.S.o \
+</#if>
+</#list>
+
+PLATFORM_VARIANT_OBJS = \
+<#list platform_variant_srcs as file>
+<#assign cpp = file?matches("${platform_variant_path}/(.*)\\.cpp")>
+<#if cpp>
+	${build_path}/variant/${cpp?groups[1]}.cpp.o \
+</#if>
+<#assign c = file?matches("${platform_variant_path}/(.*)\\.c")>
+<#if c>
+	${build_path}/variant/${c?groups[1]}.c.o \
+</#if>
+<#assign S = file?matches("${platform_variant_path}/(.*)\\.S")>
+<#if S>
+	${build_path}/variant/${S?groups[1]}.S.o \
 </#if>
 </#list>
 
@@ -80,7 +96,7 @@
 ${build_path}/${project_name}.elf: $(PROJECT_OBJS) $(LIBRARIES_OBJS) ${build_path}/core.a
 	${recipe_c_combine_pattern}
 
-${build_path}/core.a:	$(PLATFORM_OBJS)
+${build_path}/core.a:	$(PLATFORM_CORE_OBJS) $(PLATFORM_VARIANT_OBJS)
 
 clean:
 	$(RMDIR) ${build_path}
@@ -102,34 +118,69 @@
 </#if>
 </#list>
 
-<#list platform_srcs as file>
-<#assign cpp = file?matches("${platform_path}/(.*)\\.cpp")>
+<#list platform_core_srcs as file>
+<#assign cpp = file?matches("${platform_core_path}/(.*)\\.cpp")>
 <#if cpp>
-${build_path}/platform/${cpp?groups[1]}.cpp.o: ${file} ${build_path}/platform/${cpp?groups[1]}.cpp.d
+${build_path}/core/${cpp?groups[1]}.cpp.o: ${file} ${build_path}/core/${cpp?groups[1]}.cpp.d
 	@$(call mymkdir,$(dir $@))
 	${recipe_cpp_o_pattern}
 	${recipe_ar_pattern}
 
-${build_path}/platform/${cpp?groups[1]}.cpp.d: ;
+${build_path}/core/${cpp?groups[1]}.cpp.d: ;
 
--include ${build_path}/platform/${cpp?groups[1]}.cpp.d
+-include ${build_path}/core/${cpp?groups[1]}.cpp.d
 
 </#if>
-<#assign c = file?matches("${platform_path}/(.*)\\.c")>
+<#assign c = file?matches("${platform_core_path}/(.*)\\.c")>
 <#if c>
-${build_path}/platform/${c?groups[1]}.c.o: ${file} ${build_path}/platform/${c?groups[1]}.c.d
+${build_path}/core/${c?groups[1]}.c.o: ${file} ${build_path}/core/${c?groups[1]}.c.d
 	@$(call mymkdir,$(dir $@))
 	${recipe_c_o_pattern}
 	${recipe_ar_pattern}
 	
-${build_path}/platform/${c?groups[1]}.c.d: ;
+${build_path}/core/${c?groups[1]}.c.d: ;
 
--include ${build_path}/platform/${c?groups[1]}.c.d
+-include ${build_path}/core/${c?groups[1]}.c.d
 
 </#if>
-<#assign S = file?matches("${platform_path}/(.*)\\.S")>
+<#assign S = file?matches("${platform_core_path}/(.*)\\.S")>
 <#if S>
-${build_path}/platform/${S?groups[1]}.S.o: ${file}
+${build_path}/core/${S?groups[1]}.S.o: ${file}
+	@$(call mymkdir,$(dir $@))
+	${recipe_S_o_pattern}
+	${recipe_ar_pattern}
+
+</#if>
+</#list>
+
+<#list platform_variant_srcs as file>
+<#assign cpp = file?matches("${platform_variant_path}/(.*)\\.cpp")>
+<#if cpp>
+${build_path}/variant/${cpp?groups[1]}.cpp.o: ${file} ${build_path}/variant/${cpp?groups[1]}.cpp.d
+	@$(call mymkdir,$(dir $@))
+	${recipe_cpp_o_pattern}
+	${recipe_ar_pattern}
+
+${build_path}/variant/${cpp?groups[1]}.cpp.d: ;
+
+-include ${build_path}/variant/${cpp?groups[1]}.cpp.d
+
+</#if>
+<#assign c = file?matches("${platform_variant_path}/(.*)\\.c")>
+<#if c>
+${build_path}/variant/${c?groups[1]}.c.o: ${file} ${build_path}/variant/${c?groups[1]}.c.d
+	@$(call mymkdir,$(dir $@))
+	${recipe_c_o_pattern}
+	${recipe_ar_pattern}
+	
+${build_path}/variant/${c?groups[1]}.c.d: ;
+
+-include ${build_path}/variant/${c?groups[1]}.c.d
+
+</#if>
+<#assign S = file?matches("${platform_variant_path}/(.*)\\.S")>
+<#if S>
+${build_path}/variant/${S?groups[1]}.S.o: ${file}
 	@$(call mymkdir,$(dir $@))
 	${recipe_S_o_pattern}
 	${recipe_ar_pattern}
diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.ui/plugin.xml b/toolchains/arduino/org.eclipse.cdt.arduino.ui/plugin.xml
index fa5d081..36d3d02 100644
--- a/toolchains/arduino/org.eclipse.cdt.arduino.ui/plugin.xml
+++ b/toolchains/arduino/org.eclipse.cdt.arduino.ui/plugin.xml
@@ -86,12 +86,6 @@
             id="org.eclipse.cdt.arduino.preference.page"
             name="%preferencePage.name">
       </page>
-      <page
-            category="org.eclipse.cdt.arduino.preference.page"
-            class="org.eclipse.cdt.arduino.ui.internal.preferences.ArduinoPlatformsPreferencePage"
-            id="org.eclipse.cdt.arduino.ui.page.platforms"
-            name="Platforms">
-      </page>
    </extension>
    <extension
          point="org.eclipse.ui.perspectiveExtensions">
diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/remote/ArduinoTargetPropertyPage.java b/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/remote/ArduinoTargetPropertyPage.java
index 63cdd9d..a024a3a 100644
--- a/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/remote/ArduinoTargetPropertyPage.java
+++ b/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/remote/ArduinoTargetPropertyPage.java
@@ -96,15 +96,11 @@
 		IRemoteConnection remoteConnection = getElement().getAdapter(IRemoteConnection.class);
 		IRemoteConnectionWorkingCopy workingCopy = remoteConnection.getWorkingCopy();
 
-		String portName = portSelector.getItem(portSelector.getSelectionIndex());
-		workingCopy.setAttribute(ArduinoRemoteConnection.PORT_NAME, portName);
-
 		ArduinoBoard board = boards[boardSelector.getSelectionIndex()];
-		workingCopy.setAttribute(ArduinoRemoteConnection.BOARD_NAME, board.getId());
-		ArduinoPlatform platform = board.getPlatform();
-		workingCopy.setAttribute(ArduinoRemoteConnection.PLATFORM_NAME, platform.getArchitecture());
-		ArduinoPackage pkg = platform.getPackage();
-		workingCopy.setAttribute(ArduinoRemoteConnection.PACKAGE_NAME, pkg.getName());
+		ArduinoRemoteConnection.setBoardId(workingCopy, board);
+
+		String portName = portSelector.getItem(portSelector.getSelectionIndex());
+		ArduinoRemoteConnection.setPortName(workingCopy, portName);
 
 		try {
 			workingCopy.save();
diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/remote/BoardPropertyControl.java b/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/remote/BoardPropertyControl.java
index b0bfacd..38362fa 100644
--- a/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/remote/BoardPropertyControl.java
+++ b/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/remote/BoardPropertyControl.java
@@ -188,15 +188,8 @@
 	}
 
 	public void apply(IRemoteConnectionWorkingCopy workingCopy) {
-		workingCopy.setAttribute(ArduinoRemoteConnection.PORT_NAME, portName);
-
-		workingCopy.setAttribute(ArduinoRemoteConnection.BOARD_NAME, board.getId());
-
-		ArduinoPlatform platform = board.getPlatform();
-		workingCopy.setAttribute(ArduinoRemoteConnection.PLATFORM_NAME, platform.getArchitecture());
-
-		ArduinoPackage pkg = platform.getPackage();
-		workingCopy.setAttribute(ArduinoRemoteConnection.PACKAGE_NAME, pkg.getName());
+		ArduinoRemoteConnection.setBoardId(workingCopy, board);
+		ArduinoRemoteConnection.setPortName(workingCopy, portName);
 
 		String key = null;
 		for (Control control : menuControls) {
@@ -208,7 +201,7 @@
 				String value = ((List<String>) combo.getData()).get(combo.getSelectionIndex());
 
 				if (key != null) {
-					workingCopy.setAttribute(ArduinoBoard.MENU_QUALIFIER + key, value);
+					ArduinoRemoteConnection.setMenuValue(workingCopy, key, value);
 				}
 			}
 		}