Skip to content

Commit

Permalink
Adjust libc++ test infastructure to fully support modules
Browse files Browse the repository at this point in the history
This patch overhalls the libc++ test format/configuration in order to fully support modules. By "fully support" I mean get almost all of the tests passing. The main hurdle for doing this is handling tests that `#define _LIBCPP_FOO` macros to test a different configuration. This patch deals with these tests in the following ways:

1. For tests that define single `_LIBCPP_ABI_FOO` macros have been annotated with `// MODULES_DEFINES: _LIBCPP_ABI_FOO`. This allows the test suite to define the macro on the command line so it uses a different set of modules.
2. Tests for libc++'s debug mode (which define custom `_LIBCPP_ASSERT`) are automatically detected by the test suite and are compiled and run with modules disabled.

This patch also cleans up how the `CXXCompiler` helper class handles enabling/disabling language features.

NOTE: This patch uses `LIT` features which were only committed to LLVM today. If this patch breaks running the libc++ tests you probably need to update LLVM.
llvm-svn: 288728
  • Loading branch information
EricWF committed Dec 5, 2016
1 parent 800638f commit daf21c3
Show file tree
Hide file tree
Showing 37 changed files with 207 additions and 140 deletions.
2 changes: 1 addition & 1 deletion libcxx/include/module.modulemap
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,7 @@ module std [system] {
}
module strstream {
header "strstream"
requires !cplusplus11
export *
}
module system_error {
header "system_error"
Expand Down
1 change: 1 addition & 0 deletions libcxx/test/libcxx/atomics/libcpp-has-no-threads.fail.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
// Test that including <atomic> fails to compile when _LIBCPP_HAS_NO_THREADS
// is defined.

// MODULES_DEFINES: _LIBCPP_HAS_NO_THREADS
#ifndef _LIBCPP_HAS_NO_THREADS
#define _LIBCPP_HAS_NO_THREADS
#endif
Expand Down
133 changes: 83 additions & 50 deletions libcxx/test/libcxx/compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#
#===----------------------------------------------------------------------===##

import platform
import os
import lit.util
import libcxx.util
Expand All @@ -19,16 +20,47 @@ class CXXCompiler(object):
CM_Link = 3

def __init__(self, path, flags=None, compile_flags=None, link_flags=None,
use_ccache=False):
warning_flags=None, modules_flags=None, use_modules=False,
use_ccache=False, use_warnings=False, compile_env=None,
cxx_type=None, cxx_version=None):
self.path = path
self.flags = list(flags or [])
self.compile_flags = list(compile_flags or [])
self.warning_flags = []
self.warning_flags = list(warning_flags or [])
self.link_flags = list(link_flags or [])
self.modules_flags = list(modules_flags or [])
self.use_modules = use_modules
assert not use_modules or modules_flags is not None
self.use_ccache = use_ccache
self.type = None
self.version = None
self._initTypeAndVersion()
self.use_warnings = use_warnings
if compile_env is not None:
self.compile_env = dict(compile_env)
else:
self.compile_env = None
self.type = cxx_type
self.version = cxx_version
if self.type is None or self.version is None:
self._initTypeAndVersion()

def copy(self):
new_cxx = CXXCompiler(
self.path, flags=self.flags, compile_flags=self.compile_flags,
link_flags=self.link_flags, warning_flags=self.warning_flags,
modules_flags=self.modules_flags, use_modules=self.use_modules,
use_ccache=self.use_ccache, use_warnings=self.use_warnings,
compile_env=self.compile_env, cxx_type=self.type,
cxx_version=self.version)
return new_cxx

def useModules(self, value=True):
self.use_modules = value
assert not self.use_modules or self.modules_flags is not None

def useCCache(self, value=True):
self.use_ccache = value

def useWarnings(self, value=True):
self.use_warnings = value

def _initTypeAndVersion(self):
# Get compiler type and version
Expand All @@ -54,10 +86,9 @@ def _initTypeAndVersion(self):
self.version = (major_ver, minor_ver, patchlevel)

def _basicCmd(self, source_files, out, mode=CM_Default, flags=[],
input_is_cxx=False,
enable_warnings=True, disable_ccache=False):
input_is_cxx=False):
cmd = []
if self.use_ccache and not disable_ccache \
if self.use_ccache \
and not mode == self.CM_Link \
and not mode == self.CM_PreProcess:
cmd += ['ccache']
Expand All @@ -77,68 +108,64 @@ def _basicCmd(self, source_files, out, mode=CM_Default, flags=[],
elif mode == self.CM_Compile:
cmd += ['-c']
cmd += self.flags
if self.use_modules:
cmd += self.modules_flags
if mode != self.CM_Link:
cmd += self.compile_flags
if enable_warnings:
if self.use_warnings:
cmd += self.warning_flags
if mode != self.CM_PreProcess and mode != self.CM_Compile:
cmd += self.link_flags
cmd += flags
return cmd

def _getWarningFlags(self, enable_warnings=True):
return self.warning_flags if enable_warnings else []
def _getWarningFlags(self):
return self.warning_flags if self.use_warnings else []

def preprocessCmd(self, source_files, out=None, flags=[],
enable_warnings=True):
def preprocessCmd(self, source_files, out=None, flags=[]):
return self._basicCmd(source_files, out, flags=flags,
mode=self.CM_PreProcess,
enable_warnings=enable_warnings,
input_is_cxx=True)

def compileCmd(self, source_files, out=None, flags=[],
disable_ccache=False, enable_warnings=True):
def compileCmd(self, source_files, out=None, flags=[]):
return self._basicCmd(source_files, out, flags=flags,
mode=self.CM_Compile,
input_is_cxx=True,
enable_warnings=enable_warnings,
disable_ccache=disable_ccache) + ['-c']
input_is_cxx=True) + ['-c']

def linkCmd(self, source_files, out=None, flags=[]):
return self._basicCmd(source_files, out, mode=self.CM_Link)

def compileLinkCmd(self, source_files, out=None, flags=[],
enable_warnings=True):
return self._basicCmd(source_files, out, flags=flags,
enable_warnings=enable_warnings)
mode=self.CM_Link)

def preprocess(self, source_files, out=None, flags=[], env=None, cwd=None):
def compileLinkCmd(self, source_files, out=None, flags=[]):
return self._basicCmd(source_files, out, flags=flags)

def preprocess(self, source_files, out=None, flags=[], cwd=None):
cmd = self.preprocessCmd(source_files, out, flags)
out, err, rc = lit.util.executeCommand(cmd, env=env, cwd=cwd)
out, err, rc = lit.util.executeCommand(cmd, env=self.compile_env,
cwd=cwd)
return cmd, out, err, rc

def compile(self, source_files, out=None, flags=[], env=None, cwd=None,
disable_ccache=False, enable_warnings=True):
cmd = self.compileCmd(source_files, out, flags,
disable_ccache=disable_ccache,
enable_warnings=enable_warnings)
out, err, rc = lit.util.executeCommand(cmd, env=env, cwd=cwd)
def compile(self, source_files, out=None, flags=[], cwd=None):
cmd = self.compileCmd(source_files, out, flags)
out, err, rc = lit.util.executeCommand(cmd, env=self.compile_env,
cwd=cwd)
return cmd, out, err, rc

def link(self, source_files, out=None, flags=[], env=None, cwd=None):
def link(self, source_files, out=None, flags=[], cwd=None):
cmd = self.linkCmd(source_files, out, flags)
out, err, rc = lit.util.executeCommand(cmd, env=env, cwd=cwd)
out, err, rc = lit.util.executeCommand(cmd, env=self.compile_env,
cwd=cwd)
return cmd, out, err, rc

def compileLink(self, source_files, out=None, flags=[], env=None,
def compileLink(self, source_files, out=None, flags=[],
cwd=None):
cmd = self.compileLinkCmd(source_files, out, flags)
out, err, rc = lit.util.executeCommand(cmd, env=env, cwd=cwd)
out, err, rc = lit.util.executeCommand(cmd, env=self.compile_env,
cwd=cwd)
return cmd, out, err, rc

def compileLinkTwoSteps(self, source_file, out=None, object_file=None,
flags=[], env=None, cwd=None,
disable_ccache=False):
flags=[], cwd=None):
if not isinstance(source_file, str):
raise TypeError('This function only accepts a single input file')
if object_file is None:
Expand All @@ -149,22 +176,20 @@ def compileLinkTwoSteps(self, source_file, out=None, object_file=None,
with_fn = lambda: libcxx.util.nullContext(object_file)
with with_fn() as object_file:
cc_cmd, cc_stdout, cc_stderr, rc = self.compile(
source_file, object_file, flags=flags, env=env, cwd=cwd,
disable_ccache=disable_ccache)
source_file, object_file, flags=flags, cwd=cwd)
if rc != 0:
return cc_cmd, cc_stdout, cc_stderr, rc

link_cmd, link_stdout, link_stderr, rc = self.link(
object_file, out=out, flags=flags, env=env, cwd=cwd)
object_file, out=out, flags=flags, cwd=cwd)
return (cc_cmd + ['&&'] + link_cmd, cc_stdout + link_stdout,
cc_stderr + link_stderr, rc)

def dumpMacros(self, source_files=None, flags=[], env=None, cwd=None):
def dumpMacros(self, source_files=None, flags=[], cwd=None):
if source_files is None:
source_files = os.devnull
flags = ['-dM'] + flags
cmd, out, err, rc = self.preprocess(source_files, flags=flags, env=env,
cwd=cwd)
cmd, out, err, rc = self.preprocess(source_files, flags=flags, cwd=cwd)
if rc != 0:
return None
parsed_macros = {}
Expand Down Expand Up @@ -215,11 +240,11 @@ def addCompileFlagIfSupported(self, flag):
else:
return False

def addWarningFlagIfSupported(self, flag):
def hasWarningFlag(self, flag):
"""
addWarningFlagIfSupported - Add a warning flag if the compiler
supports it. Unlike addCompileFlagIfSupported, this function detects
when "-Wno-<warning>" flags are unsupported. If flag is a
hasWarningFlag - Test if the compiler supports a given warning flag.
Unlike addCompileFlagIfSupported, this function detects when
"-Wno-<warning>" flags are unsupported. If flag is a
"-Wno-<warning>" GCC will not emit an unknown option diagnostic unless
another error is triggered during compilation.
"""
Expand All @@ -230,7 +255,10 @@ def addWarningFlagIfSupported(self, flag):
return True
return False
flags = ['-Werror', flag]
cmd = self.compileCmd('-', os.devnull, flags, enable_warnings=False)
old_use_warnings = self.use_warnings
self.useWarnings(False)
cmd = self.compileCmd('-', os.devnull, flags)
self.useWarnings(True)
# Remove '-v' because it will cause the command line invocation
# to be printed as part of the error output.
# TODO(EricWF): Are there other flags we need to worry about?
Expand All @@ -240,5 +268,10 @@ def addWarningFlagIfSupported(self, flag):
assert rc != 0
if flag in err:
return False
self.warning_flags += [flag]
return True

def addWarningFlagIfSupported(self, flag):
if self.hasWarningFlag(flag):
self.warning_flags += [flag]
return True
return False
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
// deque()
// deque::iterator()

// MODULES_DEFINES: _LIBCPP_ABI_INCOMPLETE_TYPES_IN_DEQUE
#define _LIBCPP_ABI_INCOMPLETE_TYPES_IN_DEQUE
#include <deque>
#include <cassert>
Expand Down
1 change: 1 addition & 0 deletions libcxx/test/libcxx/strings/iterators.noexcept.pass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
// When exceptions are disabled, all iterators should get this "fast path"
//

// MODULES_DEFINES: _LIBCPP_NO_EXCEPTIONS
#define _LIBCPP_NO_EXCEPTIONS

#include <iterator>
Expand Down
21 changes: 11 additions & 10 deletions libcxx/test/libcxx/test/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,6 @@ def __init__(self, lit_config, config):
self.cxx_library_root = None
self.cxx_runtime_root = None
self.abi_library_root = None
self.enable_modules = False
self.modules_flags = None
self.env = {}
self.use_target = False
self.use_system_cxx_lib = False
Expand Down Expand Up @@ -128,6 +126,9 @@ def print_config_info(self):
# Print the final compile and link flags.
self.lit_config.note('Using compiler: %s' % self.cxx.path)
self.lit_config.note('Using flags: %s' % self.cxx.flags)
if self.cxx.use_modules:
self.lit_config.note('Using modules flags: %s' %
self.cxx.modules_flags)
self.lit_config.note('Using compile flags: %s'
% self.cxx.compile_flags)
if len(self.cxx.warning_flags):
Expand Down Expand Up @@ -735,8 +736,8 @@ def configure_modules(self):
if platform.system() != 'Darwin':
modules_flags += ['-Xclang', '-fmodules-local-submodule-visibility']
supports_modules = self.cxx.hasCompileFlag(modules_flags)
self.enable_modules = self.get_lit_bool('enable_modules', False)
if self.enable_modules and not supports_modules:
enable_modules = self.get_lit_bool('enable_modules', False)
if enable_modules and not supports_modules:
self.lit_config.fatal(
'-fmodules is enabled but not supported by the compiler')
if not supports_modules:
Expand All @@ -748,11 +749,11 @@ def configure_modules(self):
if os.path.isdir(module_cache):
shutil.rmtree(module_cache)
os.makedirs(module_cache)
self.modules_flags = modules_flags + \
self.cxx.modules_flags = modules_flags + \
['-fmodules-cache-path=' + module_cache]
if self.enable_modules:
if enable_modules:
self.config.available_features.add('-fmodules')
self.cxx.compile_flags += self.modules_flags
self.cxx.useModules()

def configure_substitutions(self):
sub = self.config.substitutions
Expand All @@ -777,10 +778,10 @@ def configure_substitutions(self):
build_str = self.cxx.path + ' -o %t.exe %s ' + all_flags
sub.append(('%compile', compile_str))
sub.append(('%link', link_str))
if self.enable_modules:
if self.cxx.use_modules:
sub.append(('%build_module', build_str))
elif self.modules_flags is not None:
modules_str = ' '.join(self.modules_flags) + ' '
elif self.cxx.modules_flags is not None:
modules_str = ' '.join(self.cxx.modules_flags) + ' '
sub.append(('%build_module', build_str + ' ' + modules_str))
sub.append(('%build', build_str))
# Configure exec prefix substitutions.
Expand Down
Loading

0 comments on commit daf21c3

Please sign in to comment.