This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: GCC 3.2


There are many things that can break compatibility between two releases
of a C++ compiler or between two different compilers that are expected
to be binary compatible.  In a previous position I set up some tests to
help detect such breakage between one release and another.  They
occasionally found things like entry points that were thought to no
longer be needed in runtime support libraries, or conflicts between
symbols in shared objects.  These were tests of compatibility for the
compiler and its run-time support, not for functionality within the
Standard C++ Library.

Existing tests were broken apart into two pieces plus a main program.
The main program did nothing but call a function in one of the pieces.
The test was broken apart to have as much interaction between the two
pieces as possible; for example, exception handling tests had a throw
in one piece and the catch in another.  Each piece was built into 
either a relocatable object file, a static library, or a shared object,
one piece compiled by each of the compilers.  They were then linked with
the main program and the test was run.

These tests were a pain to set up, even for testing one compiler on one
platform with one operating system.  They required either building
object files with older compilers ahead of time and then using those
archived files when testing the new compiler, or else having both old
and new compilers available when running the tests.  I'm not at all sure
how to set up such tests for use with GCC.  The test harness needs to
know about two compilers under test rather than one, and the tests need
to build static and shared libraries, which GCC tests don't normally do.
I don't know how difficult it is with either DejaGNU or QMTest to handle
either of these, but if there's interest I'll look into it.

I've attached, as a dummy patch, a shell script that demonstrates this
kind of test plus source files for two sample tests.

Janis Johnson
IBM Linux Technology Center


--- empty	Mon Aug 12 16:37:10 2002
+++ compat.sh	Mon Aug 12 16:37:10 2002
@@ -0,0 +1,242 @@
+#! /bin/sh
+
+########################################################################
+#
+# Test compatibility of two compilers that follow the same ABI.
+#
+# Each test has a main program that does nothing but call a function,
+# plus two additional source files that contain parts of a program that
+# rely on the ABI.  Those source files are compiled into relocatable
+# object files, static libraries, and shared objects with both
+# compilers.  Executables are built using various combinations of those
+# object files, with the main program compiled with the new compiler
+# and using the new compiler's runtime support.
+#
+# This kind of testing can also detect duplicate or missing symbols for
+# various kinds of object files, even using the same compiler.
+#
+# This is meant to be an example of this kind of compatibility testing.
+#
+#
+# Copyright (c) 2002 Free Software Foundation.
+#
+# This file is part of GNU CC.
+#
+# GNU CC is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# GNU CC is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU CC; see the file COPYING.  If not, write to
+# the Free Software Foundation, 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+#
+########################################################################
+
+if [ "x${NEWCPP}" = x ]; then
+  echo "$0: NEWCPP must be the new C++ compiler to test"
+  exit 1
+fi
+
+if [ "x${OLDCPP}" = x ]; then
+  echo "$0: OLDCPP must be the old C++ compiler to test"
+  exit 1
+fi
+
+if [ "x${NEWLIBPATH}" = x ]; then
+  echo "$0: NEWLIBPATH must be the lib directory for the new C++ compiler"
+  exit 1
+fi
+
+if [ "x${OLDLIBPATH}" = x ]; then
+  echo "$0: OLDLIBPATH must be the lib directory for the old C++ compiler"
+  exit 1
+fi
+
+LIB_PATH=${NEWLIBPATH}:${OLDLIBPATH}:.
+
+if [ $# -eq 0 ]; then
+  echo "Usage: $0 testname ..."
+  exit 1
+fi
+
+# Build a single relocatable object file.  Warn if it doesn't build; the
+# tests that use it will fail when they don't link.
+
+build_o ()
+{
+  CPP="$1"
+  OBJ=$2
+  SRC=$3
+
+  ${CPP} -c -o ${OBJ} ${SRC}
+  if [ $? -ne 0 ]; then
+    echo "WARNING: ${TESTNAME}: could not build ${OBJ}"
+  fi
+}
+
+# Build all needed relocatable object files.
+
+build_all_o ()
+{
+  SRC_MAIN=${TESTNAME}_main.C
+  SRC_X=${TESTNAME}_x.C
+  SRC_Y=${TESTNAME}_y.C
+
+  build_o ${NEWCPP} main.o ${SRC_MAIN}
+  build_o ${NEWCPP} x_new.o ${SRC_X}
+  build_o ${NEWCPP} y_new.o ${SRC_Y}
+  build_o ${OLDCPP} x_old.o ${SRC_X}
+  ${OLDCPP} -c -o y_old.o ${SRC_Y}
+}
+
+# Build a single static library.  Warn if it doesn't build; the tests
+# that use it will fail when they don't link.
+
+build_a ()
+{
+  LIB=$1
+  OBJ=$2
+
+  ar cq ${LIB} ${OBJ}
+  if [ $? -ne 0 ]; then
+    echo "WARNING: ${TESTNAME}: could not build ${LIB}"
+  fi
+}
+
+# Build static libraries.  This assumes the relocatable object files
+# have already been built.
+
+build_all_a ()
+{
+  build_a libx_new_a.a x_new.o
+  build_a liby_new_a.a y_new.o
+  build_a libx_old_a.a x_old.o
+  build_a liby_old_a.a y_old.o
+}
+
+# Build a single shared object file.  Warn if it doesn't build; the tests
+# that use it will fail when they don't link.
+
+build_so ()
+{
+  CPP=$1
+  SO=$2
+  SRC=$3
+
+  ${CPP} -fPIC -shared -o ${SO} ${SRC}
+  if [ $? -ne 0 ]; then
+    echo "WARNING: ${TESTNAME}: could not build ${SO}"
+  fi
+}
+
+# Build all needed shared object files.
+
+build_all_so ()
+{
+  SRC_MAIN=${TESTNAME}_main.C
+  SRC_X=${TESTNAME}_x.C
+  SRC_Y=${TESTNAME}_y.C
+
+  build_so ${NEWCPP} libx_new_so.so ${SRC_X}
+  build_so ${NEWCPP} liby_new_so.so ${SRC_Y}
+  build_so ${OLDCPP} libx_old_so.so ${SRC_X}
+  build_so ${OLDCPP} liby_old_so.so ${SRC_Y}
+}
+
+clean()
+{
+  rm -rf *.o *.a *.so a.out
+}
+
+# Link the program using a combination of object file types and then
+# run the resulting executable.  Report failure or success.
+
+link_and_go()
+{
+  ARGS="$1"
+  LD_LIBRARY_PATH=${LIB_PATH} ${NEWCPP} -L. -o a.out main.o $ARGS
+  if [ $? -ne 0 ]; then
+    echo "FAIL (link): $TESTNAME: $ARGS"
+  else
+    LD_LIBRARY_PATH=${LIB_PATH} ./a.out
+    if [ $? -ne 0 ]; then
+      echo "FAIL (run): $TESTNAME: $ARGS"
+    else
+      echo "PASS: $TESTNAME: $ARGS"
+    fi
+  fi
+}
+
+do_test ()
+{
+  # Build the object files that will be used for the tests.
+
+  build_all_o
+  build_all_a
+  build_all_so
+
+  # Build using combinations of .o, .a, and .so files that were all built
+  # with the new compiler.
+
+  link_and_go "x_new.o y_new.o"
+  link_and_go "x_new.o -ly_new_a"
+  link_and_go "x_new.o -ly_new_so"
+  link_and_go "-lx_new_a y_new.o"
+  link_and_go "-lx_new_a -ly_new_a"
+  link_and_go "-lx_new_a -ly_new_so"
+  link_and_go "-lx_new_so y_new.o"
+  link_and_go "-lx_new_so -ly_new_a"
+  link_and_go "-lx_new_so -ly_new_so"
+
+  # Build, linking with the new compiler, an executable that uses a
+  # .o, .a, or .so compiled with the new compiler and a .a or .so built
+  # using a compatible compiler.
+  #
+  # Should relocatable object files from the old compiler be supported,
+  # or only libraries?
+
+  link_and_go "x_new.o y_old.o"
+  link_and_go "x_new.o -ly_old_a"
+  link_and_go "x_new.o -ly_old_so"
+  link_and_go "-lx_new_a y_old.o"
+  link_and_go "-lx_new_a -ly_old_a"
+  link_and_go "-lx_new_a -ly_old_so"
+  link_and_go "-lx_new_so y_old.o"
+  link_and_go "-lx_new_so -ly_old_a"
+  link_and_go "-lx_new_so -ly_old_so"
+
+  # Same as the previous set of executables, but change the order of which
+  # piece is compiled with which compiler.
+
+  link_and_go "x_old.o y_new.o"
+  link_and_go "x_old.o -ly_new_a"
+  link_and_go "x_old.o -ly_new_so"
+  link_and_go "-lx_old_a y_new.o"
+  link_and_go "-lx_old_a -ly_new_a"
+  link_and_go "-lx_old_a -ly_new_so"
+  link_and_go "-lx_old_so y_new.o"
+  link_and_go "-lx_old_so -ly_new_a"
+  link_and_go "-lx_old_so -ly_new_so"
+
+  clean
+}
+
+# Process each test specified on the command line.
+
+for TESTNAME
+do
+  if [ ! -f ${TESTNAME}_main.C \
+      -o ! -f ${TESTNAME}_x.C \
+      -o ! -f ${TESTNAME}_y.C ]; then
+    echo "ERROR: ${TESTNAME}: one or more test files does not exist"
+  else
+    do_test
+  fi
+done
--- empty	Mon Aug 12 16:37:10 2002
+++ bitfield_main.C	Mon Aug 12 16:37:10 2002
@@ -0,0 +1,11 @@
+// Test for an incompatible ABI change that was made between GCC 3.1.1
+// and GCC 3.2.  This test is expected to fail for compilers that span
+// that version change.
+
+extern void bitfield_x (void);
+
+int
+main ()
+{
+  bitfield_x ();
+}
--- empty	Mon Aug 12 16:37:10 2002
+++ bitfield_x.C	Mon Aug 12 16:37:10 2002
@@ -0,0 +1,17 @@
+struct S {
+  char a;
+  int b : 224;
+  char c;
+};
+
+extern void bitfield_y (S);
+
+void
+bitfield_x ()
+{
+  S s;
+  s.a = 'a';
+  s.b = 1234;
+  s.c = 'c';
+  bitfield_y (s);
+}
--- empty	Mon Aug 12 16:37:10 2002
+++ bitfield_y.C	Mon Aug 12 16:37:10 2002
@@ -0,0 +1,18 @@
+struct S {
+  char a;
+  int b : 224;
+  char c;
+};
+
+extern "C" void abort ();
+extern "C" void exit (int);
+
+void
+bitfield_y (S s)
+{
+  if (s.a != 'a'
+      || s.b != 1234
+      || s.c != 'c')
+    abort ();
+  exit (0);
+}
--- empty	Mon Aug 12 16:37:10 2002
+++ filter1_main.C	Mon Aug 12 16:37:10 2002
@@ -0,0 +1,11 @@
+// Test that cleanups get run when a catch filter fails to match,
+// derived from g++.dg/eh/filter1.C to test compatibility between
+// different compiler versions.
+
+extern void ex_test_x (void);
+
+int
+main ()
+{
+  ex_test_x ();
+}
--- empty	Mon Aug 12 16:37:10 2002
+++ filter1_x.C	Mon Aug 12 16:37:10 2002
@@ -0,0 +1,22 @@
+extern "C" void abort();
+
+struct a
+{
+  a();
+  ~a();
+};
+
+extern void ex_test_y (void);
+
+void
+ex_test_x ()
+{
+  try
+    {
+      ex_test_y ();
+    }
+  catch (...)
+    {
+    }
+  abort ();
+}
--- empty	Mon Aug 12 16:37:10 2002
+++ filter1_y.C	Mon Aug 12 16:37:10 2002
@@ -0,0 +1,26 @@
+extern "C" void exit(int);
+
+struct a
+{
+  a();
+  ~a();
+};
+
+struct e1 {};
+struct e2 {};
+
+void
+ex_test_y ()
+{
+  a aa;
+  try
+    {
+      throw e1 ();
+    }
+  catch (e2 &)
+    {
+    }
+}
+
+a::a() { }
+a::~a() { exit (0); }


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]