summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZack Weinberg <zackw@panix.com>2020-07-28 16:29:55 -0400
committerZack Weinberg <zackw@panix.com>2020-08-04 13:08:31 -0400
commitc16be7152d883483e1b8af0bd76c8d5800cbc3d0 (patch)
tree98ef3266f64f72330a8f8b6d7c2825a24489bb54
parent2cb0ab81b975f0f69ca90c57e5a3b7ea5de26e5f (diff)
downloadautoconf-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.texi115
-rw-r--r--lib/autoconf/c.m4247
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