diff --git a/cmake/org.eclipse.cdt.cmake.is.core/src/main/java/org/eclipse/cdt/cmake/is/core/builtins/GccOutputProcessor.java b/cmake/org.eclipse.cdt.cmake.is.core/src/main/java/org/eclipse/cdt/cmake/is/core/builtins/GccOutputProcessor.java index a912187b464..f8dd7c11b15 100644 --- a/cmake/org.eclipse.cdt.cmake.is.core/src/main/java/org/eclipse/cdt/cmake/is/core/builtins/GccOutputProcessor.java +++ b/cmake/org.eclipse.cdt.cmake.is.core/src/main/java/org/eclipse/cdt/cmake/is/core/builtins/GccOutputProcessor.java @@ -13,6 +13,7 @@ import java.util.Optional; import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.eclipse.cdt.cmake.is.core.IRawIndexerInfoCollector; import org.eclipse.cdt.core.settings.model.ICLanguageSettingEntry; import org.eclipse.cdt.core.settings.model.ICSettingEntry; import org.eclipse.cdt.core.settings.model.util.CDataUtil; @@ -37,7 +38,7 @@ public class GccOutputProcessor implements IBuiltinsOutputProcessor { new OutputLineProcessor(" *(\\S.*)", 1, -1, true, 0) }; @SuppressWarnings("nls") - private static final OutputLineProcessor[] framewotks = { + private static final OutputLineProcessor[] frameworks = { new OutputLineProcessor(" *(\\S.*)", 1, -1, true, ICSettingEntry.FRAMEWORKS_MAC) }; private State state = State.NONE; @@ -49,7 +50,7 @@ public class GccOutputProcessor implements IBuiltinsOutputProcessor { @SuppressWarnings("nls") @Override - public void processLine(String line, IProcessingContext processingContext) { + public void processLine(String line, IRawIndexerInfoCollector infoCollector) { // include paths if (line.equals("#include \"...\" search starts here:")) { @@ -74,7 +75,7 @@ public class GccOutputProcessor implements IBuiltinsOutputProcessor { for (OutputLineProcessor processor : localIncludes) { Optional result = processor.process(line); if (result.isPresent()) { - processingContext.addSettingEntry(result.get()); + infoCollector.addIncludePath(result.get().getName()); return; // line matched } } @@ -82,15 +83,16 @@ public class GccOutputProcessor implements IBuiltinsOutputProcessor { for (OutputLineProcessor processor : systemIncludes) { Optional result = processor.process(line); if (result.isPresent()) { - processingContext.addSettingEntry(result.get()); + infoCollector.addSystemIncludePath(result.get().getName()); return; // line matched } } } else if (state == State.EXPECTING_FRAMEWORK) { - for (OutputLineProcessor processor : framewotks) { + for (OutputLineProcessor processor : frameworks) { Optional result = processor.process(line); if (result.isPresent()) { - processingContext.addSettingEntry(result.get()); + // IExtendedScannerInfo has no mean to specify ICSettingEntry.FRAMEWORKS_MAC + // infoCollector.addSettingEntry(result.get()); return; // line matched } } @@ -99,11 +101,12 @@ public class GccOutputProcessor implements IBuiltinsOutputProcessor { for (OutputLineProcessor processor : macros) { Optional result = processor.process(line); if (result.isPresent()) { - processingContext.addSettingEntry(result.get()); + ICLanguageSettingEntry settingEntry = result.get(); + infoCollector.addDefine(settingEntry.getName(), settingEntry.getValue()); return; // line matched } } - // System.err.println("NO MATCH ON LINE: '" + line + "'"); + // System.err.println("NO MATCH ON LINE: '" + line + "'"); } } diff --git a/cmake/org.eclipse.cdt.cmake.is.core/src/main/java/org/eclipse/cdt/cmake/is/core/builtins/IBuiltinsDetectionBehavior.java b/cmake/org.eclipse.cdt.cmake.is.core/src/main/java/org/eclipse/cdt/cmake/is/core/builtins/IBuiltinsDetectionBehavior.java index bf71bddc4f3..ee5cbb20c17 100644 --- a/cmake/org.eclipse.cdt.cmake.is.core/src/main/java/org/eclipse/cdt/cmake/is/core/builtins/IBuiltinsDetectionBehavior.java +++ b/cmake/org.eclipse.cdt.cmake.is.core/src/main/java/org/eclipse/cdt/cmake/is/core/builtins/IBuiltinsDetectionBehavior.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2019 Martin Weber. + * Copyright (c) 2019-2020 Martin Weber. * * Content is provided to you under the terms and conditions of the Eclipse Public License Version 2.0 "EPL". * A copy of the EPL is available at http://www.eclipse.org/legal/epl-2.0. @@ -36,15 +36,4 @@ public interface IBuiltinsDetectionBehavior { * cases, most implementations, should return {@code false} here. */ boolean suppressErrormessage(); - - /** - * Gets the filename extension for the input file. An empty input file will be - * created and its name will be given on the command-line when the compiler is - * invoked for built-ins detection. - * - * @param languageID the language ID - * @return the filename extension or {@code null} if no filename argument needs - * to be given for built-ins detection - */ - String getInputFileExtension(String languageID); } diff --git a/cmake/org.eclipse.cdt.cmake.is.core/src/main/java/org/eclipse/cdt/cmake/is/core/builtins/IBuiltinsOutputProcessor.java b/cmake/org.eclipse.cdt.cmake.is.core/src/main/java/org/eclipse/cdt/cmake/is/core/builtins/IBuiltinsOutputProcessor.java index ef9c869e9f8..9d70e293dcf 100644 --- a/cmake/org.eclipse.cdt.cmake.is.core/src/main/java/org/eclipse/cdt/cmake/is/core/builtins/IBuiltinsOutputProcessor.java +++ b/cmake/org.eclipse.cdt.cmake.is.core/src/main/java/org/eclipse/cdt/cmake/is/core/builtins/IBuiltinsOutputProcessor.java @@ -9,9 +9,7 @@ package org.eclipse.cdt.cmake.is.core.builtins; -import java.util.List; - -import org.eclipse.cdt.core.settings.model.ICLanguageSettingEntry; +import org.eclipse.cdt.cmake.is.core.IRawIndexerInfoCollector; /** * Responsible for parsing the output that is produced when a compiler is @@ -23,39 +21,9 @@ public interface IBuiltinsOutputProcessor { * Parsers the given line from the compiler output and places each * ICLanguageSettingEntry found in the given {@code IProcessingContext}. * - * @param line a line from the compiler output to parse - * @param processingContext the buffer that receives the new - * {@code LanguageSetting} entries + * @param line a line from the compiler output to parse + * @param infoCollector the buffer that receives the new {@code LanguageSetting} + * entries */ - void processLine(String line, IProcessingContext processingContext); - - /** - * Gathers the results of argument parsing. - * - * @author Martin Weber - */ - public interface IProcessingContext { - /** - * Adds a ICLanguageSettingEntry to the result list. - * - * @param entry the entry to add to the result list - */ - void addSettingEntry(ICLanguageSettingEntry entry); - } // IProcessingContext - - /** - * The result of processing the complete compiler output. - * - * @author Martin Weber - * - * @see IBuiltinsOutputProcessor#processLine(String, IProcessingContext) - */ - public interface IResult { - /** - * Gets the language setting entries produced during processing. - * - * @return the language setting entries - */ - List getSettingEntries(); - } // IResult + void processLine(String line, IRawIndexerInfoCollector infoCollector); } diff --git a/cmake/org.eclipse.cdt.cmake.is.core/src/main/java/org/eclipse/cdt/cmake/is/core/builtins/OutputSniffer.java b/cmake/org.eclipse.cdt.cmake.is.core/src/main/java/org/eclipse/cdt/cmake/is/core/builtins/OutputSniffer.java index e627ce5313c..cbeac2def81 100644 --- a/cmake/org.eclipse.cdt.cmake.is.core/src/main/java/org/eclipse/cdt/cmake/is/core/builtins/OutputSniffer.java +++ b/cmake/org.eclipse.cdt.cmake.is.core/src/main/java/org/eclipse/cdt/cmake/is/core/builtins/OutputSniffer.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2018-2019 Martin Weber. + * Copyright (c) 2018-2020 Martin Weber. * * Content is provided to you under the terms and conditions of the Eclipse Public License Version 2.0 "EPL". * A copy of the EPL is available at http://www.eclipse.org/legal/epl-2.0. @@ -13,7 +13,7 @@ import java.io.IOException; import java.io.OutputStream; import java.util.Objects; -import org.eclipse.cdt.cmake.is.core.builtins.IBuiltinsOutputProcessor.IProcessingContext; +import org.eclipse.cdt.cmake.is.core.IRawIndexerInfoCollector; /** * An OutputStream that passes each line written to it to a @@ -28,17 +28,18 @@ public class OutputSniffer extends OutputStream { private static final String SEP = System.lineSeparator(); private final StringBuilder buffer; private final IBuiltinsOutputProcessor processor; - private final IProcessingContext processingContext; + private final IRawIndexerInfoCollector infoCollector; private final OutputStream os; /** - * @param outputStream the OutputStream to write to or {@code null} - * @param processingContext the processing context + * @param outputStream the OutputStream to write to or {@code null} + * @param infoCollector collector for information about C preprocessor symbols + * and include paths */ public OutputSniffer(IBuiltinsOutputProcessor processor, OutputStream outputStream, - IProcessingContext processingContext) { + IRawIndexerInfoCollector infoCollector) { this.processor = Objects.requireNonNull(processor, "processor"); //$NON-NLS-1$ - this.processingContext = Objects.requireNonNull(processingContext, "processingContext"); //$NON-NLS-1$ + this.infoCollector = Objects.requireNonNull(infoCollector, "infoCollector"); //$NON-NLS-1$ this.os = outputStream; buffer = new StringBuilder(512); } @@ -100,6 +101,6 @@ public class OutputSniffer extends OutputStream { * @param line */ private void processLine(String line) { - processor.processLine(line, processingContext); + processor.processLine(line, infoCollector); } } \ No newline at end of file diff --git a/cmake/org.eclipse.cdt.cmake.is.core/src/main/java/org/eclipse/cdt/cmake/is/core/internal/builtins/CompilerBuiltinsDetector.java b/cmake/org.eclipse.cdt.cmake.is.core/src/main/java/org/eclipse/cdt/cmake/is/core/internal/builtins/CompilerBuiltinsDetector.java index 92e882c9531..fec20f43d42 100644 --- a/cmake/org.eclipse.cdt.cmake.is.core/src/main/java/org/eclipse/cdt/cmake/is/core/internal/builtins/CompilerBuiltinsDetector.java +++ b/cmake/org.eclipse.cdt.cmake.is.core/src/main/java/org/eclipse/cdt/cmake/is/core/internal/builtins/CompilerBuiltinsDetector.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2018-2019 Martin Weber. + * Copyright (c) 2018-2020 Martin Weber. * * Content is provided to you under the terms and conditions of the Eclipse Public License Version 2.0 "EPL". * A copy of the EPL is available at http://www.eclipse.org/legal/epl-2.0. @@ -9,42 +9,38 @@ package org.eclipse.cdt.cmake.is.core.internal.builtins; -import java.io.File; import java.io.IOException; +import java.nio.file.Files; import java.text.SimpleDateFormat; import java.util.ArrayList; -import java.util.Arrays; import java.util.Date; import java.util.HashSet; -import java.util.Iterator; import java.util.List; import java.util.Objects; import java.util.Set; +import org.eclipse.cdt.cmake.is.core.IRawIndexerInfo; import org.eclipse.cdt.cmake.is.core.builtins.IBuiltinsDetectionBehavior; import org.eclipse.cdt.cmake.is.core.builtins.IBuiltinsOutputProcessor; import org.eclipse.cdt.cmake.is.core.builtins.OutputSniffer; import org.eclipse.cdt.cmake.is.core.internal.Plugin; +import org.eclipse.cdt.cmake.is.core.language.settings.providers.PreferenceConstants; import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.ConsoleOutputStream; import org.eclipse.cdt.core.ICommandLauncher; import org.eclipse.cdt.core.envvar.IEnvironmentVariable; import org.eclipse.cdt.core.envvar.IEnvironmentVariableManager; -import org.eclipse.cdt.core.model.ILanguage; -import org.eclipse.cdt.core.model.LanguageManager; import org.eclipse.cdt.core.resources.IConsole; -import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; -import org.eclipse.cdt.core.settings.model.ICLanguageSettingEntry; -import org.eclipse.cdt.managedbuilder.core.ManagedBuildManager; +import org.eclipse.core.resources.IBuildConfiguration; import org.eclipse.core.resources.IMarker; import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Status; +import org.eclipse.jface.preference.IPreferenceStore; /** * Detects preprocessor macros and include paths that are built-in to a @@ -63,77 +59,66 @@ public class CompilerBuiltinsDetector { @SuppressWarnings("nls") private static final String MARKER_ID = Plugin.PLUGIN_ID + ".CompilerBuiltinsDetectorMarker"; - private ICConfigurationDescription cfgDescription; - - /** environment variables, lazily instantiated */ - private String[] envp; - - private final String languageId; - + private final String sourceFileExtension; private final String command; - - private List builtinsDetectionArgs; - + private final List builtinsDetectionArgs; private final IBuiltinsDetectionBehavior builtinsDetectionBehavior; + private IBuildConfiguration buildConfiguration; + private java.nio.file.Path buildDirectory; + /** - * @param cfgDescription configuration description. - * @param languageId language id * @param builtinsDetectionBehavior how compiler built-ins are to be detected * @param command the compiler command (argument # 0) * @param builtinsDetectionArgs the compiler arguments from the command-line * that affect built-in detection. For the GNU * compilers, these are options like * {@code --sysroot} and options that specify - * the language's standard ({@code -std=c++17}. + * the language's standard (e.g. + * {@code -std=c++17}). + * @param sourceFileExtension the extension of the source file name */ @SuppressWarnings("nls") - public CompilerBuiltinsDetector(ICConfigurationDescription cfgDescription, String languageId, - IBuiltinsDetectionBehavior builtinsDetectionBehavior, String command, List builtinsDetectionArgs) { - this.languageId = Objects.requireNonNull(languageId, "languageId"); + public CompilerBuiltinsDetector(IBuiltinsDetectionBehavior builtinsDetectionBehavior, String command, + List builtinsDetectionArgs, String sourceFileExtension) { + this.sourceFileExtension = Objects.requireNonNull(sourceFileExtension, "sourceFileExtension"); this.builtinsDetectionBehavior = Objects.requireNonNull(builtinsDetectionBehavior, "builtinsDetectionBehavior"); this.command = Objects.requireNonNull(command, "command"); this.builtinsDetectionArgs = Objects.requireNonNull(builtinsDetectionArgs, "builtinsDetectionArgs"); - this.cfgDescription = Objects.requireNonNull(cfgDescription); } /** - * Gets the language ID of this detector. - */ - public String getLanguageId() { - return languageId; - } - - /** - * Run built-in detection builtinsDetectionArgs. - * - * @param withConsole whether to show a console for the builtinsDetectionArgs - * output + * Runs built-in detection. * + * @param buildConfiguration the project build configuration to use + * @param theBuildDirectory the build directory of the build configuration + * @param launcher the launcher that can run in docker container, if + * any + * @param console the console to print the compiler output to or + * null if a separate console is to be + * allocated. * @throws CoreException */ - public List run(boolean withConsole) throws CoreException { - ProcessingContext entries = new ProcessingContext(); + public IRawIndexerInfo detectBuiltins(IBuildConfiguration buildConfiguration, java.nio.file.Path theBuildDirectory, + ICommandLauncher launcher, IConsole console, IProgressMonitor monitor) throws CoreException { + this.buildConfiguration = Objects.requireNonNull(buildConfiguration, "buildConfiguration"); //$NON-NLS-1$ + this.buildDirectory = Objects.requireNonNull(theBuildDirectory, "buildDirectory"); //$NON-NLS-1$ - final List argList = getCompilerArguments(languageId); - argList.addAll(builtinsDetectionArgs); - - IConsole console = null; - if (withConsole) { - console = startOutputConsole(); + if (monitor == null) { + monitor = new NullProgressMonitor(); } - IProject project = cfgDescription.getProjectDescription().getProject(); - // get the launcher that runs in docker container, if any - ICommandLauncher launcher = ManagedBuildManager.getConfigurationForDescription(cfgDescription) - .getEditableBuilder().getCommandLauncher(); - launcher.setProject(project); + RawIndexerInfo result = new RawIndexerInfo(); + + final List argList = getCompilerArguments(); + argList.addAll(builtinsDetectionArgs); + + console = startOutputConsole(console); + + launcher.setProject(buildConfiguration.getProject()); launcher.showCommand(console != null); - final NullProgressMonitor monitor = new NullProgressMonitor(); - final IPath builderCWD = cfgDescription.getBuildSetting().getBuilderCWD(); - IPath buildRoot = ResourcesPlugin.getWorkspace().getRoot().getFolder(builderCWD).getLocation(); final Process proc = launcher.execute(new Path(command), argList.toArray(new String[argList.size()]), getEnvp(), - buildRoot, monitor); + new Path(this.buildDirectory.toString()), monitor); if (proc != null) { try { // Close the input of the process since we will never write to it @@ -141,13 +126,22 @@ public class CompilerBuiltinsDetector { } catch (IOException e) { } // NOTE: we need 2 of these, since the output streams are not synchronized, - // causing loss of - // the internal processor state + // causing loss of the output processors' internal state final IBuiltinsOutputProcessor bopOut = builtinsDetectionBehavior.createCompilerOutputProcessor(); final IBuiltinsOutputProcessor bopErr = builtinsDetectionBehavior.createCompilerOutputProcessor(); + long start = System.currentTimeMillis(); int state = launcher.waitAndRead( - new OutputSniffer(bopOut, console == null ? null : console.getOutputStream(), entries), - new OutputSniffer(bopErr, console == null ? null : console.getErrorStream(), entries), monitor); + new OutputSniffer(bopOut, console == null ? null : console.getOutputStream(), result), + new OutputSniffer(bopErr, console == null ? null : console.getErrorStream(), result), monitor); + if (console != null) { + final ConsoleOutputStream cis = console.getInfoStream(); + try { + cis.write(String + .format("Detecting compiler built-ins took %d ms.\n", System.currentTimeMillis() - start) + .getBytes()); + } catch (IOException ignore) { + } + } if (state != ICommandLauncher.COMMAND_CANCELED) { // check exit status final int exitValue = proc.exitValue(); @@ -161,154 +155,116 @@ public class CompilerBuiltinsDetector { // process start failed createMarker(launcher.getErrorMessage()); } - return entries.getSettingEntries(); + return result; } /** - * Gets the compiler-arguments corresponding to the specified language ID and - * the builtinDetection. + * Gets the compiler-arguments corresponding to the builtinDetection. */ - private List getCompilerArguments(String languageId) { + private List getCompilerArguments() { List args = new ArrayList<>(); args.addAll(builtinsDetectionBehavior.getBuiltinsOutputEnablingArgs()); - String inputFile = getInputFile(languageId); + String inputFile = getInputFile(); if (inputFile != null) { args.add(inputFile); } return args; } - /** - * Get array of environment variables in format "var=value". - */ - @SuppressWarnings("nls") - private String[] getEnvp() { - if (envp == null) { - // On POSIX (Linux, UNIX) systems reset language variables to default - // (English) - // with UTF-8 encoding since GNU compilers can handle only UTF-8 - // characters. - // Include paths with locale characters will be handled properly - // regardless - // of the language as long as the encoding is set to UTF-8. - // English language is set for parser because it relies on English - // messages - // in the output of the 'gcc -v' builtinsDetectionArgs. - - List env = new ArrayList<>(Arrays.asList(getEnvp(cfgDescription))); - for (Iterator iterator = env.iterator(); iterator.hasNext();) { - String var = iterator.next(); - if (var.startsWith("LANGUAGE" + '=') || var.startsWith("LC_ALL" + '=')) { - iterator.remove(); - } - } - env.add("LANGUAGE" + "=en"); // override for GNU gettext //$NON-NLS-1$ - env.add("LC_ALL" + "=C.UTF-8"); // for other parts of the //$NON-NLS-1$ - // system libraries - envp = env.toArray(new String[env.size()]); - } - return envp; - } - /** * Get environment variables from configuration as array of "var=value" suitable * for using as "envp" with Runtime.exec(String[] cmdarray, String[] envp, File * dir) * - * @param cfgDescription configuration description. * @return String array of environment variables in format "var=value". Does not * return {@code null}. */ @SuppressWarnings("nls") - private static String[] getEnvp(ICConfigurationDescription cfgDescription) { + private String[] getEnvp() { IEnvironmentVariableManager mngr = CCorePlugin.getDefault().getBuildEnvironmentManager(); - IEnvironmentVariable[] vars = mngr.getVariables(cfgDescription, true); + IEnvironmentVariable[] vars = mngr.getVariables(buildConfiguration, true); // Convert into envp strings Set strings = new HashSet<>(vars.length); for (IEnvironmentVariable var : vars) { + if (var.getName().startsWith("LANGUAGE" + '=') || var.getName().startsWith("LC_ALL" + '=')) + continue; strings.add(var.getName() + '=' + var.getValue()); } - // On POSIX (Linux, UNIX) systems reset language variables to default - // (English) + // On POSIX (Linux, UNIX) systems reset language variables to default (English) // with UTF-8 encoding since GNU compilers can handle only UTF-8 characters. // Include paths with locale characters will be handled properly regardless // of the language as long as the encoding is set to UTF-8. // English language is set for parser because it relies on English messages // in the output of the 'gcc -v' builtinsDetectionArgs. strings.add("LANGUAGE" + "=en"); // override for GNU gettext - strings.add("LC_ALL" + "=C.UTF-8"); // for other parts of the system - // libraries + strings.add("LC_ALL" + "=C.UTF-8"); // for other parts of the system libraries return strings.toArray(new String[strings.size()]); } /** - * Get path to source file which is the input for the compiler. + * Gets a path to the source file which is the input for the compiler. The file + * will be created with no content in the build directory. * - * @param languageId the language ID. - * @return full path to the source file. + * @return the full file system path of the source file */ - private String getInputFile(String languageId) { - String specExt = builtinsDetectionBehavior.getInputFileExtension(languageId); - if (specExt != null) { - String specFileName = "detect_compiler_builtins" + '.' + specExt; //$NON-NLS-1$ - - final IPath builderCWD = cfgDescription.getBuildSetting().getBuilderCWD(); - IPath fileLocation = ResourcesPlugin.getWorkspace().getRoot().getFolder(builderCWD).getLocation() - .append(specFileName); - - File specFile = new java.io.File(fileLocation.toOSString()); - if (!specFile.exists()) { - try { - // In the typical case it is sufficient to have an empty file. - specFile.getParentFile().mkdirs(); // no build ran yet, must create dirs - specFile.createNewFile(); - } catch (IOException e) { - Plugin.getDefault().getLog().log(new Status(IStatus.ERROR, Plugin.PLUGIN_ID, "getInputFile()", e)); - } + private String getInputFile() { + String specFileName = "detect_compiler_builtins" + '.' + sourceFileExtension; //$NON-NLS-1$ + java.nio.file.Path specFile = buildDirectory.resolve(specFileName); + if (!Files.exists(specFile)) { + try { + // In the typical case it is sufficient to have an empty file. + Files.createDirectories(specFile.getParent()); // no build ran yet, must create dirs + Files.createFile(specFile); + } catch (IOException e) { + Plugin.getDefault().getLog().log(new Status(IStatus.ERROR, Plugin.PLUGIN_ID, "getInputFile()", e)); //$NON-NLS-1$ } - - return fileLocation.toString(); } - return null; + + return specFile.toString(); } private void createMarker(String message) throws CoreException { - IMarker marker = cfgDescription.getProjectDescription().getProject().createMarker(MARKER_ID); + IMarker marker = buildConfiguration.getProject().createMarker(MARKER_ID); marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_INFO); marker.setAttribute(IMarker.MESSAGE, message); } /** - * Creates and starts the provider console. + * Creates and starts the output console. * * @return CDT console or null * * @throws CoreException */ - private IConsole startOutputConsole() throws CoreException { - IConsole console = null; + @SuppressWarnings("nls") + private IConsole startOutputConsole(IConsole console) throws CoreException { + IPreferenceStore prefStore = Plugin.getDefault().getPreferenceStore(); + if (!prefStore.getBoolean(PreferenceConstants.P_WITH_CONSOLE)) { + return null; // no console to allocate + } else { + IProject project = buildConfiguration.getProject(); + if (console != null) { + String consoleId = CONSOLE_ID + "." + project.getName(); + console = CCorePlugin.getDefault().getConsole(CONSOLE_ID, consoleId, null, null); + } - ILanguage ld = LanguageManager.getInstance().getLanguage(languageId); - if (ld != null) { - String consoleId = CONSOLE_ID + '.' + languageId; - console = CCorePlugin.getDefault().getConsole(CONSOLE_ID, consoleId, null, null); - final IProject project = cfgDescription.getProjectDescription().getProject(); console.start(project); try { final ConsoleOutputStream cis = console.getInfoStream(); cis.write(SimpleDateFormat.getTimeInstance().format(new Date()).getBytes()); cis.write(" Detecting compiler built-ins: ".getBytes()); cis.write(project.getName().getBytes()); - cis.write("::".getBytes()); - cis.write(cfgDescription.getConfiguration().getName().getBytes()); + if (!buildConfiguration.getName().isEmpty()) { + cis.write("::".getBytes()); + cis.write(buildConfiguration.getName().getBytes()); + } cis.write(" for ".getBytes()); - cis.write(ld.getName().getBytes()); - cis.write("\n".getBytes()); + cis.write(sourceFileExtension.getBytes()); + cis.write(" files\n".getBytes()); } catch (IOException ignore) { } } - return console; } diff --git a/cmake/org.eclipse.cdt.cmake.is.core/src/main/java/org/eclipse/cdt/cmake/is/core/internal/builtins/MaybeGccBuiltinDetectionBehavior.java b/cmake/org.eclipse.cdt.cmake.is.core/src/main/java/org/eclipse/cdt/cmake/is/core/internal/builtins/MaybeGccBuiltinDetectionBehavior.java index 05631664c08..22f0a855ec2 100644 --- a/cmake/org.eclipse.cdt.cmake.is.core/src/main/java/org/eclipse/cdt/cmake/is/core/internal/builtins/MaybeGccBuiltinDetectionBehavior.java +++ b/cmake/org.eclipse.cdt.cmake.is.core/src/main/java/org/eclipse/cdt/cmake/is/core/internal/builtins/MaybeGccBuiltinDetectionBehavior.java @@ -46,16 +46,4 @@ public class MaybeGccBuiltinDetectionBehavior implements IBuiltinsDetectionBehav // detection return true; } - - @SuppressWarnings("nls") - @Override - public String getInputFileExtension(String languageId) { - if (languageId.equals("org.eclipse.cdt.core.gcc")) { - return "c"; - } - if (languageId.equals("org.eclipse.cdt.core.g++")) { - return "cpp"; - } - return null; // no input file required for built-in detection - } } diff --git a/cmake/org.eclipse.cdt.cmake.is.core/src/main/java/org/eclipse/cdt/cmake/is/core/internal/builtins/ProcessingContext.java b/cmake/org.eclipse.cdt.cmake.is.core/src/main/java/org/eclipse/cdt/cmake/is/core/internal/builtins/ProcessingContext.java deleted file mode 100644 index c9b161c4d42..00000000000 --- a/cmake/org.eclipse.cdt.cmake.is.core/src/main/java/org/eclipse/cdt/cmake/is/core/internal/builtins/ProcessingContext.java +++ /dev/null @@ -1,49 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2019-2020 Martin Weber. - * - * Content is provided to you under the terms and conditions of the Eclipse Public License Version 2.0 "EPL". - * A copy of the EPL is available at http://www.eclipse.org/legal/epl-2.0. - * - * SPDX-License-Identifier: EPL-2.0 - *******************************************************************************/ - -package org.eclipse.cdt.cmake.is.core.internal.builtins; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import org.eclipse.cdt.cmake.is.core.builtins.IBuiltinsOutputProcessor; -import org.eclipse.cdt.cmake.is.core.internal.Plugin; -import org.eclipse.cdt.core.settings.model.ICLanguageSettingEntry; -import org.eclipse.core.runtime.Platform; - -/** - * Default implementation of IProcessingContext. - * - * @author Martin Weber - */ -class ProcessingContext implements IBuiltinsOutputProcessor.IProcessingContext, IBuiltinsOutputProcessor.IResult { - @SuppressWarnings("nls") - private static final boolean DEBUG = Boolean - .parseBoolean(Platform.getDebugOption(Plugin.PLUGIN_ID + "/CECC/builtins/entries")); - - private final List entries = Collections - .synchronizedList(new ArrayList()); - - public ProcessingContext() { - } - - @Override - public void addSettingEntry(ICLanguageSettingEntry entry) { - if (DEBUG) - System.out.printf("Added builtin entry: %s%n", entry); //$NON-NLS-1$ - entries.add(entry); - } - - @Override - public List getSettingEntries() { - return entries; - } - -} diff --git a/cmake/org.eclipse.cdt.cmake.is.core/src/main/java/org/eclipse/cdt/cmake/is/core/internal/builtins/RawIndexerInfo.java b/cmake/org.eclipse.cdt.cmake.is.core/src/main/java/org/eclipse/cdt/cmake/is/core/internal/builtins/RawIndexerInfo.java new file mode 100644 index 00000000000..291d2afe322 --- /dev/null +++ b/cmake/org.eclipse.cdt.cmake.is.core/src/main/java/org/eclipse/cdt/cmake/is/core/internal/builtins/RawIndexerInfo.java @@ -0,0 +1,109 @@ +/******************************************************************************* + * Copyright (c) 2020 Martin Weber. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + *******************************************************************************/ + +package org.eclipse.cdt.cmake.is.core.internal.builtins; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Objects; + +import org.eclipse.cdt.cmake.is.core.IRawIndexerInfo; +import org.eclipse.cdt.cmake.is.core.IRawIndexerInfoCollector; +import org.eclipse.cdt.cmake.is.core.internal.Plugin; +import org.eclipse.core.runtime.Platform; + +/** + * Default implementation of IRawIndexerInfo. + * + * @author weber + */ +public class RawIndexerInfo implements IRawIndexerInfo, IRawIndexerInfoCollector { + + @SuppressWarnings("nls") + private static final boolean DEBUG = Boolean + .parseBoolean(Platform.getDebugOption(Plugin.PLUGIN_ID + "/debug/detected.entries")); + + private final Map defines = new HashMap<>(); + private final List undefines = new ArrayList<>(); + private final List includePaths = new ArrayList<>(); + private final List systemIncludePaths = new ArrayList<>(); + + @Override + public void addDefine(String name, String value) { + Objects.requireNonNull(name); + value = Objects.toString(value, ""); //$NON-NLS-1$ + if (DEBUG) + System.out.printf(" Added define: %s=%s%n", name, value); //$NON-NLS-1$ + defines.put(name, value); + } + + @Override + public void addUndefine(String name) { + Objects.requireNonNull(name); + if (DEBUG) + System.out.printf(" Added undefine: %s%n", name); //$NON-NLS-1$ + undefines.add(name); + // - The GCC man page states: + // '-U name Cancel any previous definition of name, either built in or provided + // with a -D option.' + // - The POSIX c99 man page states: + // '-U name Remove any initial definition of name.' + for (Iterator> iter = defines.entrySet().iterator(); iter.hasNext();) { + Entry define = iter.next(); + if (define.getKey().equals(name)) { + if (DEBUG) + System.out.printf(" Removed define: %s=%s%n", define.getKey(), define.getValue()); //$NON-NLS-1$ + iter.remove(); + } + } + } + + @Override + public void addIncludePath(String path) { + Objects.requireNonNull(path); + if (DEBUG) + System.out.printf(" Added incl path: %s%n", path); //$NON-NLS-1$ + includePaths.add(path); + } + + @Override + public void addSystemIncludePath(String path) { + Objects.requireNonNull(path); + if (DEBUG) + System.out.printf(" Added sys incl path: %s%n", path); //$NON-NLS-1$ + systemIncludePaths.add(path); + } + + @Override + public Map getDefines() { + return Collections.unmodifiableMap(defines); + } + + @Override + public List getUndefines() { + return Collections.unmodifiableList(undefines); + } + + @Override + public List getIncludePaths() { + return Collections.unmodifiableList(includePaths); + } + + @Override + public List getSystemIncludePaths() { + return Collections.unmodifiableList(systemIncludePaths); + } +} diff --git a/cmake/org.eclipse.cdt.cmake.is.core/src/main/java/org/eclipse/cdt/cmake/is/core/language/settings/providers/BuiltinsCompileCommandsJsonParser.java b/cmake/org.eclipse.cdt.cmake.is.core/src/main/java/org/eclipse/cdt/cmake/is/core/language/settings/providers/BuiltinsCompileCommandsJsonParser.java deleted file mode 100644 index 0a6b116ac5c..00000000000 --- a/cmake/org.eclipse.cdt.cmake.is.core/src/main/java/org/eclipse/cdt/cmake/is/core/language/settings/providers/BuiltinsCompileCommandsJsonParser.java +++ /dev/null @@ -1,273 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2018 Martin Weber. - * - * Content is provided to you under the terms and conditions of the Eclipse Public License Version 2.0 "EPL". - * A copy of the EPL is available at http://www.eclipse.org/legal/epl-2.0. - * - * SPDX-License-Identifier: EPL-2.0 - *******************************************************************************/ -package org.eclipse.cdt.cmake.is.core.language.settings.providers; - -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.Map.Entry; -import java.util.Optional; -import java.util.Set; - -import org.eclipse.cdt.build.core.scannerconfig.ScannerConfigNature; -import org.eclipse.cdt.cmake.is.core.internal.ParserDetection; -import org.eclipse.cdt.cmake.is.core.internal.Plugin; -import org.eclipse.cdt.cmake.is.core.internal.builtins.CompilerBuiltinsDetector; -import org.eclipse.cdt.core.CCorePlugin; -import org.eclipse.cdt.core.language.settings.providers.ICBuildOutputParser; -import org.eclipse.cdt.core.language.settings.providers.ICListenerAgent; -import org.eclipse.cdt.core.language.settings.providers.ILanguageSettingsEditableProvider; -import org.eclipse.cdt.core.language.settings.providers.ILanguageSettingsProvider; -import org.eclipse.cdt.core.language.settings.providers.ILanguageSettingsProvidersKeeper; -import org.eclipse.cdt.core.language.settings.providers.IWorkingDirectoryTracker; -import org.eclipse.cdt.core.language.settings.providers.LanguageSettingsManager; -import org.eclipse.cdt.core.language.settings.providers.LanguageSettingsSerializableProvider; -import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; -import org.eclipse.cdt.core.settings.model.ICLanguageSettingEntry; -import org.eclipse.cdt.core.settings.model.ICProjectDescription; -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.ILog; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Status; -import org.eclipse.swt.widgets.Display; -import org.w3c.dom.Element; - -/** - * A ILanguageSettingsProvider that detects the include paths and symbols - * built-in to the compilers found in the file 'compile_commands.json' produced - * by cmake.
- * NOTE: This class misuses interface ICBuildOutputParser to detect when a build - * did finish.
- * NOTE: This class misuses interface ICListenerAgent to populate the - * {@link #getSettingEntries setting entries} on workbench startup. - * - * @author Martin Weber - */ -/* - * TODO delete this after integration into core build - */ -public class BuiltinsCompileCommandsJsonParser extends LanguageSettingsSerializableProvider - implements ILanguageSettingsEditableProvider, ICListenerAgent, ICBuildOutputParser, Cloneable { - - public static final String PROVIDER_ID = "org.eclipse.cdt.cmake.is.core.language.settings.providers.BuiltinsCompileCommandsJsonParser"; - private static final ILog log = Plugin.getDefault().getLog(); - - /** storage key for with console */ - @SuppressWarnings("nls") - private static final String ATTR_WITH_CONSOLE = "console"; - - private ICConfigurationDescription currentCfgDescription; - - @Override - public void configureProvider(String id, String name, List languages, List entries, - Map properties) { - ArrayList scope = new ArrayList<>(); - scope.add("org.eclipse.cdt.core.gcc"); //$NON-NLS-1$ - scope.add("org.eclipse.cdt.core.g++"); //$NON-NLS-1$ - scope.addAll(ParserDetection.getCustomLanguages()); - super.configureProvider(id, name, scope, entries, properties); - } - - /** - * Detects the compiler built-in include paths and symbols. Uses - * {@link CompileCommandsJsonParser} for parsing of the json file and caching. - * - * @param initializingWorkbench {@code true} if the workbench is starting up. If - * {@code true}, this method will not trigger UI - * update to show newly detected include paths nor - * will it complain if a "compile_commands.json" - * file does not exist. - * @throws CoreException - */ - private void detectBuiltins(boolean initializingWorkbench) throws CoreException { - if (currentCfgDescription instanceof ILanguageSettingsProvidersKeeper) { - Iterable detectors; - - final List lsps = ((ILanguageSettingsProvidersKeeper) currentCfgDescription) - .getLanguageSettingProviders(); - // get the CompileCommandsJsonParser object, if the settings provider is enabled - // on the configuration - final CompileCommandsJsonParser lsp; - Optional lspO = lsps.stream() - .filter(p -> CompileCommandsJsonParser.PROVIDER_ID.equals(p.getId())).findAny(); - if (lspO.isPresent()) { - // CompileCommandsJsonParser is there, trigger it, regardless of provider order - lsp = (CompileCommandsJsonParser) LanguageSettingsManager.getRawProvider(lspO.get()); - detectors = lsp.determineBuiltinDetectors(currentCfgDescription, true, initializingWorkbench); - } else { - // get a CompileCommandsJsonParser configured with the workspace default - // settings - lsp = (CompileCommandsJsonParser) LanguageSettingsManager - .getExtensionProviderCopy(CompileCommandsJsonParser.PROVIDER_ID, false); - detectors = lsp.determineBuiltinDetectors(currentCfgDescription, false, initializingWorkbench); - } - - if (initializingWorkbench && detectors == null) { - // if initializing, always get the detectors - detectors = lsp.getBuiltinDetectors(currentCfgDescription); - } - if (detectors != null) { - // run each detector and gather the entries per language - HashMap> langMap = new HashMap<>(2, 1.0f); - for (CompilerBuiltinsDetector detector : detectors) { - final String languageId = detector.getLanguageId(); - // entries per language - List entries = detector.run(isWithConsole()); - // use a Set here to avoid duplicates by name and kind .. - Set allEntries = langMap.get(languageId); - if (allEntries == null) { - allEntries = new HashSet<>(); - langMap.put(languageId, allEntries); - } - allEntries.addAll(entries); - } - // store the entries per language - for (Entry> entry : langMap.entrySet()) { - super.setSettingEntries(currentCfgDescription, null, entry.getKey(), Arrays - .asList(entry.getValue().toArray(new ICLanguageSettingEntry[entry.getValue().size()]))); - } - } - } - } - - /*- - * interface ICBuildOutputParser - */ - @Override - public void startup(ICConfigurationDescription cfgDescription, IWorkingDirectoryTracker cwdTracker) - throws CoreException { - currentCfgDescription = cfgDescription; - } - - /** - * Invoked for each line in the build output. - */ - // interface ICBuildOutputParser - @Override - public boolean processLine(String line) { - // nothing to do - return false; - } - - /*- - * interface ICBuildOutputParser - */ - @Override - public void shutdown() { - try { - detectBuiltins(false); - } catch (CoreException ex) { - log.log(new Status(IStatus.ERROR, Plugin.PLUGIN_ID, "shutdown()", ex)); - } - // release resources for garbage collector - currentCfgDescription = null; - } - - @Override - public BuiltinsCompileCommandsJsonParser clone() throws CloneNotSupportedException { - return (BuiltinsCompileCommandsJsonParser) super.clone(); - } - - @Override - public BuiltinsCompileCommandsJsonParser cloneShallow() throws CloneNotSupportedException { - return (BuiltinsCompileCommandsJsonParser) super.cloneShallow(); - } - - /** - * Overridden to misuse this to populate the {@link #getSettingEntries setting - * entries} on startup.
- * {@inheritDoc} - */ - @Override - public void registerListener(ICConfigurationDescription cfgDescription) { - if (cfgDescription != null) { - // per-project or null if the user just added this provider on the provider tab - currentCfgDescription = cfgDescription; - try { - detectBuiltins(true); - } catch (CoreException ex) { - log.log(new Status(IStatus.ERROR, Plugin.PLUGIN_ID, "registerListener()", ex)); - } - } else { - // per workspace (to populate on startup) - Display.getDefault().asyncExec(() -> { - IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot(); - IProject[] projects = workspaceRoot.getProjects(); - CCorePlugin ccp = CCorePlugin.getDefault(); - // detect built-ins for any opened project that has a ScannerConfigNature... - for (IProject project : projects) { - try { - if (project.isOpen() && project.hasNature(ScannerConfigNature.NATURE_ID)) { - ICProjectDescription projectDescription = ccp.getProjectDescription(project, false); - if (projectDescription != null) { - ICConfigurationDescription activeConfiguration = projectDescription - .getActiveConfiguration(); - if (activeConfiguration instanceof ILanguageSettingsProvidersKeeper) { - final List lsps = ((ILanguageSettingsProvidersKeeper) activeConfiguration) - .getLanguageSettingProviders(); - for (ILanguageSettingsProvider lsp : lsps) { - if (PROVIDER_ID.equals(lsp.getId())) { - currentCfgDescription = activeConfiguration; - detectBuiltins(true); - break; - } - } - } - } - } - } catch (CoreException ex) { - log.log(new Status(IStatus.ERROR, Plugin.PLUGIN_ID, "registerListener()", ex)); - } - } - }); - } - // release resources for garbage collector - currentCfgDescription = null; - } - - /*- - * @see org.eclipse.cdt.core.language.settings.providers.ICListenerAgent#unregisterListener() - */ - @Override - public void unregisterListener() { - } - - /** - * Gets whether a console in the console view should be allocated during - * detection. - */ - public boolean isWithConsole() { - return getPropertyBool(ATTR_WITH_CONSOLE); - } - - /** - * Sets whether a console in the console view should be allocated during - * detection. - */ - public void setWithConsole(boolean enabled) { - if (enabled) { - setPropertyBool(ATTR_WITH_CONSOLE, enabled); - } else { - properties.remove(ATTR_WITH_CONSOLE); - } - } - - @Override - public void serializeEntries(Element elementProvider) { - // no language setting entries to serialize, since entries come from the - // compile_commands.json file - } - -} diff --git a/cmake/org.eclipse.cdt.cmake.is.core/src/main/java/org/eclipse/cdt/cmake/is/core/language/settings/providers/CommandEntry.java b/cmake/org.eclipse.cdt.cmake.is.core/src/main/java/org/eclipse/cdt/cmake/is/core/language/settings/providers/CommandEntry.java new file mode 100644 index 00000000000..93e46370e25 --- /dev/null +++ b/cmake/org.eclipse.cdt.cmake.is.core/src/main/java/org/eclipse/cdt/cmake/is/core/language/settings/providers/CommandEntry.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) 2020 Martin Weber. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + *******************************************************************************/ + +package org.eclipse.cdt.cmake.is.core.language.settings.providers; + +/** + * Represents a parsed command entry of a compile_commands.json file. + * @author weber + */ +class CommandEntry { + private String directory; + private String command; + private String file; + + /** + * Gets the build directory as a String. + */ + public String getDirectory() { + return directory; + } + + /** + * Gets the command-line to compile the source file. + */ + public String getCommand() { + return command; + } + + /** + * Gets the source file path as a String. + */ + public String getFile() { + return file; + } +}