From 84cf19c12597fd5b4f2c7d098a20914fbbad36a4 Mon Sep 17 00:00:00 2001 From: Jonah Graham Date: Sat, 1 Feb 2025 23:45:57 -0500 Subject: [PATCH] Add a directory tracker to the CBS Makefile builder Messages such as "make: Entering directory" are now processed so that the scanner info builder knows the correct full path to use for build. Without this code calls to ToolChain.getResourcesFromCommand() would pass in the wrong directory and resources could not be reliably calculated. With the incorrect calculation the scanner info does not get applied to the file correctly and the file cannot be indexed reliably. TODO: - [ ] Decide how to handle make -j as "make: Entering directory" becomes unreliable - [ ] Consider whether we should search project for resources so that the exact build directory is less important - [ ] Consider how to report back to the user that the detected resource was not found in the project. --- .../build/StandardBuildConfiguration.java | 83 +++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/build/StandardBuildConfiguration.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/build/StandardBuildConfiguration.java index 179cbdda0a4..826df4bac78 100644 --- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/build/StandardBuildConfiguration.java +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/build/StandardBuildConfiguration.java @@ -11,12 +11,16 @@ package org.eclipse.cdt.core.build; import java.io.IOException; +import java.net.URI; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; +import java.util.Stack; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.ConsoleOutputStream; @@ -68,6 +72,7 @@ public class StandardBuildConfiguration extends CBuildConfiguration { private String[] cleanCommand = DEFAULT_CLEAN_COMMAND; private IContainer buildContainer; private IEnvironmentVariable[] envVars; + private Stack directoryStack = new Stack<>(); public StandardBuildConfiguration(IBuildConfiguration config, String name) throws CoreException { super(config, name); @@ -342,4 +347,82 @@ public void clean(IConsole console, IProgressMonitor monitor) throws CoreExcepti } } + private abstract class DirectoryPatternParser { + private final Pattern pattern; + + public DirectoryPatternParser(String regex) { + this.pattern = Pattern.compile(regex); + } + + public void processLine(String line) { + Matcher matcher = pattern.matcher(line); + if (matcher.find()) { + recordDirectoryChange(matcher); + } + } + + abstract protected void recordDirectoryChange(Matcher matcher); + } + + private final List enteringDirectoryPatterns = List.of( // + // + new DirectoryPatternParser("make\\[(.*)\\]: Entering directory [`'](.*)'") { //$NON-NLS-1$ + @Override + protected void recordDirectoryChange(Matcher matcher) { + int level; + try { + level = Integer.valueOf(matcher.group(1)).intValue(); + } catch (NumberFormatException e) { + level = 0; + } + String dir = matcher.group(2); + /* + * Sometimes make screws up the output, so "leave" events can't be seen. Double-check + * level here. + */ + int parseLevel = directoryStack.size(); + for (; level < parseLevel; level++) { + if (!directoryStack.empty()) { + directoryStack.pop(); + } + } + directoryStack.push(dir); + } + }, + + // This is emitted by GNU make using options -w or --print-directory. + new DirectoryPatternParser("make: Entering directory [`'](.*)'") { //$NON-NLS-1$ + @Override + protected void recordDirectoryChange(Matcher matcher) { + String dir = matcher.group(1); + directoryStack.push(dir); + } + }, + + // + new DirectoryPatternParser("make(\\[.*\\])?: Leaving directory") { //$NON-NLS-1$ + @Override + protected void recordDirectoryChange(Matcher matcher) { + if (!directoryStack.empty()) { + directoryStack.pop(); + } + } + } + + ); + + @Override + public boolean processLine(String line) { + enteringDirectoryPatterns.forEach(p -> p.processLine(line)); + return super.processLine(line); + } + + @Override + public URI getBuildDirectoryURI() throws CoreException { + if (!directoryStack.isEmpty()) { + return Path.of(directoryStack.peek()).toUri(); + } else { + return super.getBuildDirectoryURI(); + } + } }