Hi Bruno, Bruno Haible <br...@clisp.org> writes:
> I agree that when the system has a working implementation of a .h file, > we should interfere with it to the least possible amount. > > But the problem here is > 1) The term "working implementation" depends on the language in effect. > It may be working C and not working in C++ — that is the case that > Collin observed with GCC 15. > Or it may be working in C++ and not working in C — that is another > case. > 2) The standards may extend the expected contents of <stdckdint.h> > in the future. In that case, our current dichotomy of "generate > the file" or "not generate the file" would break down as well. > > I would therefore propose a more future-proof approach: based on the same > approach as we have been taken for so many other .h files. > > 1) In lib/stdckdint.in.h include the system's .h file if it exists, > via include_next. (Fortunately all known compilers that have 2 copies > of stdckdint.h support include_next. The fallback with > #include "absolute file name of stdckdint.h" > will work with other compilers.) > 2) Parameterize this file with 4 AC_SUBSTed variables: > - one that tells whether the C compiler has <stdckdint.h>, > - one that tells whether the <stdckdint.h> seen by the C compiler > is complete (in the sense that it provides all that the GNU > replacement would do), > - one that tells whether the C++ compiler has <stdckdint.h>, > - one that tells whether the <stdckdint.h> seen by the C++ compiler > is complete. > 3) In the .m4 code, make two C compiler invocations to determine the > first two of these values and - if $CXX != no - two C++ compiler > invocations to determine the other two values. > 4) Determine GL_GENERATE_STDCKDINT_H based on these 4 values. > > This way, we would be prepared for changes in the standards, bugs in > specific compilers, and handle C++ independently from C (which seems > to be required in this case). Can you check the attached patch? I think it matches what you said above. With GCC 15 and C++26 the result is (*): $ ./configure CFLAGS='-std=gnu99' CXXFLAGS='-std=gnu++26' | grep stdckdint checking for stdckdint.h... yes checking whether stdckdint.h can be included in C... yes checking whether stdckdint.h defines ckd_add, ckd_sub, ckd_mul in C... yes checking whether stdckdint.h can be included in C++... yes checking whether stdckdint.h defines ckd_add, ckd_sub, ckd_mul in C++... yes $ make $ ls gllib/stdckdint.h ls: cannot access 'gllib/stdckdint.h': No such file or directory And with GCC 15 and C++14: $ ./configure CFLAGS='-std=gnu99' CXXFLAGS='-std=gnu++14' | grep stdckdint checking for stdckdint.h... yes checking whether stdckdint.h can be included in C... yes checking whether stdckdint.h defines ckd_add, ckd_sub, ckd_mul in C... yes checking whether stdckdint.h can be included in C++... yes checking whether stdckdint.h defines ckd_add, ckd_sub, ckd_mul in C++... no $ make $ ls gllib/stdckdint.h gllib/stdckdint.h In the second case, when compiling a C program <stdckdint.h> simply does an #include_next. Collin (*) I find it strange that the C++ declarations are hidden depending on the C++ standard, but the C ones are not. I would expect -std=(gnu|c)99 to disable them like the C++ version.
>From 97dbb1f1a349c4817e91ed2b5fcc5c30b484360b Mon Sep 17 00:00:00 2001 Message-ID: <97dbb1f1a349c4817e91ed2b5fcc5c30b484360b.1747882664.git.collin.fu...@gmail.com> From: Collin Funk <collin.fu...@gmail.com> Date: Wed, 21 May 2025 19:55:47 -0700 Subject: [PATCH] stdckdint-h: Don't generate header if it is not needed. Suggested by Paul Eggert in: <https://lists.gnu.org/archive/html/bug-gnulib/2025-05/msg00216.html>. * m4/stdckdint_h.m4: New file. * modules/stdckdint-h (Files): Add m4/stdckdint_h.m4. (configure.ac): Remove checks and just invoke gl_STDCKDINT_H. (Makefile.am): Replace variables set by ./configure. * lib/stdckdint.in.h: Include the compilers header if it exists. (ckd_add, ckd_sub, ckd_mul): Only define if the compilers definitions do not work. --- ChangeLog | 13 +++++ lib/stdckdint.in.h | 31 +++++++--- m4/stdckdint_h.m4 | 136 ++++++++++++++++++++++++++++++++++++++++++++ modules/stdckdint-h | 21 +++---- 4 files changed, 184 insertions(+), 17 deletions(-) create mode 100644 m4/stdckdint_h.m4 diff --git a/ChangeLog b/ChangeLog index b85c7c6e6e..f946fc5d91 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +2025-05-21 Collin Funk <collin.fu...@gmail.com> + + stdckdint-h: Don't generate header if it is not needed. + Suggested by Paul Eggert in: + <https://lists.gnu.org/archive/html/bug-gnulib/2025-05/msg00216.html>. + * m4/stdckdint_h.m4: New file. + * modules/stdckdint-h (Files): Add m4/stdckdint_h.m4. + (configure.ac): Remove checks and just invoke gl_STDCKDINT_H. + (Makefile.am): Replace variables set by ./configure. + * lib/stdckdint.in.h: Include the compilers header if it exists. + (ckd_add, ckd_sub, ckd_mul): Only define if the compilers definitions do + not work. + 2025-05-19 Collin Funk <collin.fu...@gmail.com> stdckdint-h: Work around missing declarations with g++ 15.0. diff --git a/lib/stdckdint.in.h b/lib/stdckdint.in.h index 83277b728e..2d317b9588 100644 --- a/lib/stdckdint.in.h +++ b/lib/stdckdint.in.h @@ -15,10 +15,26 @@ You should have received a copy of the GNU Lesser General Public License along with this program. If not, see <https://www.gnu.org/licenses/>. */ -#ifndef _GL_STDCKDINT_H -#define _GL_STDCKDINT_H +#ifndef _@GUARD_PREFIX@_STDCKDINT_H -#include "intprops-internal.h" +#if __GNUC__ >= 3 +@PRAGMA_SYSTEM_HEADER@ +#endif +@PRAGMA_COLUMNS@ + +#if defined __cplusplus ? @HAVE_CXX_STDCKDINT_H@ : @HAVE_C_STDCKDINT_H@ +#@INCLUDE_NEXT@ @NEXT_STDCKDINT_H@ +#endif + +/* Do nothing but include the system header if it works properly. */ +#if defined __cplusplus ? @HAVE_WORKING_CXX_STDCKDINT_H@ : @HAVE_WORKING_C_STDCKDINT_H@ + +/* Avoid redefining macros. */ +# undef ckd_add +# undef ckd_sub +# undef ckd_mul + +# include "intprops-internal.h" /* Store into *R the low-order bits of A + B, A - B, A * B, respectively. Return 1 if the result overflows, 0 otherwise. @@ -28,8 +44,9 @@ These are like the standard macros introduced in C23, except that arguments should not have side effects. */ -#define ckd_add(r, a, b) ((bool) _GL_INT_ADD_WRAPV (a, b, r)) -#define ckd_sub(r, a, b) ((bool) _GL_INT_SUBTRACT_WRAPV (a, b, r)) -#define ckd_mul(r, a, b) ((bool) _GL_INT_MULTIPLY_WRAPV (a, b, r)) +# define ckd_add(r, a, b) ((bool) _GL_INT_ADD_WRAPV (a, b, r)) +# define ckd_sub(r, a, b) ((bool) _GL_INT_SUBTRACT_WRAPV (a, b, r)) +# define ckd_mul(r, a, b) ((bool) _GL_INT_MULTIPLY_WRAPV (a, b, r)) -#endif /* _GL_STDCKDINT_H */ +#endif /* defined __cplusplus ? @HAVE_WORKING_CXX_STDCKDINT_H@ : @HAVE_WORKING_C_STDCKDINT_H@ */ +#endif /* _@GUARD_PREFIX@_STDCKDINT_H */ diff --git a/m4/stdckdint_h.m4 b/m4/stdckdint_h.m4 new file mode 100644 index 0000000000..f8e99a1920 --- /dev/null +++ b/m4/stdckdint_h.m4 @@ -0,0 +1,136 @@ +# stdckdint_h.m4 +# serial 1 +dnl Copyright 2025 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. +dnl This file is offered as-is, without any warranty. + +dnl Written by Collin Funk. + +AC_DEFUN_ONCE([gl_STDCKDINT_H], +[ + gl_CHECK_NEXT_HEADERS([stdckdint.h]) + if test $ac_cv_header_stdckdint_h = yes; then + HAVE_STDCKDINT_H=1 + else + HAVE_STDCKDINT_H=0 + fi + AC_SUBST([HAVE_STDCKDINT_H]) + + if test $HAVE_STDCKDINT_H == 1; then + AC_CACHE_CHECK([whether stdckdint.h can be included in C], + [gl_cv_header_c_stdckdint_h], + [AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM( + [[#include <stdckdint.h> + ]])], + [gl_cv_header_c_stdckdint_h=yes], + [gl_cv_header_c_stdckdint_h=no])]) + if test $gl_cv_header_c_stdckdint_h = yes; then + HAVE_C_STDCKDINT_H=1 + AC_CACHE_CHECK([whether stdckdint.h defines ckd_add, ckd_sub, ckd_mul in C], + [gl_cv_header_c_stdckdint_h_works], + [AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM( + [[#include <stdckdint.h> + ]], + [[int r; + int a = 1; + int b = 1; + return !!(ckd_add (&r, a, b) || ckd_sub (&r, a, b) + || ckd_mul (&r, a, b)); + ]])], + [gl_cv_header_c_stdckdint_h_works=yes], + [gl_cv_header_c_stdckdint_h_works=no])]) + if test $gl_cv_header_c_stdckdint_h_works = yes; then + HAVE_WORKING_C_STDCKDINT_H=1 + else + HAVE_WORKING_C_STDCKDINT_H=0 + fi + else + HAVE_C_STDCKDINT_H=0 + HAVE_WORKING_C_STDCKDINT_H=0 + fi + if test "$CXX" != no; then + AC_CACHE_CHECK([whether stdckdint.h can be included in C++], + [gl_cv_header_cxx_stdckdint_h], + [dnl We can't use AC_LANG_PUSH([C++]) and AC_LANG_POP([C++]) here, due to + dnl an autoconf bug <https://savannah.gnu.org/support/?110294>. + cat > conftest.cpp <<\EOF +#include <stdckdint.h> +EOF + gl_command="$CXX $CXXFLAGS $CPPFLAGS -c conftest.cpp" + if AC_TRY_EVAL([gl_command]); then + gl_cv_header_cxx_stdckdint_h=yes + else + gl_cv_header_cxx_stdckdint_h=no + fi + rm -fr conftest* + ]) + if test $gl_cv_header_cxx_stdckdint_h = yes; then + HAVE_CXX_STDCKDINT_H=1 + AC_CACHE_CHECK([whether stdckdint.h defines ckd_add, ckd_sub, ckd_mul in C++], + [gl_cv_header_cxx_stdckdint_h_works], + [dnl We can't use AC_LANG_PUSH([C++]) and AC_LANG_POP([C++]) here, due to + dnl an autoconf bug <https://savannah.gnu.org/support/?110294>. + cat > conftest.cpp <<\EOF +#include <stdckdint.h> +int +main (void) +{ + int r; + int a = 1; + int b = 1; + return !!(ckd_add (&r, a, b) || ckd_sub (&r, a, b) || ckd_mul (&r, a, b)); +} +EOF + gl_command="$CXX $CXXFLAGS $CPPFLAGS -c conftest.cpp" + if AC_TRY_EVAL([gl_command]); then + gl_cv_header_cxx_stdckdint_h_works=yes + else + gl_cv_header_cxx_stdckdint_h_works=no + fi + rm -fr conftest* + ]) + if test $gl_cv_header_cxx_stdckdint_h_works = yes; then + HAVE_WORKING_CXX_STDCKDINT_H=1 + else + HAVE_WORKING_CXX_STDCKDINT_H=0 + fi + else + HAVE_CXX_STDCKDINT_H=0 + HAVE_WORKING_CXX_STDCKDINT_H=0 + fi + fi + else + HAVE_C_STDCKDINT_H=0 + HAVE_WORKING_C_STDCKDINT_H=0 + HAVE_CXX_STDCKDINT_H=0 + HAVE_WORKING_CXX_STDCKDINT_H=0 + fi + AC_SUBST([HAVE_C_STDCKDINT_H]) + AC_SUBST([HAVE_WORKING_C_STDCKDINT_H]) + AC_SUBST([HAVE_CXX_STDCKDINT_H]) + AC_SUBST([HAVE_WORKING_CXX_STDCKDINT_H]) + + if test "$CXX" != no; then + dnl We might need the header for C or C++. + if test $HAVE_C_STDCKDINT_H = 1 \ + && test $HAVE_WORKING_C_STDCKDINT_H = 1 \ + && test $HAVE_CXX_STDCKDINT_H = 1 \ + && test $HAVE_WORKING_CXX_STDCKDINT_H = 1; then + GL_GENERATE_STDCKDINT_H=false + else + GL_GENERATE_STDCKDINT_H=true + fi + else + dnl We don't care about C++ here. + if test $HAVE_C_STDCKDINT_H = 1 \ + && test $HAVE_WORKING_C_STDCKDINT_H = 1; then + GL_GENERATE_STDCKDINT_H=false + else + GL_GENERATE_STDCKDINT_H=true + fi + fi +]) diff --git a/modules/stdckdint-h b/modules/stdckdint-h index ff777d8d62..7f7c612bce 100644 --- a/modules/stdckdint-h +++ b/modules/stdckdint-h @@ -2,6 +2,7 @@ Description: An <stdckdint.h> that is like C23. Files: +m4/stdckdint_h.m4 lib/stdckdint.in.h lib/intprops-internal.h @@ -10,16 +11,7 @@ gen-header bool configure.ac: -AC_CHECK_HEADERS_ONCE([stdckdint.h]) -if test $ac_cv_header_stdckdint_h = yes; then - if test -n "$CXX" && test "$CXX" != no; then - GL_GENERATE_STDCKDINT_H=true - else - GL_GENERATE_STDCKDINT_H=false - fi -else - GL_GENERATE_STDCKDINT_H=true -fi +gl_STDCKDINT_H gl_CONDITIONAL_HEADER([stdckdint.h]) AC_PROG_MKDIR_P @@ -32,6 +24,15 @@ if GL_GENERATE_STDCKDINT_H stdckdint.h: stdckdint.in.h $(top_builddir)/config.status @NMD@ $(AM_V_GEN)$(MKDIR_P) '%reldir%' $(gl_V_at)$(SED_HEADER_STDOUT) \ + -e 's|@''GUARD_PREFIX''@|${gl_include_guard_prefix}|g' \ + -e 's|@''INCLUDE_NEXT''@|$(INCLUDE_NEXT)|g' \ + -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \ + -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \ + -e 's|@''NEXT_STDCKDINT_H''@|$(NEXT_STDCKDINT_H)|g' \ + -e 's|@''HAVE_C_STDCKDINT_H''@|$(HAVE_C_STDCKDINT_H)|g' \ + -e 's|@''HAVE_WORKING_C_STDCKDINT_H''@|$(HAVE_WORKING_C_STDCKDINT_H)|g' \ + -e 's|@''HAVE_CXX_STDCKDINT_H''@|$(HAVE_CXX_STDCKDINT_H)|g' \ + -e 's|@''HAVE_WORKING_CXX_STDCKDINT_H''@|$(HAVE_WORKING_CXX_STDCKDINT_H)|g' \ $(srcdir)/stdckdint.in.h > $@-t $(AM_V_at)mv $@-t $@ else -- 2.49.0