[Subject updated for accuracy] Hi Paul,
At 2026-09-03T02:29:26-0700, Paul Eggert wrote: > On 2026-09-03 02:13, G. Branden Robinson wrote: > > Gnulib uses a 1-argument form of it no matter what version of the C > > language has been requested. > > Every Gnulib module that comes with lib/malloca.c depends on Gnulib's > assert-h module, and Gnulib's assert-h module is supposed to implement > the one-argument form of static_assert no matter what version of the C > language has been requested. I went in many circles trying to keep glibc from jamming its 2-argument- only form into the build environment. I could not defeat it. But see below. In trying to produce a minimum reproducing procedure for you, I happened upon a smoking gun--I seem to have unwittingly found a way to evade the dependency you speak of. > So I'm puzzled as to why lib/malloca.c would need to use the > 2-argument form. It turns out that if some Gnulib headers are made by being named as explicit targets, but "assert.h" is not among them, then when a "regular" "make" (using the implicit target) is done subsequently, Gnulib's Makefile(s) get fooled. I have a build script that attempts to make the headers and libgnu.a before any of groff's own targets, because I have a whole pile of compiler options I want to throw at groff to clear out technical debt and update its C++ from the Cfront 2.0/ Annotated C++ Reference Manual era to ultra-modern...C++98. :-| But I don't want to throw those same options at Gnulib. So I'm thinking Gnulib's dependency structure doesn't alert it that its replacement assert.h needs to be built--I've defeated it somehow. So glibc 2.31's gets found, and it supports only the dyadic form of the `static_assert` macro. > Is there a recipe for reproducing the problem that you ran into? Sure. Grab the groff 1.25.0.rc2 release candidate archive. https://alpha.gnu.org/gnu/groff/ Run the attached script. It assumes GCC but you can make it use Clang. $ env CORES=10 ~/bin/make-groff-fast-from-archive-reducer $ env CORES=10 CC="clang -std=c99" CXX="clang++ -std=c++98" \ ~/bin/make-groff-fast-from-archive-reducer (You can pick any `CORES` value you want. Values greater than 12 might expose missing prerequisites in groff's dependency graph, of which I would very much like to hear.) These fail equivalently for me. ../lib/malloca.c:49:56: error: macro "_Static_assert" requires 2 arguments, but only 1 given 49 | static_assert (2 * sa_alignment_max - 1 <= (small_t) -1); | ^ In file included from /usr/include/features.h:461, from /usr/include/assert.h:35, from ./src/include/config.h:2510, from ../lib/malloca.c:19: /usr/include/x86_64-linux-gnu/sys/cdefs.h:447: note: macro "_Static_assert" defined here 447 | # define _Static_assert(expr, diagnostic) \ | ../lib/malloca.c:49:57: error: expected ‘(’ before ‘;’ token 49 | static_assert (2 * sa_alignment_max - 1 <= (small_t) -1); | ^ | ( ../lib/malloca.c:49:56: error: too few arguments provided to function-like macro invocation static_assert (2 * sa_alignment_max - 1 <= (small_t) -1); ^ /usr/include/x86_64-linux-gnu/sys/cdefs.h:447:10: note: macro '_Static_assert' defined here # define _Static_assert(expr, diagnostic) \ ^ ../lib/malloca.c:49:57: error: expected '(' static_assert (2 * sa_alignment_max - 1 <= (small_t) -1); ^ 2 errors generated. Could Gnulib maybe support a stamp file whose prerequisites are calculated to be all the header files it decides it needs to create, plus the libgnu.a static object? I learned the hard way that making the latter alone before groff was not good enough. Regards, Branden
#!/bin/sh
set -e
# XXX: can't use -ftrapv (nor -fsanitize=signed-integer-overflow) at tag 1.23.0
# or earlier
: ${TAG:=HEAD}
: ${DESTDIR:=$HOME/groff-$TAG}
# XXX: Don't export CC and CXX because Autoconf tests go awry with them.
#: ${CC:=clang -std=c99}
#: ${CXX:=clang++ -std=c++98}
: ${CC:=gcc -std=c99}
: ${CXX:=g++ -std=c++98}
: ${MAKE:=make} # or bmake
test -n "$MAKE" && export MAKE
: ${CORES:=1}
PROGNAME=${0##*/}
COMMON_FLAGS="
-O0 -Og
-gdwarf
-ggdb"
# We want to be pedantically C++98-correct...except for one thing...
case "$CXX" in
(gcc*) ;;
(clang*) CXXFLAGS="$CXXFLAGS -Wno-long-long -Wno-c++11-long-long" ;;
(*) ;;
esac
gnulib_headers="
lib/alloca.h
lib/fcntl.h
lib/float.h
lib/inttypes.h
lib/limits.h
lib/locale.h
lib/math.h
lib/pthread.h
lib/sched.h
lib/stdckdint.h
lib/stdcountof.h
lib/stddef.h
lib/stdio.h
lib/stdlib.h
lib/string.h
lib/strings.h
lib/sys/stat.h
lib/sys/types.h
lib/time.h
lib/sys/wait.h
lib/uchar.h
lib/unicase.h
lib/unictype.h
lib/uninorm.h
lib/unistd.h
lib/unitypes.h
lib/uniwidth.h
lib/wchar.h
lib/wctype.h
"
gnulib_headers=$(echo $gnulib_headers)
gnulib_library=lib/libgnu.a
if [ $# -gt 1 ]; then
echo "$PROGNAME: error: expected 0 or 1 arguments, got $#" >&2
exit 1
fi
if [ -n "$1" ]; then
if expr "$1" - 0 >/dev/null 2>&1; then
CORES=$1
else
echo "$PROGNAME: usage error: argument \"$1\" should be number of" \
"cores" >&2
exit 2
fi
fi
if ! test -f ./test-groff.in; then
echo "$PROGNAME: error: ./test-groff.in not found" >&2
exit 3
fi
if ! test -f ./configure; then
echo "$PROGNAME: error: ./configure not found" >&2
exit 3
fi
: ${MAKE:=make}
export MAKE
if [ -z "$IN_TREE" ]
then
test -d build || mkdir build
cd build
SOURCE_DIR=..
else
SOURCE_DIR=.
fi
rm -rf "$DESTDIR"
jarg=-j$CORES
toolchain_args=
case "$CC" in
(gcc*) ;;
(clang*) toolchain_args="AR=llvm-ar-11 RANLIB=llvm-ranlib-11" ;;
(*) ;;
esac
SAFE_CFLAGS=$(echo "$CFLAGS" | tr '\n' ' ')
SAFE_CXXFLAGS=$(echo "$CXXFLAGS" | tr '\n' ' ')
"$SOURCE_DIR"/configure --enable-maintainer-mode \
MAKE="$MAKE" $toolchain_args --prefix=$DESTDIR \
&& $MAKE $jarg V=1 CC="$CC" CXX="$CXX" $gnulib_headers $gnulib_library \
&& $MAKE $jarg V=1 CC="$CC" CXX="$CXX" CFLAGS="$SAFE_CFLAGS"
CXXFLAGS="$SAFE_CXXFLAGS" \
&& $MAKE $jarg check \
&& $MAKE install install-doc \
&& $MAKE uninstall
# vim:set ai et sw=4 ts=4 tw=80:
signature.asc
Description: PGP signature
