[PATCH] qmtest_gcc updates
Nathaniel Smith
njs at pobox.com
Tue Mar 30 18:27:14 UTC 2004
- Rework V3 testsuite to handle the no-compiler scenario.
- Use new Result.Quote method.
-- Nathaniel
--
"...All of this suggests that if we wished to find a modern-day model
for British and American speech of the late eighteenth century, we could
probably do no better than Yosemite Sam."
-------------- next part --------------
Index: build_v3_dist
===================================================================
RCS file: /home/qm/Repository/qmtest_gcc/build_v3_dist,v
retrieving revision 1.1
diff -u -r1.1 build_v3_dist
--- build_v3_dist 18 Mar 2004 18:34:30 -0000 1.1
+++ build_v3_dist 30 Mar 2004 18:09:13 -0000
@@ -1,4 +1,6 @@
-#!/usr/bin/python
+#!/usr/bin/env python
+
+# Note that this script must be run with Python 2.3.
import sys
import os
@@ -20,8 +22,8 @@
help="Package version (default 1.0)")
optparser.add_option("-o", "--output", action="store",
dest="targetdir", metavar="DIR",
- help="Output directory"
- "(default qmtest_libstdcpp_GCCVER-PKGVER)")
+ help="Output directory "
+ "(default: qmtest_libstdcpp_GCCVER-PKGVER)")
optparser.add_option("-f", "--force", action="store_true",
dest="force", default=False,
help="If output directory already exists, delete it")
@@ -29,13 +31,10 @@
dest="baselines", default=[],
help="Additional result file to distribute (may be "
"used multiple times)")
-
-
-def usage(name):
- print "Usage: %s <full-gcc-version> <source-directory> " \
- "<destination-directory>" % name
- print "E.g., %s 3.3.3 gcc-3.3.3 my-gcc-3.3.3-package" % name
- sys.exit(2)
+optparser.add_option("-c", "--config-guess", action="store",
+ dest="config_guess", metavar="FILE",
+ help="Path to config.guess "
+ "(default: search in /usr/share/)")
def ensure_dir(dir):
@@ -54,8 +53,36 @@
os.mkdir(dir)
-def main(name, args):
+def add(source_file_or_dir, *target_path):
+ dest = os.path.join(*target_path)
+ ensure_dir(os.path.dirname(dest))
+ if os.path.isfile(source_file_or_dir):
+ shutil.copy(source_file_or_dir, dest)
+ elif os.path.isdir(source_file_or_dir):
+ shutil.copytree(source_file_or_dir, dest)
+ else:
+ assert 0, "add() must be given a file or directory"
+
+
+def generate(source_string, substitutions, *target_path):
+ dest = os.path.join(*target_path)
+ ensure_dir(os.path.dirname(dest))
+ f = open(dest, "w")
+ f.write(source_string % substitutions)
+ f.close()
+
+class InstallRecorder(object):
+ def __init__(self, file_to_record_in):
+ ensure_dir(os.path.dirname(file_to_record_in))
+ self._file = open(file_to_record_in, "w")
+ def __call__(self, path):
+ self._file.write("%s\n" % path)
+
+
+def main(fullname, args):
+
+ name = os.path.basename(fullname)
options, args = optparser.parse_args(args)
if len(args) != 4:
optparser.error("Wrong number of arguments")
@@ -80,41 +107,46 @@
sys.exit(2)
v3src = j(srcdir, "libstdc++-v3")
- ensure_dir(targetdir)
# Open a file to record which directories exist (and thus need
# installing).
- content_files = open(j(targetdir, "contents"), "w")
+ install = InstallRecorder(j(targetdir, "share-contents"))
- # Mark that this will be a standalone installation, for later use by
- # the QMTest scripts.
- f = open(j(targetdir, "THIS-IS-STANDALONE-V3"), "w")
- # In case we need to version stuff later:
- f.write("1\n")
- f.close()
- content_files.write("THIS-IS-STANDALONE-V3\n")
+ # Put 'config.guess' in.
+ if options.config_guess is None:
+ config_guesses = glob.glob("/usr/share/*/config.guess")
+ if not config_guesses:
+ optparser.error("Cannot find config.guess, use "
+ "--config-guess")
+ config_guess = config_guesses[0]
+ else:
+ config_guess = options.config_guess
+ add(config_guess, targetdir, "config.guess")
+
+ # Mark that this will be a standalone installation, for later
+ # detection by the QMTest harness. We write the numeral '1' in case
+ # we need versioning information later.
+ generate("1\n", {}, targetdir, "THIS-IS-STANDALONE-V3")
+ install("THIS-IS-STANDALONE-V3")
# Copy gcc stuff over:
- shutil.copytree(j(v3src, "testsuite"), j(targetdir, "testsuite"))
- content_files.write("testsuite\n")
- shutil.copytree(j(v3src, "po"), j(targetdir, "po"))
- content_files.write("po\n")
+ add(j(v3src, "testsuite"), targetdir, "testsuite")
+ install("testsuite")
+ add(j(v3src, "po"), targetdir, "po")
+ install("po")
ensure_dir(j(targetdir, "config"))
- shutil.copytree(j(v3src, "config", "abi"),
- j(targetdir, "config", "abi"))
- content_files.write("config\n")
+ add(j(v3src, "config", "abi"), targetdir, "config", "abi")
+ install("config")
# gcc 3.4 has a scripts dir that we need.
if os.path.exists(j(v3src, "scripts")):
- shutil.copytree(j(v3src, "scripts"), j(targetdir, "scripts"))
- content_files.write("scripts\n")
+ add(j(v3src, "scripts"), targetdir, "scripts")
+ install("scripts")
# Copy in QMTest extension classes.
- ensure_dir(j(targetdir, "qm-classes"))
- content_files.write("qm-classes\n")
- shutil.copytree(qmtcdir, j(targetdir, "qm-classes", "qmtc"))
- shutil.copytree(qmtest_gccdir,
- j(targetdir, "qm-classes", "qmtest_gcc"))
+ add(qmtcdir, targetdir, "qm-classes", "qmtc")
+ add(qmtest_gccdir, targetdir, "qm-classes", "qmtest_gcc")
+ install("qm-classes")
# And then clean them up a bit (remove backup files, compiled files,
# and CVS/ directories).
for g in "*~", "*.pyc", "*.pyo":
@@ -125,49 +157,51 @@
# Copy over any supplied baselines.
ensure_dir(j(targetdir, "qm-baselines"))
- content_files.write("qm-baselines\n")
+ install("qm-baselines")
for b in options.baselines:
- shutil.copyfile(b, j(targetdir, "qm-baselines",
- os.path.basename(b)))
+ add(b, targetdir, "qm-baselines", os.path.basename(b))
- # Now create the misc. files.
- miscdir = j(targetdir, "qm-misc")
- ensure_dir(miscdir)
- content_files.write("qm-misc\n")
+ # Copy this script into the package.
+ add(__file__, targetdir, "build_v3_dist")
+ # Set up the substitutions dict used by all our templates.
substitutions = {"prog_name": name,
+ "prog_fullname": fullname,
"gcc_version": gcc_version,
"pkg_version": pkg_version,
"prog_args": " ".join(args),
"user": getpass.getuser(),
- "time": time.strftime("%Y-%m-%d %H:%M:%S "),
+ "time": time.strftime("%Y-%m-%d %H:%M:%S"),
}
- f = open(j(miscdir, "locale-Makefile"), "w")
- f.write(locale_Makefile % substitutions)
- f.close()
-
- f = open(j(miscdir, "util-Makefile"), "w")
- f.write(util_Makefile % substitutions)
+ # Munge testsuite_hooks.h to make testsuite executables
+ # relocatable.
+ f = open(j(targetdir, "testsuite", "testsuite_hooks.h"), "a")
+ f.write(testsuite_hooks_addendum % substitutions)
f.close()
+
+ # Now create the misc. files.
+ miscdir = j(targetdir, "qm-misc")
+ ensure_dir(miscdir)
+ install("qm-misc")
- # And the distribution-level files.
- f = open(j(targetdir, "README"), "w")
- f.write(README_file % substitutions)
- f.close()
+ generate(locale_Makefile, substitutions, miscdir, "locale-Makefile")
- f = open(j(targetdir, "PKGINFO"), "w")
- f.write(PKGINFO_file % substitutions)
- f.close()
+ generate(util_Makefile, substitutions, miscdir, "util-Makefile")
- f = open(j(targetdir,
- "qmtest_libstdcpp_%(gcc_version)s.spec"
- % substitutions),
- "w")
- f.write(spec_file % substitutions)
- f.close()
+ # And the distribution-level files.
+ generate(README_file, substitutions, targetdir, "README")
+ generate(PKGINFO_file, substitutions, targetdir, "PKGINFO")
+ generate(spec_file, substitutions,
+ targetdir, "qmtest_libstdcpp_%(gcc_version)s.spec"
+ % substitutions)
+ generate(build_binary_testsuite_file, substitutions,
+ targetdir, "build_binary_testsuite")
+ os.chmod(j(targetdir, "build_binary_testsuite"), 0755)
+## All the templates for generated files:
+
locale_Makefile = """\
# Do not edit -- this file automatically generated by %(prog_name)s.
# Makefile to build locale files needed by libstdc++-v3 testsuite.
@@ -348,7 +382,7 @@
CompilerTable.cplusplus_path=g++
CompilerTable.cplusplus_options=
DejaGNUTest.target=i686-pc-linux-gnu
- V3Init.scratch_dir=scratch
+ V3Test.scratch_dir=scratch
You should adjust the "DejaGNUTest.target" line to indicate the GNU
triplet for your operating system.
@@ -386,12 +420,23 @@
http://www.codesourcery.com/qm/qmtest_manual
"""
+testsuite_hooks_addendum = """
+
+// Following added automatically by %(prog_name)s:
+#ifdef LOCALEDIR
+#error "LOCALEDIR should not be defined for standalone testing; \
+set environment variable V3_LOCALEDIR instead"
+#endif
+#include <cstdlib>
+#define LOCALEDIR (std::getenv("V3_LOCALEDIR"))
+"""
+
PKGINFO_file = """\
This package generated automatically by %(prog_name)s.
Invoked by %(user)s at %(time)s.
Call was:
- $ %(prog_name)s %(prog_args)s
+ $ %(prog_fullname)s %(prog_args)s
"""
@@ -407,7 +452,10 @@
BuildRoot: %%{_tmppath}/%%{name}-buildroot
Source: qmtest_libstdcpp_%(gcc_version)s-%(pkg_version)s.tar.gz
Vendor: CodeSourcery LLC
-BuildArchitectures: noarch
+# If we let RPM detect dependencies, it will get the idea that this
+# package requires a specific version of libstdc++.so, and that is
+# unhelpful:
+AutoReqProv: no
%%description
This package includes the libstdc++-v3 testsuite from gcc version
@@ -421,16 +469,26 @@
%%install
rm -rf $RPM_BUILD_ROOT
-DIR=$RPM_BUILD_ROOT/usr/share/qmtest_libstdcpp_%(gcc_version)s
-mkdir -p $DIR
-for thing in `cat contents`; do
+
+# We do the building first, because some of the files generated will be
+# installed later.
+LIBDIR=$RPM_BUILD_ROOT/usr/lib/qmtest_libstdcpp_%(gcc_version)s
+mkdir -p `dirname $LIBDIR`
+./build_binary_testsuite $LIBDIR 2>&1 | tee BUILD-DETAILS
+
+SHAREDIR=$RPM_BUILD_ROOT/usr/share/qmtest_libstdcpp_%(gcc_version)s
+mkdir -p $SHAREDIR
+for thing in `cat share-contents`; do
if [ -d "$thing" ]; then
- cp -r "$thing" "$DIR/$thing"
+ cp -r "$thing" "$SHAREDIR/$thing"
else
- cp "$thing" "$DIR/$thing"
+ cp "$thing" "$SHAREDIR/$thing"
fi
done
+find $LIBDIR -name '*.pyc' -o -name '*.pyo' -print0 | xargs -0 rm -f
+find $SHAREDIR -name '*.pyc' -o -name '*.pyo' -print0 | xargs -0 rm -f
+
%%clean
rm -rf $RPM_BUILD_ROOT
@@ -438,13 +496,239 @@
# Install all files as root:
%%defattr(-,root,root)
/usr/share/qmtest_libstdcpp_%(gcc_version)s/
+/usr/lib/qmtest_libstdcpp_%(gcc_version)s/
%%doc README
+%%doc PKGINFO
+%%doc BUILD-DETAILS
+%%doc executable-gen.qmr
+%%doc build_v3_dist
+%%doc build_binary_testsuite
%%changelog
+* Mon Mar 29 2004 Nathaniel Smith <njs at codesourcery.com>
+- Rework for no-compiler version of testsuite.
+
* Tue Mar 16 2004 Nathaniel Smith <njs at codesourcery.com>
- Initial release.
"""
+
+build_binary_testsuite_file = """\
+#!/usr/bin/env python
+
+# This script builds the executables needed for testing libstdc++
+# without a compiler, and then runs the tests to generate a baseline.
+# You should ensure that a canonical version of g++ is in your PATH, and
+# a canonical version of libstdc++ in your LD_LIBRARY_PATH, before
+# running this script; they will be taken as the gold standard against
+# which tested versions will be compared.
+#
+# It must be run from the directory that contains the standalone V3
+# distribution.
+
+usage = \"\"\"\\
+Usage:
+ %%(progname)s [executable-output-directory] [g++ to use] \\\\
+ [directory containing libstdc++ to use]
+If the first argument is not given, it defaults to "qm-executables". If
+the last two arguments are not given, defaults will be found in
+PATH/LD_LIBRARY_PATH.
+\"\"\"
+
+import sys
+import os
+import os.path
+import tempfile
+import shutil
+import atexit
+import glob
+
+def error(*msgs):
+ sys.stderr.write("ERROR: " + "".join(msgs) + "\\n")
+ sys.stderr.flush()
+
+def log(*msgs):
+ prefix = "%%s: " %% progname
+ sys.stdout.write(prefix + "".join(msgs) + "\\n")
+ sys.stdout.flush()
+
+def run_and_log(cmdline, failure_ok=False):
+ log("Running command: %%s" %% cmdline)
+ log("Output:")
+ status = os.system(cmdline)
+ if status != 0 and not failure_ok:
+ error("Command did not complete successfully.")
+ error("Exit status: %%i" %% status)
+ sys.exit(1)
+ log("Execution complete, status = %%i." %% status)
+ return status
+
+def resolve_executable(name):
+ if os.path.isabs(name):
+ return name
+ if os.sep in name:
+ return os.path.abspath(name)
+ log("Searching PATH for %%s." %% name)
+ path = os.environ.get("PATH", "").split(os.pathsep)
+ for dir in path:
+ candidate = os.path.join(dir, name)
+ if os.path.exists(candidate):
+ return os.path.abspath(candidate)
+ error("Cannot find executable %%s." %% name)
+ sys.exit(1)
+
+if not os.path.exists("THIS-IS-STANDALONE-V3"):
+ error("must run from root of standalone libstdc++ test "
+ "distribution.")
+ sys.exit(2)
+
+# This global variable is used directly by log().
+full_progname = sys.argv[0]
+progname = os.path.basename(full_progname)
+args = sys.argv[1:]
+
+log("Called as: %%s %%s" %% (full_progname, " ".join(args)))
+
+## Process arguments.
+if not 0 <= len(args) <= 3:
+ error("bad command line.")
+ sys.stderr.write(usage %% {"progname": progname})
+ sys.exit(2)
+
+## Find compiler output directory.
+if args:
+ compiler_output_dir = args.pop(0)
+else:
+ compiler_output_dir = "qm-executables"
+
+## Find g++.
+if args:
+ gpp_path = args.pop(0)
+else:
+ gpp_path = "g++"
+gpp_path = resolve_executable(gpp_path)
+
+log("Using g++: %%s" %% gpp_path)
+run_and_log("%%s --version" %% gpp_path)
+log()
+
+## Find libstdc++.
+if args:
+ libstdcpp_path = args.pop(0)
+ curr = os.environ.get("LD_LIBRARY_PATH", "")
+ new = "%%s:%%s" %% (libstdcpp_path, curr)
+ os.environ["LD_LIBRARY_PATH"] = new
+
+log('Using LD_LIBRARY_PATH="%%s".'
+ %% os.environ.get("LD_LIBRARY_PATH", ""))
+log()
+
+## Find qmtest.
+qmtest_path = resolve_executable("qmtest")
+log("Using qmtest: %%s" %% qmtest_path)
+run_and_log("%%s --version" %% qmtest_path)
+log()
+
+## Set up the compiler output directory.
+if os.path.exists(compiler_output_dir):
+ error("output directory %%s already exists." %% compiler_output_dir)
+ sys.exit(1)
+
+os.mkdir(compiler_output_dir)
+
+## Create the temporary scratch directory.
+if hasattr(tempfile, "mkdtemp"):
+ tmpdir = tempfile.mkdtemp()
+else:
+ tmpdir = tempfile.mktemp()
+ os.mkdir(tmpdir)
+atexit.register(shutil.rmtree, tmpdir)
+
+## Find the target triplet.
+(config_guess_in, config_guess_out) = os.popen4("./config.guess")
+config_guess_in.close()
+target_triplet = config_guess_out.read()
+target_triplet = target_triplet.strip()
+assert "-" in target_triplet, "Bad target triplet"
+log("Using target triplet: %%s" %% target_triplet)
+log()
+
+## Create the basic context to use.
+log("Creating V3 context file.")
+context_path = os.path.join(tmpdir, "__v3_context__")
+f = open(context_path, "w")
+f.write(\"\"\"\\
+CompilerTable.languages=cplusplus
+CompilerTable.cplusplus_kind=GCC
+CompilerTable.cplusplus_options=
+CompilerTable.cplusplus_path=%%(gpp_path)s
+DejaGNUTest.target=%%(target_triplet)s
+V3Test.scratch_dir=%%(tmpdir)s
+V3Test.compiler_output_dir=%%(compiler_output_dir)s
+\"\"\" %% locals())
+f.close()
+
+## Set up QMTest environment variables.
+class_paths = [os.path.abspath(os.path.join("qm-classes", pkg))
+ for pkg in "qmtc", "qmtest_gcc"]
+qmtest_class_path = os.pathsep.join(class_paths)
+os.environ["QMTEST_CLASS_PATH"] = qmtest_class_path
+log('Using QMTEST_CLASS_PATH="%%s"' %% qmtest_class_path)
+log()
+
+## Create the test database we use.
+log("Creating V3 test database.")
+dbpath = os.path.join(tmpdir, "__v3_db__")
+srcdir = os.path.abspath("testsuite")
+run_and_log("qmtest -D %%(dbpath)s create-tdb "
+ "-c v3_database.V3Database "
+ "-a srcdir=%%(srcdir)s" %% locals())
+log()
+
+## Okay, we're ready to run the tests for the first time.
+log("Running QMTest to generate executables.")
+log("Results stored in executable-gen.qmr")
+status = run_and_log("qmtest -D %%(dbpath)s run "
+ "-C %%(context_path)s --format=brief "
+ "-o executable-gen.qmr"
+ %% locals(),
+ failure_ok=True)
+if status == 0 or (os.WIFEXITED(status) and os.WEXITSTATUS(status) == 1):
+ log("Acceptable output status.")
+else:
+ error("qmtest exited unsuccessfully.")
+ sys.exit(1)
+
+## Clean the irrelevant non-executable output files; they take up a lot of
+## space.
+log("Cleaning up executable directory.")
+for junk in glob.glob(os.path.join(compiler_output_dir, "*.[sio]")):
+ os.unlink(junk)
+ log(" Deleted: %%s" %% junk)
+
+## We have the executables; all is well. Now we'll run it again to
+## generate the baseline result file.
+log("Running QMTest again to generate baseline results.")
+baseline_basename = "%%s.qmr" %% target_triplet
+baseline = os.path.abspath(os.path.join("qm-baselines",
+ baseline_basename))
+log("Results stored in %%s" %% baseline)
+run_and_log("qmtest -D %%(dbpath)s run "
+ "-C %%(context_path)s --format=brief "
+ "-c V3Test.have_compiler=no "
+ "-o %%(baseline)s"
+ %% locals(),
+ failure_ok=True)
+if status == 0 or (os.WIFEXITED(status) and os.WEXITSTATUS(status) == 1):
+ log("Acceptable output status.")
+else:
+ error("qmtest exited unsuccessfully.")
+ sys.exit(1)
+
+## All done.
+log("All done.")
+"""
+
if __name__ == "__main__":
main(sys.argv[0], sys.argv[1:])
Index: gpp_init.py
===================================================================
RCS file: /home/qm/Repository/qmtest_gcc/gpp_init.py,v
retrieving revision 1.8
diff -u -r1.8 gpp_init.py
--- gpp_init.py 18 Mar 2004 18:42:17 -0000 1.8
+++ gpp_init.py 30 Mar 2004 18:09:13 -0000
@@ -82,7 +82,7 @@
"testsuite_flags"),
"--build-includes"]
result["GPPInit.testsuite_flags_command"] \
- = "<pre>" + " ".join(command) + "</pre>"
+ = result.Quote(" ".join(command))
try:
executable = RedirectedExecutable()
executable.Run(command)
Index: v3_test.py
===================================================================
RCS file: /home/qm/Repository/qmtest_gcc/v3_test.py,v
retrieving revision 1.2
diff -u -r1.2 v3_test.py
--- v3_test.py 18 Mar 2004 22:26:11 -0000 1.2
+++ v3_test.py 30 Mar 2004 18:09:13 -0000
@@ -41,7 +41,22 @@
"LD_LIBRARY_PATH_64", "DYLD_LIBRARY_PATH"]
"""All the different envvars that might mean LD_LIBRARY_PATH."""
-class V3Init(Resource):
+class V3Base(object):
+ """Methods required by all V3 classes."""
+
+ def _HaveCompiler(self, context):
+ """Returns true if we have a compiler."""
+
+ if not context.has_key("V3Test.have_compiler"):
+ # By default we assume there is a compiler.
+ return True
+
+ # But if there is a context key, we trust it.
+ return qm.parse_boolean(context["V3Test.have_compiler"])
+
+
+
+class V3Init(Resource, V3Base):
"""All V3 tests depend on one of these for setup."""
def SetUp(self, context, result):
@@ -51,6 +66,24 @@
srcdir = self.GetDatabase().GetRoot()
target = context["DejaGNUTest.target"]
+ # If there is a compiler output directory given, ensure the path
+ # is absolute, and ensure it exists.
+ if context.has_key("V3Test.compiler_output_dir"):
+ compiler_outdir = context["V3Test.compiler_output_dir"]
+ compiler_outdir = os.path.abspath(compiler_outdir)
+ context["V3Test.compiler_output_dir"] = compiler_outdir
+ if not os.path.exists(compiler_outdir):
+ os.mkdir(compiler_outdir)
+ else:
+ compiler_outdir = None
+
+ if not self._HaveCompiler(context) and compiler_outdir is None:
+ result.SetOutcome(result.ERROR,
+ "If have_compiler is false, then "
+ "V3Test.compiler_output_dir must be "
+ "provided")
+ return
+
# Are we using the standalone testsuite to test an installed
# libstdc++/g++, or the integrated testsuite to test a
# just-built libstdc++/g++? Check for the magic file that the
@@ -60,11 +93,12 @@
standalone = os.path.exists(standalone_marker)
if standalone:
standalone_root = os.path.join(srcdir, "..")
- context["V3Init.is_standalone"] = standalone
+ context["V3Test.is_standalone"] = standalone
# Find the compiler.
- compilers = context["CompilerTable.compiler_table"]
- compiler = compilers["cplusplus"]
+ if self._HaveCompiler(context):
+ compilers = context["CompilerTable.compiler_table"]
+ compiler = compilers["cplusplus"]
if not standalone:
@@ -100,16 +134,16 @@
# Our code always refers to this directory as 'outdir' for
# parallelism with the DejaGNU code we emulate, but we call
# it "scratch_dir" for UI purposes.
- if context.has_key("V3Init.outdir"):
+ if context.has_key("V3Test.outdir"):
result.SetOutcome(result.ERROR,
- "Set V3Init.scratch_dir, not outdir")
+ "Set V3Test.scratch_dir, not outdir")
return
- outdir = context["V3Init.scratch_dir"]
+ outdir = context["V3Test.scratch_dir"]
outdir = os.path.abspath(outdir)
if not os.path.exists(outdir):
os.mkdir(outdir)
- context["V3Init.outdir"] = outdir
+ context["V3Test.outdir"] = outdir
# Ensure that the message format files are available.
# This requires different commands depending on whether we're
@@ -118,40 +152,55 @@
locale_dir = os.path.join(blddir, "po")
make_command = ["make", "-j1", "check"]
else:
- # Standalone build needs to set up the locale stuff in its
- # own directory.
- locale_dir = os.path.join(outdir, "qm_locale")
- try:
- os.mkdir(locale_dir)
- except OSError:
- pass
- makefile_in = open(os.path.join(standalone_root,
- "qm-misc",
- "locale-Makefile"))
- makefile_str = makefile_in.read()
- makefile_str = makefile_str.replace("@ROOT@",
- standalone_root)
- makefile_out = open(os.path.join(locale_dir, "Makefile"),
- "w")
- makefile_out.write(makefile_str)
- makefile_out.close()
- make_command = ["make", "-j1", "locales"]
+ if self._HaveCompiler(context):
+ # Standalone build needs to set up the locale stuff in its
+ # own directory.
+ locale_dir = os.path.join(outdir, "qm_locale")
+ try:
+ os.mkdir(locale_dir)
+ except OSError:
+ pass
+ makefile_in = open(os.path.join(standalone_root,
+ "qm-misc",
+ "locale-Makefile"))
+ makefile_str = makefile_in.read()
+ makefile_str = makefile_str.replace("@ROOT@",
+ standalone_root)
+ makefile_out = open(os.path.join(locale_dir,
+ "Makefile"),
+ "w")
+ makefile_out.write(makefile_str)
+ makefile_out.close()
+ make_command = ["make", "-j1", "locales"]
+ else:
+ # We're standalone without a compiler; we'll use the
+ # locale dir in the compiler output directory directly.
+ locale_dir = os.path.join(compiler_outdir, "qm_locale")
+ # Either way, we need to provide the locale directory as an
+ # environment variable, _not_ as a #define.
+ context["V3Init.env_V3_LOCALEDIR"] = locale_dir
- make_executable = RedirectedExecutable()
- status = make_executable.Run(make_command, dir=locale_dir)
- if not os.WIFEXITED(status) or os.WEXITSTATUS(status) != 0:
- result.SetOutcome(result.ERROR,
- "Error building locale information",
- {"status": str(status),
- "stdout": "<pre>"
- + make_executable.stdout
- + "</pre>",
- "stderr": "<pre>"
- + make_executable.stderr
- + "</pre>",
- "command": " ".join(make_command),
- })
- return
+ # Now do the actual compiling, if possible.
+ if self._HaveCompiler(context):
+ make_executable = RedirectedExecutable()
+ status = make_executable.Run(make_command, dir=locale_dir)
+ if not os.WIFEXITED(status) or os.WEXITSTATUS(status) != 0:
+ q_stdout = result.Quote(make_executable.stdout)
+ q_stderr = result.Quote(make_executable.stderr)
+ result.SetOutcome(result.ERROR,
+ "Error building locale information",
+ {"status": str(status),
+ "stdout": q_stdout,
+ "stderr": q_stderr,
+ "command": " ".join(make_command),
+ })
+ return
+
+ if compiler_outdir is not None:
+ co_ld = os.path.join(compiler_outdir, "qm_locale")
+ if os.path.exists(co_ld):
+ shutil.rmtree(co_ld, ignore_errors=True)
+ shutil.copytree(locale_dir, co_ld)
# Copy data files.
@@ -197,9 +246,9 @@
ld_library_path = ":".join(original_ld_library_path)
libpaths.append(outdir)
- context["V3Init.libpaths"] = libpaths
- context["V3Init.ld_library_path"] = ld_library_path
- result["V3Init.ld_library_path"] = ld_library_path
+ context["V3Test.libpaths"] = libpaths
+ context["V3Test.ld_library_path"] = ld_library_path
+ result["V3Test.ld_library_path"] = ld_library_path
# Calculate default g++ flags. Both branches create basic_flags
# and default_flags.
@@ -215,7 +264,11 @@
basic_flags, default_flags = all_flags
else:
# We take the union of the 3.3 and the 3.4 defines; it
- # doesn't seem to hurt.
+ # doesn't seem to hurt. Only exception is that we
+ # purposefully leave out -DLOCALEDIR when doing standalone
+ # testing, so that it will be picked up from the environment
+ # instead. This ensures that binary-only tests can be moved
+ # after being compiled.
basic_flags = [# v3.4 only:
"-D_GLIBCXX_ASSERT",
# v3.3 only:
@@ -224,50 +277,65 @@
"-g", "-O2",
"-ffunction-sections", "-fdata-sections",
"-fmessage-length=0",
- "-DLOCALEDIR=\"%s\"" % locale_dir,
"-I%s" % srcdir]
default_flags = []
+
default_flags.append("-D_GLIBCXX_ASSERT")
if fnmatch.fnmatch(context["DejaGNUTest.target"],
"powerpc-*-darwin*"):
default_flags += ["-multiply_defined", "suppress"]
- context["V3Init.basic_cxx_flags"] = basic_flags
- context["V3Init.default_cxx_flags"] = default_flags
+ context["V3Test.basic_cxx_flags"] = basic_flags
+ context["V3Test.default_cxx_flags"] = default_flags
if standalone:
- # Build libv3test.a.
- makefile_in = open(os.path.join(standalone_root,
- "qm-misc",
- "util-Makefile"))
- makefile_str = makefile_in.read()
- makefile_str = makefile_str.replace("@ROOT@",
- standalone_root)
- makefile_str = makefile_str.replace("@CXX@",
- compiler.GetPath())
- flags = compiler.GetOptions() + basic_flags
- makefile_str = makefile_str.replace("@CXXFLAGS@",
- " ".join(flags))
- makefile_out = open(os.path.join(outdir, "Makefile"), "w")
- makefile_out.write(makefile_str)
- makefile_out.close()
-
- make_executable = RedirectedExecutable()
- make_command = ["make", "libv3test.a"]
- status = make_executable.Run(make_command, dir=outdir)
- if not os.WIFEXITED(status) or os.WEXITSTATUS(status) != 0:
- result.SetOutcome(result.ERROR,
- "Error building libv3test.a",
- {"status": str(status),
- "stdout": "<pre>"
- + make_executable.stdout
- + "</pre>",
- "stderr": "<pre>"
- + make_executable.stderr
- + "</pre>",
- "command": " ".join(make_command),
- })
- return
+ # Ensure libv3test.a exists in 'outdir'.
+ if self._HaveCompiler(context):
+ # Build libv3test.a.
+ makefile_in = open(os.path.join(standalone_root,
+ "qm-misc",
+ "util-Makefile"))
+ makefile_str = makefile_in.read()
+ makefile_str = makefile_str.replace("@ROOT@",
+ standalone_root)
+ makefile_str = makefile_str.replace("@CXX@",
+ compiler.GetPath())
+ flags = compiler.GetOptions() + basic_flags
+ makefile_str = makefile_str.replace("@CXXFLAGS@",
+ " ".join(flags))
+ makefile_out = open(os.path.join(outdir, "Makefile"),
+ "w")
+ makefile_out.write(makefile_str)
+ makefile_out.close()
+
+ make_executable = RedirectedExecutable()
+ make_command = ["make", "libv3test.a"]
+ status = make_executable.Run(make_command, dir=outdir)
+ if (not os.WIFEXITED(status)
+ or os.WEXITSTATUS(status) != 0):
+ q_stdout = result.Quote(make_executable.stdout)
+ q_stderr = result.Quote(make_executable.stderr)
+ command_str = " ".join(make_command),
+ result.SetOutcome(result.ERROR,
+ "Error building libv3test.a",
+ {"status": str(status),
+ "stdout": q_stdout,
+ "stderr": q_stderr,
+ "command": command_str,
+ })
+ return
+
+ # If we have an compiler output dir, use it.
+ if compiler_outdir is not None:
+ shutil.copy(os.path.join(outdir, "libv3test.a"),
+ os.path.join(compiler_outdir,
+ "libv3test.a"))
+ else:
+ # No compiler, so we just copy it out of the compiler
+ # output dir.
+ shutil.copy(os.path.join(compiler_outdir,
+ "libv3test.a"),
+ os.path.join(outdir, "libv3test.a"))
def _CalcBuildTreeFlags(self, result, context, blddir, compiler):
@@ -283,8 +351,7 @@
if os.path.isfile(command):
break
- result["V3Init.testsuite_flags_command"] = \
- "<pre>" + command + "</pre>"
+ result["V3Test.testsuite_flags_command"] = result.Quote(command)
executable = RedirectedExecutable()
executable.Run([command, "--cxxflags"])
@@ -304,6 +371,8 @@
return (basic_flags, default_flags)
+# How DejaGNU does this, for reference:
+#
# dg-runtest calls dg-test calls "libstdc++-dg-test prog do_what
# DEFAULT_CXXFLAGS" (DEFAULT_CXXFLAGS as in normal.exp)
# Which calls
@@ -313,7 +382,7 @@
# target_compile $prog $output_file $compile_type additional_flags=$DEFAULT_CXXFLAGS,compiler=$cxx_final,ldflags=-L$blddir/testsuite,libs=-lv3test
# for us, libgloss doesn't exist, which simplifies things.
-class V3DGTest(DGTest, GCCTestBase):
+class V3DGTest(DGTest, GCCTestBase, V3Base):
"""A 'V3DGTest' is a libstdc++-v3 test using the 'dg' driver.
This test class emulates the 'lib/libstdc++.exp' and 'lib/prune.exp
@@ -324,15 +393,23 @@
_language = "cplusplus"
- _libdir_context_property = "V3Init.libpaths"
+ _libdir_context_property = "V3Test.libpaths"
def Run(self, context, result):
self._SetUp(context)
- self._RunDGTest(context["V3Init.basic_cxx_flags"],
- context["V3Init.default_cxx_flags"],
+
+ if context.has_key("V3Test.compiler_output_dir"):
+ # When using a special output directory, we always save the
+ # executables.
+ keep_output = 1
+ else:
+ keep_output = 0
+ self._RunDGTest(context["V3Test.basic_cxx_flags"],
+ context["V3Test.default_cxx_flags"],
context,
- result)
+ result,
+ keep_output=keep_output)
def _PruneOutput(self, output):
@@ -351,14 +428,16 @@
env = {}
for name in _ld_library_path_names:
- env[name] = context["V3Init.ld_library_path"]
+ env[name] = context["V3Test.ld_library_path"]
+ if context.has_key("V3Init.env_V3_LOCALEDIR"):
+ env["V3_LOCALEDIR"] = context["V3Init.env_V3_LOCALEDIR"]
return env
def _RunTargetExecutable(self, context, result, file, dir = None):
if dir is None:
- dir = context["V3Init.outdir"]
+ dir = context["V3Test.outdir"]
sup = super(V3DGTest, self)
return sup._RunTargetExecutable(context, result, file, dir)
@@ -380,9 +459,52 @@
return (output, file)
+ def _RunDGToolPortion(self, path, tool_flags, context, result):
+ """Don't run the compiler if in pre-compiled mode."""
+
+ if not self._HaveCompiler(context):
+ # Don't run the compiler, just pretend we did.
+ return self._GetOutputFile(context, self._kind, path)
+
+ return super(V3DGTest, self)._RunDGToolPortion(path, tool_flags,
+ context, result)
+
+
+ def _RunDGExecutePortion(self, file, context, result):
+ """Emit an UNTESTED result if not compiling and not running."""
+
+ if (not self._HaveCompiler(context)
+ and self._kind != DGTest.KIND_RUN):
+ # We didn't run the compiler, and we're not going to run the
+ # executable; we'd better emit something here because we're
+ # not doing it anywhere else.
+ result["V3DGTest.explanation_1"] = (
+ "This is a compiler test, and we are running in no "
+ "compiler mode. Skipped.")
+ # Magic marker for the TET output stream to pick up on:
+ result["test_not_relevant_to_testing_mode"] = "true"
+ self._RecordDejaGNUOutcome(result,
+ self.UNTESTED, self._name)
+ return
+
+ super(V3DGTest, self)._RunDGExecutePortion(file,
+ context, result)
+
+
def _GetOutputFile(self, context, kind, path):
- base = os.path.basename(path)
+ if context.has_key("V3Test.compiler_output_dir"):
+ dir = context["V3Test.compiler_output_dir"]
+ srcdir = self.GetDatabase().GetRoot()
+ path = os.path.normpath(path)
+ srcdir = os.path.normpath(srcdir)
+ assert path.startswith(srcdir)
+ base = path[len(srcdir):]
+ base = base.replace("/", "_")
+ else:
+ dir = context.GetTemporaryDirectory()
+ base = os.path.basename(path)
+
if kind != self.KIND_PRECOMPILE:
base = os.path.splitext(base)[0]
base += { DGTest.KIND_PREPROCESS : ".i",
@@ -393,7 +515,7 @@
GCCTestBase.KIND_PRECOMPILE : ".gch",
}[kind]
- return os.path.join(context.GetTemporaryDirectory(), base)
+ return os.path.join(dir, base)
def _DGrequire_iconv(self, line_num, args, context):
@@ -416,6 +538,16 @@
charset = args[0]
+ # First check to see if we have a compiler. We can't do
+ # anything useful without one.
+ if not self._HaveCompiler(context):
+ # No compiler; we'll go ahead and hope for the best.
+ # Better would be to save the test programs to the output
+ # directory, but this is difficult; on the other hand, not
+ # doing so may cause spurious failures if a character set is
+ # not in fact supported by our local libiconv...
+ return
+
# Check to see if iconv does exist and work.
# First by creating and compiling a test program...
tmpdir = context.GetTemporaryDirectory()
@@ -439,9 +571,9 @@
compiler = context["CompilerTable.compiler_table"][self._language]
options = []
- options += context["V3Init.basic_cxx_flags"]
- options += context["V3Init.default_cxx_flags"]
- libpaths = context["V3Init.libpaths"]
+ options += context["V3Test.basic_cxx_flags"]
+ options += context["V3Test.default_cxx_flags"]
+ libpaths = context["V3Test.libpaths"]
options += ["-L" + p for p in libpaths]
if context.has_key("GCCTest.libiconv"):
@@ -471,6 +603,7 @@
+# How the real GCC tree does things:
# check-abi first builds
# abi_check
# baseline_symbols
@@ -484,12 +617,12 @@
#
#
# new-abi-baseline is what actually generates a new baseline.
-# it does it with ${extract_symvers} ../src/.libs/libstdc++.so ${baseline_file}
+# It does it with ${extract_symvers} ../src/.libs/libstdc++.so ${baseline_file}
# baseline_file = ${baseline_dir}/baseline_symbols.txt
# baseline_dir is set by autoconf to some mad thing...
# $glibcxx_srcdir/config/abi/${abi_baseline_pair}\$(MULTISUBDIR)"
# abi_baseline_pair is set by autoconf to host_cpu-host_os by default.
-# but there are some special cases, in particular:
+# But there are some special cases, in particular:
# x86_64-*-linux* -> x86_64-linux-gnu
# alpha*-*-freebsd5* -> alpha-freebsd5
# i*86-*-freebsd4* -> i386-freebsd4
@@ -497,9 +630,10 @@
# sparc*-*-freebsd5* -> sparc-freebsd5
#
# extract_symvers = $(glibcxx_srcdir)/scripts/extract_symvers
-# extract_symvers is actually just a shell script
+# extract_symvers is actually just a shell script; we don't need to
+# compile it.
-class V3ABITest(Test):
+class V3ABITest(Test, V3Base):
"""A 'V3ABITest' checks the ABI of libstdc++ against a baseline.
Depends on context variable 'V3Test.abi_baseline_file'."""
@@ -509,25 +643,48 @@
# Some variables we'll need throughout.
executable = RedirectedExecutable()
tmpdir = context.GetTemporaryDirectory()
- outdir = context["V3Init.outdir"]
+ outdir = context["V3Test.outdir"]
srcdir = self.GetDatabase().GetRoot()
+ if context.has_key("V3Test.compiler_output_dir"):
+ compiler_outdir = context["V3Test.compiler_output_dir"]
+ else:
+ compiler_outdir = None
# First we make sure that the abi_check program exists.
- abi_check = os.path.join(outdir, "abi_check")
- status = executable.Run(["make", "abi_check"], dir=outdir)
- result["make_abi_check_stdout"] = ("<pre>" + executable.stdout
- + "</pre>")
- result["make_abi_check_stderr"] = ("<pre>" + executable.stderr
- + "</pre>")
- result["make_abi_check_status"] = str(status)
- if not os.WIFEXITED(status) or os.WEXITSTATUS(status) != 0:
- result.SetOutcome(result.ERROR, "Error building abi_check")
- return
+ if not self._HaveCompiler(context):
+ # If we have no compiler, we must find it in the compiler
+ # output dir.
+ if compiler_outdir is None:
+ result.SetOutcome(result.ERROR,
+ "No compiler output dir, "
+ "but no compiler either.")
+ return
+ abi_check = os.path.join(compiler_outdir, "abi_check")
+ else:
+ # Otherwise, we have to try building it.
+ abi_check = os.path.join(outdir, "abi_check")
+ status = executable.Run(["make", "abi_check"], dir=outdir)
+ quote = result.Quote
+ result["make_abi_check_stdout"] = quote(executable.stdout)
+ result["make_abi_check_stderr"] = quote(executable.stderr)
+ result["make_abi_check_status"] = str(status)
+ if not os.WIFEXITED(status) or os.WEXITSTATUS(status) != 0:
+ result.SetOutcome(result.ERROR,
+ "Error building abi_check")
+ return
+ # Ensure that the abi_check program does end up in the
+ # compiler output dir, if necessary.
+ if compiler_outdir is not None:
+ shutil.copy(abi_check,
+ os.path.join(compiler_outdir, "abi_check"))
+
if not os.path.isfile(abi_check):
result.SetOutcome(result.ERROR,
- "No abi_check program '%s'" % abi_check)
+ "No abi_check program '%s'"
+ % abi_check)
return
+
# Now make sure the baseline file exists.
baseline_type = self._GetAbiName(context["DejaGNUTest.target"])
baseline_file = os.path.join(srcdir, "..", "config", "abi",
@@ -554,12 +711,12 @@
return
# Extract the current symbols.
- # First use ldd to find the libstdc++ in use.
- status = executable.Run(["ldd", "abi_check"], dir=outdir)
- result["ldd_stdout"] = ("<pre>" + executable.stdout
- + "</pre>")
- result["ldd_stderr"] = ("<pre>" + executable.stderr
- + "</pre>")
+ # First use ldd to find the libstdc++ in use. 'abi_check' is a
+ # handy C++ program; we'll check which library it's linked
+ # against.
+ status = executable.Run(["ldd", abi_check], dir=outdir)
+ result["ldd_stdout"] = result.Quote(executable.stdout)
+ result["ldd_stderr"] = result.Quote(executable.stderr)
result["ldd_status"] = str(status)
if not os.WIFEXITED(status) or os.WEXITSTATUS(status) != 0:
result.SetOutcome(result.ERROR,
@@ -580,10 +737,9 @@
status = executable.Run([extract_symvers,
libstdcpp,
curr_symbols])
- result["extract_symvers_stdout"] = ("<pre>" + executable.stdout
- + "</pre>")
- result["extract_symvers_stderr"] = ("<pre>" + executable.stderr
- + "</pre>")
+ quote = result.Quote
+ result["extract_symvers_stdout"] = quote(executable.stdout)
+ result["extract_symvers_stderr"] = quote(executable.stderr)
result["extract_symvers_status"] = str(status)
if not os.WIFEXITED(status) or os.WEXITSTATUS(status) != 0:
result.SetOutcome(result.ERROR, "Error extracting symbols")
@@ -597,10 +753,9 @@
# latter.
status = executable.Run([abi_check, "--check-verbose",
curr_symbols, baseline_file])
- result["comparison_stdout"] = ("<pre>" + executable.stdout
- + "</pre>")
- result["comparison_stderr"] = ("<pre>" + executable.stderr
- + "</pre>")
+ quote = result.Quote
+ result["comparison_stdout"] = quote(executable.stdout)
+ result["comparison_stderr"] = quote(executable.stderr)
result["comparison_status"] = str(status)
if not os.WIFEXITED(status) or os.WEXITSTATUS(status) != 0:
result.SetOutcome(result.ERROR,
More information about the qmtest
mailing list