mirror of
git://git.sv.gnu.org/autoconf
synced 2025-02-11 13:51:04 +08:00
AC_PROG_CXX: Add checks for C++11, C++98TR1 and C++98
These checks are the C++ equivalent of the existing C standards checks. * doc/autoconf.texi (C++ Compiler): Document new behavior. * lib/autoconf/c.m4 (AC_PROG_CXX): Try for C++11, falling back to C++98. (_AC_CXX_STD_TRY, _AC_CXX_CXX98_TEST_HEADER, _AC_CXX_CXX98_TEST_BODY) (_AC_CXX_CXX11_TEST_HEADER, _AC_CXX_CXX11_TEST_BODY) (_AC_PROG_CXX_CXX98, _AC_PROG_CXX_CXX11): New macros.
This commit is contained in:
parent
93ed0f1524
commit
bd79b51000
@ -7642,6 +7642,35 @@ like this:
|
||||
AC_PROG_CXX([gcc cl KCC CC cxx cc++ xlC aCC c++ g++])
|
||||
@end example
|
||||
|
||||
If necessary, add an option to output variable @code{CXX} to enable
|
||||
support for ISO Standard C++ features with extensions. Prefer the
|
||||
newest C++ standard that is supported. Currently the newest standard is
|
||||
ISO C++11, with ISO C++98 being the previous standard. After calling
|
||||
this macro you can check whether the C++ compiler has been set to accept
|
||||
Standard C++; if not, the shell variable @code{ac_cv_prog_cxx_stdcxx} is
|
||||
set to @samp{no}. If the C++ compiler will not accept C++11, the shell
|
||||
variable @code{ac_cv_prog_cxx_cxx11} is set to @samp{no}, and if it will
|
||||
not accept C++98, the shell variable @code{ac_cv_prog_cxx_cxx98} is set
|
||||
to @samp{no}.
|
||||
|
||||
When attempting to add compiler options, prefer extended functionality
|
||||
to strict conformance: the goal is to enable whatever standard features
|
||||
that are available, not to check for full conformance to the standard or
|
||||
to prohibit incompatible extensions. Test for C++11 support by checking
|
||||
for the language features @code{auto}, @code{constexpr},
|
||||
@code{decltype}, @code{default}ed and @code{delete}ed constructors,
|
||||
delegate constructors, @code{final}, initializer lists, lambda
|
||||
functions, @code{nullptr}, @code{override}, range-based for loops,
|
||||
template brackets without spaces and unicode literals, and library
|
||||
features @code{std::array}, @code{std::shared_ptr},
|
||||
@code{std::weak_ptr}, @code{std::regex} and @code{std::tuple}. Test for
|
||||
C++98 support using basic features of the @code{std} namespace including
|
||||
@code{std::string}, containers (@code{std::list}, @code{std::map},
|
||||
@code{std::set}, @code{std::vector}), streams (fstreams, iostreams,
|
||||
stringstreams, iomanip), @code{std::pair}, exceptions (@code{try},
|
||||
@code{catch} and @code{std::runtime_error}) and algorithms. Tests for
|
||||
more recent standards include all the tests for older standards.
|
||||
|
||||
If using the GNU C++ compiler, set shell variable @code{GXX} to
|
||||
@samp{yes}. If output variable @code{CXXFLAGS} was not already set, set
|
||||
it to @option{-g -O2} for the GNU C++ compiler (@option{-O2} on
|
||||
@ -7649,7 +7678,6 @@ systems where G++ does not accept @option{-g}), or @option{-g} for other
|
||||
compilers. If your package does not like this default, then it is
|
||||
acceptable to insert the line @samp{: $@{CXXFLAGS=""@}} after @code{AC_INIT}
|
||||
and before @code{AC_PROG_CXX} to select an empty default instead.
|
||||
|
||||
@end defmac
|
||||
|
||||
@defmac AC_PROG_CXXCPP
|
||||
|
@ -749,6 +749,13 @@ else
|
||||
GXX=
|
||||
fi
|
||||
_AC_PROG_CXX_G
|
||||
_AC_PROG_CXX_CXX11([ac_prog_cxx_stdcxx=cxx11
|
||||
ac_cv_prog_cxx_stdcxx=$ac_cv_prog_cxx_cxx11
|
||||
ac_cv_prog_cxx_cxx98=$ac_cv_prog_cxx_cxx11],
|
||||
[_AC_PROG_CXX_CXX98([ac_prog_cxx_stdcxx=cxx98
|
||||
ac_cv_prog_cxx_stdcxx=$ac_cv_prog_cxx_cxx98],
|
||||
[ac_prog_cxx_stdcxx=no
|
||||
ac_cv_prog_cxx_stdcxx=no])])
|
||||
AC_LANG_POP(C++)dnl
|
||||
])# AC_PROG_CXX
|
||||
|
||||
@ -2158,3 +2165,332 @@ AC_DEFUN([AC_OPENMP],
|
||||
fi
|
||||
AC_SUBST([OPENMP_]_AC_LANG_PREFIX[FLAGS])
|
||||
])
|
||||
|
||||
# _AC_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([_AC_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])
|
||||
])# _AC_CXX_STD_TRY
|
||||
|
||||
# _AC_CXX_CXX98_TEST_HEADER
|
||||
# -------------------------
|
||||
# A C++ header suitable for testing for CXX98.
|
||||
AC_DEFUN([_AC_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;
|
||||
};
|
||||
}
|
||||
]])# _AC_CXX_CXX98_TEST_HEADER
|
||||
|
||||
# _AC_CXX_CXX98_TEST_BODY
|
||||
# -----------------------
|
||||
# A C++ body suitable for testing for CXX98, assuming the corresponding header.
|
||||
AC_DEFUN([_AC_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);
|
||||
]])
|
||||
|
||||
# _AC_CXX_CXX11_TEST_HEADER
|
||||
# -------------------------
|
||||
# A C++ header suitable for testing for CXX11.
|
||||
AC_DEFUN([_AC_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;
|
||||
};
|
||||
}
|
||||
]])# _AC_CXX_CXX11_TEST_HEADER
|
||||
|
||||
# _AC_CXX_CXX11_TEST_BODY
|
||||
# -----------------------
|
||||
# A C++ body suitable for testing for CXX11, assuming the corresponding header.
|
||||
AC_DEFUN([_AC_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";
|
||||
}
|
||||
]])
|
||||
|
||||
# _AC_PROG_CXX_CXX98 ([ACTION-IF-AVAILABLE], [ACTION-IF-UNAVAILABLE])
|
||||
# -------------------------------------------------------------------
|
||||
|
||||
# If the C++ compiler is not in ISO C++98 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++98 on some system or another. It
|
||||
# considers the compiler to be in ISO C++98 mode if it handles basic
|
||||
# features of the std namespace including: string, containers (list,
|
||||
# map, set, vector), streams (fstreams, iostreams, stringstreams,
|
||||
# iomanip), pair, exceptions and algorithms.
|
||||
|
||||
|
||||
AC_DEFUN([_AC_PROG_CXX_CXX98],
|
||||
[_AC_CXX_STD_TRY([cxx98],
|
||||
[_AC_CXX_CXX98_TEST_HEADER],
|
||||
[_AC_CXX_CXX98_TEST_BODY],
|
||||
dnl Try
|
||||
dnl GCC -std=gnu++98 (unused restrictive mode: -std=c++98)
|
||||
dnl IBM XL C -qlanglvl=extended
|
||||
dnl HP aC++ -AA
|
||||
dnl Intel ICC -std=gnu++98
|
||||
dnl Solaris N/A (default)
|
||||
dnl Tru64 N/A (default, but -std gnu could be used)
|
||||
dnl with extended modes being tried first.
|
||||
[[-std=gnu++98 -std=c++98 -qlanglvl=extended -AA]], [$1], [$2])[]dnl
|
||||
])# _AC_PROG_CXX_CXX98
|
||||
|
||||
# _AC_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([_AC_PROG_CXX_CXX11],
|
||||
[_AC_CXX_STD_TRY([cxx11],
|
||||
[_AC_CXX_CXX11_TEST_HEADER
|
||||
_AC_CXX_CXX98_TEST_HEADER],
|
||||
[_AC_CXX_CXX11_TEST_BODY
|
||||
_AC_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
|
||||
])# _AC_PROG_CXX_CXX11
|
||||
|
Loading…
Reference in New Issue
Block a user