changeset 21304:0cf6c08cb252

configure.ac: check support for C11 and C++11 (patch #8906) * configure.ac: two new checks for support of C++11 and C11 versions of the standard and to add required flags to CXX and CC. These need to be done before AC_PROG_CPP and AC_PROG_CXXPP since the later will make use of the defined CXX and CC. * m4/prog_c.m4, m4/prog_cxx.m4: added files for OCTAVE_PROG_CC_C11 and OCTAVE_PROG_CXX_CXX11 which are copied from autoconf source tree implementations of _AC_PROG_CC_C11 and _AC_PROG_CXX_CXX11.
author Carnë Draug <carandraug@octave.org>
date Thu, 18 Feb 2016 16:20:49 +0000
parents 325e04c63f8c
children 46284491ffc5
files configure.ac m4/prog_c.m4 m4/prog_cxx.m4
diffstat 3 files changed, 610 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/configure.ac	Thu Feb 18 16:58:37 2016 -0500
+++ b/configure.ac	Thu Feb 18 16:20:49 2016 +0000
@@ -305,12 +305,20 @@
 
 ### Determine which C++ compiler to use (we expect to find g++).
 
+## Note that OCTAVE_PROG_CXX_CXX11 must come before AC_PROG_CXXCPP since
+## the later uses the value of CXX which may be modified by the first.
+
 AC_PROG_CXX
+OCTAVE_PROG_CXX_CXX11
 AC_PROG_CXXCPP
 
 ### Determine which C compiler to use (we expect to find gcc).
 
+## Note that OCTAVE_PROG_CC_C11 must come before AC_PROG_CPP since
+## the later uses the value of CC which may be modified by the first.
+
 AC_PROG_CC
+OCTAVE_PROG_CC_C11
 AC_PROG_CPP
 AC_PROG_GCC_TRADITIONAL
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/m4/prog_c.m4	Thu Feb 18 16:20:49 2016 +0000
@@ -0,0 +1,276 @@
+# Copyright (C) 2001-2016 Free Software Foundation, Inc.
+#
+#
+# This is pretty much copy and paste of the unreleased autoconf macros
+# (where it is named AC_PROG_CXX_CXX11).  Once we are dependent on
+# autoconf version with that macro, we can simply change to use that
+# one instead.  Copied from autoconf commit 04be2b7a (2016/02/06)
+#
+#
+# This file is part of Autoconf.  This program is free
+# software; you can redistribute it and/or modify it under the
+# terms of the GNU General Public License as published by the
+# Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+# OCTAVE_PROG_CC_C11 ([ACTION-IF-AVAILABLE], [ACTION-IF-UNAVAILABLE])
+# ----------------------------------------------------------------
+# If the C compiler is not in ISO C11 mode by default, try to add an
+# option to output variable CC to make it so.  This macro tries
+# various options that select ISO C11 on some system or another.  It
+# considers the compiler to be in ISO C11 mode if it handles _Alignas,
+# _Alignof, _Noreturn, _Static_assert, UTF-8 string literals,
+# duplicate typedefs, and anonymous structures and unions.
+AC_DEFUN([OCTAVE_PROG_CC_C11],
+[_OCTAVE_C_STD_TRY([c11],
+[_OCTAVE_C_C99_TEST_HEADER[
+// Check _Alignas.
+char _Alignas (double) aligned_as_double;
+char _Alignas (0) no_special_alignment;
+extern char aligned_as_int;
+char _Alignas (0) _Alignas (int) aligned_as_int;
+
+// Check _Alignof.
+enum
+{
+  int_alignment = _Alignof (int),
+  int_array_alignment = _Alignof (int[100]),
+  char_alignment = _Alignof (char)
+};
+_Static_assert (0 < -_Alignof (int), "_Alignof is signed");
+
+// Check _Noreturn.
+int _Noreturn does_not_return (void) { for (;;) continue; }
+
+// Check _Static_assert.
+struct test_static_assert
+{
+  int x;
+  _Static_assert (sizeof (int) <= sizeof (long int),
+                  "_Static_assert does not work in struct");
+  long int y;
+};
+
+// Check UTF-8 literals.
+#define u8 syntax error!
+char const utf8_literal[] = u8"happens to be ASCII" "another string";
+
+// Check duplicate typedefs.
+typedef long *long_ptr;
+typedef long int *long_ptr;
+typedef long_ptr long_ptr;
+
+// Anonymous structures and unions -- taken from C11 6.7.2.1 Example 1.
+struct anonymous
+{
+  union {
+    struct { int i; int j; };
+    struct { int k; long int l; } w;
+  };
+  int m;
+} v1;
+]],
+[_OCTAVE_C_C99_TEST_BODY[
+  v1.i = 2;
+  v1.w.k = 5;
+  _Static_assert (&v1.i == &v1.w.k, "Anonymous union alignment botch");
+]],
+dnl Try
+dnl GCC		-std=gnu11 (unused restrictive mode: -std=c11)
+dnl with extended modes being tried first.
+dnl
+dnl Do not try -qlanglvl=extc1x, because IBM XL C V12.1 (the latest version as
+dnl of September 2012) does not pass the C11 test.  For now, try extc1x when
+dnl compiling the C99 test instead, since it enables _Static_assert and
+dnl _Noreturn, which is a win.  If -qlanglvl=extc11 or -qlanglvl=extc1x passes
+dnl the C11 test in some future version of IBM XL C, we'll add it here,
+dnl preferably extc11.
+[[-std=gnu11]], [$1], [$2])[]dnl
+])# OCTAVE_PROG_CC_C11
+
+
+# _OCTAVE_C_STD_TRY(STANDARD, TEST-PROLOGUE, TEST-BODY, OPTION-LIST,
+#		ACTION-IF-AVAILABLE, ACTION-IF-UNAVAILABLE)
+# --------------------------------------------------------------
+# Check whether the C compiler accepts features of STANDARD (e.g `c89', `c99')
+# by trying to compile a program of TEST-PROLOGUE and TEST-BODY.  If this fails,
+# try again with each compiler option in the space-separated OPTION-LIST; if one
+# helps, append it to CC.  If eventually successful, run ACTION-IF-AVAILABLE,
+# else ACTION-IF-UNAVAILABLE.
+AC_DEFUN([_OCTAVE_C_STD_TRY],
+[AC_MSG_CHECKING([for $CC option to enable ]m4_translit($1, [c], [C])[ features])
+AC_CACHE_VAL(ac_cv_prog_cc_$1,
+[ac_cv_prog_cc_$1=no
+ac_save_CC=$CC
+AC_LANG_CONFTEST([AC_LANG_PROGRAM([$2], [$3])])
+for ac_arg in '' $4
+do
+  CC="$ac_save_CC $ac_arg"
+  _AC_COMPILE_IFELSE([], [ac_cv_prog_cc_$1=$ac_arg])
+  test "x$ac_cv_prog_cc_$1" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+])# AC_CACHE_VAL
+ac_prog_cc_stdc_options=
+case "x$ac_cv_prog_cc_$1" in
+  x)
+    AC_MSG_RESULT([none needed]) ;;
+  xno)
+    AC_MSG_RESULT([unsupported]) ;;
+  *)
+    ac_prog_cc_stdc_options=" $ac_cv_prog_cc_$1"
+    CC=$CC$ac_prog_cc_stdc_options
+    AC_MSG_RESULT([$ac_cv_prog_cc_$1]) ;;
+esac
+AS_IF([test "x$ac_cv_prog_cc_$1" != xno], [$5], [$6])
+])# _OCTAVE_C_STD_TRY
+
+# _OCTAVE_C_C99_TEST_HEADER
+# ---------------------
+# A C header suitable for testing for C99.
+AC_DEFUN([_OCTAVE_C_C99_TEST_HEADER],
+[[#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;
+#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 bool
+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 = 0;
+  float fnumber = 0;
+
+  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);
+
+  return *str && number && fnumber;
+}]])# _OCTAVE_C_C99_TEST_HEADER
+
+# _OCTAVE_C_C99_TEST_BODY
+# -------------------
+# A C body suitable for testing for C99, assuming the corresponding header.
+AC_DEFUN([_OCTAVE_C_C99_TEST_BODY],
+[[
+  // Check bool.
+  _Bool success = false;
+
+  // Check restrict.
+  if (test_restrict ("String literal") == 0)
+    success = true;
+  char *restrict newvar = "Another string";
+
+  // Check varargs.
+  success &= 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);
+]])
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/m4/prog_cxx.m4	Thu Feb 18 16:20:49 2016 +0000
@@ -0,0 +1,326 @@
+# Copyright (C) 2001-2016 Free Software Foundation, Inc.
+#
+#
+# This is pretty much copy and paste of the unreleased autoconf macros
+# (where it is named AC_PROG_CC_C11).  Once we are dependent on
+# autoconf version with that macro, we can simply change to use that
+# one instead.  Copied from autoconf commit 04be2b7a (2016/02/06)
+#
+#
+# This file is part of Autoconf.  This program is free
+# software; you can redistribute it and/or modify it under the
+# terms of the GNU General Public License as published by the
+# Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+# OCTAVE_PROG_CXX_CXX11 ([ACTION-IF-AVAILABLE], [ACTION-IF-UNAVAILABLE])
+# -------------------------------------------------------------------
+# If the C++ compiler is not in ISO CXX11 mode by default, try to add
+# an option to output variable CXX to make it so.  This macro tries
+# various options that select ISO C++11 on some system or another.  It
+# considers the compiler to be in ISO C++11 mode if it handles all the
+# tests from the C++98 checks, plus the following: Language features
+# (auto, constexpr, decltype, default/deleted constructors, delegate
+# constructors, final, initialiser lists, lambda functions, nullptr,
+# override, range-based for loops, template brackets without spaces,
+# unicode literals) and library features (array, memory (shared_ptr,
+# weak_ptr), regex and tuple types).
+AC_DEFUN([OCTAVE_PROG_CXX_CXX11],
+[OCTAVE_CXX_STD_TRY([cxx11],
+[OCTAVE_CXX_CXX11_TEST_HEADER
+OCTAVE_CXX_CXX98_TEST_HEADER],
+[OCTAVE_CXX_CXX11_TEST_BODY
+OCTAVE_CXX_CXX98_TEST_BODY],
+dnl Try
+dnl GCC		-std=gnu++11 (unused restrictive mode: -std=c++11) [and 0x variants]
+dnl IBM XL C	-qlanglvl=extended0x
+dnl		(pre-V12.1; unused restrictive mode: -qlanglvl=stdcxx11)
+dnl HP aC++	-AA
+dnl Intel ICC	-std=c++11 -std=c++0x
+dnl Solaris	N/A (no support)
+dnl Tru64	N/A (no support)
+dnl with extended modes being tried first.
+[[-std=gnu++11 -std=c++11 -std=gnu++0x -std=c++0x -qlanglvl=extended0x -AA]], [$1], [$2])[]dnl
+])# OCTAVE_PROG_CXX_CXX11
+
+
+# OCTAVE_CXX_STD_TRY(STANDARD, TEST-PROLOGUE, TEST-BODY, OPTION-LIST,
+#		  ACTION-IF-AVAILABLE, ACTION-IF-UNAVAILABLE)
+# ----------------------------------------------------------------
+# Check whether the C++ compiler accepts features of STANDARD (e.g
+# `cxx98', `cxx11') by trying to compile a program of TEST-PROLOGUE
+# and TEST-BODY.  If this fails, try again with each compiler option
+# in the space-separated OPTION-LIST; if one helps, append it to CXX.
+# If eventually successful, run ACTION-IF-AVAILABLE, else
+# ACTION-IF-UNAVAILABLE.
+AC_DEFUN([OCTAVE_CXX_STD_TRY],
+[AC_MSG_CHECKING([for $CXX option to enable ]m4_translit(m4_translit($1, [x], [+]), [a-z], [A-Z])[ features])
+AC_LANG_PUSH(C++)dnl
+AC_CACHE_VAL(ac_cv_prog_cxx_$1,
+[ac_cv_prog_cxx_$1=no
+ac_save_CXX=$CXX
+AC_LANG_CONFTEST([AC_LANG_PROGRAM([$2], [$3])])
+for ac_arg in '' $4
+do
+  CXX="$ac_save_CXX $ac_arg"
+  _AC_COMPILE_IFELSE([], [ac_cv_prog_cxx_$1=$ac_arg])
+  test "x$ac_cv_prog_cxx_$1" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CXX=$ac_save_CXX
+])# AC_CACHE_VAL
+ac_prog_cxx_stdcxx_options=
+case "x$ac_cv_prog_cxx_$1" in
+  x)
+    AC_MSG_RESULT([none needed]) ;;
+  xno)
+    AC_MSG_RESULT([unsupported]) ;;
+  *)
+    ac_prog_cxx_stdcxx_options=" $ac_cv_prog_cxx_$1"
+    CXX=$CXX$ac_prog_cxx_stdcxx_options
+    AC_MSG_RESULT([$ac_cv_prog_cxx_$1]) ;;
+esac
+AC_LANG_POP(C++)dnl
+AS_IF([test "x$ac_cv_prog_cxx_$1" != xno], [$5], [$6])
+])# OCTAVE_CXX_STD_TRY
+
+# OCTAVE_CXX_CXX98_TEST_HEADER
+# -------------------------
+# A C++ header suitable for testing for CXX98.
+AC_DEFUN([OCTAVE_CXX_CXX98_TEST_HEADER],
+[[
+#include <algorithm>
+#include <cstdlib>
+#include <fstream>
+#include <iomanip>
+#include <iostream>
+#include <list>
+#include <map>
+#include <set>
+#include <sstream>
+#include <stdexcept>
+#include <string>
+#include <utility>
+#include <vector>
+
+namespace test {
+  typedef std::vector<std::string> string_vec;
+  typedef std::pair<int,bool> map_value;
+  typedef std::map<std::string,map_value> map_type;
+  typedef std::set<int> set_type;
+
+  template<typename T>
+  class printer {
+  public:
+    printer(std::ostringstream& os): os(os) {}
+    void operator() (T elem) { os << elem << std::endl; }
+  private:
+    std::ostringstream& os;
+  };
+}
+]])# OCTAVE_CXX_CXX98_TEST_HEADER
+
+# OCTAVE_CXX_CXX98_TEST_BODY
+# -----------------------
+# A C++ body suitable for testing for CXX98, assuming the corresponding header.
+AC_DEFUN([OCTAVE_CXX_CXX98_TEST_BODY],
+[[
+
+try {
+  // Basic string.
+  std::string teststr("ASCII text");
+  teststr += " string";
+
+  // Simple vector.
+  test::string_vec testvec;
+  testvec.push_back(teststr);
+  testvec.push_back("foo");
+  testvec.push_back("bar");
+  if (testvec.size() != 3) {
+    throw std::runtime_error("vector size is not 1");
+  }
+
+  // Dump vector into stringstream and obtain string.
+  std::ostringstream os;
+  for (test::string_vec::const_iterator i = testvec.begin();
+       i != testvec.end(); ++i) {
+    if (i + 1 != testvec.end()) {
+      os << teststr << '\n';
+    }
+  }
+  // Check algorithms work.
+  std::for_each(testvec.begin(), testvec.end(), test::printer<std::string>(os));
+  std::string os_out = os.str();
+
+  // Test pair and map.
+  test::map_type testmap;
+  testmap.insert(std::make_pair(std::string("key"),
+                                std::make_pair(53,false)));
+
+  // Test set.
+  int values[] = {9, 7, 13, 15, 4, 18, 12, 10, 5, 3, 14, 19, 17, 8, 6, 20, 16, 2, 11, 1};
+  test::set_type testset(values, values + sizeof(values)/sizeof(values[0]));
+  std::list<int> testlist(testset.begin(), testset.end());
+  std::copy(testset.begin(), testset.end(), std::back_inserter(testlist));
+} catch (const std::exception& e) {
+  std::cerr << "Caught exception: " << e.what() << std::endl;
+
+  // Test fstream
+  std::ofstream of("test.txt");
+  of << "Test ASCII text\n" << std::flush;
+  of << "N= " << std::hex << std::setw(8) << std::left << 534 << std::endl;
+  of.close();
+}
+std::exit(0);
+]])
+
+
+# OCTAVE_CXX_CXX11_TEST_HEADER
+# -------------------------
+# A C++ header suitable for testing for CXX11.
+AC_DEFUN([OCTAVE_CXX_CXX11_TEST_HEADER],
+[[
+#include <deque>
+#include <functional>
+#include <memory>
+#include <tuple>
+#include <array>
+#include <regex>
+#include <iostream>
+
+namespace cxx11test
+{
+  typedef std::shared_ptr<std::string> sptr;
+  typedef std::weak_ptr<std::string> wptr;
+
+  typedef std::tuple<std::string,int,double> tp;
+  typedef std::array<int, 20> int_array;
+
+  constexpr int get_val() { return 20; }
+
+  struct testinit
+  {
+    int i;
+    double d;
+  };
+
+  class delegate  {
+  public:
+    delegate(int n) : n(n) {}
+    delegate(): delegate(2354) {}
+
+    virtual int getval() { return this->n; };
+  protected:
+    int n;
+  };
+
+  class overridden : public delegate {
+  public:
+    overridden(int n): delegate(n) {}
+    virtual int getval() override final { return this->n * 2; }
+  };
+
+  class nocopy {
+  public:
+    nocopy(int i): i(i) {}
+    nocopy() = default;
+    nocopy(const nocopy&) = delete;
+    nocopy & operator=(const nocopy&) = delete;
+  private:
+    int i;
+  };
+}
+]])# OCTAVE_CXX_CXX11_TEST_HEADER
+
+# OCTAVE_CXX_CXX11_TEST_BODY
+# -----------------------
+# A C++ body suitable for testing for CXX11, assuming the corresponding header.
+AC_DEFUN([OCTAVE_CXX_CXX11_TEST_BODY],
+[[
+{
+  // Test auto and decltype
+  std::deque<int> d;
+  d.push_front(43);
+  d.push_front(484);
+  d.push_front(3);
+  d.push_front(844);
+  int total = 0;
+  for (auto i = d.begin(); i != d.end(); ++i) { total += *i; }
+
+  auto a1 = 6538;
+  auto a2 = 48573953.4;
+  auto a3 = "String literal";
+
+  decltype(a2) a4 = 34895.034;
+}
+{
+  // Test constexpr
+  short sa[cxx11test::get_val()] = { 0 };
+}
+{
+  // Test initialiser lists
+  cxx11test::testinit il = { 4323, 435234.23544 };
+}
+{
+  // Test range-based for and lambda
+  cxx11test::int_array array = {9, 7, 13, 15, 4, 18, 12, 10, 5, 3, 14, 19, 17, 8, 6, 20, 16, 2, 11, 1};
+  for (int &x : array) { x += 23; }
+  std::for_each(array.begin(), array.end(), [](int v1){ std::cout << v1; });
+}
+{
+  using cxx11test::sptr;
+  using cxx11test::wptr;
+
+  sptr sp(new std::string("ASCII string"));
+  wptr wp(sp);
+  sptr sp2(wp);
+}
+{
+  cxx11test::tp tuple("test", 54, 45.53434);
+  double d = std::get<2>(tuple);
+  std::string s;
+  int i;
+  std::tie(s,i,d) = tuple;
+}
+{
+  static std::regex filename_regex("^_?([a-z0-9_.]+-)+[a-z0-9]+$");
+  std::string testmatch("Test if this string matches");
+  bool match = std::regex_search(testmatch, filename_regex);
+}
+{
+  cxx11test::int_array array = {9, 7, 13, 15, 4, 18, 12, 10, 5, 3, 14, 19, 17, 8, 6, 20, 16, 2, 11, 1};
+  cxx11test::int_array::size_type size = array.size();
+}
+{
+  // Test constructor delegation
+  cxx11test::delegate d1;
+  cxx11test::delegate d2();
+  cxx11test::delegate d3(45);
+}
+{
+  // Test override and final
+  cxx11test::overridden o1(55464);
+}
+{
+  // Test nullptr
+  char *c = nullptr;
+}
+{
+  // Test template brackets
+  std::vector<std::pair<int,char*>> v1;
+}
+{
+  // Unicode literals
+  char *utf8 = u8"UTF-8 string \u2500";
+  char16_t *utf16 = u"UTF-8 string \u2500";
+  char32_t *utf32 = U"UTF-32 string \u2500";
+}
+]])