Raise C requirement to C11

This changes configure and meson.build to require at least C11,
instead of the previous C99.  The installation documentation is
updated accordingly.

configure.ac previously used AC_PROG_CC_C99 to activate C99.  But
there is no AC_PROG_CC_C11 in Autoconf 2.69, because it's too
old.  (Also, post-2.69, the AC_PROG_CC_Cnn macros were deprecated and
AC_PROG_CC activates the last supported C mode.)  We could update the
required Autoconf version, but that might be a separate project that
no one wants to undertake at the moment.  Instead, we open-code the
test for C11 using some inspiration from later Autoconf versions.  But
instead of writing an elaborate test program, we keep it simple and
just check __STDC_VERSION__, which should be good enough in practice.

In meson.build, we update the existing C99 test to C11, but again we
just check for __STDC_VERSION__.

This also removes the separate option for the conforming preprocessor
on MSVC, added by commit 8fd9bb1d96, since that is activated
automatically in C11 mode.

Note, we don't use the "official" way to set the C standard in Meson
using the c_std project option, because that is impossible to use
correctly (see <https://github.com/mesonbuild/meson/issues/14717>).

Reviewed-by: David Rowley <dgrowleyml@gmail.com>
Discussion: https://www.postgresql.org/message-id/flat/01a69441-af54-4822-891b-ca28e05b215a@eisentraut.org
master
Peter Eisentraut 3 weeks ago
parent 99234e9ddc
commit f5e0186f86
  1. 204
      configure
  2. 29
      configure.ac
  3. 7
      doc/src/sgml/installation.sgml
  4. 12
      doc/src/sgml/sources.sgml
  5. 59
      meson.build

204
configure vendored

@ -4475,190 +4475,49 @@ ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_c_compiler_gnu
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C99" >&5
$as_echo_n "checking for $CC option to accept ISO C99... " >&6; }
if ${ac_cv_prog_cc_c99+:} false; then :
# Detect option needed for C11
# loosely modeled after code in later Autoconf versions
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C11" >&5
$as_echo_n "checking for $CC option to accept ISO C11... " >&6; }
if ${pgac_cv_prog_cc_c11+:} false; then :
$as_echo_n "(cached) " >&6
else
ac_cv_prog_cc_c99=no
ac_save_CC=$CC
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
pgac_cv_prog_cc_c11=no
pgac_save_CC=$CC
for pgac_arg in '' '-std=gnu11' '-std=c11'; do
CC="$pgac_save_CC $pgac_arg"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdarg.h>
#include <stdbool.h>
#include <stdlib.h>
#include <wchar.h>
#include <stdio.h>
// Check varargs macros. These examples are taken from C99 6.10.3.5.
#define debug(...) fprintf (stderr, __VA_ARGS__)
#define showlist(...) puts (#__VA_ARGS__)
#define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__))
static void
test_varargs_macros (void)
{
int x = 1234;
int y = 5678;
debug ("Flag");
debug ("X = %d\n", x);
showlist (The first, second, and third items.);
report (x>y, "x is %d but y is %d", x, y);
}
// Check long long types.
#define BIG64 18446744073709551615ull
#define BIG32 4294967295ul
#define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0)
#if !BIG_OK
your preprocessor is broken;
#endif
#if BIG_OK
#else
your preprocessor is broken;
#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112L
# error "Compiler does not advertise C11 conformance"
#endif
static long long int bignum = -9223372036854775807LL;
static unsigned long long int ubignum = BIG64;
struct incomplete_array
{
int datasize;
double data[];
};
struct named_init {
int number;
const wchar_t *name;
double average;
};
typedef const char *ccp;
static inline int
test_restrict (ccp restrict text)
{
// See if C++-style comments work.
// Iterate through items via the restricted pointer.
// Also check for declarations in for loops.
for (unsigned int i = 0; *(text+i) != '\0'; ++i)
continue;
return 0;
}
// Check varargs and va_copy.
static void
test_varargs (const char *format, ...)
{
va_list args;
va_start (args, format);
va_list args_copy;
va_copy (args_copy, args);
const char *str;
int number;
float fnumber;
while (*format)
{
switch (*format++)
{
case 's': // string
str = va_arg (args_copy, const char *);
break;
case 'd': // int
number = va_arg (args_copy, int);
break;
case 'f': // float
fnumber = va_arg (args_copy, double);
break;
default:
break;
}
}
va_end (args_copy);
va_end (args);
}
int
main ()
{
// Check bool.
_Bool success = false;
// Check restrict.
if (test_restrict ("String literal") == 0)
success = true;
char *restrict newvar = "Another string";
// Check varargs.
test_varargs ("s, d' f .", "string", 65, 34.234);
test_varargs_macros ();
// Check flexible array members.
struct incomplete_array *ia =
malloc (sizeof (struct incomplete_array) + (sizeof (double) * 10));
ia->datasize = 10;
for (int i = 0; i < ia->datasize; ++i)
ia->data[i] = i * 1.234;
// Check named initializers.
struct named_init ni = {
.number = 34,
.name = L"Test wide string",
.average = 543.34343,
};
ni.number = 58;
int dynamic_array[ni.number];
dynamic_array[ni.number - 1] = 543;
// work around unused variable warnings
return (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == 'x'
|| dynamic_array[ni.number - 1] != 543);
;
return 0;
}
_ACEOF
for ac_arg in '' -std=gnu99 -std=c99 -c99 -AC99 -D_STDC_C99= -qlanglvl=extc99
do
CC="$ac_save_CC $ac_arg"
if ac_fn_c_try_compile "$LINENO"; then :
ac_cv_prog_cc_c99=$ac_arg
if ac_fn_c_try_compile "$LINENO"; then :
pgac_cv_prog_cc_c11=$pgac_arg
fi
rm -f core conftest.err conftest.$ac_objext
test "x$ac_cv_prog_cc_c99" != "xno" && break
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
test x"$pgac_cv_prog_cc_c11" != x"no" && break
done
rm -f conftest.$ac_ext
CC=$ac_save_CC
fi
# AC_CACHE_VAL
case "x$ac_cv_prog_cc_c99" in
x)
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
$as_echo "none needed" >&6; } ;;
xno)
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
$as_echo "unsupported" >&6; } ;;
*)
CC="$CC $ac_cv_prog_cc_c99"
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5
$as_echo "$ac_cv_prog_cc_c99" >&6; } ;;
esac
if test "x$ac_cv_prog_cc_c99" != xno; then :
CC=$pgac_save_CC
fi
# Error out if the compiler does not support C99, as the codebase
# relies on that.
if test "$ac_cv_prog_cc_c99" = no; then
as_fn_error $? "C compiler \"$CC\" does not support C99" "$LINENO" 5
if test x"$pgac_cv_prog_cc_c11" = x"no"; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
$as_echo "unsupported" >&6; }
as_fn_error $? "C compiler \"$CC\" does not support C11" "$LINENO" 5
elif test x"$pgac_cv_prog_cc_c11" = x""; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
$as_echo "none needed" >&6; }
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $pgac_cv_prog_cc_c11" >&5
$as_echo "$pgac_cv_prog_cc_c11" >&6; }
CC="$CC $pgac_cv_prog_cc_c11"
fi
ac_ext=cpp
ac_cpp='$CXXCPP $CPPFLAGS'
ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
@ -4920,7 +4779,6 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
# Check if it's Intel's compiler, which (usually) pretends to be gcc,
# but has idiosyncrasies of its own. We assume icc will define
# __INTEL_COMPILER regardless of CFLAGS.
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */

@ -364,14 +364,33 @@ pgac_cc_list="gcc cc"
pgac_cxx_list="g++ c++"
AC_PROG_CC([$pgac_cc_list])
AC_PROG_CC_C99()
# Error out if the compiler does not support C99, as the codebase
# relies on that.
if test "$ac_cv_prog_cc_c99" = no; then
AC_MSG_ERROR([C compiler "$CC" does not support C99])
# Detect option needed for C11
# loosely modeled after code in later Autoconf versions
AC_MSG_CHECKING([for $CC option to accept ISO C11])
AC_CACHE_VAL([pgac_cv_prog_cc_c11],
[pgac_cv_prog_cc_c11=no
pgac_save_CC=$CC
for pgac_arg in '' '-std=gnu11' '-std=c11'; do
CC="$pgac_save_CC $pgac_arg"
AC_COMPILE_IFELSE([AC_LANG_SOURCE([[#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112L
# error "Compiler does not advertise C11 conformance"
#endif]])], [[pgac_cv_prog_cc_c11=$pgac_arg]])
test x"$pgac_cv_prog_cc_c11" != x"no" && break
done
CC=$pgac_save_CC])
if test x"$pgac_cv_prog_cc_c11" = x"no"; then
AC_MSG_RESULT([unsupported])
AC_MSG_ERROR([C compiler "$CC" does not support C11])
elif test x"$pgac_cv_prog_cc_c11" = x""; then
AC_MSG_RESULT([none needed])
else
AC_MSG_RESULT([$pgac_cv_prog_cc_c11])
CC="$CC $pgac_cv_prog_cc_c11"
fi
AC_PROG_CXX([$pgac_cxx_list])
# Check if it's Intel's compiler, which (usually) pretends to be gcc,

@ -71,10 +71,9 @@
<listitem>
<para>
You need an <acronym>ISO</acronym>/<acronym>ANSI</acronym> C compiler (at least
C99-compliant). Recent
versions of <productname>GCC</productname> are recommended, but
<productname>PostgreSQL</productname> is known to build using a wide variety
You need a C compiler that supports at least C11. Recent versions of
<productname>GCC</productname> are recommended, but
<productname>PostgreSQL</productname> is known to build using a variety
of compilers from different vendors.
</para>
</listitem>

@ -907,12 +907,12 @@ BETTER: unrecognized node type: 42
<title>C Standard</title>
<para>
Code in <productname>PostgreSQL</productname> should only rely on language
features available in the C99 standard. That means a conforming
C99 compiler has to be able to compile postgres, at least aside
features available in the C11 standard. That means a conforming
C11 compiler has to be able to compile postgres, at least aside
from a few platform dependent pieces.
</para>
<para>
A few features included in the C99 standard are, at this time, not
A few features included in the C11 standard are, at this time, not
permitted to be used in core <productname>PostgreSQL</productname>
code. This currently includes variable length arrays, intermingled
declarations and code, <literal>//</literal> comments, universal
@ -924,13 +924,11 @@ BETTER: unrecognized node type: 42
features can be used, if a fallback is provided.
</para>
<para>
For example <literal>_Static_assert()</literal> and
For example <literal>typeof()</literal> and
<literal>__builtin_constant_p</literal> are currently used, even though
they are from newer revisions of the C standard and a
<productname>GCC</productname> extension respectively. If not available
we respectively fall back to using a C99 compatible replacement that
performs the same checks, but emits rather cryptic messages and do not
use <literal>__builtin_constant_p</literal>.
we do not use them.
</para>
</simplesect>

@ -280,10 +280,6 @@ elif host_system == 'windows'
# define before including <time.h> for getting localtime_r() etc. on MinGW
cppflags += '-D_POSIX_C_SOURCE'
endif
if cc.get_id() == 'msvc'
# required for VA_ARGS_NARGS() in c.h; requires VS 2019
cppflags += '/Zc:preprocessor'
endif
export_file_format = 'win'
export_file_suffix = 'def'
@ -550,44 +546,29 @@ dir_doc_extension = dir_doc / 'extension'
# used, they need to be added to test_c_args as well.
###############################################################
# Do we need -std=c99 to compile C99 code? We don't want to add -std=c99
# unnecessarily, because we optionally rely on newer features.
c99_test = '''
#include <stdbool.h>
#include <complex.h>
#include <tgmath.h>
#include <inttypes.h>
struct named_init_test {
int a;
int b;
};
extern void structfunc(struct named_init_test);
int main(int argc, char **argv)
{
struct named_init_test nit = {
.a = 3,
.b = 5,
};
for (int loop_var = 0; loop_var < 3; loop_var++)
{
nit.a += nit.b;
}
structfunc((struct named_init_test){1, 0});
return nit.a != 0;
}
# Do we need an option to enable C11?
c11_test = '''
#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112L
# error "Compiler does not advertise C11 conformance"
#endif
'''
if not cc.compiles(c99_test, name: 'c99')
if cc.compiles(c99_test, name: 'c99 with -std=c99', args: ['-std=c99'])
cflags += '-std=c99'
if not cc.compiles(c11_test, name: 'C11')
c11_ok = false
if cc.get_id() == 'msvc'
c11_test_args = ['/std:c11']
else
error('C compiler does not support C99')
c11_test_args = ['-std=gnu11', '-std=c11']
endif
foreach arg : c11_test_args
if cc.compiles(c11_test, name: 'C11 with @0@'.format(arg), args: [arg])
c11_ok = true
cflags += arg
break
endif
endforeach
if not c11_ok
error('C compiler does not support C11')
endif
endif

Loading…
Cancel
Save