Skip to content

7903933: Move sharable items from different generations to a common file #278

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
29 changes: 15 additions & 14 deletions doc/GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -975,20 +975,21 @@ glutSolidTeapot(0.5)

A complete list of all the supported command line options is given below:

| Option | Meaning |
| :----------------------------------------------------------- | ------------------------------------------------------------ |
| `-D --define-macro <macro>=<value>` | define `<macro>` to `<value>` (or 1 if `<value>` omitted) |
| `--header-class-name <name>` | name of the generated header class. If this option is not specified, then header class name is derived from the header file name. For example, class "foo_h" for header "foo.h". If multiple headers are specified, then this option is mandatory. |
| `-t, --target-package <package>` | target package name for the generated classes. If this option is not specified, then unnamed package is used. |
| `-I, --include-dir <dir>` | append directory to the include search paths. Include search paths are searched in order. For example, if `-I foo -I bar` is specified, header files will be searched in "foo" first, then (if nothing is found) in "bar".|
| `-l, --library <name \| path>` | specify a shared library that should be loaded by the generated header class. If <libspec> starts with `:`, then what follows is interpreted as a library path. Otherwise, `<libspec>` denotes a library name. Examples: <br>`-l GL`<br>`-l :libGL.so.1`<br>`-l :/usr/lib/libGL.so.1`|
| `--use-system-load-library` | libraries specified using `-l` are loaded in the loader symbol lookup (using either `System::loadLibrary`, or `System::load`). Useful if the libraries must be loaded from one of the paths in `java.library.path`.|
| `--output <path>` | specify where to place generated files |
| `--dump-includes <String>` | dump included symbols into specified file (see below) |
| `--include-[function,constant,struct,union,typedef,var]<String>` | Include a symbol of the given name and kind in the generated bindings. When one of these options is specified, any symbol that is not matched by any specified filters is omitted from the generated bindings. |
| `--version` | print version information and exit |
| `-F <dir>` (macOs only) | specify the framework directory include files. Defaults to the current Mac OS X SDK dir.|
| `--framework <framework>` (macOs only) | specify the name of the library, path will be expanded to that of the framework folder.|
| Option | Meaning |
|:-----------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `-D --define-macro <macro>=<value>` | define `<macro>` to `<value>` (or 1 if `<value>` omitted) |
| `--header-class-name <name>` | name of the generated header class. If this option is not specified, then header class name is derived from the header file name. For example, class "foo_h" for header "foo.h". If multiple headers are specified, then this option is mandatory. |
| `-t, --target-package <package>` | target package name for the generated classes. If this option is not specified, then unnamed package is used. |
| `-I, --include-dir <dir>` | append directory to the include search paths. Include search paths are searched in order. For example, if `-I foo -I bar` is specified, header files will be searched in "foo" first, then (if nothing is found) in "bar". |
| `-l, --library <name \| path>` | specify a shared library that should be loaded by the generated header class. If <libspec> starts with `:`, then what follows is interpreted as a library path. Otherwise, `<libspec>` denotes a library name. Examples: <br>`-l GL`<br>`-l :libGL.so.1`<br>`-l :/usr/lib/libGL.so.1` |
| `--use-system-load-library` | libraries specified using `-l` are loaded in the loader symbol lookup (using either `System::loadLibrary`, or `System::load`). Useful if the libraries must be loaded from one of the paths in `java.library.path`. |
| `--output <path>` | specify where to place generated files |
| `--dump-includes <String>` | dump included symbols into specified file (see below) |
| `--include-[function,constant,struct,union,typedef,var]<String>` | Include a symbol of the given name and kind in the generated bindings. When one of these options is specified, any symbol that is not matched by any specified filters is omitted from the generated bindings. |
| `--symbols-class-name <name>` | override the name of the root header class |
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
| `--symbols-class-name <name>` | override the name of the root header class |
| `--symbols-class-name <name>` | override the name of the root header class |

| `--version` | print version information and exit |
| `-F <dir>` (macOs only) | specify the framework directory include files. Defaults to the current Mac OS X SDK dir. |
| `--framework <framework>` (macOs only) | specify the name of the library, path will be expanded to that of the framework folder. |


Jextract accepts one or more header files. When multiple header files are specified,
Expand Down
14 changes: 10 additions & 4 deletions src/main/java/org/openjdk/jextract/JextractTool.java
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,8 @@ private static List<JavaSourceFile> generateInternal(Declaration.Scoped decl, St
.findFirst().get();
return logger.hasErrors() ?
List.of() :
List.of(OutputFactory.generateWrapped(transformedDecl, targetPkg, libs, useSystemLoadLibrary));
List.of(OutputFactory.generateWrapped(transformedDecl, targetPkg, libs, useSystemLoadLibrary,
includeHelper.getSharedSymbolsFile()));
}

/**
Expand Down Expand Up @@ -334,7 +335,7 @@ OptionSet parse(String[] args) {
// so that option lookup, value lookup will work regardless
// which alias was used to check.
options.put(spec.name(), values);
for (String alias : spec.aliases()) {
for (String _ : spec.aliases()) {
options.put(spec.name(), values);
}
} else { // !isOption(arg)
Expand All @@ -356,6 +357,7 @@ private int run(String[] args) {
OptionParser parser = new OptionParser();
parser.accepts("-D", List.of("--define-macro"), "help.D", true);
parser.accepts("--dump-includes", "help.dump-includes", true);
parser.accepts("--symbols-class-name", "help.shared.symbols", true);
for (IncludeHelper.IncludeKind includeKind : IncludeHelper.IncludeKind.values()) {
parser.accepts("--" + includeKind.optionName(), "help." + includeKind.optionName(), true);
}
Expand Down Expand Up @@ -399,7 +401,7 @@ private int run(String[] args) {
Path compileFlagsTxt = Paths.get(".", "compile_flags.txt");
if (Files.exists(compileFlagsTxt)) {
try {
Files.lines(compileFlagsTxt).forEach(opt -> builder.addClangArg(opt));
Files.lines(compileFlagsTxt).forEach(builder::addClangArg);
} catch (IOException ioExp) {
logger.fatal(ioExp, "jextract.bad.compile.flags", ioExp.getMessage());
return OPTION_ERROR;
Expand Down Expand Up @@ -439,6 +441,10 @@ private int run(String[] args) {
builder.setDumpIncludeFile(optionSet.valueOf("--dump-includes"));
}

if (optionSet.has("--symbols-class-name")) {
builder.setSharedUtilsName(optionSet.valueOf("--symbols-class-name"));
}

if (optionSet.has("--output")) {
builder.setOutputDir(optionSet.valueOf("--output"));
}
Expand Down Expand Up @@ -471,7 +477,7 @@ private int run(String[] args) {

builder.addClangArg("-I" + System.getProperty("user.dir"));

if (optionSet.nonOptionArguments().size() == 0) {
if (optionSet.nonOptionArguments().isEmpty()) {
printOptionError(logger.format("expected.atleast.one.header"));
return OPTION_ERROR;
}
Expand Down
11 changes: 10 additions & 1 deletion src/main/java/org/openjdk/jextract/impl/ClassSourceBuilder.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 2025, 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
Expand Down Expand Up @@ -160,6 +160,15 @@ final void emitDefaultConstructor() {
""", className);
}

final void emitPrivateConstructor() {
appendIndentedLines("""

private %1$s() {
// Should not be called directly
}
""", className);
}

final void emitDocComment(Declaration decl) {
emitDocComment(decl, "");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ final class FunctionalInterfaceBuilder extends ClassSourceBuilder {

private FunctionalInterfaceBuilder(SourceFileBuilder builder, String className, ClassSourceBuilder enclosing,
String runtimeHelperName, Type.Function funcType, boolean isNested) {
super(builder, isNested ? "public static" : "public", Kind.CLASS, className, null, enclosing, runtimeHelperName);
super(builder, isNested ? "public final static" : "public final", Kind.CLASS, className, null, enclosing, runtimeHelperName);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes in this file seem unrelated? Leftover from other work?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change was to make the utility classes final, it's somewhat unrelated to this patch but it didn't seem to be worth a separate PR.

this.parameterNames = funcType.parameterNames().map(NameMangler::javaSafeIdentifiers);
this.funcType = funcType;
this.methodType = Utils.methodTypeFor(funcType);
Expand All @@ -55,7 +55,7 @@ public static void generate(SourceFileBuilder builder, String className, ClassSo
fib.appendBlankLine();
fib.emitDocComment(parentDecl);
fib.classBegin();
fib.emitDefaultConstructor();
fib.emitPrivateConstructor();
String fiName = fib.emitFunctionalInterface();
fib.emitDescriptorDecl();
fib.emitFunctionalFactory(fiName);
Expand Down Expand Up @@ -99,7 +99,7 @@ private void emitInvoke() {
boolean needsAllocator = Utils.isStructOrUnion(funcType.returnType());
String allocParam = needsAllocator ? ", SegmentAllocator alloc" : "";
String allocArg = needsAllocator ? ", alloc" : "";
String paramStr = methodType.parameterCount() != 0 ? String.format(",%1$s", paramExprs()) : "";
String paramStr = methodType.parameterCount() != 0 ? String.format(", %1$s", paramExprs()) : "";
appendIndentedLines("""

private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC);
Expand Down
26 changes: 25 additions & 1 deletion src/main/java/org/openjdk/jextract/impl/HeaderFileBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -351,10 +351,14 @@ void emitFirstHeaderPreamble(List<Options.Library> libraries, boolean useSystemL
.collect(Collectors.joining(String.format("\n%1$s", indentString(2)), "static final SymbolLookup SYMBOL_LOOKUP = ", ";")));
}

void emitLibaryArena(){appendIndentedLines("""

static final Arena LIBRARY_ARENA = Arena.ofAuto();""");
}
Comment on lines +354 to +357
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
void emitLibaryArena(){appendIndentedLines("""
static final Arena LIBRARY_ARENA = Arena.ofAuto();""");
}
void emitLibaryArena(){
appendIndentedLines("""
static final Arena LIBRARY_ARENA = Arena.ofAuto();""");
}


void emitRuntimeHelperMethods() {
appendIndentedLines("""

static final Arena LIBRARY_ARENA = Arena.ofAuto();
static final boolean TRACE_DOWNCALLS = Boolean.getBoolean("jextract.trace.downcalls");

static void traceDowncall(String name, Object... args) {
Expand Down Expand Up @@ -388,6 +392,26 @@ static MemoryLayout align(MemoryLayout layout, long align) {
""");
}

void emitBasicPrimitiveTypes(){
appendIndentedLines("""

public static final ValueLayout.OfBoolean C_BOOL = (ValueLayout.OfBoolean) Linker.nativeLinker().canonicalLayouts().get("bool");
public static final ValueLayout.OfByte C_CHAR =(ValueLayout.OfByte)Linker.nativeLinker().canonicalLayouts().get("char");
public static final ValueLayout.OfShort C_SHORT = (ValueLayout.OfShort) Linker.nativeLinker().canonicalLayouts().get("short");
public static final ValueLayout.OfInt C_INT = (ValueLayout.OfInt) Linker.nativeLinker().canonicalLayouts().get("int");
public static final ValueLayout.OfLong C_LONG_LONG = (ValueLayout.OfLong) Linker.nativeLinker().canonicalLayouts().get("long long");
public static final ValueLayout.OfFloat C_FLOAT = (ValueLayout.OfFloat) Linker.nativeLinker().canonicalLayouts().get("float");
public static final ValueLayout.OfDouble C_DOUBLE = (ValueLayout.OfDouble) Linker.nativeLinker().canonicalLayouts().get("double");
public static final AddressLayout C_POINTER = ((AddressLayout) Linker.nativeLinker().canonicalLayouts().get("void*"))
.withTargetLayout(MemoryLayout.sequenceLayout(java.lang.Long.MAX_VALUE, C_CHAR));
""");
if (TypeImpl.IS_WINDOWS) {
appendIndentedLines("public static final ValueLayout.OfInt C_LONG = (ValueLayout.OfInt) Linker.nativeLinker().canonicalLayouts().get(\"long\");");
appendIndentedLines("public static final ValueLayout.OfDouble C_LONG_DOUBLE = (ValueLayout.OfDouble) Linker.nativeLinker().canonicalLayouts().get(\"double\");");
} else {
appendIndentedLines("public static final ValueLayout.OfLong C_LONG = (ValueLayout.OfLong) Linker.nativeLinker().canonicalLayouts().get(\"long\");");
}
}
private void emitGlobalGetter(String holderClass, String javaName,
Declaration.Variable decl, String docHeader) {
appendBlankLine();
Expand Down
9 changes: 7 additions & 2 deletions src/main/java/org/openjdk/jextract/impl/IncludeHelper.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 2025, 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
Expand Down Expand Up @@ -84,6 +84,11 @@ static IncludeKind fromScoped(Declaration.Scoped scoped) {
private final EnumMap<IncludeKind, Set<String>> includesSymbolNamesByKind = new EnumMap<>(IncludeKind.class);
private final Set<Declaration> usedDeclarations = new HashSet<>();
public String dumpIncludesFile;
public String sharedSymbolsFile;

public String getSharedSymbolsFile() {
return sharedSymbolsFile;
}
Comment on lines +87 to +91
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Uhm, I think this should just be in Options, not in IncludeHelper, since it's not related to the --include options.


public void addSymbol(IncludeKind kind, String symbolName) {
Set<String> names = includesSymbolNamesByKind.computeIfAbsent(kind, (_unused) -> new HashSet<>());
Expand Down Expand Up @@ -122,7 +127,7 @@ private boolean isIncludedInternal(IncludeKind kind, Declaration declaration) {
if (!isEnabled()) {
return true;
} else {
Set<String> names = includesSymbolNamesByKind.computeIfAbsent(kind, (_unused) -> new HashSet<>());
Set<String> names = includesSymbolNamesByKind.computeIfAbsent(kind, _unused -> new HashSet<>());
return names.contains(declaration.name());
}
}
Expand Down
6 changes: 5 additions & 1 deletion src/main/java/org/openjdk/jextract/impl/Options.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 2025, 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
Expand Down Expand Up @@ -102,6 +102,10 @@ public void setDumpIncludeFile(String dumpIncludesFile) {
includeHelper.dumpIncludesFile = dumpIncludesFile;
}

public void setSharedUtilsName(String sharedSymbolsFile) {
includeHelper.sharedSymbolsFile = sharedSymbolsFile;
}

public void addIncludeSymbol(IncludeHelper.IncludeKind kind, String symbolName) {
includeHelper.addSymbol(kind, symbolName);
}
Expand Down
9 changes: 6 additions & 3 deletions src/main/java/org/openjdk/jextract/impl/OutputFactory.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, 2022 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 2025, 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
Expand Down Expand Up @@ -45,9 +45,12 @@ public class OutputFactory implements Declaration.Visitor<Void, Declaration> {

public static JavaSourceFile[] generateWrapped(Declaration.Scoped decl,
String pkgName,
List<Options.Library> libs, boolean useSystemLoadLibrary) {
List<Options.Library> libs,
boolean useSystemLoadLibrary,
String sharedSymbolsFile) {
String clsName = JavaName.getOrThrow(decl);
ToplevelBuilder toplevelBuilder = new ToplevelBuilder(pkgName, clsName, libs, useSystemLoadLibrary);
ToplevelBuilder toplevelBuilder = new ToplevelBuilder(pkgName, clsName,
libs, useSystemLoadLibrary, sharedSymbolsFile);
return new OutputFactory(toplevelBuilder).generate(decl);
}

Expand Down
Loading