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 | |
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.
-rw-r--r-- | doc/autoconf.texi | 115 | ||||
-rw-r--r-- | lib/autoconf/c.m4 | 247 |
2 files changed, 167 insertions, 195 deletions
diff --git a/doc/autoconf.texi b/doc/autoconf.texi index 70d37834..8e563bf8 100644 --- a/doc/autoconf.texi +++ b/doc/autoconf.texi @@ -7671,62 +7671,65 @@ compiler fix the header files automatically when installed. @evindex CXXFLAGS @ovindex CXX @ovindex CXXFLAGS -Determine a C++ compiler to use. Check whether the environment variable -@code{CXX} or @code{CCC} (in that order) is set; if so, then set output -variable @code{CXX} to its value. - -Otherwise, if the macro is invoked without an argument, then search for -a C++ compiler under the likely names (first @code{g++} and @code{c++} -then other names). If none of those checks succeed, then as a last -resort set @code{CXX} to @code{g++}. - -This macro may, however, be invoked with an optional first argument -which, if specified, must be a blank-separated list of C++ compilers to -search for. This just gives the user an opportunity to specify an -alternative search list for the C++ compiler. For example, if you -didn't like the default order, then you could invoke @code{AC_PROG_CXX} -like this: - -@example -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 -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. +Determine a C++ compiler to use. + +If either the environment variable @code{CXX} or the environment +variable @code{CCC} is set, its value will be taken as the name of a +C++ compiler. If both are set, @code{CXX} is preferred. If neither +are set, search for a C++ compiler under a series of likely names, +trying @code{g++} and @code{c++} first. Regardless, the output +variable @code{CXX} is set to the chosen compiler. + +If the optional first argument to the macro is used, it must be a +whitespace-separated list of potential names for a C++ compiler, +which overrides the built-in list. + +If no C++ compiler can be found, as a last resort @code{CXX} is set to +@code{g++} (and subsequent tests will probably fail). + +If the selected C++ compiler is found to be GNU C++ (regardless of +its name), the shell variable @code{GXX} will be set to @samp{yes}. +If the shell variable @code{CXXFLAGS} was not already set, it is set +to @option{-g -O2} for the GNU C++ compiler (@option{-O2} on systems +where G++ does not accept @option{-g}), or @option{-g} for other +compilers. @code{CXXFLAGS} is then made an output variable. +You can override the default for @code{CXXFLAGS} by inserting a shell +default assignment between @code{AC_INIT} and @code{AC_PROG_CXX}: + +@example +: $@{CXXFLAGS="@var{options}"@} +@end example + +where @var{options} are the appropriate set of options to use by +default. (It is important to use this construct rather than a normal +assignment, so that @code{CXXFLAGS} can still be overridden by the +person building the package. @xref{Preset Output Variables}.) + +If necessary, options are added to @code{CXX} to enable support for +ISO Standard C++ features with extensions. ISO C++ 2011 is preferred +if the compiler supports it. After calling this macro, you can check +whether the C++ compiler has been set to accept standard C++ by +inspecting cache variables. If @code{ac_cv_prog_cxx_cxx11} is set to +any value other than @samp{no} (including the empty string), then +@code{CXX} can compile code as standard C++ 2011, and this mode has +been enabled. Otherwise, if @code{ac_cv_prog_cxx_cxx98} is set to +any value other than @samp{no} (including the empty string), then +@code{CXX} can compile code as standard C++ 1998, and this mode has +been enabled. Finally, if both variables are set to @samp{no}, then +@code{CXX} cannot compile standard C++ at all. + +The tests for standard conformance are not comprehensive. They test +the value of @code{__cplusplus} and a representative sample of the +language features added in each version of the C++ standard. They do +not exercise the C++ standard library, because this can be extremely +slow. If you need to know whether a particular C++ standard header +exists, use @code{AC_CHECK_HEADER}. + +None of the options that may be added to @code{CXX} by this macro +enable @emph{strict} conformance to the C++ standard. In particular, +system-specific extensions are not disabled. (For example, for GNU +C++, the @option{-std=gnu++@var{nn}} options may be used, but not the +@option{-std=c++@var{nn}} options.) @end defmac @defmac AC_PROG_CXXCPP 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 |