Skip to content

build: keep full git version out of config.h (ccache-friendly) - #3759

Merged
jimklimov merged 8 commits into
networkupstools:masterfrom
nmbro:build-stable-config-h
Oct 21, 2026
Merged

jimklimov merged 8 commits into
networkupstools:masterfrom
nmbro:build-stable-config-h

Conversation

@nmbro

@nmbro nmbro commented Oct 14, 2026

Copy link
Copy Markdown
Contributor

Follow-up to #3754: instead of an AppVeyor-only CI_AUTOGEN_STABLE_VERSION workaround in ci_build.sh, keep the volatile git-derived version out of include/config.h for everyone (CI, packagers/OBS, local builds).

Problem

include/config.h is included by every source file and carried the full version (e.g. 2.8.5.1466.13) in PACKAGE_VERSION, PACKAGE_STRING and VERSION. These change with every commit, so ccache direct mode missed for every object on each new commit or fresh checkout.

Debug builds with CCACHE_DEBUG=1 across two commits showed:

  • Only those 3 lines of config.h differ between commits. No C code uses them (only an #if 0 block and #undefs next to net-snmp headers).
  • Without -g3, ccache's preprocessed mode mostly recovered the hits (364/381 on Linux), at the cost of a preprocessor pass per file.
  • With -g3 (as on AppVeyor), gcc -E keeps all #define lines in its output, so preprocessed mode misses too, and every object was recompiled. AppVeyor stats before CI: speed up AppVeyor build, fix ccache misses across PRs #3754: preprocessed mode hit 15 times in 1071 lookups.

Change

  • configure.ac: AC_INIT gets the base SEMVER (e.g. 2.8.5), which only changes with releases, so that is what lands in config.h. Right after AC_INIT, the shell PACKAGE_VERSION/PACKAGE_STRING are set back to the full VER50 value, so all @PACKAGE_VERSION@ substitutions are unchanged (Makefiles, *.pc, packaging recipes, driver.list, tarball name, configure report).
  • AM_INIT_AUTOMAKE([... no-define]): drops the unused PACKAGE/VERSION macros; VERSION is reset to the full version for distdir.
  • Programs still report the full version via NUT_VERSION_MACRO in include/nut_version.h, which only common/common-nut_version.c and clients/upsclient.c include.
  • Second commit: removes the now redundant CI_AUTOGEN_STABLE_VERSION from ci_build.sh (back to its pre-CI: speed up AppVeyor build, fix ccache misses across PRs #3754 form) and appveyor.yml. That workaround still changed whenever master advanced, and it also shortened the substituted version (tarball, *.pc).
  • Docs: INSTALL.nut.adoc ("Repetitive build/test optimizations"), docs/developers.txt, NEWS.adoc, UPGRADING.adoc.

Testing

  • Clean build (git clean -fdx, autogen, configure, make with CC="ccache gcc"), empty commit, then the same again: config.h byte-identical; all objects direct hits except the 2 nut_version.h consumers (x2 for libtool).
    • WSL Ubuntu 24.04, gcc 13, ccache 4.9: 377/381 hits, all direct.
    • ubuntu-plucky container, gcc 14, ccache 4.10: 427/431 hits, all direct.
  • make distcheck-light, plus building from the resulting tarball without git (VERSION_DEFAULT path): config.h gets 2.8.5, Makefiles get the full version.
  • NUT_VERSION_FORCED set: the semver goes into config.h, the forced value everywhere else.
  • autoconf 2.69 on CentOS 7 and Ubuntu Trusty containers: same result (same pre-existing "AC_INIT: not a literal" warning).
  • make spellcheck, ASCII-only check on all changed text.
  • Not yet verified: AppVeyor ccache hits without CI_AUTOGEN_STABLE_VERSION. This PR's AppVeyor run should show it (after a warm-up build, since config.h content changes once).

Open question

./configure --version and the config.log header now show the base semver (2.8.5) instead of the full version. If that matters, the alternative is to keep AC_INIT full and strip the defines from confdefs.h before AC_OUTPUT, which is uglier and more fragile.

Checklist

  • Described the changes in the PR submission
  • Multiple commits, each with a functional change
  • Use of coding helper tools and AI disclosed: Claude Code was used for development assistance
  • Revised for NUT code style, ASCII-only text
  • Added a bullet point into NEWS.adoc, and UPGRADING.adoc
  • Passed make spellcheck
  • make distcheck-light passes

🤖 Generated with Claude Code

@github-actions

github-actions Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

A ZIP file with standard source tarball and another tarball with pre-built docs for commit b6ff843 is temporarily available: NUT-tarballs-PR-3759.zip.

@jimklimov jimklimov 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.

Looks like a promising start, thanks! Added a few thoughts as I was reading through this PR, to challenge some assumptions. Feel free to prove me misled :D

Comment thread configure.ac
Comment thread configure.ac Outdated
Comment thread UPGRADING.adoc
nmbro added a commit to nmbro/nut that referenced this pull request Oct 14, 2026
Pass a new SEMVER_ACINIT query of gitlog2version.sh to AC_INIT instead
of the bare SEMVER: it is the SEMVER for releases, and by the legacy
convention a nominal "SEMVER.1" for any development iteration after
that release, so the include/config.h macros still tell releases and
development builds apart, but do not change between releases and keep
build caches valid. It is built from the triplet, so a 4-component
NUT_VERSION_DEFAULT (e.g. 2.8.5.1) does not get a second ".1" suffix.
For pre-release tagged commits SEMVER is the upcoming release, so the
VER50 triplet is used there (unless NUT_VERSION_FORCED_SEMVER is set).

Checked with sh, dash and bash for git and NUT_VERSION_DEFAULT values
(release, development, tarball and pre-release ones), and that
config.h gets 2.8.5.1 while Makefiles keep the full 2.8.5.1503.2.
Spellcheck passes with both current and old aspell-en 7.1.

Suggested in PR networkupstools#3759 review.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: nmbro <nmbro@users.noreply.github.com>
@user01010111

Copy link
Copy Markdown
Contributor

Tested bb5de632 on native Linux using the source archive, NUT_VERSION_FORCED, GCC 16.2.1 and ccache 4.14 with -g3 -O2.

A clean rebuild after changing the full version produced 174 direct hits out of 178 cacheable calls. The four misses were exactly common-nut_version.c and upsclient.c, each built twice by libtool. config.h stayed byte-identical, and upsc -V reported the new full version. The cache behaviour matches the intention in this build.

One test expectation update turned up: make shellcheck-nde, with NDE pointed at the generated enumerator, gave 13 failures and 123 passes. report_debug() now includes SEMVER_ACINIT, but the existing version tests still expect the old diagnostic output.

Keeping the PR’s helper unchanged and updating only those 13 expected diagnostic strings in a temporary test copy gave 136 passes and no failures. Looks like those expectations need updating alongside the helper.

nmbro and others added 3 commits October 15, 2026 10:27
include/config.h is included by every source file, and carried the full
git-derived version (e.g. 2.8.5.1466.13) in PACKAGE_VERSION,
PACKAGE_STRING and VERSION macros. It changed with every commit, so
ccache direct mode missed for all objects on each new commit or fresh
CI checkout. Without -g3, preprocessed mode mostly recovered the hits
(no code uses these macros), but with -g3 (e.g. AppVeyor) the
preprocessed output keeps all #define lines, so every object was
recompiled.

Pass the base SEMVER (e.g. 2.8.5) to AC_INIT, so config.h only changes
with releases, and set the shell PACKAGE_VERSION/PACKAGE_STRING right
after it back to the full VER50 value, so all @PACKAGE_VERSION@
substitutions (Makefiles, *.pc files, packaging recipes, tarball names,
configure reports) keep the full version. Use AM_INIT_AUTOMAKE
no-define (PACKAGE and VERSION macros are unused) and reset VERSION
for distdir. Programs still report the full version via
NUT_VERSION_MACRO in include/nut_version.h, consumed by two files.

Checked with CCACHE_DEBUG=1 builds across two commits (WSL gcc 13,
ubuntu-plucky gcc 14): config.h byte-identical, all objects direct
hits except upsclient.o and common-nut_version.o. Also checked a dist
tarball build (VERSION_DEFAULT), NUT_VERSION_FORCED, and autoconf
2.69 on CentOS 7 and Ubuntu Trusty.

Docs go into the "Repetitive build/test optimizations" chapter of
INSTALL.nut.adoc. Follow-up to PR networkupstools#3754.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: nmbro <nmbro@users.noreply.github.com>
With the full git version kept out of include/config.h, there is no
need for ci_build.sh to force a shortened version into autogen.sh to
keep ccache hits across pull requests. The workaround was AppVeyor
only, still changed whenever master advanced, and also shortened the
substituted @PACKAGE_VERSION@ (tarball, *.pc). Restore the plain
autogen.sh call and drop the setting from appveyor.yml and the docs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: nmbro <nmbro@users.noreply.github.com>
Pass a new SEMVER_ACINIT query of gitlog2version.sh to AC_INIT instead
of the bare SEMVER: it is the SEMVER for releases, and by the legacy
convention a nominal "SEMVER.1" for any development iteration after
that release, so the include/config.h macros still tell releases and
development builds apart, but do not change between releases and keep
build caches valid. It is built from the triplet, so a 4-component
NUT_VERSION_DEFAULT (e.g. 2.8.5.1) does not get a second ".1" suffix.
For pre-release tagged commits SEMVER is the upcoming release, so the
VER50 triplet is used there (unless NUT_VERSION_FORCED_SEMVER is set).

Checked with sh, dash and bash for git and NUT_VERSION_DEFAULT values
(release, development, tarball and pre-release ones), and that
config.h gets 2.8.5.1 while Makefiles keep the full 2.8.5.1503.2.
Spellcheck passes with both current and old aspell-en 7.1.

Update the gitlog2version test expectations in
tests/nut-driver-enumerator-test.sh for the SEMVER_ACINIT value now
included in the debug output, and add test cases for the new query
(release, development, 4-component default and release candidate).

Suggested in PR networkupstools#3759 review.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: nmbro <nmbro@users.noreply.github.com>
@nmbro
nmbro force-pushed the build-stable-config-h branch from bb5de63 to 4878552 Compare October 15, 2026 09:40
@nmbro

nmbro commented Oct 15, 2026

Copy link
Copy Markdown
Contributor Author

Thanks, fixed in 4878552 (also added SEMVER_ACINIT test cases).

@nmbro
nmbro marked this pull request as ready for review October 15, 2026 10:17
@jimklimov jimklimov added enhancement CI Entries related to continuous integration infrastructure (here CI = tools + scripts + recipes) labels Oct 15, 2026
@jimklimov jimklimov added this to the 2.8.6 milestone Oct 15, 2026
jimklimov added a commit to nmbro/nut that referenced this pull request Oct 15, 2026
…SEMVER_ACINIT corner case of `X.Y.Z.0(.0...)` [networkupstools#3759]

Signed-off-by: Jim Klimov <jimklimov+nut@gmail.com>
jimklimov added a commit to nmbro/nut that referenced this pull request Oct 15, 2026
… not worth mentioning in these notes [networkupstools#3759]

Signed-off-by: Jim Klimov <jimklimov+nut@gmail.com>

@jimklimov jimklimov 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.

Thanks for both PRs!

nmbro added a commit to nmbro/nut that referenced this pull request Oct 15, 2026
Add a "GHA-07: ShellCheck" workflow for pull requests, which runs
ShellCheck on the shell scripts changed by the PR. The existing scripts
have many known findings (about 2900 in the tree, 28 of them errors),
so checking the whole tree would always fail. Instead, the new
tools/shellcheck-ci.pl helper checks both the base and the PR versions
of the changed scripts, and reports only new findings, matched by file,
ShellCheck code and source line text (so moved code does not count as
new). It fails for new "warning" or "error" level findings; new "note"
level (info and style) ones are shown as notices. In GitHub Actions,
the findings are shown as annotations on the changed lines and listed
in the job summary, with links to the lines and the ShellCheck wiki.
It can be run locally against any base revision, including uncommitted
changes.

The helper is in Perl, like tools/check-source-nonascii.pl (Perl is
already needed for autogen.sh in Git workspaces). It only uses core
Perl 5 modules, and parses the "gcc" output format of shellcheck, so
no JSON module is needed on older systems.

The workflow uses only actions/checkout (no new third-party actions)
and compares the PR merge commit with its first parent.

A new .shellcheckrc file disables the checks for deliberate portability
idioms of NUT scripts: backticks (SC2006), x"$var" comparisons (SC2268)
and expr (SC2003). It is distributed like .editorconfig, to help the
tarball users contribute too.

Describe both in docs/qa-guide.adoc, replacing the note that the tool
could be introduced at a later time. The .shellcheckrc backticks setting
does for ShellCheck what the previous commit did for "make shellcheck"
(issue networkupstools#1058).

Checked with the "build: keep full git version out of config.h" series
(PR networkupstools#3759): its first version is reported for one new SC2166 warning
([ p -a q ]) and the final one passes. Checked renamed, added, removed
and non-shell files, a bad base revision, and the workflow with
actionlint and zizmor. In a test PR on a fork, deliberate findings
showed as annotations on the changed lines.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: nmbro <nmbro@users.noreply.github.com>
…SEMVER_ACINIT corner case of `X.Y.Z.0(.0...)` [networkupstools#3759]

Signed-off-by: Jim Klimov <jimklimov+nut@gmail.com>
… not worth mentioning in these notes [networkupstools#3759]

Signed-off-by: Jim Klimov <jimklimov+nut@gmail.com>
@jimklimov
jimklimov force-pushed the build-stable-config-h branch from 1759fa5 to 6056077 Compare October 15, 2026 20:38
nmbro added a commit to nmbro/nut that referenced this pull request Oct 15, 2026
Add a "GHA-07: ShellCheck" workflow for pull requests, which runs
ShellCheck on the shell scripts changed by the PR. The existing scripts
have many known findings (about 2900 in the tree, 28 of them errors),
so checking the whole tree would always fail. Instead, the new
tools/shellcheck-ci.pl helper checks both the base and the PR versions
of the changed scripts, and reports only new findings, matched by file,
ShellCheck code and source line text (so moved code does not count as
new). It fails for new "warning" or "error" level findings; new "note"
level (info and style) ones are shown as notices. In GitHub Actions,
the findings are shown as annotations on the changed lines and listed
in the job summary, with links to the lines and the ShellCheck wiki.
It can be run locally against any base revision, including uncommitted
changes.

The helper is in Perl, like tools/check-source-nonascii.pl (Perl is
already needed for autogen.sh in Git workspaces). It only uses core
Perl 5 modules, and parses the "gcc" output format of shellcheck, so
no JSON module is needed on older systems.

The workflow uses only actions/checkout (no new third-party actions)
and compares the PR merge commit with its first parent.

A new .shellcheckrc file disables the checks for deliberate portability
idioms of NUT scripts: backticks (SC2006), x"$var" comparisons (SC2268)
and expr (SC2003). It is distributed like .editorconfig, to help the
tarball users contribute too.

Describe both in docs/qa-guide.adoc, replacing the note that the tool
could be introduced at a later time. The .shellcheckrc backticks setting
does for ShellCheck what the previous commit did for "make shellcheck"
(issue networkupstools#1058).

Checked with the "build: keep full git version out of config.h" series
(PR networkupstools#3759): its first version is reported for one new SC2166 warning
([ p -a q ]) and the final one passes. Checked renamed, added, removed
and non-shell files, a bad base revision, and the workflow with
actionlint and zizmor. In a test PR on a fork, deliberate findings
showed as annotations on the changed lines.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: nmbro <nmbro@users.noreply.github.com>
@github-actions github-actions Bot deleted a comment from AppVeyorBot Oct 18, 2026
@github-actions github-actions Bot deleted a comment from AppVeyorBot Oct 18, 2026
@AppVeyorBot

Copy link
Copy Markdown

@AppVeyorBot

Copy link
Copy Markdown

@AppVeyorBot

Copy link
Copy Markdown

@AppVeyorBot

Copy link
Copy Markdown

@nmbro

nmbro commented Oct 20, 2026

Copy link
Copy Markdown
Contributor Author

@jimklimov I'm trying to collect all of the red crosses, got to catch them all!

I have spotted some other improvements that can be done to AppVeyor build (again) (will open another PR with those)

but this is still the biggest immediate save, since it's adding unused ccache per PR

@jimklimov

Copy link
Copy Markdown
Member

@nmbro : thanks! Note that PR #3786 aims to fix some flaky test failure causes that got into upstream and were discovered with recent faults of unrelated PRs, so assuming it passes okay, many of the recently-regular red crosses will dissipate. I expect to merge it then, roughly in 12 hours...

@jimklimov
jimklimov merged commit 3a703f8 into networkupstools:master Oct 21, 2026
127 of 134 checks passed
@nmbro
nmbro deleted the build-stable-config-h branch October 21, 2026 15:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CI Entries related to continuous integration infrastructure (here CI = tools + scripts + recipes) enhancement

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants