diff --git a/cmake/modules/AddLLVM.cmake b/cmake/modules/AddLLVM.cmake index b30d002aa20..824d2ff3fa9 100644 --- a/cmake/modules/AddLLVM.cmake +++ b/cmake/modules/AddLLVM.cmake @@ -1173,6 +1173,10 @@ function(configure_lit_site_cfg input output) set(TARGET_TRIPLE "\"+config.target_triple+\"") endif() + string(CONCAT LIT_SITE_CFG_IN_FOOTER + "import lit.llvm\n" + "lit.llvm.initialize(lit_config, config)\n") + configure_file(${input} ${output} @ONLY) get_filename_component(INPUT_DIR ${input} DIRECTORY) if (EXISTS "${INPUT_DIR}/lit.cfg") diff --git a/test/lit.cfg b/test/lit.cfg index 05176dc6711..3931a7431b2 100644 --- a/test/lit.cfg +++ b/test/lit.cfg @@ -10,35 +10,13 @@ import subprocess import lit.util import lit.formats +from lit.llvm import llvm_config # name: The name of this test suite. config.name = 'LLVM' -# Tweak PATH for Win32 to decide to use bash.exe or not. -if sys.platform in ['win32']: - # Seek sane tools in directories and set to $PATH. - path = getattr(config, 'lit_tools_dir', None) - path = lit_config.getToolsPath(path, - config.environment['PATH'], - ['cmp.exe', 'grep.exe', 'sed.exe']) - if path is not None: - path = os.path.pathsep.join((path, - config.environment['PATH'])) - config.environment['PATH'] = path - -# Choose between lit's internal shell pipeline runner and a real shell. If -# LIT_USE_INTERNAL_SHELL is in the environment, we use that as an override. -use_lit_shell = os.environ.get("LIT_USE_INTERNAL_SHELL") -if use_lit_shell: - # 0 is external, "" is default, and everything else is internal. - execute_external = (use_lit_shell == "0") -else: - # Otherwise we default to internal on Windows and external elsewhere, as - # bash on Windows is usually very slow. - execute_external = (not sys.platform in ['win32']) - # testFormat: The test format to use to interpret tests. -config.test_format = lit.formats.ShTest(execute_external) +config.test_format = lit.formats.ShTest(not llvm_config.use_lit_shell) # suffixes: A list of file extensions to treat as test files. This is overriden # by individual lit.local.cfg files in the test subdirectories. @@ -56,57 +34,27 @@ config.test_source_root = os.path.dirname(__file__) config.test_exec_root = os.path.join(config.llvm_obj_root, 'test') # Tweak the PATH to include the tools dir. -path = os.path.pathsep.join((config.llvm_tools_dir, config.environment['PATH'])) -config.environment['PATH'] = path +llvm_config.with_environment('PATH', config.llvm_tools_dir, append_path=True) -# Propagate 'HOME' through the environment. -if 'HOME' in os.environ: - config.environment['HOME'] = os.environ['HOME'] - -# Propagate 'INCLUDE' through the environment. -if 'INCLUDE' in os.environ: - config.environment['INCLUDE'] = os.environ['INCLUDE'] - -# Propagate 'LIB' through the environment. -if 'LIB' in os.environ: - config.environment['LIB'] = os.environ['LIB'] - -# Propagate the temp directory. Windows requires this because it uses \Windows\ -# if none of these are present. -if 'TMP' in os.environ: - config.environment['TMP'] = os.environ['TMP'] -if 'TEMP' in os.environ: - config.environment['TEMP'] = os.environ['TEMP'] +# Propagate some variables from the host environment. +llvm_config.with_system_environment(['HOME', 'INCLUDE', 'LIB', 'TMP', 'TEMP', 'ASAN_SYMBOLIZER_PATH', 'MSAN_SYMBOLIZER_PATH']) # Propagate LLVM_SRC_ROOT into the environment. config.environment['LLVM_SRC_ROOT'] = config.llvm_src_root -# Propagate PYTHON_EXECUTABLE into the environment -config.environment['PYTHON_EXECUTABLE'] = getattr(config, 'python_executable', - '') - -# Propagate path to symbolizer for ASan/MSan. -for symbolizer in ['ASAN_SYMBOLIZER_PATH', 'MSAN_SYMBOLIZER_PATH']: - if symbolizer in os.environ: - config.environment[symbolizer] = os.environ[symbolizer] - # Set up OCAMLPATH to include newly built OCaml libraries. top_ocaml_lib = os.path.join(config.llvm_lib_dir, 'ocaml') llvm_ocaml_lib = os.path.join(top_ocaml_lib, 'llvm') -ocamlpath = os.path.pathsep.join((llvm_ocaml_lib, top_ocaml_lib)) -if 'OCAMLPATH' in os.environ: - ocamlpath = os.path.pathsep.join((ocamlpath, os.environ['OCAMLPATH'])) -config.environment['OCAMLPATH'] = ocamlpath -if 'CAML_LD_LIBRARY_PATH' in os.environ: - caml_ld_library_path = os.path.pathsep.join((llvm_ocaml_lib, - os.environ['CAML_LD_LIBRARY_PATH'])) - config.environment['CAML_LD_LIBRARY_PATH'] = caml_ld_library_path -else: - config.environment['CAML_LD_LIBRARY_PATH'] = llvm_ocaml_lib +llvm_config.with_system_environment('OCAMLPATH') +llvm_config.with_environment('OCAMLPATH', top_ocaml_lib, append_path=True) +llvm_config.with_environment('OCAMLPATH', llvm_ocaml_lib, append_path=True) + +llvm_config.with_system_environment('CAML_LD_LIBRARY_PATH') +llvm_config.with_environment('CAML_LD_LIBRARY_PATH', llvm_ocaml_lib, append_path=True) # Set up OCAMLRUNPARAM to enable backtraces in OCaml tests. -config.environment['OCAMLRUNPARAM'] = 'b' +llvm_config.with_environment('OCAMLRUNPARAM', 'b') # Provide the path to asan runtime lib 'libclang_rt.asan_osx_dynamic.dylib' if # available. This is darwin specific since it's currently only needed on darwin. @@ -300,10 +248,6 @@ for arch in config.targets_to_build.split(): ### Features -# Shell execution -if execute_external: - config.available_features.add('shell') - # Others/can-execute.txt if sys.platform not in ['win32']: config.available_features.add('can-execute') @@ -323,45 +267,14 @@ if loadable_module: if not config.build_shared_libs: config.available_features.add("static-libs") -# Sanitizers. -if 'Address' in config.llvm_use_sanitizer: - config.available_features.add("asan") -else: - config.available_features.add("not_asan") -if 'Memory' in config.llvm_use_sanitizer: - config.available_features.add("msan") -else: - config.available_features.add("not_msan") -if 'Undefined' in config.llvm_use_sanitizer: - config.available_features.add("ubsan") -else: - config.available_features.add("not_ubsan") - -# Check if we should run long running tests. -if lit_config.params.get("run_long_tests", None) == "true": - config.available_features.add("long_tests") - # Direct object generation if not 'hexagon' in config.target_triple: config.available_features.add("object-emission") -if config.have_zlib: - config.available_features.add("zlib") -else: - config.available_features.add("nozlib") - # LLVM can be configured with an empty default triple # Some tests are "generic" and require a valid default triple if config.target_triple: config.available_features.add("default_triple") - if re.match(r'^x86_64.*-linux', config.target_triple): - config.available_features.add("x86_64-linux") - -# Native compilation: host arch == default triple arch -# FIXME: Consider cases that target can be executed -# even if host_triple were different from target_triple. -if config.host_triple == config.target_triple: - config.available_features.add("native") import subprocess @@ -416,19 +329,9 @@ def have_ld64_plugin_support(): if have_ld64_plugin_support(): config.available_features.add('ld64_plugin') -# Ask llvm-config about assertion mode. -try: - llvm_config_cmd = subprocess.Popen( - [os.path.join(config.llvm_tools_dir, 'llvm-config'), '--assertion-mode'], - stdout = subprocess.PIPE, - env=config.environment) -except OSError: - print("Could not find llvm-config in " + config.llvm_tools_dir) - exit(42) - -if re.search(r'ON', llvm_config_cmd.stdout.read().decode('ascii')): - config.available_features.add('asserts') -llvm_config_cmd.wait() +# Ask llvm-config about asserts and global-isel. +llvm_config.feature_config('--assertion-mode', 'asserts') +llvm_config.feature_config('--has-global-isel', 'global-isel') if 'darwin' == sys.platform: try: @@ -441,56 +344,12 @@ if 'darwin' == sys.platform: config.available_features.add('fma3') sysctl_cmd.wait() -if platform.system() in ['Windows']: - if re.match(r'.*-win32$', config.target_triple): - config.available_features.add('target-windows') - # For tests that require Windows to run. - config.available_features.add('system-windows') - # .debug_frame is not emitted for targeting Windows x64. if not re.match(r'^x86_64.*-(mingw32|windows-gnu|win32)', config.target_triple): config.available_features.add('debug_frame') -# Check if we should use gmalloc. -use_gmalloc_str = lit_config.params.get('use_gmalloc', None) -if use_gmalloc_str is not None: - if use_gmalloc_str.lower() in ('1', 'true'): - use_gmalloc = True - elif use_gmalloc_str.lower() in ('', '0', 'false'): - use_gmalloc = False - else: - lit_config.fatal('user parameter use_gmalloc should be 0 or 1') -else: - # Default to not using gmalloc - use_gmalloc = False - -# Allow use of an explicit path for gmalloc library. -# Will default to '/usr/lib/libgmalloc.dylib' if not set. -gmalloc_path_str = lit_config.params.get('gmalloc_path', - '/usr/lib/libgmalloc.dylib') - -if use_gmalloc: - config.environment.update({'DYLD_INSERT_LIBRARIES' : gmalloc_path_str}) - -# Ask llvm-config about global-isel. -try: - llvm_config_cmd = subprocess.Popen( - [os.path.join(config.llvm_tools_dir, 'llvm-config'), '--has-global-isel'], - stdout = subprocess.PIPE, - env=config.environment) -except OSError: - print("Could not find llvm-config in " + config.llvm_tools_dir) - exit(42) - -if re.search(r'ON', llvm_config_cmd.stdout.read().decode('ascii')): - config.available_features.add('global-isel') -llvm_config_cmd.wait() - if config.have_libxar: config.available_features.add('xar') -if config.enable_abi_breaking_checks == "1": - config.available_features.add('abi-breaking-checks') - if config.llvm_libxml2_enabled == "1": config.available_features.add('libxml2') diff --git a/test/lit.site.cfg.in b/test/lit.site.cfg.in index 6de225ecc58..a45a000624c 100644 --- a/test/lit.site.cfg.in +++ b/test/lit.site.cfg.in @@ -52,5 +52,7 @@ except KeyError: key, = e.args lit_config.fatal("unable to find %r parameter, use '--param=%s=VALUE'" % (key,key)) +@LIT_SITE_CFG_IN_FOOTER@ + # Let the main config do the real work. lit_config.load_config(config, "@LLVM_SOURCE_DIR@/test/lit.cfg") diff --git a/utils/lit/lit/llvm/__init__.py b/utils/lit/lit/llvm/__init__.py new file mode 100644 index 00000000000..c4cad04649f --- /dev/null +++ b/utils/lit/lit/llvm/__init__.py @@ -0,0 +1,9 @@ + +from lit.llvm import config + +llvm_config = None + +def initialize(lit_config, test_config): + global llvm_config + llvm_config = config.LLVMConfig(lit_config, test_config) + diff --git a/utils/lit/lit/llvm/config.py b/utils/lit/lit/llvm/config.py new file mode 100644 index 00000000000..edceba6a7bf --- /dev/null +++ b/utils/lit/lit/llvm/config.py @@ -0,0 +1,125 @@ +import os +import re +import subprocess +import sys + +import lit.util + +# Choose between lit's internal shell pipeline runner and a real shell. If +# LIT_USE_INTERNAL_SHELL is in the environment, we use that as an override. +litshenv = os.environ.get("LIT_USE_INTERNAL_SHELL") +litsh = lit.util.pythonize_bool(litshenv) if litshenv else (sys.platform == 'win32') + +def binary_feature(on, feature, off_prefix): + return feature if on else off_prefix + feature + +class LLVMConfig(object): + + def __init__(self, lit_config, config): + self.lit_config = lit_config + self.config = config + + features = config.available_features + + # Tweak PATH for Win32 to decide to use bash.exe or not. + if sys.platform == 'win32': + # For tests that require Windows to run. + features.add('system-windows') + + # Seek sane tools in directories and set to $PATH. + path = self.lit_config.getToolsPath(config.lit_tools_dir, + config.environment['PATH'], + ['cmp.exe', 'grep.exe', 'sed.exe']) + self.with_environment('PATH', path, append_path=True) + + if use_lit_shell: + # 0 is external, "" is default, and everything else is internal. + self.use_lit_shell = (use_lit_shell != "0") + else: + # Otherwise we default to internal on Windows and external elsewhere, as + # bash on Windows is usually very slow. + self.use_lit_shell = (sys.platform in ['win32']) + + self.use_lit_shell = litsh + if not self.litsh: + features.add('shell') + + # Native compilation: host arch == default triple arch + # FIXME: Consider cases that target can be executed + # even if host_triple were different from target_triple. + if config.host_triple == config.target_triple: + features.add("native") + + # Sanitizers. + sanitizers = frozenset(x.lower() for x in getattr(config, 'llvm_use_sanitizer', []).split(';')) + features.add(binary_feature('address' in sanitizers, 'asan', 'not_')) + features.add(binary_feature('memory' in sanitizers, 'msan', 'not_')) + features.add(binary_feature('undefined' in sanitizers, 'ubsan', 'not_')) + + have_zlib = getattr(config, 'have_zlib', None) + features.add(binary_feature(have_zlib, 'zlib', 'no')) + + # Check if we should run long running tests. + long_tests = lit_config.params.get("run_long_tests", None) + if lit.util.pythonize_bool(long_tests): + features.add("long_tests") + + target_triple = getattr(config, 'target_triple', None) + if target_triple: + if re.match(r'^x86_64.*-linux', target_triple): + features.add("x86_64-linux") + if re.match(r'.*-win32$', target_triple): + features.add('target-windows') + + use_gmalloc = lit_config.params.get('use_gmalloc', None) + if lit.util.pythonize_bool(use_gmalloc): + # Allow use of an explicit path for gmalloc library. + # Will default to '/usr/lib/libgmalloc.dylib' if not set. + gmalloc_path_str = lit_config.params.get('gmalloc_path', + '/usr/lib/libgmalloc.dylib') + if gmalloc_path_str is not None: + self.with_environment('DYLD_INSERT_LIBRARIES', gmalloc_path_str) + + breaking_checks = getattr(config, 'enable_abi_breaking_checks') + if lit.util.pythonize_bool(lit_config, breaking_checks): + features.add('abi-breaking-checks') + + def with_environment(self, variable, value, append_path = False): + if append_path and variable in self.config.environment: + def norm(x): + return os.path.normcase(os.path.normpath(x)) + + # Move it to the front if it already exists, otherwise insert it at the + # beginning. + value = norm(value) + current_value = self.config.environment[variable] + items = [norm(x) for x in current_value.split(os.path.pathsep)] + try: + items.remove(value) + except ValueError: + pass + value = os.path.pathsep.join([value] + items) + self.config.environment[variable] = value + + + def with_system_environment(self, variables, append_path = False): + if isinstance(variables, basestring): + variables = [variables] + for v in variables: + value = os.environ.get(v) + if value: + self.with_environment(v, value, append_path) + + def feature_config(self, flag, feature): + # Ask llvm-config about assertion mode. + try: + llvm_config_cmd = subprocess.Popen( + [os.path.join(self.config.llvm_tools_dir, 'llvm-config'), flag], + stdout = subprocess.PIPE, + env=self.config.environment) + except OSError: + self.lit_config.fatal("Could not find llvm-config in " + self.config.llvm_tools_dir) + + output, _ = llvm_config_cmd.communicate() + if re.search(r'ON', llvm_config_cmd.stdout.read().decode('ascii')): + self.config.available_features.add(feature) diff --git a/utils/lit/lit/util.py b/utils/lit/lit/util.py index 1819d4d1c34..b171a0ec36f 100644 --- a/utils/lit/lit/util.py +++ b/utils/lit/lit/util.py @@ -8,6 +8,22 @@ import subprocess import sys import threading + +def pythonize_bool(value): + if value is None: + return False + if type(value) is bool: + return value + if isinstance(value, (int, long)): + return value != 0 + if isinstance(value, basestring): + if value.lower() in ('1', 'true', 'on', 'yes'): + return True + if value.lower() in ('0', 'false', 'off', 'no'): + return False + raise ValueError('"{}" is not a valid boolean'.format(value)) + + def to_bytes(s): """Return the parameter as type 'bytes', possibly encoding it.