Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
8260976: investigate ways to filter jextract output
Reviewed-by: jvernee
  • Loading branch information
mcimadamore committed Apr 8, 2021
1 parent 94b76fd commit 04160de
Show file tree
Hide file tree
Showing 8 changed files with 396 additions and 80 deletions.
Expand Up @@ -26,7 +26,7 @@
package jdk.incubator.jextract;

import jdk.internal.jextract.impl.ClangException;
import jdk.internal.jextract.impl.Filter;
import jdk.internal.jextract.impl.IncludeHelper;
import jdk.internal.jextract.impl.OutputFactory;
import jdk.internal.jextract.impl.Parser;
import jdk.internal.jextract.impl.Options;
Expand All @@ -46,7 +46,6 @@
import java.text.MessageFormat;
import java.util.List;
import java.util.Locale;
import java.util.Optional;
import java.util.ResourceBundle;
import java.util.spi.ToolProvider;
import java.util.stream.Collectors;
Expand Down Expand Up @@ -112,13 +111,14 @@ public static Declaration.Scoped parse(List<Path> headers, String... parserOptio
return new Parser().parse(source, Stream.of(parserOptions).collect(Collectors.toList()));
}

public static Declaration.Scoped filter(Declaration.Scoped decl, String... includedNames) {
return Filter.filter(decl, includedNames);
}

public static List<JavaFileObject> generate(Declaration.Scoped decl, String headerName,
String targetPkg, List<String> libNames) {
return List.of(OutputFactory.generateWrapped(decl, headerName, targetPkg, libNames));
return List.of(OutputFactory.generateWrapped(decl, headerName, targetPkg, new IncludeHelper(), libNames));
}

private static List<JavaFileObject> generateInternal(Declaration.Scoped decl, String headerName,
String targetPkg, IncludeHelper includeHelper, List<String> libNames) {
return List.of(OutputFactory.generateWrapped(decl, headerName, targetPkg, includeHelper, libNames));
}

/**
Expand Down Expand Up @@ -162,7 +162,10 @@ private int run(String[] args) {
parser.accepts("C", format("help.C")).withRequiredArg();
parser.accepts("I", format("help.I")).withRequiredArg();
parser.accepts("d", format("help.d")).withRequiredArg();
parser.accepts("filter", format("help.filter")).withRequiredArg();
parser.accepts("dump-includes", format("help.dump-includes")).withRequiredArg();
for (IncludeHelper.IncludeKind includeKind : IncludeHelper.IncludeKind.values()) {
parser.accepts(includeKind.optionName(), format("help." + includeKind.optionName())).withRequiredArg();
}
parser.accepts("l", format("help.l")).withRequiredArg();
parser.accepts("source", format("help.source"));
parser.acceptsAll(List.of("t", "target-package"), format("help.t")).withRequiredArg();
Expand Down Expand Up @@ -200,6 +203,16 @@ private int run(String[] args) {
optionSet.valuesOf("filter").forEach(p -> builder.addFilter((String) p));
}

for (IncludeHelper.IncludeKind includeKind : IncludeHelper.IncludeKind.values()) {
if (optionSet.has(includeKind.optionName())) {
optionSet.valuesOf(includeKind.optionName()).forEach(p -> builder.addIncludeSymbol(includeKind, (String)p));
}
}

if (optionSet.has("dump-includes")) {
builder.setDumpIncludeFile(optionSet.valueOf("dump-includes").toString());
}

if (optionSet.has("d")) {
builder.setOutputDir(optionSet.valueOf("d").toString());
}
Expand Down Expand Up @@ -244,18 +257,13 @@ private int run(String[] args) {
try {
Declaration.Scoped toplevel = parse(List.of(header), options.clangArgs.toArray(new String[0]));

//filter
if (!options.filters.isEmpty()) {
toplevel = filter(toplevel, options.filters.toArray(new String[0]));
}

if (JextractTool.DEBUG) {
System.out.println(toplevel);
}

files = generate(
files = generateInternal(
toplevel, header.getFileName().toString(),
options.targetPackage, options.libraryNames);
options.targetPackage, options.includeHelper, options.libraryNames);
} catch (ClangException ce) {
err.println(ce.getMessage());
if (JextractTool.DEBUG) {
Expand All @@ -271,8 +279,12 @@ private int run(String[] args) {
}

try {
Path output = Path.of(options.outputDir);
write(output, !options.source, files);
if (options.includeHelper.dumpIncludesFile != null) {
options.includeHelper.dumpIncludes();
} else {
Path output = Path.of(options.outputDir);
write(output, !options.source, files);
}
} catch (UncheckedIOException uioe) {
err.println(uioe.getMessage());
if (JextractTool.DEBUG) {
Expand Down

This file was deleted.

@@ -0,0 +1,164 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/

package jdk.internal.jextract.impl;

import jdk.incubator.jextract.Declaration;

import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.Comparator;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.stream.Collectors;

public class IncludeHelper {

public enum IncludeKind {
MACRO,
VAR,
FUNCTION,
TYPEDEF,
STRUCT,
UNION;

public String optionName() {
return "include-" + name().toLowerCase();
}

static IncludeKind fromDeclaration(Declaration d) {
if (d instanceof Declaration.Constant) {
return MACRO;
} else if (d instanceof Declaration.Variable) {
return VAR;
} else if (d instanceof Declaration.Function) {
return FUNCTION;
} else if (d instanceof Declaration.Typedef) {
return TYPEDEF;
} else if (d instanceof Declaration.Scoped scoped) {
return fromScoped(scoped);
} else {
throw new IllegalStateException("Cannot get here!");
}
}

static IncludeKind fromScoped(Declaration.Scoped scoped) {
return switch (scoped.kind()) {
case STRUCT -> IncludeKind.STRUCT;
case UNION -> IncludeKind.UNION;
default -> throw new IllegalStateException("Cannot get here!");
};
}
}

private final EnumMap<IncludeKind, Set<String>> includesSymbolNamesByKind = new EnumMap<>(IncludeKind.class);
private final Set<Declaration> usedDeclarations = new HashSet<>();
public String dumpIncludesFile;

public void addSymbol(IncludeKind kind, String symbolName) {
Set<String> names = includesSymbolNamesByKind.computeIfAbsent(kind, (_unused) -> new HashSet<>());
names.add(symbolName);
}

public boolean isIncluded(Declaration.Variable variable) {
return checkIncludedAndAddIfNeeded(IncludeKind.VAR, variable);
}

public boolean isIncluded(Declaration.Function function) {
return checkIncludedAndAddIfNeeded(IncludeKind.FUNCTION, function);
}

public boolean isIncluded(Declaration.Constant constant) {
return checkIncludedAndAddIfNeeded(IncludeKind.MACRO, constant);
}

public boolean isIncluded(Declaration.Typedef typedef) {
return checkIncludedAndAddIfNeeded(IncludeKind.TYPEDEF, typedef);
}

public boolean isIncluded(Declaration.Scoped scoped) {
return checkIncludedAndAddIfNeeded(IncludeKind.fromScoped(scoped), scoped);
}

private boolean checkIncludedAndAddIfNeeded(IncludeKind kind, Declaration declaration) {
boolean included = isIncludedInternal(kind, declaration);
if (included && dumpIncludesFile != null) {
usedDeclarations.add(declaration);
}
return included;
}

private boolean isIncludedInternal(IncludeKind kind, Declaration declaration) {
if (!isEnabled()) {
return true;
} else {
Set<String> names = includesSymbolNamesByKind.computeIfAbsent(kind, (_unused) -> new HashSet<>());
return names.contains(declaration.name());
}
}

public boolean isEnabled() {
return includesSymbolNamesByKind.size() > 0;
}

public void dumpIncludes() {
try (var writer = Files.newBufferedWriter(Path.of(dumpIncludesFile), StandardOpenOption.CREATE)) {
Map<Path, Set<Declaration>> declsByPath = usedDeclarations.stream()
.collect(Collectors.groupingBy(d -> d.pos().path(),
() -> new TreeMap<>(Path::compareTo),
Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(Declaration::name)))));
String lineSep = "";
for (Map.Entry<Path, Set<Declaration>> pathEntries : declsByPath.entrySet()) {
writer.append(lineSep);
writer.append("#### Extracted from: " + pathEntries.getKey().toString() + "\n\n");
Map<IncludeKind, List<Declaration>> declsByKind = pathEntries.getValue().stream()
.collect(Collectors.groupingBy(IncludeKind::fromDeclaration));
int maxLengthOptionCol = pathEntries.getValue().stream().mapToInt(d -> d.name().length()).max().getAsInt();
maxLengthOptionCol += 2; // --
maxLengthOptionCol += IncludeKind.FUNCTION.optionName().length(); // max option name
maxLengthOptionCol += 1; // space
for (Map.Entry<IncludeKind, List<Declaration>> kindEntries : declsByKind.entrySet()) {
for (Declaration d : kindEntries.getValue()) {
writer.append(String.format("%-" + maxLengthOptionCol + "s %s",
"--" + kindEntries.getKey().optionName() + " " + d.name(),
"# header: " + pathEntries.getKey() + "\n"));
}
}
lineSep = "\n";
}
} catch (IOException exception) {
throw new UncheckedIOException(exception);
}
}
}
Expand Up @@ -27,6 +27,7 @@
import java.util.List;

public final class Options {

// The args for parsing C
public final List<String> clangArgs;
// The list of library names
Expand All @@ -37,16 +38,18 @@ public final class Options {
// output directory
public final String outputDir;
public final boolean source;
public final IncludeHelper includeHelper;

private Options(List<String> clangArgs, List<String> libraryNames,
List<String> filters, String targetPackage,
String outputDir, boolean source) {
String outputDir, boolean source, IncludeHelper includeHelper) {
this.clangArgs = clangArgs;
this.libraryNames = libraryNames;
this.filters = filters;
this.targetPackage = targetPackage;
this.outputDir = outputDir;
this.source = source;
this.includeHelper = includeHelper;
}

public static Builder builder() {
Expand All @@ -64,6 +67,7 @@ public static class Builder {
private String targetPackage;
private String outputDir;
private boolean source;
private IncludeHelper includeHelper = new IncludeHelper();

public Builder() {
this.clangArgs = new ArrayList<>();
Expand All @@ -79,7 +83,7 @@ public Options build() {
Collections.unmodifiableList(clangArgs),
Collections.unmodifiableList(libraryNames),
Collections.unmodifiableList(filters),
targetPackage, outputDir, source
targetPackage, outputDir, source, includeHelper
);
}

Expand All @@ -106,5 +110,13 @@ public void addFilter(String filter) {
public void setGenerateSource() {
source = true;
}

public void setDumpIncludeFile(String dumpIncludesFile) {
includeHelper.dumpIncludesFile = dumpIncludesFile;
}

public void addIncludeSymbol(IncludeHelper.IncludeKind kind, String symbolName) {
includeHelper.addSymbol(kind, symbolName);
}
}
}

0 comments on commit 04160de

Please sign in to comment.