package io.sloeber.core.toolchain; import java.util.ArrayList; import java.util.List; import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.envvar.IEnvironmentVariable; import org.eclipse.cdt.core.envvar.IEnvironmentVariableManager; import org.eclipse.cdt.core.language.settings.providers.ILanguageSettingsEditableProvider; import org.eclipse.cdt.core.language.settings.providers.IWorkingDirectoryTracker; import org.eclipse.cdt.core.model.CoreModel; import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; import org.eclipse.cdt.core.settings.model.ICProjectDescription; import org.eclipse.cdt.core.settings.model.ICSettingEntry; import org.eclipse.cdt.managedbuilder.core.ManagedBuilderCorePlugin; import org.eclipse.cdt.managedbuilder.language.settings.providers.ToolchainBuiltinSpecsDetector; import org.eclipse.core.resources.IFolder; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import io.sloeber.core.common.Common; import io.sloeber.core.common.Const; @SuppressWarnings("nls") public class ArduinoLanguageProvider extends ToolchainBuiltinSpecsDetector implements ILanguageSettingsEditableProvider { // ID must match the tool-chain definition in // org.eclipse.cdt.managedbuilder.core.buildDefinitions extension point private static final String GCC_TOOLCHAIN_ID = "cdt.managedbuild.toolchain.gnu.base"; //$NON-NLS-1$ private enum State { NONE, EXPECTING_LOCAL_INCLUDE, EXPECTING_SYSTEM_INCLUDE, EXPECTING_FRAMEWORKS } private State state = State.NONE; private static final AbstractOptionParser[] optionParsers = { new IncludePathOptionParser("#include \"(\\S.*)\"", "$1", //$NON-NLS-1$ //$NON-NLS-2$ ICSettingEntry.BUILTIN | ICSettingEntry.READONLY | ICSettingEntry.LOCAL), new IncludePathOptionParser("#include <(\\S.*)>", "$1", ICSettingEntry.BUILTIN | ICSettingEntry.READONLY), //$NON-NLS-1$ //$NON-NLS-2$ new IncludePathOptionParser("#framework <(\\S.*)>", "$1", //$NON-NLS-1$ //$NON-NLS-2$ ICSettingEntry.BUILTIN | ICSettingEntry.READONLY | ICSettingEntry.FRAMEWORKS_MAC), new MacroOptionParser("#define\\s+(\\S*\\(.*?\\))\\s*(.*)", "$1", "$2", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ ICSettingEntry.BUILTIN | ICSettingEntry.READONLY), new MacroOptionParser("#define\\s+(\\S*)\\s*(\\S*)", "$1", "$2", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ ICSettingEntry.BUILTIN | ICSettingEntry.READONLY), }; @Override public String getToolchainId() { return GCC_TOOLCHAIN_ID; } @Override protected AbstractOptionParser[] getOptionParsers() { return optionParsers; } /** * Create a list from one item. */ private static List<String> makeList(String line) { List<String> list = new ArrayList<>(); list.add(line); return list; } @Override protected List<String> parseOptions(String lineIn) { String line = lineIn.trim(); // contribution of -dD option if (line.startsWith("#define")) { //$NON-NLS-1$ return makeList(line); } // contribution of includes if (line.equals("#include \"...\" search starts here:")) { //$NON-NLS-1$ this.state = State.EXPECTING_LOCAL_INCLUDE; } else if (line.equals("#include <...> search starts here:")) { //$NON-NLS-1$ this.state = State.EXPECTING_SYSTEM_INCLUDE; } else if (line.startsWith("End of search list.")) { //$NON-NLS-1$ this.state = State.NONE; } else if (line.equals("Framework search starts here:")) { //$NON-NLS-1$ this.state = State.EXPECTING_FRAMEWORKS; } else if (line.startsWith("End of framework search list.")) { //$NON-NLS-1$ this.state = State.NONE; } else if (this.state == State.EXPECTING_LOCAL_INCLUDE) { // making that up for the parser to figure out line = "#include \"" + line + "\""; //$NON-NLS-1$ //$NON-NLS-2$ return makeList(line); } else { String frameworkIndicator = "(framework directory)"; //$NON-NLS-1$ if (this.state == State.EXPECTING_SYSTEM_INCLUDE) { // making that up for the parser to figure out if (line.contains(frameworkIndicator)) { line = "#framework <" + line.replace(frameworkIndicator, "").trim() + ">"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } else { line = "#include <" + line + ">"; //$NON-NLS-1$ //$NON-NLS-2$ } return makeList(line); } else if (this.state == State.EXPECTING_FRAMEWORKS) { // making that up for the parser to figure out line = "#framework <" + line.replace(frameworkIndicator, "").trim() + ">"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ return makeList(line); } } return null; } @Override public void startup(ICConfigurationDescription cfgDescription, IWorkingDirectoryTracker cwdTracker1) throws CoreException { super.startup(cfgDescription, cwdTracker1); this.state = State.NONE; } @Override public void shutdown() { this.state = State.NONE; super.shutdown(); } @Override public ArduinoLanguageProvider cloneShallow() throws CloneNotSupportedException { return (ArduinoLanguageProvider) super.cloneShallow(); } @Override public ArduinoLanguageProvider clone() throws CloneNotSupportedException { return (ArduinoLanguageProvider) super.clone(); } @Override protected String getCompilerCommand(String languageId) { String compilerCommand = new String(); ICProjectDescription prjDesc = CoreModel.getDefault().getProjectDescription(this.currentProject); if (prjDesc == null) return compilerCommand; IEnvironmentVariableManager envManager = CCorePlugin.getDefault().getBuildEnvironmentManager(); ICConfigurationDescription confDesc = prjDesc.getActiveConfiguration(); // Bug fix for CDT 8.1 fixed in 8.2 IFolder buildFolder = this.currentProject.getFolder(confDesc.getName()); if (!buildFolder.exists()) { try { buildFolder.create(true, true, null); } catch (CoreException e) { Common.log(new Status(IStatus.ERROR, Const.CORE_PLUGIN_ID, "failed to create folder " + confDesc.getName(), e)); } } // End of Bug fix for CDT 8.1 fixed in 8.2 String recipeKey = new String(); String OptionKey = new String(); if (languageId.equals("org.eclipse.cdt.core.gcc")) { recipeKey = Common.get_ENV_KEY_RECIPE(Const.ACTION_C_to_O); OptionKey = Const.ENV_KEY_JANTJE_ADDITIONAL_C_COMPILE_OPTIONS; } else if (languageId.equals("org.eclipse.cdt.core.g++")) { recipeKey = Common.get_ENV_KEY_RECIPE(Const.ACTION_CPP_to_O); OptionKey = Const.ENV_KEY_JANTJE_ADDITIONAL_CPP_COMPILE_OPTIONS; } else { ManagedBuilderCorePlugin.error( "Unable to find compiler command for language " + languageId + " in toolchain=" + getToolchainId()); } try { compilerCommand = envManager.getVariable(recipeKey + Const.DOT + "1", confDesc, true).getValue(); compilerCommand = compilerCommand + envManager.getVariable(recipeKey + Const.DOT + "2", confDesc, true).getValue(); compilerCommand = compilerCommand + envManager.getVariable(recipeKey + Const.DOT + "3", confDesc, true).getValue(); } catch (Exception e) { compilerCommand = new String(); } IEnvironmentVariable op1 = envManager.getVariable(Const.ENV_KEY_JANTJE_ADDITIONAL_COMPILE_OPTIONS, confDesc, true); IEnvironmentVariable op2 = envManager.getVariable(OptionKey, confDesc, true); if (op1 != null) { compilerCommand = compilerCommand + ' ' + op1.getValue(); } if (op2 != null) { compilerCommand = compilerCommand + ' ' + op2.getValue(); } return compilerCommand.replaceAll(" -o ", " "); } }