Bernd said (in https://gcc.gnu.org/ml/gcc-patches/2015-11/msg01981.html ): > For some of the simpler infrastructure tests such as the ones in this > patch kit (bitmap, vec or wide-int functionality testing and such), > we had the idea of putting these into every ENABLE_CHECKING compiler, > and run them after building stage1, controlled by a -fself-test flag. > It's better to detect such basic failures early rather than complete > a full bootstrap and test cycle. It also keeps the tests alongside the > rest of the implementation, which I consider desirable for such > relatively simple data structures."
This patch implements this idea by adding a "selftests" phony target to gcc/Makefile.in ensuring that the selftests must be successfully run for the build to complete. The time taken to run the testsuite is also printed. A "s-selftests" file is created, so that the selftests need only be run once each time "cc1" is rebuilt in a working copy. They are run at each stage in a bootstrap. For example, looking at a bootstrap log: $ grep "fself-test:" test/experiment/x86_64-pc-linux-gnu/build/make.log -fself-test: 576 pass(es); 0 failure(s) in 0.028000 seconds -fself-test: 576 pass(es); 0 failure(s) in 0.009000 seconds -fself-test: 576 pass(es); 0 failure(s) in 0.011000 seconds shows that the selftests are indeed run at each stage of a bootstrap, and that they're fast (well under a second). There's also a debug target, so that we can type: make selftests-gdb to run the selftests under gdb. For a release build, the "sorry" in toplev.c leads to an error, and hence an effective failure. Changing it to an "inform" fixes this. gcc/ChangeLog: * Makefile.in (all.internal): Add "selftests". (all.cross): Likewise. (selftests): New phony target. (s-selftests): New target. (selftests-gdb): New phony target. * selftest.c (selftest::runner::runner): Initialize m_start_time. (selftest::runner::~runner): Print the elapsed time. * selftest.h (class selftest::runner): Add field "m_start_time". * toplev.c (toplev::run_self_tests): Use "inform" rather than "sorry" in an unchecked build. --- gcc/Makefile.in | 19 +++++++++++++++++-- gcc/selftest.c | 10 +++++++--- gcc/selftest.h | 1 + gcc/toplev.c | 2 +- 4 files changed, 26 insertions(+), 6 deletions(-) diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 33dd75b..f01e123 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1817,10 +1817,10 @@ config.status: $(srcdir)/configure $(srcdir)/config.gcc quickstrap: all cd $(toplevel_builddir) && $(MAKE) all-target-libgcc -all.internal: start.encap rest.encap doc +all.internal: start.encap rest.encap doc selftests # This is what to compile if making a cross-compiler. all.cross: native gcc-cross$(exeext) cpp$(exeext) specs \ - libgcc-support lang.all.cross doc @GENINSRC@ srcextra + libgcc-support lang.all.cross doc selftests @GENINSRC@ srcextra # This is what must be made before installing GCC and converting libraries. start.encap: native xgcc$(exeext) cpp$(exeext) specs \ libgcc-support lang.start.encap @GENINSRC@ srcextra @@ -1840,6 +1840,21 @@ endif # This does the things that can't be done on the host machine. rest.cross: specs +# Run the selftests during the build once we have a driver and a cc1, +# so that self-test failures are caught as early as possible. +# Use "s-selftests" to ensure that we only run the selftests if the +# driver or cc1 change. +.PHONY: selftests +selftests: s-selftests +s-selftests: $(GCC_PASSES) cc1$(exeext) stmp-int-hdrs + $(GCC_FOR_TARGET) -xc -S -c /dev/null -fself-test + $(STAMP) $@ + +# Convenience method for running selftests under gdb: +.PHONY: selftests-gdb +selftests-gdb: $(GCC_PASSES) cc1$(exeext) stmp-int-hdrs + $(GCC_FOR_TARGET) -xc -S -c /dev/null -fself-test -wrapper gdb,--args + # Recompile all the language-independent object files. # This is used only if the user explicitly asks for it. compilations: $(BACKEND) diff --git a/gcc/selftest.c b/gcc/selftest.c index abb6585..af95312 100644 --- a/gcc/selftest.c +++ b/gcc/selftest.c @@ -80,7 +80,8 @@ selftest::run_all_tests () runner::runner () : m_passes (0), - m_failures (0) + m_failures (0), + m_start_time (get_run_time ()) { } @@ -88,8 +89,11 @@ runner::runner () runner::~runner () { - fprintf (stderr, "NOTE: %i pass(es); %i failure(s)\n", - m_passes, m_failures); + long finish_time = get_run_time (); + long elapsed_time = finish_time - m_start_time; + fprintf (stderr, "NOTE: %i pass(es); %i failure(s) in %ld.%06ld seconds\n", + m_passes, m_failures, + elapsed_time / 1000000, elapsed_time % 1000000); } /* Notify the user that a particular test is about to be run. */ diff --git a/gcc/selftest.h b/gcc/selftest.h index 884bdbf..720e1d5 100644 --- a/gcc/selftest.h +++ b/gcc/selftest.h @@ -54,6 +54,7 @@ public: private: int m_passes; int m_failures; + long m_start_time; }; /* The class ::selftest::test is a base class from which specific diff --git a/gcc/toplev.c b/gcc/toplev.c index 74712e5..ccb9c79 100644 --- a/gcc/toplev.c +++ b/gcc/toplev.c @@ -2079,7 +2079,7 @@ toplev::run_self_tests () /* Cleanup. */ bitmap_obstack_release (NULL); #else - sorry ("self-tests are not enabled in this build"); + inform (UNKNOWN_LOCATION, "self-tests are not enabled in this build"); #endif /* #if CHECKING_P */ } -- 1.8.5.3