mirror of
https://github.com/postgres/postgres.git
synced 2025-10-15 05:46:52 +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_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
|
||||||
ac_compiler_gnu=$ac_cv_c_compiler_gnu
|
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; }
|
# Detect option needed for C11
|
||||||
if ${ac_cv_prog_cc_c99+:} false; then :
|
# 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
|
$as_echo_n "(cached) " >&6
|
||||||
else
|
else
|
||||||
ac_cv_prog_cc_c99=no
|
pgac_cv_prog_cc_c11=no
|
||||||
ac_save_CC=$CC
|
pgac_save_CC=$CC
|
||||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
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. */
|
/* end confdefs.h. */
|
||||||
#include <stdarg.h>
|
#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112L
|
||||||
#include <stdbool.h>
|
# error "Compiler does not advertise C11 conformance"
|
||||||
#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
|
#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
|
_ACEOF
|
||||||
for ac_arg in '' -std=gnu99 -std=c99 -c99 -AC99 -D_STDC_C99= -qlanglvl=extc99
|
if ac_fn_c_try_compile "$LINENO"; then :
|
||||||
do
|
pgac_cv_prog_cc_c11=$pgac_arg
|
||||||
CC="$ac_save_CC $ac_arg"
|
|
||||||
if ac_fn_c_try_compile "$LINENO"; then :
|
|
||||||
ac_cv_prog_cc_c99=$ac_arg
|
|
||||||
fi
|
fi
|
||||||
rm -f core conftest.err conftest.$ac_objext
|
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
|
||||||
test "x$ac_cv_prog_cc_c99" != "xno" && break
|
test x"$pgac_cv_prog_cc_c11" != x"no" && break
|
||||||
done
|
done
|
||||||
rm -f conftest.$ac_ext
|
CC=$pgac_save_CC
|
||||||
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 :
|
|
||||||
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
if test x"$pgac_cv_prog_cc_c11" = x"no"; then
|
||||||
# Error out if the compiler does not support C99, as the codebase
|
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
|
||||||
# relies on that.
|
$as_echo "unsupported" >&6; }
|
||||||
if test "$ac_cv_prog_cc_c99" = no; then
|
as_fn_error $? "C compiler \"$CC\" does not support C11" "$LINENO" 5
|
||||||
as_fn_error $? "C compiler \"$CC\" does not support C99" "$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
|
fi
|
||||||
|
|
||||||
|
|
||||||
ac_ext=cpp
|
ac_ext=cpp
|
||||||
ac_cpp='$CXXCPP $CPPFLAGS'
|
ac_cpp='$CXXCPP $CPPFLAGS'
|
||||||
ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
|
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,
|
# Check if it's Intel's compiler, which (usually) pretends to be gcc,
|
||||||
# but has idiosyncrasies of its own. We assume icc will define
|
# but has idiosyncrasies of its own. We assume icc will define
|
||||||
# __INTEL_COMPILER regardless of CFLAGS.
|
# __INTEL_COMPILER regardless of CFLAGS.
|
||||||
|
|
||||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||||
/* end confdefs.h. */
|
/* end confdefs.h. */
|
||||||
|
|
||||||
|
29
configure.ac
29
configure.ac
@@ -364,14 +364,33 @@ pgac_cc_list="gcc cc"
|
|||||||
pgac_cxx_list="g++ c++"
|
pgac_cxx_list="g++ c++"
|
||||||
|
|
||||||
AC_PROG_CC([$pgac_cc_list])
|
AC_PROG_CC([$pgac_cc_list])
|
||||||
AC_PROG_CC_C99()
|
|
||||||
|
|
||||||
# Error out if the compiler does not support C99, as the codebase
|
# Detect option needed for C11
|
||||||
# relies on that.
|
# loosely modeled after code in later Autoconf versions
|
||||||
if test "$ac_cv_prog_cc_c99" = no; then
|
AC_MSG_CHECKING([for $CC option to accept ISO C11])
|
||||||
AC_MSG_ERROR([C compiler "$CC" does not support C99])
|
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
|
fi
|
||||||
|
|
||||||
|
|
||||||
AC_PROG_CXX([$pgac_cxx_list])
|
AC_PROG_CXX([$pgac_cxx_list])
|
||||||
|
|
||||||
# Check if it's Intel's compiler, which (usually) pretends to be gcc,
|
# Check if it's Intel's compiler, which (usually) pretends to be gcc,
|
||||||
|
@@ -71,10 +71,9 @@
|
|||||||
|
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
You need an <acronym>ISO</acronym>/<acronym>ANSI</acronym> C compiler (at least
|
You need a C compiler that supports at least C11. Recent versions of
|
||||||
C99-compliant). Recent
|
<productname>GCC</productname> are recommended, but
|
||||||
versions of <productname>GCC</productname> are recommended, but
|
<productname>PostgreSQL</productname> is known to build using a variety
|
||||||
<productname>PostgreSQL</productname> is known to build using a wide variety
|
|
||||||
of compilers from different vendors.
|
of compilers from different vendors.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
|
@@ -907,12 +907,12 @@ BETTER: unrecognized node type: 42
|
|||||||
<title>C Standard</title>
|
<title>C Standard</title>
|
||||||
<para>
|
<para>
|
||||||
Code in <productname>PostgreSQL</productname> should only rely on language
|
Code in <productname>PostgreSQL</productname> should only rely on language
|
||||||
features available in the C99 standard. That means a conforming
|
features available in the C11 standard. That means a conforming
|
||||||
C99 compiler has to be able to compile postgres, at least aside
|
C11 compiler has to be able to compile postgres, at least aside
|
||||||
from a few platform dependent pieces.
|
from a few platform dependent pieces.
|
||||||
</para>
|
</para>
|
||||||
<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>
|
permitted to be used in core <productname>PostgreSQL</productname>
|
||||||
code. This currently includes variable length arrays, intermingled
|
code. This currently includes variable length arrays, intermingled
|
||||||
declarations and code, <literal>//</literal> comments, universal
|
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.
|
features can be used, if a fallback is provided.
|
||||||
</para>
|
</para>
|
||||||
<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
|
<literal>__builtin_constant_p</literal> are currently used, even though
|
||||||
they are from newer revisions of the C standard and a
|
they are from newer revisions of the C standard and a
|
||||||
<productname>GCC</productname> extension respectively. If not available
|
<productname>GCC</productname> extension respectively. If not available
|
||||||
we respectively fall back to using a C99 compatible replacement that
|
we do not use them.
|
||||||
performs the same checks, but emits rather cryptic messages and do not
|
|
||||||
use <literal>__builtin_constant_p</literal>.
|
|
||||||
</para>
|
</para>
|
||||||
</simplesect>
|
</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
|
# define before including <time.h> for getting localtime_r() etc. on MinGW
|
||||||
cppflags += '-D_POSIX_C_SOURCE'
|
cppflags += '-D_POSIX_C_SOURCE'
|
||||||
endif
|
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_format = 'win'
|
||||||
export_file_suffix = 'def'
|
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.
|
# 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
|
# Do we need an option to enable C11?
|
||||||
# unnecessarily, because we optionally rely on newer features.
|
c11_test = '''
|
||||||
c99_test = '''
|
#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112L
|
||||||
#include <stdbool.h>
|
# error "Compiler does not advertise C11 conformance"
|
||||||
#include <complex.h>
|
#endif
|
||||||
#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;
|
|
||||||
}
|
|
||||||
'''
|
'''
|
||||||
|
|
||||||
if not cc.compiles(c99_test, name: 'c99')
|
if not cc.compiles(c11_test, name: 'C11')
|
||||||
if cc.compiles(c99_test, name: 'c99 with -std=c99', args: ['-std=c99'])
|
c11_ok = false
|
||||||
cflags += '-std=c99'
|
if cc.get_id() == 'msvc'
|
||||||
|
c11_test_args = ['/std:c11']
|
||||||
else
|
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
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user