[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:

Attachment: signature.asc
Description: PGP signature

Reply via email to