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