Skip to content

Commit

Permalink
Add a directory tracker to the CBS Makefile builder
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
jonahgraham committed Feb 2, 2025
1 parent c8e47b3 commit 84cf19c
Showing 1 changed file with 83 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -68,6 +72,7 @@ public class StandardBuildConfiguration extends CBuildConfiguration {
private String[] cleanCommand = DEFAULT_CLEAN_COMMAND;
private IContainer buildContainer;
private IEnvironmentVariable[] envVars;
private Stack<String> directoryStack = new Stack<>();

public StandardBuildConfiguration(IBuildConfiguration config, String name) throws CoreException {
super(config, name);
Expand Down Expand Up @@ -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<DirectoryPatternParser> 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();
}
}
}

0 comments on commit 84cf19c

Please sign in to comment.