Skip to content

Speed up workspace compilation e.g. in Eclipse - New -rebuildtriggerpolicy instruction to avoid unnecessary rebuild cascades#7209

Open
chrisrueger with Copilot wants to merge 2 commits into
masterfrom
copilot/optimize-bnd-workspace-builds
Open

Speed up workspace compilation e.g. in Eclipse - New -rebuildtriggerpolicy instruction to avoid unnecessary rebuild cascades#7209
chrisrueger with Copilot wants to merge 2 commits into
masterfrom
copilot/optimize-bnd-workspace-builds

Conversation

Copilot AI commented Apr 18, 2026

Copy link
Copy Markdown
Contributor

This pull request introduces a new build optimization to the bnd build system, allowing projects to avoid unnecessary rebuilds of dependent artifacts when the output JAR's content or exported API has not changed. The feature is controlled by a new -rebuildtriggerpolicy property, which can be set to either always (the default) or api. When set to api, the system preserves the JAR's timestamp if the content or exported API is unchanged, thereby preventing downstream rebuild cascades. The implementation includes content and API digest calculation and storage, as well as comprehensive tests validating the new behavior.

Eclipse bndtools Preference

There is a new bndtools Preference setting in Eclipse, which can override the -rebuildtriggerpolicy: in cnf/build.bnd. That means you can also use the feature without touching cnf/build.bnd at all.

image

Testing the value via cnf/build.bnd

  1. use Eclipse with bndtools
  2. put the following in your /cnf/build.bnd
-rebuildtriggerpolicy: api

or to tie it only to Eclipse builds

-rebuildtriggerpolicy: ${if;${driver;eclipse};api;always}
  1. Press Refresh Bnd Workspace button

  2. rebuild the whole workspace (e.g. clean all just once)

  3. Go to a Bundle A of your choise which has many downstream bundles which depend on A (usually some util bundle at the root of the bundle hiearchy which is used by every bundle)

  4. Pick a random java method and add a System.out.println("hello");

  5. Save the file

Expected result:

  • now only the bundle where you added the change should be build (this is the new behavior and optimization... it just builds the bundle you just changed). Try the same with adding a method comment.
  1. Now make a public API change: e.g. add a new default method to an interface (which just prints hello world)
    Expected result:
  • the current bundle and all downstream bundles should be rebuild (since this is an API change it should behave as before)

Previous bahavior before this PR:
If you remove -rebuildtriggerpolicy from build.bnd if should behave as before this PR - all downstream projects should be build with each change all the time.

Key changes:

Build Optimization: Content/API Digest and Timestamp Preservation

  • Introduced the RebuildTriggerPolicy mechanism in Project.java, which determines whether to preserve the build artifact's timestamp based on content or API digests. This prevents unnecessary downstream rebuilds when the output JAR is unchanged or only non-API changes occurred. The policy supports always (default) and api modes, with digest files (.digest and .api-digest) used for comparison. [1] [2] [3]
  • On build, content and API digests are computed and stored as sidecar files. If the digests match the previous build, the JAR's timestamp is preserved. If not, the timestamp is updated as usual. [1] [2]
  • When removing build files, any associated digest files are also deleted to avoid stale state.

Configuration and Documentation

  • Added the new -rebuildtriggerpolicy property to Constants.java and included it in the recognized options set. [1] [2]
  • Updated the help system with a detailed description of the new property, including usage and examples, in Syntax.java.

Testing

  • Added comprehensive tests in ProjectTest.java to verify:
    • Builds are skipped and timestamps preserved when content is unchanged.
    • JARs are rewritten and digests updated when content changes.
    • The API digest mechanism correctly preserves timestamps when only internal (non-API) changes are made.

Dependency and Import Updates

  • Added necessary imports for digest calculation and API analysis in Project.java. [1] [2] [3] [4] [5]

Copilot AI requested a review from chrisrueger April 18, 2026 08:49
@chrisrueger chrisrueger changed the title Add content-hash optimization to avoid unnecessary rebuild cascades Add content-hash optimization to avoid unnecessary rebuild cascades (Opus 4.6) Apr 18, 2026
@chrisrueger

Copy link
Copy Markdown
Contributor

First experiments in my larger project look very promising. Simple java changes which do not change public API or the manifest do not cause a downstream rebuild cascade. Only e.g. changes to interfaces , method signatures etc. would cause a downstream rebuild of dependant projects like before.

This makes development nicer since it cuts down waiting time a lot.

@chrisrueger chrisrueger changed the title Add content-hash optimization to avoid unnecessary rebuild cascades (Opus 4.6) New -rebuildtriggerpolicy instruction to avoid unnecessary rebuild cascades (Opus 4.6) Apr 18, 2026
@chrisrueger chrisrueger marked this pull request as ready for review April 18, 2026 19:49
@chrisrueger

Copy link
Copy Markdown
Contributor

@peterkir FYI Let's discuss next week.

@chrisrueger chrisrueger changed the title New -rebuildtriggerpolicy instruction to avoid unnecessary rebuild cascades (Opus 4.6) New -rebuildtriggerpolicy instruction to avoid unnecessary rebuild cascades Apr 18, 2026
@chrisrueger chrisrueger changed the title New -rebuildtriggerpolicy instruction to avoid unnecessary rebuild cascades Speed up workspace compilation e.g. in Eclipse - New -rebuildtriggerpolicy instruction to avoid unnecessary rebuild cascades Apr 29, 2026
After building a project's JAR, compute a timeless content digest
and compare with the previously stored digest. If the content is
unchanged, preserve the old JAR's timestamp. This prevents
dependent projects from seeing a newer timestamp and triggering
unnecessary rebuilds.

The optimization uses Jar.getTimelessDigest() which ignores
build-time-specific data (BND_LASTMODIFIED, version qualifier)
to determine if the meaningful content has changed. A .digest
sidecar file stores the hex digest alongside each build output.

Agent-Logs-Url: https://github.com/bndtools/bnd/sessions/662b413c-3754-4104-a50f-cb8503721220

Signed-off-by: Christoph Rueger <chrisrueger@gmail.com>
Co-Authored-By: chrisrueger <188422+chrisrueger@users.noreply.github.com>
@chrisrueger chrisrueger force-pushed the copilot/optimize-bnd-workspace-builds branch from bb790c6 to 8ec68dc Compare June 24, 2026 12:30
Adds a new 'Rebuild Trigger Policy' dropdown to the Bnd Build preferences
page, letting users choose between 'Always rebuild' and
'API-based (skip if API unchanged)' without editing cnf/build.bnd.

Signed-off-by: Christoph Rueger <chrisrueger@gmail.com>
RebuildTriggerPolicyResult doRebuildTriggerPolicy(Processor proc, Jar jar, File outputFile) {
String rebuildTriggerPolicy = proc.get(Constants.REBUILDTRIGGERPOLICY, ALWAYS);
if (ALWAYS.equals(rebuildTriggerPolicy)) {
String rebuildTriggerPolicy = proc.get(Constants.REBUILDTRIGGERPOLICY,

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.

@chrisrueger
Idea: also define a SystemProperty which can override the instruction.
Why? Then Eclipse Preferences (or CI) could set this to override whatever is in build.bnd

This would make the Eclipse Pref. switch behavior more predictable.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants