Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

docs: add JabKit native-image how-to#16135

Draft
wanling0000 wants to merge 7 commits into
JabRef:mainJabRef/jabref:mainfrom
wanling0000:docs/jabkit-native-imagewanling0000/jabref:docs/jabkit-native-imageCopy head branch name to clipboard
Draft

docs: add JabKit native-image how-to#16135
wanling0000 wants to merge 7 commits into
JabRef:mainJabRef/jabref:mainfrom
wanling0000:docs/jabkit-native-imagewanling0000/jabref:docs/jabkit-native-imageCopy head branch name to clipboard

Conversation

@wanling0000

Copy link
Copy Markdown
Collaborator

Related issues and pull requests

Closes no related issue.

This PR is part of JabRef components as native images project.

PR Description

Adds a developer how-to at docs/code-howtos/native-image.md.

Steps to test

Check the page under code-howtos -> jabkit-native-image.md

AI usage

Claude Code (model claude-opus-4-8). I used it to brainstorm the structure, draft the outline, and fill in details. All technical claims were verified against the codebase and the GraalVM documentation. I reviewed, edited, and take full ownership of the final text.

Checklist

  • I own the copyright of the code submitted and I license it under the MIT license
  • If AI tools were used, I disclosed them in the "AI usage" section and reviewed, understood, and take full ownership of all AI-generated code
  • I manually tested my changes in running JabRef (always required)
  • [/] I added JUnit tests for changes (if applicable)
  • [/] I added screenshots in the PR description (if change is visible to the user)
  • [/] I added a screenshot in the PR description showing a library with a single entry with me as author and as title the issue number
  • [/] I described the change in CHANGELOG.md in a way that can be understood by the average user (if change is visible to the user)
  • [/] I checked the user documentation for up to dateness and submitted a pull request to our user documentation repository

@qodo-free-for-open-source-projects

Copy link
Copy Markdown
Contributor

PR Summary by Qodo

Add developer how-to for building JabKit as a GraalVM native image

📝 Documentation 🕐 10-20 Minutes

Grey Divider

AI Description

• Document the JabKit GraalVM native-image build workflow and output artifacts.
• Explain reachability-metadata ownership, generation options, and troubleshooting loop.
• Describe Liberica NIK requirements and native-image smoke testing with clitest.
Diagram

graph TD
  Dev[Developer] --> Gradle["Gradle :jabkit:nativeCompile"] --> Compiler["GraalVM native-image"] --> Bin["jabkit executable"] --> Smoke["clitest smoke tests"]
  Repo[("Upstream metadata repo")] --> Meta["Reachability metadata"] --> Gradle
  Pico["picocli codegen"] --> Meta
  Local["JabRef reachability-metadata.json"] --> Meta
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Move the how-to into jabkit/README.md
  • ➕ Keeps build guidance closest to the module it describes
  • ➕ Improves discoverability for contributors focused on JabKit
  • ➖ Less consistent with the docs site's “Code Howtos” structure
  • ➖ Harder to include diagrams and broader project context
2. Encode more guidance as build-time checks/messages
  • ➕ Reduces reliance on tribal knowledge (e.g., NIK/AWT requirement)
  • ➕ Failures become self-explanatory in CI/local builds
  • ➖ Requires code/config changes and ongoing maintenance
  • ➖ Not all workflow knowledge (e.g., trimming metadata) is automatable

Recommendation: Keep the how-to under docs/code-howtos as in this PR, since it’s project-wide developer guidance spanning build, metadata ownership, and CI smoke tests. Consider adding a short pointer/link from JabKit’s module README (or CONTRIBUTING area) to improve discoverability without duplicating content.

Files changed (1) +173 / -0

Documentation (1) +173 / -0
jabkit-native-image.mdAdd JabKit GraalVM native-image developer how-to +173/-0

Add JabKit GraalVM native-image developer how-to

• Introduces a new guide describing how to build JabKit as a native executable, where reachability metadata lives, and how to iteratively add missing metadata. Documents the Liberica NIK rationale/limitations (AWT/PDFBox) and the clitest-based smoke testing approach used to prevent metadata regressions.

docs/code-howtos/jabkit-native-image.md

@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Code Review by Qodo

🐞 Bugs (2) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Remediation recommended

1. Phantom PDF smoke test 🐞 Bug ≡ Correctness
Description
The how-to documents a jabkit-offline-pdf.md smoke test and claims it runs from
jabkit-native-smoke-test.yml, but the current workflow only executes jabkit-offline.md and
jabkit-online.md, so the described PDF/AWT coverage is incorrect.
Code

docs/code-howtos/jabkit-native-image.md[R167-173]

+| File | Scope | Runs |
+|---|---|---|
+| `jabkit-offline.md` | Commands needing no network | Linux and macOS |
+| `jabkit-offline-pdf.md` | The PDF/AWT path | Linux only; see [Liberica NIK](#liberica-nik) |
+| `jabkit-online.md` | Commands hitting external APIs | Opt-in with `run-online-tests` |
+
+All three files live in `jabkit/src/test/nativeimage/` and run from `jabkit-native-smoke-test.yml`.
Evidence
The new doc explicitly lists jabkit-offline-pdf.md and states all three files run from the
workflow, but the workflow only invokes the offline and online markdown files.

docs/code-howtos/jabkit-native-image.md[165-173]
.github/workflows/jabkit-native-smoke-test.yml[47-53]
jabkit/src/test/nativeimage/jabkit-offline.md[1-5]
jabkit/src/test/nativeimage/jabkit-online.md[1-5]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The new documentation claims there are three clitest smoke-test files (including `jabkit-offline-pdf.md`) and that all run in `jabkit-native-smoke-test.yml`, but the repository CI only runs the offline and online tests.
### Issue Context
This is a documentation correctness issue: readers will look for a non-existent/unused PDF smoke test and may assume PDF/AWT paths are continuously validated when they are not.
### Fix Focus Areas
- docs/code-howtos/jabkit-native-image.md[165-173]
- .github/workflows/jabkit-native-smoke-test.yml[47-53]
### Suggested fix
Either (A) remove/mark as future work the `jabkit-offline-pdf.md` row and update the text to reflect the two files currently run by CI, or (B) actually add `jabkit-offline-pdf.md` and update the workflow to run it on Linux only.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Wrong CI setup instructions 🐞 Bug ≡ Correctness
Description
The how-to instructs using graalvm/setup-graalvm with distribution: liberica in
jabkit-native-smoke-test.yml, but the actual workflow uses the repo composite action
setup-gradle which delegates to actions/setup-java with distribution: graalvm, so following
the doc will not reproduce CI.
Code

docs/code-howtos/jabkit-native-image.md[R125-126]

+- **Locally:** install the Liberica NIK Full package that matches the project's JDK version, and point `GRAALVM_HOME` and `JAVA_HOME` at it.
+- **In CI** (`jabkit-native-smoke-test.yml`): use [`graalvm/setup-graalvm`](https://github.com/graalvm/setup-graalvm#supported-distributions) with `distribution: liberica` (NIK) and `java-package: jdk+fx` (the Full package).
Evidence
The how-to claims a specific CI action/distribution, but the referenced workflow file and the
composite setup action show a different mechanism and distribution.

docs/code-howtos/jabkit-native-image.md[123-127]
.github/workflows/jabkit-native-smoke-test.yml[31-36]
.github/actions/setup-gradle/action.yml[17-23]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The CI setup documented in the new page does not match the actual workflow configuration.
### Issue Context
The doc specifically names `graalvm/setup-graalvm` + Liberica NIK Full, but the repo workflow uses `./.github/actions/setup-gradle` (actions/setup-java) with distribution `graalvm`.
### Fix Focus Areas
- docs/code-howtos/jabkit-native-image.md[123-127]
- .github/workflows/jabkit-native-smoke-test.yml[31-36]
- .github/actions/setup-gradle/action.yml[17-23]
### Suggested fix
Update the documentation to reflect the real CI setup (or, if the intent is to switch CI to Liberica NIK Full, update the workflow accordingly and keep the docs in sync).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Informational

3. Docs link escapes site root ✓ Resolved 🐞 Bug ⚙ Maintainability
Description
The page links to ../../.jbang, but the developer documentation site is built/served from the
docs/ directory, so that relative URL points outside the rendered site content and is likely
broken for readers.
Code

docs/code-howtos/jabkit-native-image.md[8]

+It is currently shipped through `jpackage` (installer and portable build, both bundling a JDK) and [JBang](../../.jbang) (which downloads a JRE plus `jablib`). For a command-line tool, **JVM start-up is the bottleneck**.
Evidence
The new doc uses a relative link that traverses outside docs/, while the docs are served from
docs/ (see local development instructions) and .jbang is a top-level repo directory.

docs/code-howtos/jabkit-native-image.md[6-9]
docs/README.md[19-24]
.jbang/README.md[1-4]
docs/decisions/0048-jbang-script-modification-for-testing-in-ci.md[12-16]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The how-to uses a relative link to `../../.jbang`, which navigates outside the `docs/` tree used to build/serve the developer documentation site.
### Issue Context
When serving docs locally (and typically when publishing the site), only the `docs/` directory is part of the site root. Linking to paths outside that directory is likely to 404.
### Fix Focus Areas
- docs/code-howtos/jabkit-native-image.md[6-9]
### Suggested fix
Replace `../../.jbang` with a stable GitHub URL (e.g., `https://github.com/JabRef/jabref/tree/main/.jbang` or a link to `.jbang/README.md`).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

Comment thread docs/code-howtos/jabkit-native-image.md
Comment on lines +125 to +126
- **Locally:** install the Liberica NIK Full package that matches the project's JDK version, and point `GRAALVM_HOME` and `JAVA_HOME` at it.
- **In CI** (`jabkit-native-smoke-test.yml`): use [`graalvm/setup-graalvm`](https://github.com/graalvm/setup-graalvm#supported-distributions) with `distribution: liberica` (NIK) and `java-package: jdk+fx` (the Full package).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Remediation recommended

2. Wrong ci setup instructions 🐞 Bug ≡ Correctness

The how-to instructs using graalvm/setup-graalvm with distribution: liberica in
jabkit-native-smoke-test.yml, but the actual workflow uses the repo composite action
setup-gradle which delegates to actions/setup-java with distribution: graalvm, so following
the doc will not reproduce CI.
Agent Prompt
### Issue description
The CI setup documented in the new page does not match the actual workflow configuration.

### Issue Context
The doc specifically names `graalvm/setup-graalvm` + Liberica NIK Full, but the repo workflow uses `./.github/actions/setup-gradle` (actions/setup-java) with distribution `graalvm`.

### Fix Focus Areas
- docs/code-howtos/jabkit-native-image.md[123-127]
- .github/workflows/jabkit-native-smoke-test.yml[31-36]
- .github/actions/setup-gradle/action.yml[17-23]

### Suggested fix
Update the documentation to reflect the real CI setup (or, if the intent is to switch CI to Liberica NIK Full, update the workflow accordingly and keep the docs in sync).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment thread docs/code-howtos/jabkit-native-image.md Outdated
@github-actions github-actions Bot added the status: changes-required Pull requests that are not yet complete label Jul 1, 2026
@github-actions github-actions Bot added status: no-bot-comments and removed status: changes-required Pull requests that are not yet complete labels Jul 1, 2026

@koppor koppor left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

OKish good start.

Should be more clear and more structured

first present the as-is thing and then the howto to change things and then the limitations

Comment thread docs/code-howtos/jabkit-native-image.md Outdated

[GraalVM Native Image](https://www.graalvm.org/latest/reference-manual/native-image/) turns JabKit into a self-contained executable that starts in milliseconds. JabKit is the first target because it is headless; the JabLS, JabSrv and JabGui come later.

The catch is the closed-world assumption: Native Image must know every class, method, and resource the program can use. Anything reached only through **reflection, resources, serialization, dynamic proxies, or JNI** must be declared as **reachability metadata**. Producing that metadata correctly, minimally, and with clear ownership is what most of this page is about.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This is a bit lengthy.

  • shorten
  • link GraalVM documentation

Comment thread docs/code-howtos/jabkit-native-image.md Outdated
Comment thread docs/code-howtos/jabkit-native-image.md Outdated
Comment on lines +42 to +44
### Platform support

CI builds on Linux (`ubuntu-22.04`) and macOS (`macos-15`). The PDF attachment command currently works only on Linux because it uses an AWT path. See [Liberica NIK](#liberica-nik).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

?

Why not Windows would be more interesting. -- Limitations should be at the end, not in the middle.


### What the build produces on Linux

The build emits the `jabkit` binary plus companion `.so` files; native-image externalizes the JDK's AWT libraries. Check for `libfreetype.so` as part of that output: GraalVM CE emits `libawt.so` and `libfontmanager.so` too, but its AWT chain is incomplete, so it crashes at runtime. NIK Full completes the chain. Ship the whole `nativeCompile/` directory.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

?

I think, this can be removed

Or streamlined !!!!

say: binary and libraries and list them - not the long text. - and NOT the AWT AGAIN - AWT should be lsited at limitations once... at the end.


### macOS is a known limitation

Liberica NIK Full fixes the AWT path on **Linux**, verified end-to-end. On **macOS** it does not: the PDF-attachment command crashes loading `libawt_lwawt.dylib`, blocked by [oracle/graal#13272](https://github.com/oracle/graal/issues/13272) (runtime symptom: [oracle/graal#4124](https://github.com/oracle/graal/issues/4124)). The upstream fix landed in GraalVM `master` in May 2026 but is not in any released GraalVM/NIK yet; it should arrive in a future release. Until then, native PDF support on macOS is unavailable, which is why the [PDF smoke test](#smoke-testing) runs on Linux only.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

move to the end of the holw thing. we have the known AWT information aGAIN.


- Assert data or exit code, not fragile status text. Check `$?`, or use `grep -c` on a known stable string in the output.
- Silence expected noise. Add `--porcelain` at the leaf command.
- If a command has no `--porcelain`, assert the exit code. Commands without `SharedOptions`, such as `preferences export`, cannot take the flag, so check `; echo $?`.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

All commands should have --porcelain.

Modify JabKit to have all comamnds supporting --porcelain (even if internally, nothing is chaniged yet)


### How to write assertions

- Assert data or exit code, not fragile status text. Check `$?`, or use `grep -c` on a known stable string in the output.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

What is "fragile status text"? We have --porcelain... Give an example why procelain cannot help.

Currently, its not justified...

| --- | --- | --- |
| `jabkit-offline.md` | Commands needing no network | Linux and macOS |
| `jabkit-offline-pdf.md` | The PDF/AWT path | Linux only; see [Liberica NIK](#liberica-nik) |
| `jabkit-online.md` | Commands hitting external APIs | Opt-in with `run-online-tests` |

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

run-online-tests is defined where?

@github-actions github-actions Bot added status: changes-required Pull requests that are not yet complete and removed status: no-bot-comments labels Jul 2, 2026
@github-actions

Copy link
Copy Markdown
Contributor

The requested changes were not addressed for 10 days. Please follow-up in the next 10 days or your PR will be automatically closed. You can check the contributing guidelines for hints on the pull request process.

@github-actions github-actions Bot added the status: stale Issues marked by a bot as "stale". All issues need to be investigated manually. label Jul 13, 2026
Co-authored-by: Oliver Kopp <kopp.dev@gmail.com>
@wanling0000
wanling0000 marked this pull request as draft July 13, 2026 18:28
@github-actions github-actions Bot added status: no-bot-comments and removed status: changes-required Pull requests that are not yet complete status: stale Issues marked by a bot as "stale". All issues need to be investigated manually. labels Jul 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

Morty Proxy This is a proxified and sanitized view of the page, visit original site.