[libc++] Migrate Lit platform detection to the DSL

As an important fly-by fix, also make sure we set those features to their
value on the target we run on, not on the host compiling the test suite.
This commit is contained in:
Louis Dionne
2020-04-17 16:00:58 -04:00
parent 9bf4c9e416
commit 3ea9450bda
5 changed files with 116 additions and 66 deletions

View File

@@ -114,6 +114,56 @@ class TestSourceBuilds(SetupConfigs):
int main(int, char**) { this_isnt_defined_anywhere(); }"""
self.assertFalse(dsl.sourceBuilds(self.config, source))
class TestProgramOutput(SetupConfigs):
"""
Tests for libcxx.test.dsl.programOutput
"""
def test_valid_program_returns_output(self):
source = """
#include <cstdio>
int main(int, char**) { std::printf("FOOBAR"); }
"""
self.assertEqual(dsl.programOutput(self.config, source), "FOOBAR")
def test_valid_program_returns_output_newline_handling(self):
source = """
#include <cstdio>
int main(int, char**) { std::printf("FOOBAR\\n"); }
"""
self.assertEqual(dsl.programOutput(self.config, source), "FOOBAR\n")
def test_valid_program_returns_no_output(self):
source = """
int main(int, char**) { }
"""
self.assertEqual(dsl.programOutput(self.config, source), "")
def test_invalid_program_returns_None_1(self):
# The program compiles, but exits with an error
source = """
int main(int, char**) { return 1; }
"""
self.assertEqual(dsl.programOutput(self.config, source), None)
def test_invalid_program_returns_None_2(self):
# The program doesn't compile
source = """
int main(int, char**) { this doesnt compile }
"""
self.assertEqual(dsl.programOutput(self.config, source), None)
def test_pass_arguments_to_program(self):
source = """
#include <cassert>
#include <string>
int main(int argc, char** argv) {
assert(argc == 3);
assert(argv[1] == std::string("first-argument"));
assert(argv[2] == std::string("second-argument"));
}
"""
args = ["first-argument", "second-argument"]
self.assertEqual(dsl.programOutput(self.config, source, args=args), "")
class TestHasLocale(SetupConfigs):
"""

View File

@@ -317,9 +317,6 @@ class Configuration(object):
self.config.available_features.add('availability=%s' % name)
self.config.available_features.add('availability=%s%s' % (name, version))
# Insert the platform name and version into the available features.
self.target_info.add_platform_features(self.config.available_features)
# Simulator testing can take a really long time for some of these tests
# so add a feature check so we can REQUIRES: long_tests in them
self.long_tests = self.get_lit_bool('long_tests')
@@ -333,7 +330,6 @@ class Configuration(object):
self.config.available_features.add('long_tests')
if self.target_info.is_windows():
self.config.available_features.add('windows')
if self.cxx_stdlib_under_test == 'libc++':
# LIBCXX-WINDOWS-FIXME is the feature name used to XFAIL the
# initial Windows failures until they can be properly diagnosed

View File

@@ -12,6 +12,7 @@ import lit.util
import os
import pipes
import platform
import re
import tempfile
def _memoize(f):
@@ -75,6 +76,39 @@ def sourceBuilds(config, source):
_executeScriptInternal(test, ['rm %t.exe'])
return exitCode == 0
def programOutput(config, program, args=[]):
"""
Compiles a program for the test target, run it on the test target and return
the output.
If the program fails to compile or run, None is returned instead. Note that
execution of the program is done through the %{exec} substitution, which means
that the program may be run on a remote host depending on what %{exec} does.
"""
with _makeConfigTest(config) as test:
with open(test.getSourcePath(), 'w') as source:
source.write(program)
try:
_, _, exitCode, _ = _executeScriptInternal(test, [
"mkdir -p %T",
"%{cxx} %s %{flags} %{compile_flags} %{link_flags} -o %t.exe",
])
if exitCode != 0:
return None
out, err, exitCode, _ = _executeScriptInternal(test, [
"%{{exec}} %t.exe {}".format(' '.join(args))
])
if exitCode != 0:
return None
actualOut = re.search("command output:\n(.+)\n$", out, flags=re.DOTALL)
actualOut = actualOut.group(1) if actualOut else ""
return actualOut
finally:
_executeScriptInternal(test, ['rm %t.exe'])
def hasCompileFlag(config, flag):
"""
Return whether the compiler in the configuration supports a given compiler flag.
@@ -96,22 +130,14 @@ def hasLocale(config, locale):
%{exec} -- this means that the command may be executed on a remote host
depending on the %{exec} substitution.
"""
with _makeConfigTest(config) as test:
with open(test.getSourcePath(), 'w') as source:
source.write("""
#include <locale.h>
int main(int, char** argv) {
if (::setlocale(LC_ALL, argv[1]) != NULL) return 0;
else return 1;
}
""")
out, err, exitCode, timeoutInfo = _executeScriptInternal(test, [
"mkdir -p %T",
"%{cxx} %s %{flags} %{compile_flags} %{link_flags} -o %t.exe",
"%{{exec}} %t.exe {}".format(pipes.quote(locale)),
])
_executeScriptInternal(test, ['rm %t.exe'])
return exitCode == 0
program = """
#include <locale.h>
int main(int, char** argv) {
if (::setlocale(LC_ALL, argv[1]) != NULL) return 0;
else return 1;
}
"""
return programOutput(config, program, args=[pipes.quote(locale)]) != None
def compilerMacros(config, flags=''):
"""

View File

@@ -7,6 +7,7 @@
#===----------------------------------------------------------------------===##
from libcxx.test.dsl import *
import pipes
import sys
_isClang = lambda cfg: '__clang__' in compilerMacros(cfg) and '__apple_build_version__' not in compilerMacros(cfg)
@@ -108,3 +109,24 @@ for locale, alts in locales.items():
Feature(name='locale.{}'.format(locale),
when=lambda cfg: any(hasLocale(cfg, alt) for alt in alts))
]
# Add a feature representing the platform name: darwin, linux, windows, etc...
features += [
Feature(name=lambda cfg: programOutput(cfg, """
#include <cstdio>
int main() {
#if defined(__APPLE__)
std::printf("darwin");
#elif defined(_WIN32)
std::printf("windows");
#elif defined(__NetBSD__)
std::printf("netbsd");
#elif defined(__linux__)
std::printf("linux");
#else
std::printf("unknown-platform");
#endif
}
"""))
]

View File

@@ -21,23 +21,17 @@ class DefaultTargetInfo(object):
self.full_config = full_config
self.executor = None
def platform(self):
return sys.platform.lower().strip()
def is_windows(self):
return self.platform() == 'win32'
return sys.platform.lower().strip() == 'win32'
def is_darwin(self):
return self.platform() == 'darwin'
return sys.platform.lower().strip() == 'darwin'
def add_cxx_compile_flags(self, flags): pass
def add_cxx_link_flags(self, flags): pass
def allow_cxxabi_link(self): return True
def use_lit_shell_default(self): return False
def add_platform_features(self, features):
features.add(self.platform())
def add_path(self, dest_env, new_path):
if not new_path:
return
@@ -143,44 +137,6 @@ class LinuxLocalTI(DefaultTargetInfo):
def __init__(self, full_config):
super(LinuxLocalTI, self).__init__(full_config)
def platform(self):
return 'linux'
def _distribution(self):
try:
# linux_distribution is not available since Python 3.8
# However, this function is only used to detect SLES 11,
# which is quite an old distribution that doesn't have
# Python 3.8.
return platform.linux_distribution()
except AttributeError:
return '', '', ''
def platform_name(self):
name, _, _ = self._distribution()
# Some distros have spaces, e.g. 'SUSE Linux Enterprise Server'
# lit features can't have spaces
name = name.lower().strip().replace(' ', '-')
return name # Permitted to be None
def platform_ver(self):
_, ver, _ = self._distribution()
ver = ver.lower().strip().replace(' ', '-')
return ver # Permitted to be None.
def add_platform_features(self, features):
super(LinuxLocalTI, self).add_platform_features(features)
# Some linux distributions have different locale data than others.
# Insert the distributions name and name-version into the available
# features to allow tests to XFAIL on them.
name = self.platform_name()
ver = self.platform_ver()
if name:
features.add(name)
if name and ver:
features.add('%s-%s' % (name, ver))
def add_cxx_compile_flags(self, flags):
flags += ['-D__STDC_FORMAT_MACROS',
'-D__STDC_LIMIT_MACROS',