diff --git a/core/org.eclipse.cdt.core.tests/misc/org/eclipse/cdt/core/internal/build/GCCTests.java b/core/org.eclipse.cdt.core.tests/misc/org/eclipse/cdt/core/internal/build/GCCTests.java new file mode 100644 index 00000000000..dfdfbe9eb6e --- /dev/null +++ b/core/org.eclipse.cdt.core.tests/misc/org/eclipse/cdt/core/internal/build/GCCTests.java @@ -0,0 +1,17 @@ +package org.eclipse.cdt.core.internal.build; + +import java.io.IOException; + +import org.eclipse.cdt.core.build.gcc.GCCToolChainFactory; +import org.junit.Test; + +public class GCCTests { + + @Test + public void tryGCCDiscovery() throws IOException { + long start = System.currentTimeMillis(); + new GCCToolChainFactory().discover(); + System.out.println("Time: " + (System.currentTimeMillis() - start)); + } + +} diff --git a/core/org.eclipse.cdt.core/.classpath b/core/org.eclipse.cdt.core/.classpath index 560b7243736..8672427f779 100644 --- a/core/org.eclipse.cdt.core/.classpath +++ b/core/org.eclipse.cdt.core/.classpath @@ -1,12 +1,12 @@ + + - - diff --git a/core/org.eclipse.cdt.core/.settings/org.eclipse.jdt.core.prefs b/core/org.eclipse.cdt.core/.settings/org.eclipse.jdt.core.prefs index 11e273c7aee..62448898674 100644 --- a/core/org.eclipse.cdt.core/.settings/org.eclipse.jdt.core.prefs +++ b/core/org.eclipse.cdt.core/.settings/org.eclipse.jdt.core.prefs @@ -1,8 +1,8 @@ eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve -org.eclipse.jdt.core.compiler.compliance=1.7 +org.eclipse.jdt.core.compiler.compliance=1.8 org.eclipse.jdt.core.compiler.debug.lineNumber=generate org.eclipse.jdt.core.compiler.debug.localVariable=generate org.eclipse.jdt.core.compiler.debug.sourceFile=generate @@ -77,7 +77,7 @@ org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disa org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning -org.eclipse.jdt.core.compiler.source=1.7 +org.eclipse.jdt.core.compiler.source=1.8 org.eclipse.jdt.core.formatter.align_type_members_on_columns=false org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0 diff --git a/core/org.eclipse.cdt.core/META-INF/MANIFEST.MF b/core/org.eclipse.cdt.core/META-INF/MANIFEST.MF index bd44f8fcfd0..43cabd3e52c 100644 --- a/core/org.eclipse.cdt.core/META-INF/MANIFEST.MF +++ b/core/org.eclipse.cdt.core/META-INF/MANIFEST.MF @@ -9,6 +9,7 @@ Bundle-Localization: plugin Export-Package: org.eclipse.cdt.core, org.eclipse.cdt.core.browser, org.eclipse.cdt.core.build, + org.eclipse.cdt.core.build.gcc, org.eclipse.cdt.core.cdtvariables, org.eclipse.cdt.core.dom, org.eclipse.cdt.core.dom.ast, @@ -130,4 +131,4 @@ Require-Bundle: org.eclipse.cdt.core.native;bundle-version="[5.7.0,6.0.0)";visib com.ibm.icu;bundle-version="4.4.2", com.google.gson;bundle-version="2.2.4" Bundle-ActivationPolicy: lazy -Bundle-RequiredExecutionEnvironment: JavaSE-1.7 +Bundle-RequiredExecutionEnvironment: JavaSE-1.8 diff --git a/core/org.eclipse.cdt.core/build.properties b/core/org.eclipse.cdt.core/build.properties index dbbe7f7419e..49e306809f2 100644 --- a/core/org.eclipse.cdt.core/build.properties +++ b/core/org.eclipse.cdt.core/build.properties @@ -1,5 +1,5 @@ ############################################################################### -# Copyright (c) 2003, 2014 IBM Corporation and others. +# Copyright (c) 2003, 2015 IBM Corporation 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 @@ -30,7 +30,3 @@ source.. = src/,\ browser/,\ templateengine/,\ utils/ - -jre.compilation.profile=JavaSE-1.7 -javacSource=1.7 -javacTarget=1.7 diff --git a/core/org.eclipse.cdt.core/plugin.xml b/core/org.eclipse.cdt.core/plugin.xml index f258d41eec2..dd0c96dd826 100644 --- a/core/org.eclipse.cdt.core/plugin.xml +++ b/core/org.eclipse.cdt.core/plugin.xml @@ -683,7 +683,7 @@ - + @@ -858,20 +858,10 @@ - - - - + point="org.eclipse.cdt.core.ToolChainFactory"> - - + class="org.eclipse.cdt.core.build.gcc.GCCToolChainFactory" + family="GCC"> diff --git a/core/org.eclipse.cdt.core/schema/ToolChain.exsd b/core/org.eclipse.cdt.core/schema/ToolChainFactory.exsd similarity index 79% rename from core/org.eclipse.cdt.core/schema/ToolChain.exsd rename to core/org.eclipse.cdt.core/schema/ToolChainFactory.exsd index c421b87247b..bc18ce610ab 100644 --- a/core/org.eclipse.cdt.core/schema/ToolChain.exsd +++ b/core/org.eclipse.cdt.core/schema/ToolChainFactory.exsd @@ -3,7 +3,7 @@ - + [Enter description of this extension point.] @@ -18,7 +18,7 @@ - + @@ -47,27 +47,22 @@ - - - - A toolchain that implements the CToolChain interface and identified with the id attribute. - - + - + - id for the toolchain. + - + - The adaptor class for the toolchain. This is passed to getAdaptor on the CBuildConfiguration object. + - + 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 62034ee006b..ff28c16cbb1 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 @@ -8,7 +8,11 @@ package org.eclipse.cdt.core.build; import org.eclipse.cdt.core.CCorePlugin; +import org.eclipse.cdt.core.model.ILanguage; +import org.eclipse.cdt.core.parser.ExtendedScannerInfo; import org.eclipse.cdt.core.parser.IScannerInfo; +import org.eclipse.cdt.internal.core.build.ScannerInfoData; +import org.eclipse.cdt.internal.core.build.ToolChainScannerInfo; import org.eclipse.core.resources.IBuildConfiguration; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IProjectDescription; @@ -39,6 +43,7 @@ public abstract class CBuildConfiguration extends PlatformObject { private final IBuildConfiguration config; private CToolChain toolChain; + private ScannerInfoData scannerInfoData; protected CBuildConfiguration(IBuildConfiguration config) { this.config = config; @@ -97,23 +102,17 @@ public abstract class CBuildConfiguration extends PlatformObject { return null; } - public synchronized void setToolChain(String id) throws CoreException { - CToolChain newtc = getToolChain(id); - if (newtc == null) { - throw new CoreException( - new Status(IStatus.ERROR, CCorePlugin.PLUGIN_ID, "unknown toolchain: " + id)); //$NON-NLS-1$ - } + public synchronized void setToolChain(CToolChain toolChain) throws CoreException { + this.toolChain = toolChain; IEclipsePreferences settings = getSettings(); - settings.put(TOOLCHAIN, id); + settings.put(TOOLCHAIN, toolChain.getId()); try { settings.flush(); } catch (BackingStoreException e) { throw new CoreException( new Status(IStatus.ERROR, CCorePlugin.PLUGIN_ID, "saving toolchain id", e)); //$NON-NLS-1$ } - - toolChain = newtc; } public CToolChain getToolChain() throws CoreException { @@ -130,12 +129,26 @@ public abstract class CBuildConfiguration extends PlatformObject { } public IScannerInfo getScannerInfo(IResource resource) throws CoreException { - // By default, get it from the toolchain. - CToolChain toolChain = getToolChain(); - return toolChain != null ? toolChain.getScannerInfo(resource) : null; + return getScannerInfoData().getScannerInfo(resource); + } + + public void putScannerInfo(ILanguage language, ExtendedScannerInfo info) { + getScannerInfoData().putScannerInfo(language, info); + } + + public void putScannerInfo(IResource resource, ToolChainScannerInfo info) { + getScannerInfoData().putScannerInfo(resource, info); + } + + private ScannerInfoData getScannerInfoData() { + if (scannerInfoData == null) { + scannerInfoData = ScannerInfoData.load(this); + } + return scannerInfoData; } public void clearScannerInfo() throws CoreException { + scannerInfoData = null; } public CConsoleParser[] getConsoleParsers() throws CoreException { diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/build/CToolChain.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/build/CToolChain.java index f027cb42496..4bc6182a1b6 100644 --- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/build/CToolChain.java +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/build/CToolChain.java @@ -10,14 +10,12 @@ package org.eclipse.cdt.core.build; import java.util.List; import java.util.Map; -import org.eclipse.cdt.core.model.ILanguage; -import org.eclipse.cdt.core.parser.IScannerInfo; -import org.eclipse.cdt.internal.core.build.ScannerInfoData; -import org.eclipse.cdt.internal.core.build.ToolChainScannerInfo; +import org.eclipse.cdt.core.parser.ExtendedScannerInfo; +import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IFolder; -import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.PlatformObject; +import org.osgi.service.prefs.Preferences; /** * Root class for CDT toolchains. @@ -26,12 +24,38 @@ import org.eclipse.core.runtime.PlatformObject; */ public abstract class CToolChain extends PlatformObject { - private final CBuildConfiguration config; + public static final String FAMILY = "family"; //$NON-NLS-1$ + private static final String NAME = "name"; //$NON-NLS-1$ - private ScannerInfoData scannerInfo; + private String id; + private String name; - protected CToolChain(CBuildConfiguration config) { - this.config = config; + protected CToolChain(String id, Preferences settings) { + this.id = id; + this.name = settings.get(NAME, ""); //$NON-NLS-1$ + } + + protected CToolChain(String name) { + this.name = name; + } + + public abstract String getFamily(); + + public String getId() { + return id; + } + + void setId(String id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void save(Preferences settings) { + settings.put(FAMILY, getFamily()); + settings.put(NAME, name); } public static String[] splitCommand(String command) { @@ -39,8 +63,13 @@ public abstract class CToolChain extends PlatformObject { return command.replace("\"", "").split("\\s+"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } - public CBuildConfiguration getBuildConfiguration() { - return config; + public static String[] fixPaths(String[] command) { + for (int i = 0; i < command.length; ++i) { + if (command[i].indexOf('\\') >= 0) { + command[i] = command[i].replace('\\', '/'); + } + } + return command; } /** @@ -53,71 +82,40 @@ public abstract class CToolChain extends PlatformObject { } /** - * Scan the commandLine and save the scanner info for the resource being - * built, or if perProject is true, for all resources in the project. The - * buildFolder to help find the resource is where the command ran. + * Find the file mentioned in the command line. * * @param buildFolder * @param commandLine - * @throws CoreException + * @return the file in the command line or null if can't be found. */ - public void scanBuildOutput(IFolder buildFolder, String commandLine, boolean perProject) - throws CoreException { - // default, nothing + public IFile getResource(IFolder buildFolder, String[] commandLine) { + // default, not found + return null; } - protected void putScannerInfo(IResource resource, Map definedSymbols, - List includePaths, List macroFiles, List includeFiles, - List localIncludePath) throws CoreException { - if (scannerInfo == null) { - loadScannerInfo(); - } - scannerInfo.putScannerInfo(resource, new ToolChainScannerInfo(definedSymbols, includePaths, - macroFiles, includeFiles, localIncludePath)); - } - - protected void putScannerInfo(ILanguage language, Map definedSymbols, - List includePaths, List macroFiles, List includeFiles, - List localIncludePath) throws CoreException { - if (scannerInfo == null) { - loadScannerInfo(); - } - scannerInfo.putScannerInfo(language, new ToolChainScannerInfo(definedSymbols, includePaths, - macroFiles, includeFiles, localIncludePath)); - } - - private void loadScannerInfo() { - if (scannerInfo == null) { - scannerInfo = ScannerInfoData.load(this); - } + public IFile getResource(IFolder buildFolder, String commandLine) { + return getResource(buildFolder, splitCommand(commandLine)); } /** - * Return the scanner info for the given resource. + * Calculate the scanner info from the given command line * - * @param resource - * @return scanner info for the resource + * @param buildFolder + * @param commandLine + * @return scanner info, or null if can't be calculated * @throws CoreException */ - public IScannerInfo getScannerInfo(IResource resource) throws CoreException { - loadScannerInfo(); - return scannerInfo.getScannerInfo(resource); - } - - public void clearScannerInfo() throws CoreException { - if (scannerInfo == null) { - scannerInfo = new ScannerInfoData(); - scannerInfo.queueSave(); - } else { - scannerInfo.clear(); - } + public ExtendedScannerInfo getScannerInfo(IFolder buildFolder, List commandLine) + throws CoreException { + // default, null + return null; } /** * Return the console parsers to be used when this toolchain is being used * for a build. * - * @return console parsers + * @return console parsers, or null if there aren't any */ public CConsoleParser[] getConsoleParsers() { return null; diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/build/CToolChainManager.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/build/CToolChainManager.java new file mode 100644 index 00000000000..4ea9fe4c0b8 --- /dev/null +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/build/CToolChainManager.java @@ -0,0 +1,127 @@ +/******************************************************************************* + * Copyright (c) 2015 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ +package org.eclipse.cdt.core.build; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.cdt.core.CCorePlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.core.runtime.IExtension; +import org.eclipse.core.runtime.IExtensionPoint; +import org.eclipse.core.runtime.IExtensionRegistry; +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.core.runtime.preferences.ConfigurationScope; +import org.osgi.service.prefs.BackingStoreException; +import org.osgi.service.prefs.Preferences; + +/** + * Manager that manages the list of toolchains available. + * + * @since 5.12 + */ +public class CToolChainManager { + + private static final String TOOLCHAINS = "toolchains"; //$NON-NLS-1$ + + public static final CToolChainManager instance = new CToolChainManager(); + + private Map toolChainFamilies = new HashMap<>(); + private Map toolChains = new HashMap<>(); + + private CToolChainManager() { + new Job("Load toolchains") { + @Override + protected IStatus run(IProgressMonitor monitor) { + try { + // Load up the families + IExtensionRegistry registry = Platform.getExtensionRegistry(); + IExtensionPoint point = registry + .getExtensionPoint("org.eclipse.cdt.core.ToolChainFactory"); //$NON-NLS-1$ + for (IExtension extension : point.getExtensions()) { + for (IConfigurationElement element : extension.getConfigurationElements()) { + String family = element.getAttribute(CToolChain.FAMILY); + if (family != null) { + toolChainFamilies.put(family, element); + } + } + } + + // Load up the toolchains + Preferences toolChainsPref = getToolChainSettings(); + for (String toolChainId : toolChainsPref.childrenNames()) { + Preferences toolChainPref = toolChainsPref.node(toolChainId); + String family = toolChainPref.get(CToolChain.FAMILY, ""); //$NON-NLS-1$ + if (!family.isEmpty()) { + IConfigurationElement element = toolChainFamilies.get(family); + if (element != null) { + IToolChainFactory factory = (IToolChainFactory) element + .createExecutableExtension("class"); //$NON-NLS-1$ + CToolChain toolChain = factory.createToolChain(toolChainId, toolChainPref); + toolChains.put(toolChain.getName(), toolChain); + } + } + } + return Status.OK_STATUS; + } catch (BackingStoreException e) { + return new Status(IStatus.ERROR, CCorePlugin.PLUGIN_ID, "loading toolchains", e); + } catch (CoreException e) { + return e.getStatus(); + } + } + }.schedule(); + } + + private Preferences getToolChainSettings() { + return ConfigurationScope.INSTANCE.getNode(CCorePlugin.PLUGIN_ID).node(TOOLCHAINS); + } + + Preferences getSettings(String id) { + return getToolChainSettings().node(id); + } + + public Collection getToolChains() { + return toolChains.values(); + } + + public void addToolChain(CToolChain toolChain) throws CoreException { + // First find an open id for the toolchain + String id = null; + for (int i = 0; i < toolChains.size(); ++i) { + String istr = String.valueOf(i); + if (toolChains.containsKey(istr)) { + id = istr; + break; + } + } + + if (id == null) { + id = String.valueOf(toolChains.size()); + } + + toolChain.setId(id); + toolChains.put(id, toolChain); + + // save + try { + Preferences toolChainsPref = getToolChainSettings(); + toolChain.save(toolChainsPref.node(id)); + toolChainsPref.flush(); + } catch (BackingStoreException e) { + throw new CoreException( + new Status(IStatus.ERROR, CCorePlugin.PLUGIN_ID, "saving toolchain " + id, e)); + } + } + +} diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/build/IToolChainFactory.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/build/IToolChainFactory.java new file mode 100644 index 00000000000..ff310c718a5 --- /dev/null +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/build/IToolChainFactory.java @@ -0,0 +1,22 @@ +/******************************************************************************* + * Copyright (c) 2015 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ +package org.eclipse.cdt.core.build; + +import org.osgi.service.prefs.Preferences; + +/** + * @since 5.12 + */ +public interface IToolChainFactory { + + CToolChain createToolChain(String id, Preferences settings); + + default void discover() { + } + +} diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/build/GCCToolChain.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/build/gcc/GCCToolChain.java similarity index 58% rename from core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/build/GCCToolChain.java rename to core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/build/gcc/GCCToolChain.java index fcda887c2d9..5eefd9fbbdd 100644 --- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/build/GCCToolChain.java +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/build/gcc/GCCToolChain.java @@ -5,7 +5,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html *******************************************************************************/ -package org.eclipse.cdt.core.build; +package org.eclipse.cdt.core.build.gcc; import java.io.BufferedReader; import java.io.File; @@ -22,19 +22,17 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import org.eclipse.cdt.core.CCorePlugin; +import org.eclipse.cdt.core.build.CConsoleParser; +import org.eclipse.cdt.core.build.CToolChain; import org.eclipse.cdt.core.model.CoreModel; -import org.eclipse.cdt.core.model.ILanguage; -import org.eclipse.cdt.core.model.LanguageManager; +import org.eclipse.cdt.core.parser.ExtendedScannerInfo; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IMarker; -import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IAdapterFactory; import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Status; -import org.eclipse.core.runtime.content.IContentType; +import org.osgi.service.prefs.Preferences; /** * The GCC toolchain. Placing it in cdt.core for now. @@ -45,68 +43,60 @@ import org.eclipse.core.runtime.content.IContentType; */ public class GCCToolChain extends CToolChain { - public static final String ID = "org.eclipse.cdt.core.gcc"; //$NON-NLS-1$ - - public GCCToolChain(CBuildConfiguration config) { - super(config); + public GCCToolChain(String id, Preferences settings) { + super(id, settings); } - private static Map cache = new HashMap<>(); - - public static class Factory implements IAdapterFactory { - @SuppressWarnings("unchecked") - @Override - public T getAdapter(Object adaptableObject, Class adapterType) { - if (adapterType.equals(GCCToolChain.class) && adaptableObject instanceof CBuildConfiguration) { - CBuildConfiguration config = (CBuildConfiguration) adaptableObject; - GCCToolChain toolChain = cache.get(config); - if (toolChain == null) { - toolChain = new GCCToolChain(config); - cache.put(config, toolChain); - } - return (T) toolChain; - } - return null; - } - - @Override - public Class[] getAdapterList() { - return new Class[] { GCCToolChain.class }; - } + public GCCToolChain(String name) { + super(name); } @Override - public void scanBuildOutput(IFolder buildFolder, String commandLine, boolean perProject) - throws CoreException { - try { - if (Platform.getOS().equals(Platform.OS_WIN32)) { - // Need to flip over the slashes on Windows - commandLine = commandLine.replace('\\', '/'); + public String getFamily() { + return "GCC"; //$NON-NLS-1$ + } + + @Override + public IFile getResource(IFolder buildFolder, String[] commandLine) { + for (String arg : commandLine) { + if (!arg.startsWith("-")) { //$NON-NLS-1$ + // TODO optimize by dealing with multi arg options like -o + IFile file = buildFolder.getFile(arg); + if (file.exists() && CoreModel.isTranslationUnit(file)) { + return file; + } } - String[] command = splitCommand(commandLine); + } + + return null; + } + + @Override + public ExtendedScannerInfo getScannerInfo(IFolder buildFolder, List cmd) throws CoreException { + try { + String[] commandLine = cmd.toArray(new String[cmd.size()]); // Change output to stdout - for (int i = 0; i < command.length - 1; ++i) { - if (command[i].equals("-o")) { //$NON-NLS-1$ - command[i + 1] = "-"; //$NON-NLS-1$ + for (int i = 0; i < commandLine.length - 1; ++i) { + if (commandLine[i].equals("-o")) { //$NON-NLS-1$ + commandLine[i + 1] = "-"; //$NON-NLS-1$ break; } } // Change source file to a tmp file (needs to be empty) Path tmpFile = null; - IFile file = null; - for (int i = 1; i < command.length; ++i) { - if (!command[i].startsWith("-")) { //$NON-NLS-1$ + for (int i = 1; i < commandLine.length; ++i) { + if (!commandLine[i].startsWith("-")) { //$NON-NLS-1$ // TODO optimize by dealing with multi arg options like -o - IFile f = buildFolder.getFile(command[i]); - if (f.exists() && CoreModel.isTranslationUnit(f)) { + IFile file = buildFolder.getFile(commandLine[i]); + if (file.exists() && CoreModel.isTranslationUnit(file)) { // replace it with a temp file - Path parentPath = new File(((IFolder) f.getParent()).getLocationURI()).toPath(); + Path parentPath = new File(((IFolder) file.getParent()).getLocationURI()).toPath(); int n = 0; while (true) { - tmpFile = parentPath.resolve(".sc" + n + "." + f.getFileExtension()); //$NON-NLS-1$ //$NON-NLS-2$ - command[i] = tmpFile.toString(); + tmpFile = parentPath.resolve(".sc" + n + "." + file.getFileExtension()); //$NON-NLS-1$ //$NON-NLS-2$ + commandLine[i] = tmpFile.toString(); try { Files.createFile(tmpFile); break; @@ -115,26 +105,20 @@ public class GCCToolChain extends CToolChain { ++n; } } - file = f; break; } } } - if (file == null) { - // can't do much without the source file - CCorePlugin.log("No source file for scanner discovery"); //$NON-NLS-1$ - return; - } - // Add in the magic potion: -E -P -v -dD - String[] fullCmd = new String[command.length + 4]; - fullCmd[0] = command[0]; + String[] fullCmd = new String[commandLine.length + 4]; + fullCmd[0] = commandLine[0]; fullCmd[1] = "-E"; //$NON-NLS-1$ fullCmd[2] = "-P"; //$NON-NLS-1$ fullCmd[3] = "-v"; //$NON-NLS-1$ fullCmd[4] = "-dD"; //$NON-NLS-1$ - System.arraycopy(command, 1, fullCmd, 5, command.length - 1); + System.arraycopy(commandLine, 1, fullCmd, 5, commandLine.length - 1); + fixPaths(fullCmd); File buildDir = new File(buildFolder.getLocationURI()); Files.createDirectories(buildDir.toPath()); @@ -170,23 +154,9 @@ public class GCCToolChain extends CToolChain { } } - if (perProject) { - IProject project = buildFolder.getProject(); - IContentType contentType = CCorePlugin.getContentType(project, file.getName()); - if (contentType != null) { - ILanguage language = LanguageManager.getInstance().getLanguage(contentType, project); - putScannerInfo(language, symbols, includePath, null, null, null); - } - } else { - putScannerInfo(file, symbols, includePath, null, null, null); - } - - if (tmpFile != null) { - Files.delete(tmpFile); - } + return new ExtendedScannerInfo(symbols, includePath.toArray(new String[includePath.size()])); } catch (IOException e) { - throw new CoreException( - new Status(IStatus.ERROR, CCorePlugin.PLUGIN_ID, "Scanning build output", e)); //$NON-NLS-1$ + throw new CoreException(new Status(IStatus.ERROR, CCorePlugin.PLUGIN_ID, "scanner info", e)); //$NON-NLS-1$ } } diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/build/gcc/GCCToolChainFactory.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/build/gcc/GCCToolChainFactory.java new file mode 100644 index 00000000000..0309a44acc9 --- /dev/null +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/build/gcc/GCCToolChainFactory.java @@ -0,0 +1,121 @@ +/******************************************************************************* + * Copyright (c) 2015 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ +package org.eclipse.cdt.core.build.gcc; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.eclipse.cdt.core.build.CToolChain; +import org.eclipse.cdt.core.build.IToolChainFactory; +import org.osgi.service.prefs.Preferences; + +/** + * @since 5.12 + */ +public class GCCToolChainFactory implements IToolChainFactory { + + private static Pattern gccPattern = Pattern.compile("(.*-)?(gcc|g\\+\\+|clang|clang\\+\\+)(-[0-9].*)?"); //$NON-NLS-1$ + + /** + * Discover gcc installs that exist on the path. + */ + @Override + public void discover() { + String path = null; + for (Entry entry : System.getenv().entrySet()) { + if (entry.getKey().equalsIgnoreCase("PATH")) { //$NON-NLS-1$ + path = entry.getValue(); + break; + } + } + + if (path != null) { + Map> installs = new HashMap<>(); + + for (String dirStr : path.split(File.pathSeparator)) { + File dir = new File(dirStr); + for (String file : dir.list()) { + Matcher matcher = gccPattern.matcher(file); + if (matcher.matches()) { + String prefix = matcher.group(1); + String suffix = matcher.group(3); + String command = dirStr + File.separatorChar + file; + String version = getVersion(command); + if (version != null) { + List commands = installs.get(version); + if (commands == null) { + commands = new ArrayList<>(); + installs.put(version, commands); + } + commands.add(command); + } + } + } + } + + for (Entry> entry : installs.entrySet()) { + System.out.println(entry.getKey()); + for (String command : entry.getValue()) { + System.out.println("\t" + command); + } + } + } + } + + private static Pattern versionPattern = Pattern.compile(".*(gcc|LLVM) version .*"); //$NON-NLS-1$ + private static Pattern targetPattern = Pattern.compile("Target: (.*)"); //$NON-NLS-1$ + + private String getVersion(String command) { + try { + Process proc = new ProcessBuilder(new String[] { command, "-v" }).redirectErrorStream(true) //$NON-NLS-1$ + .start(); + String version = null; + String target = null; + try (BufferedReader reader = new BufferedReader(new InputStreamReader(proc.getInputStream()))) { + for (String line = reader.readLine(); line != null; line = reader.readLine()) { + Matcher versionMatcher = versionPattern.matcher(line); + if (versionMatcher.matches()) { + version = line.trim(); + continue; + } + Matcher targetMatcher = targetPattern.matcher(line); + if (targetMatcher.matches()) { + target = targetMatcher.group(1); + continue; + } + } + } + if (version != null) { + if (target != null) { + return version + " " + target; // $NON-NLS-1$ + } else { + return version; + } + } else { + return null; + } + } catch (IOException e) { + return null; + } + } + + @Override + public CToolChain createToolChain(String id, Preferences settings) { + return new GCCToolChain(id, settings); + } + +} diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/build/ScannerInfoData.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/build/ScannerInfoData.java index a9e2083a7b7..7da5ae3797d 100644 --- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/build/ScannerInfoData.java +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/build/ScannerInfoData.java @@ -21,9 +21,9 @@ import java.util.Set; import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.build.CBuildConfiguration; -import org.eclipse.cdt.core.build.CToolChain; import org.eclipse.cdt.core.model.ILanguage; import org.eclipse.cdt.core.model.LanguageManager; +import org.eclipse.cdt.core.parser.ExtendedScannerInfo; import org.eclipse.cdt.core.parser.IScannerInfo; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; @@ -33,6 +33,10 @@ import org.eclipse.core.runtime.content.IContentType; import com.google.gson.Gson; +/** + * Class representing scanner info data for a project as stored in the metadata + * area. + */ public class ScannerInfoData { private Set perResourceInfo; @@ -117,17 +121,16 @@ public class ScannerInfoData { queueSave(); } - public void putScannerInfo(ILanguage language, ToolChainScannerInfo info) { + public void putScannerInfo(ILanguage language, ExtendedScannerInfo info) { if (perLanguageInfo == null) { perLanguageInfo = new HashMap<>(); } - perLanguageInfo.put(language.getId(), info); + perLanguageInfo.put(language.getId(), new ToolChainScannerInfo(info)); queueSave(); } - public static ScannerInfoData load(CToolChain toolChain) { + public static ScannerInfoData load(CBuildConfiguration config) { IPath stateLoc = Platform.getStateLocation(CCorePlugin.getDefault().getBundle()); - CBuildConfiguration config = toolChain.getBuildConfiguration(); IPath scannerInfoPath = stateLoc.append(config.getProject().getName()) .append(config.getName() + ".scInfo"); //$NON-NLS-1$ File scannerInfoFile = scannerInfoPath.toFile(); diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/build/ToolChainScannerInfo.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/build/ToolChainScannerInfo.java index 0ee5c726d49..050991bcf22 100644 --- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/build/ToolChainScannerInfo.java +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/build/ToolChainScannerInfo.java @@ -10,7 +10,6 @@ package org.eclipse.cdt.internal.core.build; import java.util.Collection; import java.util.Collections; import java.util.HashSet; -import java.util.List; import java.util.Map; import java.util.Set; @@ -20,31 +19,27 @@ import org.eclipse.core.resources.IResource; public class ToolChainScannerInfo { private Map definedSymbols; - private List includePaths; - private List macroFiles; - private List includeFiles; - private List localIncludePath; + private String[] includePaths; + private String[] macroFiles; + private String[] includeFiles; + private String[] localIncludePath; private Set resourcePaths; private transient IScannerInfo scannerInfo; - public ToolChainScannerInfo(Map definedSymbols, List includePaths, - List macroFiles, List includeFiles, List localIncludePath) { - this.definedSymbols = definedSymbols; - this.includePaths = includePaths; - this.macroFiles = macroFiles; - this.includeFiles = includeFiles; - this.localIncludePath = localIncludePath; + public ToolChainScannerInfo(ExtendedScannerInfo scannerInfo) { + this.scannerInfo = scannerInfo; + this.definedSymbols = scannerInfo.getDefinedSymbols(); + this.includePaths = scannerInfo.getIncludePaths(); + this.macroFiles = scannerInfo.getMacroFiles(); + this.includeFiles = scannerInfo.getIncludeFiles(); + this.localIncludePath = scannerInfo.getLocalIncludePath(); } public IScannerInfo getScannerInfo() { if (scannerInfo == null) { - scannerInfo = new ExtendedScannerInfo(definedSymbols, - includePaths != null ? includePaths.toArray(new String[includePaths.size()]) : null, - macroFiles != null ? macroFiles.toArray(new String[includePaths.size()]) : null, - includeFiles != null ? includeFiles.toArray(new String[includePaths.size()]) : null, - localIncludePath != null ? localIncludePath.toArray(new String[includePaths.size()]) - : null); + scannerInfo = new ExtendedScannerInfo(definedSymbols, includePaths, macroFiles, includeFiles, + localIncludePath); } return scannerInfo; } diff --git a/qt/org.eclipse.cdt.qt.core/.classpath b/qt/org.eclipse.cdt.qt.core/.classpath index 27ef2aeea4f..9ace5bdb161 100644 --- a/qt/org.eclipse.cdt.qt.core/.classpath +++ b/qt/org.eclipse.cdt.qt.core/.classpath @@ -1,8 +1,8 @@ - - + + diff --git a/qt/org.eclipse.cdt.qt.core/.settings/org.eclipse.jdt.core.prefs b/qt/org.eclipse.cdt.qt.core/.settings/org.eclipse.jdt.core.prefs index f42de363afa..0c68a61dca8 100644 --- a/qt/org.eclipse.cdt.qt.core/.settings/org.eclipse.jdt.core.prefs +++ b/qt/org.eclipse.cdt.qt.core/.settings/org.eclipse.jdt.core.prefs @@ -1,7 +1,7 @@ eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7 -org.eclipse.jdt.core.compiler.compliance=1.7 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.compliance=1.8 org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -org.eclipse.jdt.core.compiler.source=1.7 +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/qt/org.eclipse.cdt.qt.core/META-INF/MANIFEST.MF b/qt/org.eclipse.cdt.qt.core/META-INF/MANIFEST.MF index 49518054b12..1c950642c58 100644 --- a/qt/org.eclipse.cdt.qt.core/META-INF/MANIFEST.MF +++ b/qt/org.eclipse.cdt.qt.core/META-INF/MANIFEST.MF @@ -11,8 +11,12 @@ Require-Bundle: org.eclipse.core.runtime, org.eclipse.cdt.core, org.eclipse.cdt.codan.core, org.eclipse.cdt.codan.core.cxx, - org.eclipse.core.filesystem -Bundle-RequiredExecutionEnvironment: JavaSE-1.7 + org.eclipse.core.filesystem, + org.eclipse.launchbar.core;bundle-version="1.0.1", + org.eclipse.remote.core;bundle-version="2.0.0", + org.eclipse.debug.core;bundle-version="3.10.0", + org.eclipse.cdt.debug.core +Bundle-RequiredExecutionEnvironment: JavaSE-1.8 Bundle-ActivationPolicy: lazy Bundle-Localization: plugin Export-Package: org.eclipse.cdt.internal.qt.core;x-friends:="org.eclipse.cdt.qt.ui,org.eclipse.cdt.qt.tests", diff --git a/qt/org.eclipse.cdt.qt.core/build.properties b/qt/org.eclipse.cdt.qt.core/build.properties index 9773163cbb8..f2748e1059a 100644 --- a/qt/org.eclipse.cdt.qt.core/build.properties +++ b/qt/org.eclipse.cdt.qt.core/build.properties @@ -5,7 +5,6 @@ bin.includes = META-INF/,\ plugin.xml,\ templates/,\ about.html,\ - plugin.properties,\ - libs/freemarker-2.3.22.jar + plugin.properties src.includes = about.html,\ schema/ diff --git a/qt/org.eclipse.cdt.qt.core/plugin.xml b/qt/org.eclipse.cdt.qt.core/plugin.xml index 6815519847a..b99dd5f513f 100644 --- a/qt/org.eclipse.cdt.qt.core/plugin.xml +++ b/qt/org.eclipse.cdt.qt.core/plugin.xml @@ -134,4 +134,54 @@ class="org.eclipse.cdt.internal.qt.core.build.QtBuilder"> + + + + + + + + + + + + + + + + + + + + + + + + + + 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 8b79e1c3729..5f07cca71d1 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 @@ -7,15 +7,40 @@ *******************************************************************************/ package org.eclipse.cdt.internal.qt.core.build; +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; +import java.util.HashSet; +import java.util.List; import java.util.Map; +import java.util.Set; +import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.build.CBuildConfiguration; +import org.eclipse.cdt.core.model.ILanguage; +import org.eclipse.cdt.core.model.LanguageManager; +import org.eclipse.cdt.core.parser.IScannerInfo; +import org.eclipse.cdt.internal.qt.core.QtPlugin; import org.eclipse.core.resources.IBuildConfiguration; +import org.eclipse.core.resources.IFolder; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IProjectDescription; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IAdapterFactory; +import org.eclipse.core.runtime.IProgressMonitor; public class QtBuildConfiguration extends CBuildConfiguration { + private QtInstall qtInstall; + private String launchMode; + private Map properties; + public QtBuildConfiguration(IBuildConfiguration config) { super(config); } @@ -46,4 +71,157 @@ public class QtBuildConfiguration extends CBuildConfiguration { } } + public static QtBuildConfiguration getConfig(IProject project, String os, String arch, String launchMode, + IProgressMonitor monitor) throws CoreException { + // return it if it exists already + for (IBuildConfiguration config : project.getBuildConfigs()) { + QtBuildConfiguration qtConfig = config.getAdapter(QtBuildConfiguration.class); + QtInstall qtInstall = qtConfig.getQtInstall(); + if (qtInstall != null && qtInstall.supports(os, arch) && launchMode.equals(qtConfig.getLaunchMode())) { + return qtConfig; + } + } + + // Nope, create it + for (QtInstall qtInstall : QtInstallManager.instance.getInstalls()) { + if (qtInstall.supports(os, arch)) { + Set configNames = new HashSet<>(); + for (IBuildConfiguration config : project.getBuildConfigs()) { + configNames.add(config.getName()); + } + String baseName = qtInstall.getSpec() + ":" + launchMode; //$NON-NLS-1$ + String newName = baseName; + int n = 0; + while (configNames.contains(newName)) { + newName = baseName + (++n); + } + configNames.add(newName); + IProjectDescription projectDesc = project.getDescription(); + projectDesc.setBuildConfigs(configNames.toArray(new String[configNames.size()])); + project.setDescription(projectDesc, monitor); + + QtBuildConfiguration qtConfig = project.getBuildConfig(newName).getAdapter(QtBuildConfiguration.class); + qtConfig.setup(qtInstall, launchMode); + return qtConfig; + } + } + return null; + } + + public QtInstall getQtInstall() { + if (qtInstall == null) { + // TODO set based on settings + } + return qtInstall; + } + + private String getLaunchMode() { + if (launchMode != null) { + // TODO set based on settings + } + return launchMode; + } + + private void setup(QtInstall qtInstall, String launchMode) { + this.qtInstall = qtInstall; + this.launchMode = launchMode; + // TODO save settings + } + + public String getQmakeCommand() { + return qtInstall.getQmakePath().toString(); + } + + 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 Path getProjectFile() { + File projectDir = getProject().getLocation().toFile(); + File[] proFiles = projectDir.listFiles((dir, name) -> name.endsWith(".pro")); //$NON-NLS-1$ + if (proFiles.length > 0) { + // TODO what if there are more than one. + return proFiles[0].toPath(); + } else { + return null; + } + } + + public IFolder getBuildFolder() { + return getProject().getFolder("build").getFolder(getBuildConfiguration().getName()); //$NON-NLS-1$ + } + + public Path getBuildDirectory() { + return getBuildFolder().getLocation().toFile().toPath(); + } + + public String getProperty(String key) { + if (properties == null) { + List cmd = new ArrayList<>(); + cmd.add(getQmakeCommand()); + cmd.add("-E"); //$NON-NLS-1$ + + String config = getQmakeConfig(); + if (config != null) { + cmd.add(config); + } + + cmd.add(getProjectFile().toString()); + + try { + Process proc = new ProcessBuilder(cmd).directory(getBuildDirectory().toFile()).start(); + try (BufferedReader reader = new BufferedReader(new InputStreamReader(proc.getInputStream()))) { + properties = new HashMap<>(); + for (String line = reader.readLine(); line != null; line = reader.readLine()) { + if (line.contains("=")) { //$NON-NLS-1$ + String[] parts = line.split("="); //$NON-NLS-1$ + if (parts.length == 2) { + properties.put(parts[0].trim(), parts[1].trim()); + } + } + } + } + } catch (IOException e) { + QtPlugin.log(e); + } + } + + return properties != null ? properties.get(key) : null; + } + + @Override + public IScannerInfo getScannerInfo(IResource resource) throws CoreException { + IScannerInfo info = super.getScannerInfo(resource); + if (info == null) { + List cmd = new ArrayList<>(); + cmd.add(getProperty("QMAKE_CXX")); //$NON-NLS-1$ + cmd.addAll(Arrays.asList(getProperty("QMAKE_CXXFLAGS").split(" "))); //$NON-NLS-1$ //$NON-NLS-2$ + + for (String include : getProperty("INCLUDEPATH").split(" ")) { //$NON-NLS-1$ //$NON-NLS-2$ + cmd.add("-I"); //$NON-NLS-1$ + cmd.add(include); + } + + cmd.add("-o"); //$NON-NLS-1$ + cmd.add("-"); //$NON-NLS-1$ + + // TODO need to make sure this path is valid + // The gcc toolchain uses IFile to make sure it exists + cmd.add(resource.getFullPath().toPortableString()); + + ILanguage language = LanguageManager.getInstance() + .getLanguage(CCorePlugin.getContentType(getProject(), resource.getName()), getProject()); // $NON-NLS-1$ + putScannerInfo(language, getToolChain().getScannerInfo(getBuildFolder(), cmd)); + } + return info; + } + } diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/build/QtBuilder.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/build/QtBuilder.java index 6050c620264..56c3d739553 100644 --- a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/build/QtBuilder.java +++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/build/QtBuilder.java @@ -9,10 +9,13 @@ package org.eclipse.cdt.internal.qt.core.build; import java.io.File; import java.io.IOException; +import java.util.ArrayList; +import java.util.List; import java.util.Map; import org.eclipse.cdt.core.build.IConsoleService; import org.eclipse.cdt.internal.qt.core.QtPlugin; +import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IProject; @@ -27,23 +30,30 @@ public class QtBuilder extends IncrementalProjectBuilder { public static final String ID = QtPlugin.ID + ".qtBuilder"; //$NON-NLS-1$ - private static final String qmake = "/Users/dschaefer/Qt/5.5/clang_64/bin/qmake"; //$NON-NLS-1$ - @Override protected IProject[] build(int kind, Map args, IProgressMonitor monitor) throws CoreException { IProject project = getProject(); try { IConsoleService console = QtPlugin.getService(IConsoleService.class); + QtBuildConfiguration qtConfig = getBuildConfig().getAdapter(QtBuildConfiguration.class); - IFolder buildFolder = project.getFolder("build"); //$NON-NLS-1$ - if (!buildFolder.exists()) { - buildFolder.create(IResource.FORCE | IResource.DERIVED, true, monitor); - } + IFolder buildFolder = qtConfig.getBuildFolder(); + createFolder(buildFolder, monitor); IFile makeFile = buildFolder.getFile("Makefile"); //$NON-NLS-1$ if (!makeFile.exists()) { // Need to run qmake - String[] command = new String[] { qmake, "../main.pro", "CONFIG+=debug" }; //$NON-NLS-1$ //$NON-NLS-2$ + List command = new ArrayList<>(); + command.add(qtConfig.getQmakeCommand()); + + String config = qtConfig.getQmakeConfig(); + if (config != null) { + command.add(config); + } + + IFile projectFile = qtConfig.getProject().getFile("main.pro"); + command.add(projectFile.getLocation().toOSString()); + Process process = new ProcessBuilder(command).directory(new File(buildFolder.getLocationURI())).start(); StringBuffer msg = new StringBuffer(); for (String arg : command) { @@ -56,6 +66,7 @@ public class QtBuilder extends IncrementalProjectBuilder { // run make Process process = new ProcessBuilder("make").directory(new File(buildFolder.getLocationURI())).start(); //$NON-NLS-1$ + console.writeOutput("make\n"); //$NON-NLS-1$ console.monitor(process, null, buildFolder); buildFolder.refreshLocal(IResource.DEPTH_INFINITE, monitor); @@ -65,4 +76,13 @@ public class QtBuilder extends IncrementalProjectBuilder { } } + private void createFolder(IFolder folder, IProgressMonitor monitor) throws CoreException { + IContainer parent = folder.getParent(); + if (!parent.exists()) { + createFolder((IFolder) parent, monitor); + } + if (!folder.exists()) { + folder.create(IResource.FORCE | IResource.DERIVED, true, monitor); + } + } } diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/build/QtInstall.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/build/QtInstall.java new file mode 100644 index 00000000000..ae4306aae51 --- /dev/null +++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/build/QtInstall.java @@ -0,0 +1,60 @@ +/******************************************************************************* + * Copyright (c) 2015 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ +package org.eclipse.cdt.internal.qt.core.build; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.file.Path; + +import org.eclipse.cdt.internal.qt.core.QtPlugin; +import org.eclipse.core.runtime.Platform; + +public class QtInstall { + + private final Path qmakePath; + private String spec; + + public QtInstall(Path qmakePath) { + this.qmakePath = qmakePath; + } + + public Path getQmakePath() { + return qmakePath; + } + + public Path getLibPath() { + return qmakePath.resolve("../lib"); //$NON-NLS-1$ + } + + public boolean supports(String os, String arch) { + switch (getSpec()) { + case "macx-clang": //$NON-NLS-1$ + return Platform.OS_MACOSX.equals(os) && Platform.ARCH_X86_64.equals(arch); + } + return false; + } + + public String getSpec() { + if (spec == null) { + try { + Process proc = new ProcessBuilder(getQmakePath().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) { + spec = line.trim(); + } + } + } catch (IOException e) { + QtPlugin.log(e); + } + } + return spec; + } + +} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/build/QtInstallManager.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/build/QtInstallManager.java new file mode 100644 index 00000000000..1074dc387e2 --- /dev/null +++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/build/QtInstallManager.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2015 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ +package org.eclipse.cdt.internal.qt.core.build; + +import java.io.File; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; + +public class QtInstallManager { + + public static final QtInstallManager instance = new QtInstallManager(); + + private List installs; + + public List getInstalls() { + if (installs == null) { + installs = new ArrayList<>(); + // TODO hack to get going + File qtDir = new File(System.getProperty("user.home"), "Qt/5.5"); + if (qtDir.isDirectory()) { + for (File dir : qtDir.listFiles()) { + Path qmakePath = dir.toPath().resolve("bin/qmake"); + if (qmakePath.toFile().canExecute()) { + installs.add(new QtInstall(qmakePath)); + } + } + } + } + + return installs; + } + +} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/build/QtScannerInfoProvider.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/build/QtScannerInfoProvider.java new file mode 100644 index 00000000000..e17d379b744 --- /dev/null +++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/build/QtScannerInfoProvider.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright (c) 2015 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ +package org.eclipse.cdt.internal.qt.core.build; + +import org.eclipse.cdt.core.parser.IScannerInfo; +import org.eclipse.cdt.core.parser.IScannerInfoChangeListener; +import org.eclipse.cdt.core.parser.IScannerInfoProvider; +import org.eclipse.cdt.internal.qt.core.QtPlugin; +import org.eclipse.core.resources.IBuildConfiguration; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.CoreException; + +public class QtScannerInfoProvider implements IScannerInfoProvider { + + @Override + public IScannerInfo getScannerInformation(IResource resource) { + try { + IProject project = resource.getProject(); + IBuildConfiguration config = project.getActiveBuildConfig(); + QtBuildConfiguration qtConfig = config.getAdapter(QtBuildConfiguration.class); + return qtConfig.getScannerInfo(resource); + } catch (CoreException e) { + QtPlugin.log(e); + return null; + } + } + + @Override + public void subscribe(IResource resource, IScannerInfoChangeListener listener) { + } + + @Override + public void unsubscribe(IResource resource, IScannerInfoChangeListener listener) { + } + +} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/launch/QtLaunchDescriptor.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/launch/QtLaunchDescriptor.java new file mode 100644 index 00000000000..9ff56e4c490 --- /dev/null +++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/launch/QtLaunchDescriptor.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * Copyright (c) 2015 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ +package org.eclipse.cdt.internal.qt.core.launch; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.PlatformObject; +import org.eclipse.launchbar.core.ILaunchDescriptor; +import org.eclipse.launchbar.core.ILaunchDescriptorType; + +public class QtLaunchDescriptor extends PlatformObject implements ILaunchDescriptor { + + private final QtLaunchDescriptorType type; + private final IProject project; + + public QtLaunchDescriptor(QtLaunchDescriptorType type, IProject project) { + this.type = type; + this.project = project; + } + + @Override + public String getName() { + return project.getName(); + } + + @Override + public ILaunchDescriptorType getType() { + return type; + } + + public IProject getProject() { + return project; + } + + @SuppressWarnings("unchecked") + @Override + public T getAdapter(Class adapter) { + if (adapter.equals(IProject.class)) { + return (T) project; + } else { + return super.getAdapter(adapter); + } + } + +} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/launch/QtLaunchDescriptorType.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/launch/QtLaunchDescriptorType.java new file mode 100644 index 00000000000..41f8cbdbe13 --- /dev/null +++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/launch/QtLaunchDescriptorType.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright (c) 2015 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ +package org.eclipse.cdt.internal.qt.core.launch; + +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.cdt.internal.qt.core.QtNature; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.launchbar.core.ILaunchDescriptor; +import org.eclipse.launchbar.core.ILaunchDescriptorType; + +public class QtLaunchDescriptorType implements ILaunchDescriptorType { + + private Map descriptors = new HashMap<>(); + + @Override + public ILaunchDescriptor getDescriptor(Object launchObject) throws CoreException { + // TODO also check to make sure it's an application project and not a library. + // qmake -E will give the TEMPLATE variable + if (launchObject instanceof IProject) { + IProject project = (IProject) launchObject; + if (QtNature.hasNature(project)) { + QtLaunchDescriptor desc = descriptors.get(project); + if (desc == null) { + desc = new QtLaunchDescriptor(this, project); + descriptors.put(project, desc); + } + return desc; + } + } + return null; + } + +} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/launch/QtLocalLaunchConfigProvider.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/launch/QtLocalLaunchConfigProvider.java new file mode 100644 index 00000000000..bceb0a7a841 --- /dev/null +++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/launch/QtLocalLaunchConfigProvider.java @@ -0,0 +1,106 @@ +/******************************************************************************* + * Copyright (c) 2015 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ +package org.eclipse.cdt.internal.qt.core.launch; + +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.debug.core.DebugPlugin; +import org.eclipse.debug.core.ILaunchConfiguration; +import org.eclipse.debug.core.ILaunchConfigurationType; +import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; +import org.eclipse.launchbar.core.AbstractLaunchConfigProvider; +import org.eclipse.launchbar.core.ILaunchDescriptor; +import org.eclipse.remote.core.IRemoteConnection; + +/** + * Launch config provider for Qt projects running on the Local connection. Simply uses the C++ Application launch config + * type. + */ +public class QtLocalLaunchConfigProvider extends AbstractLaunchConfigProvider { + + private static final String localConnectionTypeId = "org.eclipse.remote.LocalServices"; //$NON-NLS-1$ + + private Map configs = new HashMap<>(); + + @Override + public boolean supports(ILaunchDescriptor descriptor, IRemoteConnection target) throws CoreException { + return localConnectionTypeId.equals(target.getConnectionType().getId()); + } + + @Override + public ILaunchConfigurationType getLaunchConfigurationType(ILaunchDescriptor descriptor, IRemoteConnection target) + throws CoreException { + return DebugPlugin.getDefault().getLaunchManager() + .getLaunchConfigurationType(QtLocalRunLaunchConfigDelegate.TYPE_ID); + } + + @Override + public ILaunchConfiguration getLaunchConfiguration(ILaunchDescriptor descriptor, IRemoteConnection target) + throws CoreException { + ILaunchConfiguration config = configs.get(descriptor); + if (config == null) { + config = createLaunchConfiguration(descriptor, target); + configs.put(descriptor.getAdapter(IProject.class), config); + } + return config; + } + + @Override + protected void populateLaunchConfiguration(ILaunchDescriptor descriptor, IRemoteConnection target, + ILaunchConfigurationWorkingCopy workingCopy) throws CoreException { + super.populateLaunchConfiguration(descriptor, target, workingCopy); + + // Set the project and the connection + QtLaunchDescriptor qtDesc = (QtLaunchDescriptor) descriptor; + workingCopy.setMappedResources(new IResource[] { qtDesc.getProject() }); + } + + @Override + public boolean launchConfigurationAdded(ILaunchConfiguration configuration) throws CoreException { + if (ownsLaunchConfiguration(configuration)) { + + } + return false; + } + + @Override + public boolean launchConfigurationRemoved(ILaunchConfiguration configuration) throws CoreException { + for (Entry entry : configs.entrySet()) { + if (configuration.equals(entry.getValue())) { + configs.remove(entry.getKey()); + return true; + } + } + return false; + } + + @Override + public boolean launchConfigurationChanged(ILaunchConfiguration configuration) throws CoreException { + // TODO not sure I care + return false; + } + + @Override + public void launchDescriptorRemoved(ILaunchDescriptor descriptor) throws CoreException { + IProject project = descriptor.getAdapter(IProject.class); + if (project != null) { + configs.remove(project); + } + } + + @Override + public void launchTargetRemoved(IRemoteConnection target) throws CoreException { + // nothing to do since the Local connection can't be removed + } + +} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/launch/QtLocalRunLaunchConfigDelegate.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/launch/QtLocalRunLaunchConfigDelegate.java new file mode 100644 index 00000000000..88dabf5073a --- /dev/null +++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/launch/QtLocalRunLaunchConfigDelegate.java @@ -0,0 +1,112 @@ +/******************************************************************************* + * Copyright (c) 2015 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ +package org.eclipse.cdt.internal.qt.core.launch; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Path; +import java.util.Map; + +import org.eclipse.cdt.internal.qt.core.QtPlugin; +import org.eclipse.cdt.internal.qt.core.build.QtBuildConfiguration; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IFolder; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IProjectDescription; +import org.eclipse.core.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.debug.core.DebugPlugin; +import org.eclipse.debug.core.ILaunch; +import org.eclipse.debug.core.ILaunchConfiguration; +import org.eclipse.debug.core.model.LaunchConfigurationDelegate; + +public class QtLocalRunLaunchConfigDelegate extends LaunchConfigurationDelegate { + + public static final String TYPE_ID = QtPlugin.ID + ".launchConfigurationType"; //$NON-NLS-1$ + + @Override + public void launch(ILaunchConfiguration configuration, String mode, ILaunch launch, IProgressMonitor monitor) + throws CoreException { + new Job("Running Qt App") { + @Override + protected IStatus run(IProgressMonitor monitor) { + try { + QtBuildConfiguration qtBuildConfig = getQtBuildConfiguration(configuration, mode, monitor); + + // get the executable + IFolder buildFolder = qtBuildConfig.getBuildFolder(); + // 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 + IFolder appFolder = buildFolder.getFolder("main.app"); + IFolder contentsFolder = appFolder.getFolder("Contents"); + IFolder macosFolder = contentsFolder.getFolder("MacOS"); + IFile exeFile = macosFolder.getFile("main"); + + ProcessBuilder builder = new ProcessBuilder(exeFile.getLocation().toFile().getAbsolutePath()) + .directory(qtBuildConfig.getProject().getLocation().toFile()); + + // need to add the Qt libraries to the env + Map env = builder.environment(); + String libPathEnv = env.get("DYLD_LIBRARY_PATH"); + Path libPath = qtBuildConfig.getQtInstall().getLibPath(); + if (libPathEnv == null) { + libPathEnv = libPath.toString(); + } else { + libPathEnv = libPath.toString() + File.pathSeparator + libPathEnv; + } + env.put("DYLD_LIBRARY_PATH", libPathEnv); + + Process process = builder.start(); + DebugPlugin.newProcess(launch, process, "main.app"); + } catch (IOException e) { + return new Status(IStatus.ERROR, QtPlugin.ID, "running", e); + } catch (CoreException e) { + return e.getStatus(); + } + return Status.OK_STATUS; + } + }.schedule(); + } + + @Override + public boolean buildForLaunch(ILaunchConfiguration configuration, String mode, IProgressMonitor monitor) + throws CoreException { + QtBuildConfiguration qtBuildConfig = getQtBuildConfiguration(configuration, mode, monitor); + + // Set it as active + IProject project = qtBuildConfig.getProject(); + IProjectDescription desc = project.getDescription(); + desc.setActiveBuildConfig(qtBuildConfig.getBuildConfiguration().getName()); + project.setDescription(desc, monitor); + + // And build + return super.buildForLaunch(configuration, mode, monitor); + } + + @Override + protected IProject[] getBuildOrder(ILaunchConfiguration configuration, String mode) throws CoreException { + // 1. Extract project from configuration + // TODO dependencies too. + IProject project = configuration.getMappedResources()[0].getProject(); + return new IProject[] { project }; + } + + private QtBuildConfiguration getQtBuildConfiguration(ILaunchConfiguration configuration, String mode, + IProgressMonitor monitor) throws CoreException { + // Find the Qt build config + IProject project = configuration.getMappedResources()[0].getProject(); + String os = Platform.getOS(); + String arch = Platform.getOSArch(); + return QtBuildConfiguration.getConfig(project, os, arch, mode, monitor); + } + +} diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.core/plugin.xml b/toolchains/arduino/org.eclipse.cdt.arduino.core/plugin.xml index 170aa8240e1..ae405304997 100644 --- a/toolchains/arduino/org.eclipse.cdt.arduino.core/plugin.xml +++ b/toolchains/arduino/org.eclipse.cdt.arduino.core/plugin.xml @@ -108,4 +108,11 @@ + + + + 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 030dbd88c74..e2483f6ebcd 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 @@ -208,6 +208,23 @@ public class ArduinoManager { return null; } + public ArduinoTool getLatestTool(String packageName, String toolName) { + for (PackageIndex index : packageIndices) { + ArduinoPackage pkg = index.getPackage(packageName); + if (pkg != null) { + ArduinoTool latestTool = null; + for (ArduinoTool tool : pkg.getTools()) { + if (tool.getName().equals(toolName)) { + if (latestTool == null || compareVersions(latestTool.getVersion(), tool.getVersion()) > 1) { + latestTool = tool; + } + } + } + } + } + return null; + } + private static final String LIBRARIES = "libraries"; //$NON-NLS-1$ private IEclipsePreferences getSettings(IProject project) { @@ -378,4 +395,49 @@ public class ArduinoManager { return perms; } + public static int compareVersions(String version1, String version2) { + if (version1 == null) { + return version2 == null ? 0 : -1; + } + + if (version2 == null) { + return 1; + } + + String[] v1 = version1.split("\\."); //$NON-NLS-1$ + String[] v2 = version2.split("\\."); //$NON-NLS-1$ + for (int i = 0; i < Math.max(v1.length, v2.length); ++i) { + if (v1.length <= i) { + return v2.length < i ? 0 : -1; + } + + if (v2.length <= i) { + return 1; + } + + try { + int vi1 = Integer.parseInt(v1[i]); + int vi2 = Integer.parseInt(v2[i]); + if (vi1 < vi2) { + return -1; + } + + if (vi1 > vi2) { + return 1; + } + } catch (NumberFormatException e) { + // not numbers, do string compares + int c = v1[i].compareTo(v2[i]); + if (c < 0) { + return -1; + } + if (c > 0) { + return 1; + } + } + } + + return 0; + } + } 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 39f8329ea98..1fce5bac8af 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 @@ -72,7 +72,7 @@ public class ArduinoPackage { Map platformMap = new HashMap<>(); for (ArduinoPlatform platform : platforms) { ArduinoPlatform p = platformMap.get(platform.getName()); - if (p == null || compareVersions(platform.getVersion(), p.getVersion()) > 0) { + if (p == null || ArduinoManager.compareVersions(platform.getVersion(), p.getVersion()) > 0) { platformMap.put(platform.getName(), platform); } } @@ -84,7 +84,7 @@ public class ArduinoPackage { for (ArduinoPlatform platform : platforms) { if (platform.isInstalled()) { ArduinoPlatform p = platformMap.get(platform.getName()); - if (p == null || compareVersions(platform.getVersion(), p.getVersion()) > 0) { + if (p == null || ArduinoManager.compareVersions(platform.getVersion(), p.getVersion()) > 0) { platformMap.put(platform.getName(), platform); } } @@ -92,52 +92,6 @@ public class ArduinoPackage { return Collections.unmodifiableCollection(platformMap.values()); } - // TODO move somewhere. - public static int compareVersions(String version1, String version2) { - if (version1 == null) { - return version2 == null ? 0 : -1; - } - - if (version2 == null) { - return 1; - } - - String[] v1 = version1.split("\\."); //$NON-NLS-1$ - String[] v2 = version2.split("\\."); //$NON-NLS-1$ - for (int i = 0; i < Math.max(v1.length, v2.length); ++i) { - if (v1.length <= i) { - return v2.length < i ? 0 : -1; - } - - if (v2.length <= i) { - return 1; - } - - try { - int vi1 = Integer.parseInt(v1[i]); - int vi2 = Integer.parseInt(v2[i]); - if (vi1 < vi2) { - return -1; - } - - if (vi1 > vi2) { - return 1; - } - } catch (NumberFormatException e) { - // not numbers, do string compares - int c = v1[i].compareTo(v2[i]); - if (c < 0) { - return -1; - } - if (c > 0) { - return 1; - } - } - } - - return 0; - } - public ArduinoPlatform getPlatform(String name) { ArduinoPlatform foundPlatform = null; for (ArduinoPlatform platform : platforms) { @@ -146,7 +100,7 @@ public class ArduinoPackage { foundPlatform = platform; } else { if (platform.isInstalled() - && compareVersions(platform.getVersion(), foundPlatform.getVersion()) > 0) { + && ArduinoManager.compareVersions(platform.getVersion(), foundPlatform.getVersion()) > 0) { foundPlatform = platform; } } @@ -168,6 +122,19 @@ public class ArduinoPackage { return null; } + public ArduinoTool getLatestTool(String toolName) { + ArduinoTool latestTool = null; + for (ArduinoTool tool : tools) { + if (tool.getName().equals(toolName)) { + if (latestTool == null + || ArduinoManager.compareVersions(tool.getVersion(), latestTool.getVersion()) > 0) { + latestTool = tool; + } + } + } + return latestTool; + } + @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/LibraryIndex.java b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/LibraryIndex.java index a0bbef428ca..3747d1442ef 100644 --- a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/LibraryIndex.java +++ b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/LibraryIndex.java @@ -36,7 +36,7 @@ public class LibraryIndex { ArduinoLibrary current = latestLibs.get(name); if (current != null) { - if (ArduinoPackage.compareVersions(library.getVersion(), current.getVersion()) > 0) { + if (ArduinoManager.compareVersions(library.getVersion(), current.getVersion()) > 0) { latestLibs.put(name, library); } } else { 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 91ef2068ee6..7a2a1eb861e 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 @@ -10,7 +10,9 @@ package org.eclipse.cdt.arduino.core.internal.build; import java.io.File; import java.io.FilenameFilter; import java.nio.file.Path; +import java.nio.file.Paths; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; @@ -32,7 +34,7 @@ import org.eclipse.cdt.arduino.core.internal.board.ToolDependency; import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.build.CBuildConfiguration; import org.eclipse.cdt.core.build.CToolChain; -import org.eclipse.cdt.core.build.GCCToolChain; +import org.eclipse.cdt.core.build.CToolChainManager; import org.eclipse.cdt.core.model.CoreModel; import org.eclipse.cdt.core.model.ICProject; import org.eclipse.cdt.core.model.IOutputEntry; @@ -69,16 +71,6 @@ public class ArduinoBuildConfiguration extends CBuildConfiguration { private ArduinoBuildConfiguration(IBuildConfiguration config) { super(config); - - try { - if (getToolChain() == null) { - // For now, assume GCC is the toolchain, - // not sure it's ever not. - setToolChain(GCCToolChain.ID); - } - } catch (CoreException e) { - Activator.log(e); - } } private static Map cache = new HashMap<>(); @@ -438,6 +430,41 @@ public class ArduinoBuildConfiguration extends CBuildConfiguration { } } + @Override + public CToolChain getToolChain() throws CoreException { + CToolChain toolChain = super.getToolChain(); + if (toolChain == null) { + // figure out which one it is + ArduinoPlatform platform = board.getPlatform(); + String compilerPath = resolveProperty("compiler.path", platform.getPlatformProperties()); //$NON-NLS-1$ + if (compilerPath != null) { + // TODO what if it is null? + Path path = Paths.get(compilerPath); + for (ToolDependency toolDep : platform.getToolsDependencies()) { + ArduinoTool tool = toolDep.getTool(); + if (path.startsWith(tool.getInstallPath())) { + // this is it, find the matching + for (CToolChain tc : CToolChainManager.instance.getToolChains()) { + if (tc instanceof ArduinoGCCToolChain) { + if (((ArduinoGCCToolChain) tc).getTool().equals(tool)) { + setToolChain(tc); + toolChain = tc; + break; + } + } + } + // not found, create + toolChain = new ArduinoGCCToolChain(tool); + CToolChainManager.instance.addToolChain(toolChain); + setToolChain(toolChain); + break; + } + } + } + } + return toolChain; + } + public IScannerInfo getScannerInfo(IResource resource) throws CoreException { IScannerInfo info = super.getScannerInfo(resource); if (info == null) { @@ -473,8 +500,8 @@ public class ArduinoBuildConfiguration extends CBuildConfiguration { } properties.put("includes", includes); //$NON-NLS-1$ - getToolChain().scanBuildOutput(getBuildFolder(), resolveProperty(recipe, properties), true); - info = super.getScannerInfo(resource); + List cmd = Arrays.asList(resolveProperty(recipe, properties).split(" ")); //$NON-NLS-1$ + info = getToolChain().getScannerInfo(getBuildFolder(), cmd); } return info; } diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/build/ArduinoGCCToolChain.java b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/build/ArduinoGCCToolChain.java new file mode 100644 index 00000000000..7670e100830 --- /dev/null +++ b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/build/ArduinoGCCToolChain.java @@ -0,0 +1,64 @@ +/******************************************************************************* + * Copyright (c) 2015 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ +package org.eclipse.cdt.arduino.core.internal.build; + +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.ArduinoTool; +import org.eclipse.cdt.core.build.CToolChain; +import org.eclipse.cdt.core.build.IToolChainFactory; +import org.eclipse.cdt.core.build.gcc.GCCToolChain; +import org.osgi.service.prefs.Preferences; + +public class ArduinoGCCToolChain extends GCCToolChain { + + private static final String PACKAGE = "arduinoPackage"; //$NON-NLS-1$ + private static final String TOOL = "arduinoTool"; //$NON-NLS-1$ + + private final ArduinoTool tool; + + public ArduinoGCCToolChain(String id, Preferences settings) { + super(id, settings); + ArduinoPackage pkg = ArduinoManager.instance.getPackage(settings.get(PACKAGE, "")); //$NON-NLS-1$ + if (pkg != null) { + this.tool = pkg.getLatestTool(settings.get(TOOL, "")); //$NON-NLS-1$ + } else { + // TODO where did it go? + this.tool = null; + } + } + + public ArduinoGCCToolChain(ArduinoTool tool) { + super(tool.getName()); + this.tool = tool; + } + + public static class ArduinoFactory implements IToolChainFactory { + @Override + public CToolChain createToolChain(String id, Preferences settings) { + return new ArduinoGCCToolChain(id, settings); + } + } + + @Override + public String getFamily() { + return "Arduino GCC"; //$NON-NLS-1$ + } + + public ArduinoTool getTool() { + return tool; + } + + @Override + public void save(Preferences settings) { + super.save(settings); + settings.put(TOOL, tool.getName()); + settings.put(PACKAGE, tool.getPackage().getName()); + } + +}