Skip to content

fix: Stop running autogen.sh when building bundled libuv#430

Merged
cpsievert merged 5 commits intomainfrom
fix/libuv-autotools-build
Mar 11, 2026
Merged

fix: Stop running autogen.sh when building bundled libuv#430
cpsievert merged 5 commits intomainfrom
fix/libuv-autotools-build

Conversation

@cpsievert
Copy link
Contributor

@cpsievert cpsievert commented Mar 9, 2026

Problem

httpuv is failing to install on CRAN r-devel-macos-arm64 with:

autogen.sh: line 43: glibtoolize: command not found
WARNING: 'aclocal-1.16' is missing on your system.
make: *** [libuv/.libs/libuv.b] Error 2

Root cause

When building the bundled libuv, src/Makevars.in checks whether automake is on the system PATH:

  • No automake found → touches timestamps on pre-generated autotools files so make doesn't try to regenerate them, then runs ./configure (safe path)
  • automake found → runs autoupdate + autogen.sh to regenerate everything from scratch, then runs ./configure

On the CRAN r-devel-macos-arm64 machine, automake is present (so the else branch fires), but the rest of the autotools toolchain (glibtoolize, matching aclocal-1.16) is missing or version-mismatched. autogen.sh calls these tools and fails.

This automake-detection logic was added in #319 (Dec 2021) to handle cases where a newer system automake caused timestamp-related regeneration issues (#280). However, the regeneration approach introduced its own fragility — it requires a complete, version-matched autotools toolchain.

Fix

Three layers of defense, each sufficient on its own:

1. Remove autogen.sh at build time (1ec74b9)

Remove the if/else automake detection and autoupdate/autogen.sh calls from Makevars.in. The bundled libuv ships pre-generated autotools output — there is no reason to regenerate at build time. This eliminates all "Class 2" failures (#331, #338, #341, #429) where autogen.sh was called with an incomplete toolchain.

2. Touch inputs AND outputs (071c300)

The pre-#319 touch approach only touched output files (aclocal.m4, configure, Makefile.in). The generated Makefile contains regeneration rules that compare input timestamps (Makefile.am, configure.ac, m4/*.m4) against outputs. If any input has a newer timestamp (e.g. due to extraction ordering), make fires these rules — this was the cause of #124 and #280.

We now touch all autotools files, inputs first then outputs set to match, ensuring mtime(inputs) <= mtime(outputs).

3. AM_MAINTAINER_MODE (913474c)

Added AM_MAINTAINER_MODE to libuv's configure.ac and regenerated the autotools files. This wraps all regeneration rules in Makefile.in behind a @MAINTAINER_MODE_TRUE@ conditional that is disabled by default. Without --enable-maintainer-mode passed to ./configure, the rules are structurally absent from the generated Makefilemake never sees them regardless of timestamps or installed toolchain.

This is the standard approach used by projects that ship pre-generated autotools output (curl, libffi, libexpat, libxml2).

Historical evidence

Every libuv build failure in this repo's history falls into one of two classes:

Class 1: Regeneration triggered despite intent to prevent it (#124, #280)

Issue Platform Failure Fixed by
#124 CRAN Fedora automake 1.15 vs committed 1.15.1 Touch inputs (#2) + AM_MAINTAINER_MODE (#3)
#280 Alpine 3.12 automake 1.16.2 vs committed 1.16.1 Touch inputs (#2) + AM_MAINTAINER_MODE (#3)

Class 2: autogen.sh called with incomplete toolchain (#331, #338, #341, #429)

Issue Platform Missing tool Fixed by
#331 Ubuntu 18 libtoolize Remove autogen.sh (#1)
#338 User system Perl version mismatch in automake Remove autogen.sh (#1)
#341 Ubuntu 18 libtoolize Remove autogen.sh (#1)
#429 CRAN macOS arm64 glibtoolize + aclocal-1.16 Remove autogen.sh (#1)

🤖 Generated with Claude Code

The bundled libuv ships pre-generated autotools files (configure,
Makefile.in, aclocal.m4), so regenerating them via autogen.sh is
unnecessary and fragile. On CRAN r-devel-macos-arm64, automake is
present but the rest of the toolchain (glibtoolize, aclocal-1.16) is
missing, causing installation failure.

The timestamp-touch approach already prevents make from attempting
regeneration, regardless of whether automake is installed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@cpsievert cpsievert requested a review from shikokuchuo March 9, 2026 17:18
@shikokuchuo
Copy link
Member

@copilot review

Copy link

Copilot AI commented Mar 9, 2026

@shikokuchuo I've opened a new pull request, #431, to work on those changes. Once the pull request is ready, I'll request review from you.

Copy link
Member

@shikokuchuo shikokuchuo left a comment

Choose a reason for hiding this comment

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

Removing the conditional branch would seem to re-introduce #280, which would trigger when the system automake version is different to that used to generate the committed files?

Address review feedback re #280: the generated Makefile has rules that
trigger automake if input files (Makefile.am, configure.ac, m4/*.m4)
are newer than output files (configure, Makefile.in). Previously only
the output files were touched, which could still trigger regeneration
if inputs had newer timestamps from extraction ordering.

Now touch all autotools-related files (inputs first, then outputs) so
make never sees staleness and never fires the regeneration rules.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@cpsievert
Copy link
Contributor Author

Thanks for catching that @shikokuchuo! 071c300 should address the issues there. Also note the updated PR description with the reasoning behind It addressing #280.

I also had Claude do a bit of research into other issues that have reported install problems. It generated a little summary that's also included in the PR description.

@shikokuchuo
Copy link
Member

shikokuchuo commented Mar 10, 2026

Below solution suggested by Claude Code. I was sceptical about the diagnosis for "Class 1" problems that the "input files (Makefile.am, configure.ac, m4/*.m4) had newer timestamps than outputs after extraction". Given we just touched the output files, how could the input files have newer timestamps? => Removing the regeneration logic entirely seems to be surer.


Thanks for the fix — removing the autogen.sh path is clearly the right call and fixes #429 and the whole "class 2" (incomplete toolchain) category.

One suggestion for a more robust solution to the "class 1" failures (#124, #280) where make fires regeneration rules despite the touch. The touch approach works in practice, but the proper autotools mechanism for this is AM_MAINTAINER_MODE. Adding it to configure.ac:

AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects] UV_EXTRA_AUTOMAKE_FLAGS)
AM_MAINTAINER_MODE

This causes automake to wrap all regeneration rules in the generated Makefile.in behind a @MAINTAINER_MODE_TRUE@ conditional, which is disabled by default. Without --enable-maintainer-mode passed to ./configure, the rules are completely absent from the generated Makefilemake never sees them, so it can never try to run automake/autoconf regardless of timestamps.

This is the standard approach used by projects that ship pre-generated autotools output (curl, libffi, libexpat, libxml2 all use it).

With AM_MAINTAINER_MODE in place, the touch logic could be dropped entirely, or kept as belt-and-suspenders. Either way, the regeneration rules would be structurally eliminated rather than suppressed via timestamp manipulation.

This would need to be done at "Phase 1" time (developer runs autogen.sh and commits the regenerated files).

This is the standard autotools mechanism for preventing make from
trying to regenerate autotools files at build time. It wraps all
regeneration rules in Makefile.in behind a @MAINTAINER_MODE_TRUE@
conditional, which is disabled by default.

The touch logic in Makevars.in is kept as belt-and-suspenders.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Member

@shikokuchuo shikokuchuo left a comment

Choose a reason for hiding this comment

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

Great! I would not still touch the files, but it shouldn't do any harm.

@cpsievert cpsievert merged commit 93e515a into main Mar 11, 2026
25 of 26 checks passed
@cpsievert cpsievert deleted the fix/libuv-autotools-build branch March 11, 2026 16:46
cpsievert added a commit that referenced this pull request Mar 17, 2026
)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
cpsievert added a commit that referenced this pull request Mar 17, 2026
) (#434)

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
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.

3 participants