diff options
author | Zack Weinberg <zackw@panix.com> | 2020-07-28 16:29:55 -0400 |
---|---|---|
committer | Zack Weinberg <zackw@panix.com> | 2020-08-04 13:08:31 -0400 |
commit | c16be7152d883483e1b8af0bd76c8d5800cbc3d0 (patch) | |
tree | 98ef3266f64f72330a8f8b6d7c2825a24489bb54 /lib | |
parent | 2cb0ab81b975f0f69ca90c57e5a3b7ea5de26e5f (diff) | |
download | autoconf-c16be7152d883483e1b8af0bd76c8d5800cbc3d0.tar.gz |
Only probe C++ language features, not library, for speed (#110285)
The test programs used by _AC_PROG_CXX_CXX98 and _AC_PROG_CXX_CXX11
can take several seconds to compile, even on current-generation CPUs.
Each of them may be test-compiled up to six times as the configure
script searches for appropriate command-line switches. This is
reported to cancel out all of the other performance gains made since
2.69.
Replace these programs with simpler ones that do not exercise the C++
standard *library* and can be compiled in less than a second each.
On my computer, which is quite new, the minimal configure script
AC_INIT
AC_PROG_CXX
executes in 4.5 seconds (wall-clock) before this change and 0.5
seconds after.
* lib/autoconf/c.m4 (_AC_CXX_CXX98_TEST_HEADER, _AC_CXX_CXX98_TEST_BODY):
Rewrite to test only C++ 1998 language features, not library features.
(_AC_CXX_CXX11_TEST_HEADER, _AC_CXX_CXX11_TEST_BODY):
Similarly for C++ 2011.
* doc/autoconf.texi (AC_PROG_CXX): Document this change.
Diffstat (limited to 'lib')
-rw-r--r-- | lib/autoconf/c.m4 | 247 |
1 files changed, 108 insertions, 139 deletions
diff --git a/lib/autoconf/c.m4 b/lib/autoconf/c.m4 index b2129d5d..d9858669 100644 --- a/lib/autoconf/c.m4 +++ b/lib/autoconf/c.m4 @@ -2235,37 +2235,44 @@ AS_IF([test "x$ac_cv_prog_cxx_$1" != xno], [$5], [$6]) # _AC_CXX_CXX98_TEST_HEADER # ------------------------- # A C++ header suitable for testing for CXX98. +# We only test *language* features that were new in the 1998 C++ standard, +# because testing for library features is too slow. AC_DEFUN([_AC_CXX_CXX98_TEST_HEADER], -[[ -#include <algorithm> -#include <cstdlib> -#include <fstream> -#include <iomanip> +[[// Does the compiler advertise C++98 conformance? +#if !defined __cplusplus || __cplusplus < 199711L +# error "Compiler does not advertise C++98 conformance" +#endif + +// These inclusions are cheap compared to including any STL header, but will +// reliably reject old compilers that lack the unsuffixed header files. +#undef NDEBUG +#include <cassert> +#include <cstring> #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; - }; + +// Namespaces, exceptions, and templates were all added after "C++ 2.0". +using std::cout; +using std::strcmp; + +namespace { + +void test_exception_syntax() +{ + try { + throw "test"; + } catch (const char *s) { + assert (!strcmp (s, "test")); + } } + +template <typename T> struct test_template +{ + T const val; + explicit test_template(T t) : val(t) {} + template <typename U> T add(U u) { return static_cast<T>(u) + val; } +}; + +} // anonymous namespace ]])# _AC_CXX_CXX98_TEST_HEADER # _AC_CXX_CXX98_TEST_BODY @@ -2273,76 +2280,29 @@ namespace test { # 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(); +{ + test_exception_syntax (); + test_template<double> tt (2.0); + assert (tt.add (4) == 6.0); + assert (true && !false); + cout << "ok\n"; } -std::exit(0); ]]) # _AC_CXX_CXX11_TEST_HEADER # ------------------------- # A C++ header suitable for testing for CXX11. +# As above, we test only new *language* features, not new STL features, +# for speed's sake. AC_DEFUN([_AC_CXX_CXX11_TEST_HEADER], [[ -#include <deque> -#include <functional> -#include <memory> -#include <tuple> -#include <array> -#include <regex> -#include <iostream> +// Does the compiler advertise C++ 2011 conformance? +#if !defined __cplusplus || __cplusplus < 201103L +# error "Compiler does not advertise C++11 conformance" +#endif 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 @@ -2351,7 +2311,8 @@ namespace cxx11test double d; }; - class delegate { + class delegate + { public: delegate(int n) : n(n) {} delegate(): delegate(2354) {} @@ -2361,13 +2322,15 @@ namespace cxx11test int n; }; - class overridden : public delegate { + class overridden : public delegate + { public: overridden(int n): delegate(n) {} virtual int getval() override final { return this->n * 2; } }; - class nocopy { + class nocopy + { public: nocopy(int i): i(i) {} nocopy() = default; @@ -2376,6 +2339,22 @@ namespace cxx11test private: int i; }; + + // for testing lambda expressions + template <typename Ret, typename Fn> Ret eval(Fn f, Ret v) + { + return f(v); + } + + // for testing variadic templates and trailing return types + template <typename V> auto sum(V first) -> V + { + return first; + } + template <typename V, typename... Args> auto sum(V first, Args... rest) -> V + { + return first + sum(rest...); + } } ]])# _AC_CXX_CXX11_TEST_HEADER @@ -2386,18 +2365,13 @@ 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"; + int total = 0; + for (auto i = a3; *i; ++i) { total += *i; } + decltype(a2) a4 = 34895.034; } { @@ -2409,34 +2383,27 @@ AC_DEFUN([_AC_CXX_CXX11_TEST_BODY], 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; + // Test range-based for + int array[] = {9, 7, 13, 15, 4, 18, 12, 10, 5, 3, + 14, 19, 17, 8, 6, 20, 16, 2, 11, 1}; + for (auto &x : array) { x += 23; } } { - 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); + // Test lambda expressions + using cxx11test::eval; + assert (eval ([](int x) { return x*2; }, 21) == 42); + double d = 2.0; + assert (eval ([&](double x) { return d += x; }, 3.0) == 5.0); + assert (d == 5.0); + assert (eval ([=](double x) mutable { return d += x; }, 4.0) == 9.0); + assert (d == 5.0); } { - 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 use of variadic templates + using cxx11test::sum; + auto a = sum(1); + auto b = sum(1, 2); + auto c = sum(1.0, 2.0, 3.0); } { // Test constructor delegation @@ -2454,7 +2421,7 @@ AC_DEFUN([_AC_CXX_CXX11_TEST_BODY], } { // Test template brackets - std::vector<std::pair<int,char*>> v1; + test_template<::test_template<int>> v(test_template<int>(12)); } { // Unicode literals @@ -2466,16 +2433,15 @@ AC_DEFUN([_AC_CXX_CXX11_TEST_BODY], # _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. - - +# 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 defines +# the __cplusplus macro appropriately and it supports language +# features that were added since "C++ 2.0" (namespaces, exceptions, +# and templates). It does not check for the presence of any STL +# headers, as this was found to make AC_PROG_CXX unacceptably slow. +# Use AC_CHECK_HEADER if you need that. AC_DEFUN([_AC_PROG_CXX_CXX98], [_AC_CXX_STD_TRY([cxx98], [_AC_CXX_CXX98_TEST_HEADER], @@ -2495,14 +2461,17 @@ dnl with extended modes being tried first. # ------------------------------------------------------------------- # 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, initializer 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). +# 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 defines the +# __cplusplus macro appropriately, can compile all of the code from +# the C++98 test, and can also handle many of the new language +# features in C++11 (auto, constexpr, decltype, default/deleted +# constructors, delegate constructors, final, initializer lists, +# lambda functions, nullptr, override, range-based for loops, template +# brackets without spaces, variadic templates, trailing return types, +# unicode literals). It does not check for the presence of the new +# library headers; again, this was found to make AC_PROG_CXX +# unacceptably slow. Use AC_CHECK_HEADER if you need that. AC_DEFUN([_AC_PROG_CXX_CXX11], [_AC_CXX_STD_TRY([cxx11], [_AC_CXX_CXX11_TEST_HEADER |