From 1ec74b98bbc0c417af995a20f03f9071ece2e01b Mon Sep 17 00:00:00 2001 From: Carson Date: Mon, 9 Mar 2026 12:10:56 -0500 Subject: [PATCH 1/5] fix: Stop running autogen.sh when building bundled libuv 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 --- src/Makevars.in | 26 +++++++------------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/src/Makevars.in b/src/Makevars.in index c744e24c..0dcc2eba 100644 --- a/src/Makevars.in +++ b/src/Makevars.in @@ -47,16 +47,11 @@ libuv/m4/lt~obsolete.m4: libuv/m4/lt_obsolete.m4 # Run ./configure to create the Makefile. # -# On systems that do _not_ have automake installed, we need to make sure that -# configure does not try to run automake, because it will fail. To do that, we -# we need to touch various autotools-related files so it doesn't try to run -# autotools programs again. We also need to make sure configure is executable, -# because on some platforms, calling unzip() in R does not preserve the -# executable bit. -# -# If the system does have automake, then we'll run autogen.sh before configure, -# as per the official build instructions for libuv. autogen.sh will in turn run -# aclocal, autoconf, and automake. +# We need to make sure that configure does not try to run automake, because it +# may not be present (or may be incomplete/mismatched). To do that, we touch +# various autotools-related files so it doesn't try to run autotools programs +# again. We also need to make sure configure is executable, because on some +# platforms, calling unzip() in R does not preserve the executable bit. # # It's VERY IMPORTANT that mtime(aclocal.m4) <= mtime(configure), and also # mtime(aclocal.m4) <= mtime(Makefile.in). On some platforms, passing multiple @@ -67,15 +62,8 @@ libuv/m4/lt~obsolete.m4: libuv/m4/lt_obsolete.m4 # precisely the same timestamp value. libuv/Makefile: libuv/m4/lt~obsolete.m4 cd libuv; \ - if ! command -v automake >/dev/null 2>&1 ; then \ - echo "automake not found. Touching files so configure will not try to run automake."; \ - touch aclocal.m4; \ - touch -r aclocal.m4 configure Makefile.in; \ - else \ - echo "automake found. Running autoupdate and autogen.sh."; \ - autoupdate; \ - sh autogen.sh; \ - fi; \ + touch aclocal.m4; \ + touch -r aclocal.m4 configure Makefile.in; \ chmod +x configure; \ CC="$(CC)" CFLAGS="$(CFLAGS) $(CPICFLAGS) $(C_VISIBILITY) -DNDEBUG" CPPFLAGS="$(CPPFLAGS)" AR="$(AR)" RANLIB="$(RANLIB)" LDFLAGS="$(LDFLAGS)" ./configure $(CONFIGURE_FLAGS) From 071c30068a3d63b47839358c05861b69c868663f Mon Sep 17 00:00:00 2001 From: Carson Date: Mon, 9 Mar 2026 16:09:31 -0500 Subject: [PATCH 2/5] fix: Also touch autotools input files to prevent make regeneration 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 --- src/Makevars.in | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/src/Makevars.in b/src/Makevars.in index 0dcc2eba..64e67ab6 100644 --- a/src/Makevars.in +++ b/src/Makevars.in @@ -47,22 +47,32 @@ libuv/m4/lt~obsolete.m4: libuv/m4/lt_obsolete.m4 # Run ./configure to create the Makefile. # -# We need to make sure that configure does not try to run automake, because it -# may not be present (or may be incomplete/mismatched). To do that, we touch -# various autotools-related files so it doesn't try to run autotools programs -# again. We also need to make sure configure is executable, because on some -# platforms, calling unzip() in R does not preserve the executable bit. +# The bundled libuv ships pre-generated autotools output files (configure, +# Makefile.in, aclocal.m4), so we do NOT need to run autogen.sh or automake. +# However, we must ensure that make doesn't try to regenerate these files +# either. The generated Makefile contains rules like: # -# It's VERY IMPORTANT that mtime(aclocal.m4) <= mtime(configure), and also -# mtime(aclocal.m4) <= mtime(Makefile.in). On some platforms, passing multiple -# files to a single touch command gives them all the same time, but on others -# (Solaris and possibly some Fedoras) the timestamps are slightly increasing -# from one to the next, i.e. the order matters. To remove this fragility, we -# use "-r aclocal.m4" to ensure that all three files are guaranteed to have -# precisely the same timestamp value. +# Makefile.in: Makefile.am $(am__configure_deps) +# $(AUTOMAKE) --foreign +# +# If any input file (Makefile.am, configure.ac, m4/*.m4) has a newer timestamp +# than the output files (configure, Makefile.in), make will fire these rules +# and try to run automake/autoconf — which may not be installed, or may be a +# mismatched version (see #280, #319). +# +# To prevent this, we touch ALL autotools-related files so that inputs and +# outputs share the same timestamp. We touch inputs first, then set outputs +# to match, ensuring mtime(inputs) <= mtime(outputs). +# +# On some platforms (Solaris, some Fedoras), passing multiple files to touch +# gives slightly increasing timestamps, so order matters. We use +# "-r aclocal.m4" to copy the exact timestamp to the output files. +# +# We also need to make sure configure is executable, because on some platforms, +# calling unzip() in R does not preserve the executable bit. libuv/Makefile: libuv/m4/lt~obsolete.m4 cd libuv; \ - touch aclocal.m4; \ + touch aclocal.m4 configure.ac Makefile.am m4/*.m4; \ touch -r aclocal.m4 configure Makefile.in; \ chmod +x configure; \ CC="$(CC)" CFLAGS="$(CFLAGS) $(CPICFLAGS) $(C_VISIBILITY) -DNDEBUG" CPPFLAGS="$(CPPFLAGS)" AR="$(AR)" RANLIB="$(RANLIB)" LDFLAGS="$(LDFLAGS)" ./configure $(CONFIGURE_FLAGS) From e054dfd45937e1fc8846ceb0bd4c65c71069ae87 Mon Sep 17 00:00:00 2001 From: Carson Date: Mon, 9 Mar 2026 16:30:05 -0500 Subject: [PATCH 3/5] ci: trigger workflow run From 3545935b581f1e4e98cb0c64ee9dbac82d576c95 Mon Sep 17 00:00:00 2001 From: cpsievert Date: Mon, 9 Mar 2026 21:35:36 +0000 Subject: [PATCH 4/5] `devtools::document()` (GitHub Actions) --- DESCRIPTION | 2 +- man/runStaticServer.Rd | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 95e79acc..d942436b 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -76,7 +76,7 @@ Config/testthat/edition: 3 Config/usethis/last-upkeep: 2025-07-01 Encoding: UTF-8 Roxygen: list(markdown = TRUE) -RoxygenNote: 7.3.2 +RoxygenNote: 7.3.3 SystemRequirements: GNU make, zlib Collate: 'RcppExports.R' diff --git a/man/runStaticServer.Rd b/man/runStaticServer.Rd index 37e226d8..3da02c59 100644 --- a/man/runStaticServer.Rd +++ b/man/runStaticServer.Rd @@ -72,7 +72,7 @@ When \code{background = TRUE}, the \code{server} object is returned invisibly. a single static directory, either in the foreground or the background. } \examples{ -\dontshow{if (interactive()) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} +\dontshow{if (interactive()) withAutoprint(\{ # examplesIf} website_dir <- system.file("example-static-site", package = "httpuv") runStaticServer(dir = website_dir) \dontshow{\}) # examplesIf} From 913474c427927ca3eed4d112df8a4cc8c3802961 Mon Sep 17 00:00:00 2001 From: Carson Date: Tue, 10 Mar 2026 12:10:07 -0500 Subject: [PATCH 5/5] fix: Add AM_MAINTAINER_MODE to bundled libuv configure.ac 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 --- src/Makevars.in | 22 ++++++---------------- src/README.md | 12 ++++++++---- src/libuv/Makefile.in | 7 ++++--- src/libuv/aclocal.m4 | 40 ++++++++++++++++++++++++++++++++++++++-- src/libuv/configure | 35 +++++++++++++++++++++++++++++++++++ src/libuv/configure.ac | 1 + 6 files changed, 92 insertions(+), 25 deletions(-) diff --git a/src/Makevars.in b/src/Makevars.in index 64e67ab6..29bd7ed0 100644 --- a/src/Makevars.in +++ b/src/Makevars.in @@ -49,24 +49,14 @@ libuv/m4/lt~obsolete.m4: libuv/m4/lt_obsolete.m4 # # The bundled libuv ships pre-generated autotools output files (configure, # Makefile.in, aclocal.m4), so we do NOT need to run autogen.sh or automake. -# However, we must ensure that make doesn't try to regenerate these files -# either. The generated Makefile contains rules like: # -# Makefile.in: Makefile.am $(am__configure_deps) -# $(AUTOMAKE) --foreign +# To prevent make from trying to regenerate these files, libuv's configure.ac +# uses AM_MAINTAINER_MODE, which wraps all regeneration rules behind a +# conditional that is disabled by default (see #280, #319, #429). # -# If any input file (Makefile.am, configure.ac, m4/*.m4) has a newer timestamp -# than the output files (configure, Makefile.in), make will fire these rules -# and try to run automake/autoconf — which may not be installed, or may be a -# mismatched version (see #280, #319). -# -# To prevent this, we touch ALL autotools-related files so that inputs and -# outputs share the same timestamp. We touch inputs first, then set outputs -# to match, ensuring mtime(inputs) <= mtime(outputs). -# -# On some platforms (Solaris, some Fedoras), passing multiple files to touch -# gives slightly increasing timestamps, so order matters. We use -# "-r aclocal.m4" to copy the exact timestamp to the output files. +# As belt-and-suspenders, we also touch autotools files so that +# mtime(inputs) <= mtime(outputs), preventing regeneration rules from firing +# even if AM_MAINTAINER_MODE were somehow bypassed. # # We also need to make sure configure is executable, because on some platforms, # calling unzip() in R does not preserve the executable bit. diff --git a/src/README.md b/src/README.md index bcbc5bae..b3657a6b 100644 --- a/src/README.md +++ b/src/README.md @@ -135,15 +135,19 @@ CC_CHECK_CFLAGS_APPEND([-Wno-declaration-after-statement]) ``` -#### Run `autoupdate` and `autogen.sh` +#### Run `autogen.sh` -After modifying Makefile.am, run `autoupdate` and then `./autogen.sh`. This requires automake and libtool, and generates the `configure` script, along with a number of other related files. These generated files are checked into the repository so that other systems to not need automake and libtool to build libuv. +After modifying Makefile.am or configure.ac, run `./autogen.sh`. This requires automake and libtool, and generates the `configure` script, along with a number of other related files. These generated files are checked into the repository so that other systems do not need automake and libtool to build libuv. The file `libuv/m4/lt~obsolete.m4` (generated by autogen.sh) is renamed to `lt_obsolete.m4` because the filename with the `~` causes problems with `R CMD check`. In the Makevars file, it gets copied to `lt~obsolete.m4` so that it's present during the build process. -In Makevars, before running `./configure`, it updates the timestamps output files `aclocal.m4`, `Makefile.in`, and `configure`, to make sure they are newer than the input files. Note that order matters: `aclocal.m4` must not be newer than the other files. On some platforms (like Solaris), the order in which the files are specified can matter. In our case, we touched `aclocal.m4`, and copied its date to the other files. +#### `AM_MAINTAINER_MODE` -If this is not done, then the `configure` script may generate a Makefile which tries to find `aclocal-1.15` and other autotools-related programs ([#124](https://github.com/rstudio/httpuv/issues/124)). See this [SO question](https://stackoverflow.com/questions/33278928/how-to-overcome-aclocal-1-15-is-missing-on-your-system-warning-when-compilin) for more information. +The `configure.ac` includes `AM_MAINTAINER_MODE`, which wraps all autotools regeneration rules in the generated `Makefile.in` behind a `@MAINTAINER_MODE_TRUE@` conditional. Since `--enable-maintainer-mode` is not passed to `./configure` at build time, these rules are disabled and `make` never attempts to re-run automake, autoconf, or aclocal — regardless of file timestamps or what autotools versions are installed on the build machine. + +This is the standard approach used by projects that ship pre-generated autotools output (e.g. curl, libffi, libexpat). See [#280](https://github.com/rstudio/httpuv/issues/280), [#319](https://github.com/rstudio/httpuv/pull/319), and [#429](https://github.com/rstudio/httpuv/issues/429) for history. + +As an additional safeguard, `Makevars.in` also touches autotools input and output files to ensure `mtime(inputs) <= mtime(outputs)`, preventing regeneration even if `AM_MAINTAINER_MODE` were somehow bypassed. The following generated files are checked into the repository: diff --git a/src/libuv/Makefile.in b/src/libuv/Makefile.in index 2461036b..5b0d6017 100644 --- a/src/libuv/Makefile.in +++ b/src/libuv/Makefile.in @@ -1271,6 +1271,7 @@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ @@ -1498,7 +1499,7 @@ all: all-am .SUFFIXES: .c .lo .o .obj am--refresh: Makefile @: -$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ @@ -1524,9 +1525,9 @@ Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) $(SHELL) ./config.status --recheck -$(top_srcdir)/configure: $(am__configure_deps) +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) $(am__cd) $(srcdir) && $(AUTOCONF) -$(ACLOCAL_M4): $(am__aclocal_m4_deps) +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) $(am__aclocal_m4_deps): libuv.pc: $(top_builddir)/config.status $(srcdir)/libuv.pc.in diff --git a/src/libuv/aclocal.m4 b/src/libuv/aclocal.m4 index 52076686..ac4b8fe5 100644 --- a/src/libuv/aclocal.m4 +++ b/src/libuv/aclocal.m4 @@ -14,8 +14,8 @@ m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl -m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.71],, -[m4_warning([this file was generated for autoconf 2.71. +m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.72],, +[m4_warning([this file was generated for autoconf 2.72. You have another version of autoconf. It may work, but is not guaranteed to. If you have problems, you may need to regenerate the build system entirely. To do so, use the procedure documented by the package, typically 'autoreconf'.])]) @@ -715,6 +715,42 @@ fi rmdir .tst 2>/dev/null AC_SUBST([am__leading_dot])]) +# Add --enable-maintainer-mode option to configure. -*- Autoconf -*- +# From Jim Meyering + +# Copyright (C) 1996-2021 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_MAINTAINER_MODE([DEFAULT-MODE]) +# ---------------------------------- +# Control maintainer-specific portions of Makefiles. +# Default is to disable them, unless 'enable' is passed literally. +# For symmetry, 'disable' may be passed as well. Anyway, the user +# can override the default with the --enable/--disable switch. +AC_DEFUN([AM_MAINTAINER_MODE], +[m4_case(m4_default([$1], [disable]), + [enable], [m4_define([am_maintainer_other], [disable])], + [disable], [m4_define([am_maintainer_other], [enable])], + [m4_define([am_maintainer_other], [enable]) + m4_warn([syntax], [unexpected argument to AM@&t@_MAINTAINER_MODE: $1])]) +AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles]) + dnl maintainer-mode's default is 'disable' unless 'enable' is passed + AC_ARG_ENABLE([maintainer-mode], + [AS_HELP_STRING([--]am_maintainer_other[-maintainer-mode], + am_maintainer_other[ make rules and dependencies not useful + (and sometimes confusing) to the casual installer])], + [USE_MAINTAINER_MODE=$enableval], + [USE_MAINTAINER_MODE=]m4_if(am_maintainer_other, [enable], [no], [yes])) + AC_MSG_RESULT([$USE_MAINTAINER_MODE]) + AM_CONDITIONAL([MAINTAINER_MODE], [test $USE_MAINTAINER_MODE = yes]) + MAINT=$MAINTAINER_MODE_TRUE + AC_SUBST([MAINT])dnl +] +) + # Check to see how 'make' treats includes. -*- Autoconf -*- # Copyright (C) 2001-2021 Free Software Foundation, Inc. diff --git a/src/libuv/configure b/src/libuv/configure index c6cbcbd4..40e98680 100755 --- a/src/libuv/configure +++ b/src/libuv/configure @@ -742,6 +742,9 @@ build_os build_vendor build_cpu build +MAINT +MAINTAINER_MODE_FALSE +MAINTAINER_MODE_TRUE AM_BACKSLASH AM_DEFAULT_VERBOSITY AM_DEFAULT_V @@ -816,6 +819,7 @@ ac_subst_files='' ac_user_opts=' enable_option_checking enable_silent_rules +enable_maintainer_mode enable_shared enable_static enable_dependency_tracking @@ -1466,6 +1470,9 @@ Optional Features: --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-silent-rules less verbose build output (undo: "make V=1") --disable-silent-rules verbose build output (undo: "make V=0") + --enable-maintainer-mode + enable make rules and dependencies not useful (and + sometimes confusing) to the casual installer --enable-shared[=PKGS] build shared libraries [default=yes] --enable-static[=PKGS] build static libraries [default=yes] --enable-dependency-tracking @@ -3262,6 +3269,30 @@ END fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable maintainer-specific portions of Makefiles" >&5 +printf %s "checking whether to enable maintainer-specific portions of Makefiles... " >&6; } + # Check whether --enable-maintainer-mode was given. +if test ${enable_maintainer_mode+y} +then : + enableval=$enable_maintainer_mode; USE_MAINTAINER_MODE=$enableval +else $as_nop + USE_MAINTAINER_MODE=no +fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $USE_MAINTAINER_MODE" >&5 +printf "%s\n" "$USE_MAINTAINER_MODE" >&6; } + if test $USE_MAINTAINER_MODE = yes; then + MAINTAINER_MODE_TRUE= + MAINTAINER_MODE_FALSE='#' +else + MAINTAINER_MODE_TRUE='#' + MAINTAINER_MODE_FALSE= +fi + + MAINT=$MAINTAINER_MODE_TRUE + + + # Make sure we can run config.sub. $SHELL "${ac_aux_dir}config.sub" sun4 >/dev/null 2>&1 || @@ -15206,6 +15237,10 @@ else am__EXEEXT_FALSE= fi +if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then + as_fn_error $? "conditional \"MAINTAINER_MODE\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then as_fn_error $? "conditional \"AMDEP\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 diff --git a/src/libuv/configure.ac b/src/libuv/configure.ac index 9aa1890c..eda93b22 100644 --- a/src/libuv/configure.ac +++ b/src/libuv/configure.ac @@ -19,6 +19,7 @@ m4_include([m4/libuv-extra-automake-flags.m4]) m4_include([m4/as_case.m4]) m4_include([m4/libuv-check-flags.m4]) AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects] UV_EXTRA_AUTOMAKE_FLAGS) +AM_MAINTAINER_MODE AC_CANONICAL_HOST AC_ENABLE_SHARED AC_ENABLE_STATIC