From 0e5338966d013be0d5fe38738cb828209ea990a1 Mon Sep 17 00:00:00 2001 From: Jonah Graham Date: Wed, 19 Feb 2025 21:02:38 -0500 Subject: [PATCH] Add a directory tracker to the CBS Makefile builder (#1071) 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. --- .../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 49e97f4453f..442b55174a0 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; @@ -70,6 +74,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); @@ -361,4 +366,82 @@ public class StandardBuildConfiguration extends CBuildConfiguration { } } + 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(); + } + } }