mirror of
https://github.com/postgres/postgres.git
synced 2025-12-01 12:18:01 +03:00
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
This commit is contained in:
204
configure
vendored
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;
|
||||
#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112L
|
||||
# error "Compiler does not advertise C11 conformance"
|
||||
#endif
|
||||
#if BIG_OK
|
||||
#else
|
||||
your preprocessor is broken;
|
||||
#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. */
|
||||
|
||||
|
||||
29
configure.ac
29
configure.ac
@@ -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>
|
||||
|
||||
|
||||
59
meson.build
59
meson.build
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user