Index: clang/test/lit.cfg =================================================================== --- clang/test/lit.cfg +++ clang/test/lit.cfg @@ -10,6 +10,7 @@ import lit.util from lit.llvm import llvm_config +from lit.llvm import ToolFilter # Configuration file for the 'lit' test runner. @@ -112,55 +113,12 @@ if config.clang_examples: config.available_features.add('examples') -# Note that when substituting %clang_cc1 also fill in the include directory of -# the builtin headers. Those are part of even a freestanding environment, but -# Clang relies on the driver to locate them. -def getClangBuiltinIncludeDir(clang): - # FIXME: Rather than just getting the version, we should have clang print - # out its resource dir here in an easy to scrape form. - cmd = subprocess.Popen([clang, '-print-file-name=include'], - stdout=subprocess.PIPE, - env=config.environment) - if not cmd.stdout: - lit_config.fatal("Couldn't find the include dir for Clang ('%s')" % clang) - dir = cmd.stdout.read().strip() - if sys.platform in ['win32'] and not llvm_config.use_lit_shell: - # Don't pass dosish path separator to msys bash.exe. - dir = dir.replace('\\', '/') - # Ensure the result is an ascii string, across Python2.5+ - Python3. - return str(dir.decode('ascii')) - -def makeItaniumABITriple(triple): - m = re.match(r'(\w+)-(\w+)-(\w+)', triple) - if not m: - lit_config.fatal("Could not turn '%s' into Itanium ABI triple" % triple) - if m.group(3).lower() != 'win32': - # All non-win32 triples use the Itanium ABI. - return triple - return m.group(1) + '-' + m.group(2) + '-mingw32' - -def makeMSABITriple(triple): - m = re.match(r'(\w+)-(\w+)-(\w+)', triple) - if not m: - lit_config.fatal("Could not turn '%s' into MS ABI triple" % triple) - isa = m.group(1).lower() - vendor = m.group(2).lower() - os = m.group(3).lower() - if os == 'win32': - # If the OS is win32, we're done. - return triple - if isa.startswith('x86') or isa == 'amd64' or re.match(r'i\d86', isa): - # For x86 ISAs, adjust the OS. - return isa + '-' + vendor + '-win32' - # -win32 is not supported for non-x86 targets; use a default. - return 'i686-pc-win32' - +builtin_include_dir = llvm_config.get_clang_builtin_include_dir(config.clang) config.substitutions.append( ('%clang_analyze_cc1', '%clang_cc1 -analyze %analyze') ) config.substitutions.append( ('%clang_cc1', '%s -cc1 -internal-isystem %s -nostdsysteminc' - % (config.clang, - getClangBuiltinIncludeDir(config.clang))) ) + % (config.clang, builtin_include_dir)) ) config.substitutions.append( ('%clang_cpp', ' ' + config.clang + ' --driver-mode=cpp ')) config.substitutions.append( ('%clang_cl', ' ' + config.clang + @@ -168,16 +126,20 @@ config.substitutions.append( ('%clangxx', ' ' + config.clang + ' --driver-mode=g++ ')) config.substitutions.append( ('%clang', ' ' + config.clang + ' ') ) -config.substitutions.append( ('%test_debuginfo', ' ' + config.llvm_src_root + '/utils/test_debuginfo.pl ') ) -config.substitutions.append( ('%itanium_abi_triple', makeItaniumABITriple(config.target_triple)) ) -config.substitutions.append( ('%ms_abi_triple', makeMSABITriple(config.target_triple)) ) -config.substitutions.append( ('%resource_dir', getClangBuiltinIncludeDir(config.clang)) ) +config.substitutions.append( ('%test_debuginfo', + ' ' + config.llvm_src_root + '/utils/test_debuginfo.pl ') ) +config.substitutions.append( ('%itanium_abi_triple', + llvm_config.make_itanium_abi_triple(config.target_triple)) ) +config.substitutions.append( ('%ms_abi_triple', + llvm_config.make_msabi_triple(config.target_triple)) ) +config.substitutions.append( ('%resource_dir', builtin_include_dir) ) config.substitutions.append( ('%python', config.python_executable) ) # The host triple might not be set, at least if we're compiling clang from # an already installed llvm. if config.host_triple and config.host_triple != '@LLVM_HOST_TRIPLE@': - config.substitutions.append( ('%target_itanium_abi_host_triple', '--target=%s' % makeItaniumABITriple(config.host_triple)) ) + config.substitutions.append( ('%target_itanium_abi_host_triple', + '--target=%s' % llvm_config.make_itanium_abi_triple(config.host_triple)) ) else: config.substitutions.append( ('%target_itanium_abi_host_triple', '') ) @@ -207,50 +169,27 @@ (' %clang-cl ', """*** invalid substitution, use '%clang_cl'. ***""") ) -# For each occurrence of a clang tool name as its own word, replace it -# with the full path to the build directory holding that tool. This -# ensures that we are testing the tools just built and not some random +# For each occurrence of a clang tool name, replace it with the full path to +# the build directory holding that tool. We explicitly specify the directories +# to search to ensure that we get the tools just built and not some random # tools that might happen to be in the user's PATH. -tool_dirs = os.path.pathsep.join((config.clang_tools_dir, config.llvm_tools_dir)) - -# Regex assertions to reject neighbor hyphens/dots (seen in some tests). -# For example, don't match 'clang-check-' or '.clang-format'. -NoPreHyphenDot = r"(? 0: + pre = any_char_in(pre) + regex = '(? 0: + post = any_char_in(post) + regex = '(?!(%s))' % post + name = name + regex + self.regex = name + + def __str__(self): + return self.regex + + def initialize(lit_config, test_config): global llvm_config + llvm_config = config.LLVMConfig(lit_config, test_config) Index: llvm/utils/lit/lit/llvm/config.py =================================================================== --- llvm/utils/lit/lit/llvm/config.py +++ llvm/utils/lit/lit/llvm/config.py @@ -132,22 +132,26 @@ if name in self.config.environment: del self.config.environment[name] + def get_process_output(self, command, encoding='ascii'): + try: + cmd = subprocess.Popen( + command, stdout=subprocess.PIPE, + stderr=subprocess.PIPE, env=self.config.environment) + stdout, stderr = cmd.communicate() + stdout = stdout.decode(encoding) + stderr = stderr.decode(encoding) + return (stdout, stderr) + except OSError: + self.lit_config.fatal("Could not run process %s" % command) + def feature_config(self, features, encoding = 'ascii'): # Ask llvm-config about the specified feature. arguments = [x for (x, _) in features] - try: - config_path = os.path.join(self.config.llvm_tools_dir, 'llvm-config') - - llvm_config_cmd = subprocess.Popen( - [config_path] + arguments, - stdout = subprocess.PIPE, - env=self.config.environment) - except OSError: - self.lit_config.fatal("Could not find llvm-config in " + self.config.llvm_tools_dir) + config_path = os.path.join(self.config.llvm_tools_dir, 'llvm-config') - output, _ = llvm_config_cmd.communicate() - output = output.decode(encoding) + output, _ = self.get_process_output([config_path] + arguments, encoding) lines = output.split('\n') + for (line, (_, patterns)) in zip(lines, features): # We should have either a callable or a dictionary. If it's a # dictionary, grep each key against the output and use the value if @@ -159,3 +163,84 @@ for (match, feature) in patterns.items(): if re.search(line, match): self.config.available_features.add(feature) + + + # Note that when substituting %clang_cc1 also fill in the include directory of + # the builtin headers. Those are part of even a freestanding environment, but + # Clang relies on the driver to locate them. + def get_clang_builtin_include_dir(self, clang): + # FIXME: Rather than just getting the version, we should have clang print + # out its resource dir here in an easy to scrape form. + dir, _ = self.get_process_output([clang, '-print-file-name=include'], encoding='ascii') + + if not dir: + self.lit_config.fatal("Couldn't find the include dir for Clang ('%s')" % clang) + + dir = dir.strip() + if sys.platform in ['win32'] and not self.use_lit_shell: + # Don't pass dosish path separator to msys bash.exe. + dir = dir.replace('\\', '/') + # Ensure the result is an ascii string, across Python2.5+ - Python3. + return dir + + def make_itanium_abi_triple(self, triple): + m = re.match(r'(\w+)-(\w+)-(\w+)', triple) + if not m: + self.lit_config.fatal("Could not turn '%s' into Itanium ABI triple" % triple) + if m.group(3).lower() != 'win32': + # All non-win32 triples use the Itanium ABI. + return triple + return m.group(1) + '-' + m.group(2) + '-mingw32' + + def make_msabi_triple(self, triple): + m = re.match(r'(\w+)-(\w+)-(\w+)', triple) + if not m: + self.lit_config.fatal("Could not turn '%s' into MS ABI triple" % triple) + isa = m.group(1).lower() + vendor = m.group(2).lower() + os = m.group(3).lower() + if os == 'win32': + # If the OS is win32, we're done. + return triple + if isa.startswith('x86') or isa == 'amd64' or re.match(r'i\d86', isa): + # For x86 ISAs, adjust the OS. + return isa + '-' + vendor + '-win32' + # -win32 is not supported for non-x86 targets; use a default. + return 'i686-pc-win32' + + def add_tool_substitutions(self, tools, search_dirs, warn_missing = True): + if isinstance(search_dirs, basestring): + search_dirs = [search_dirs] + search_dirs = os.pathsep.join(search_dirs) + for tool in tools: + # Extract the tool name from the pattern. This relies on the tool + # name being surrounded by \b word match operators. If the + # pattern starts with "| ", include it in the string to be + # substituted. + if isinstance(tool, basestring): + tool = lit.util.make_word_regex(tool) + else: + tool = str(tool) + + tool_match = re.match(r"^(\\)?((\| )?)\W+b([0-9A-Za-z-_]+)\\b\W*$", + tool) + if not tool_match: + continue + + tool_pipe = tool_match.group(2) + tool_name = tool_match.group(4) + tool_path = lit.util.which(tool_name, search_dirs) + if not tool_path: + if warn_missing: + # Warn, but still provide a substitution. + self.lit_config.note('Did not find ' + tool_name + ' in %s' % search_dirs) + tool_path = self.config.llvm_tools_dir + '/' + tool_name + + if tool_name == 'llc' and os.environ.get('LLVM_ENABLE_MACHINE_VERIFIER') == '1': + tool_path += ' -verify-machineinstrs' + if tool_name == 'llvm-go': + exe = getattr(self.config, 'go_executable', None) + if exe: + tool_path += " go=" + exe + + self.config.substitutions.append((tool, tool_pipe + tool_path)) Index: llvm/utils/lit/lit/util.py =================================================================== --- llvm/utils/lit/lit/util.py +++ llvm/utils/lit/lit/util.py @@ -23,6 +23,8 @@ return False raise ValueError('"{}" is not a valid boolean'.format(value)) +def make_word_regex(word): + return r'\b' + word + r'\b' def to_bytes(s): """Return the parameter as type 'bytes', possibly encoding it.