| import os |
| import re |
| |
| import lit.util |
| |
| expr = re.compile(r"^(\\)?((\| )?)\W+b(\S+)\\b\W*$") |
| wordifier = re.compile(r"(\W*)(\b[^\b]+\b)") |
| |
| |
| class FindTool(object): |
| def __init__(self, name): |
| self.name = name |
| |
| def resolve(self, config, dirs): |
| # Check for a user explicitely overriding a tool. This allows: |
| # llvm-lit -D llc="llc -enable-misched -verify-machineinstrs" |
| command = config.lit_config.params.get(self.name) |
| if command is None: |
| # Then check out search paths. |
| command = lit.util.which(self.name, dirs) |
| if not command: |
| return None |
| |
| if self.name == 'llc' and os.environ.get('LLVM_ENABLE_MACHINE_VERIFIER') == '1': |
| command += ' -verify-machineinstrs' |
| elif self.name == 'llvm-go': |
| exe = getattr(config.config, 'go_executable', None) |
| if exe: |
| command += ' go=' + exe |
| return command |
| |
| |
| class ToolSubst(object): |
| """String-like class used to build regex substitution patterns for llvm |
| tools. |
| |
| Handles things like adding word-boundary patterns, and filtering |
| characters from the beginning an end of a tool name |
| |
| """ |
| |
| def __init__(self, key, command=None, pre=r'.-^/\<', post='-.', verbatim=False, |
| unresolved='warn', extra_args=None): |
| """Construct a ToolSubst. |
| |
| key: The text which is to be substituted. |
| |
| command: The command to substitute when the key is matched. By default, |
| this will treat `key` as a tool name and search for it. If it is |
| a string, it is intereprted as an exact path. If it is an instance of |
| FindTool, the specified tool name is searched for on disk. |
| |
| pre: If specified, the substitution will not find matches where |
| the character immediately preceding the word-boundary that begins |
| `key` is any of the characters in the string `pre`. |
| |
| post: If specified, the substitution will not find matches where |
| the character immediately after the word-boundary that ends `key` |
| is any of the characters specified in the string `post`. |
| |
| verbatim: If True, `key` is an exact regex that is passed to the |
| underlying substitution |
| |
| unresolved: Action to take if the tool substitution cannot be |
| resolved. Valid values: |
| 'warn' - log a warning but add the substitution anyway. |
| 'fatal' - Exit the test suite and log a fatal error. |
| 'break' - Don't add any of the substitutions from the current |
| group, and return a value indicating a failure. |
| 'ignore' - Don't add the substitution, and don't log an error |
| |
| extra_args: If specified, represents a list of arguments that will be |
| appended to the tool's substitution. |
| |
| explicit_path: If specified, the exact path will be used as a substitution. |
| Otherwise, the tool will be searched for as if by calling which(tool) |
| |
| """ |
| self.unresolved = unresolved |
| self.extra_args = extra_args |
| self.key = key |
| self.command = command if command is not None else FindTool(key) |
| self.was_resolved = False |
| if verbatim: |
| self.regex = key |
| return |
| |
| def not_in(chars, where=''): |
| if not chars: |
| return '' |
| pattern_str = '|'.join(re.escape(x) for x in chars) |
| return r'(?{}!({}))'.format(where, pattern_str) |
| |
| def wordify(word): |
| match = wordifier.match(word) |
| introducer = match.group(1) |
| word = match.group(2) |
| return introducer + r'\b' + word + r'\b' |
| |
| self.regex = not_in(pre, '<') + wordify(key) + not_in(post) |
| |
| def resolve(self, config, search_dirs): |
| # 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. |
| |
| tool_match = expr.match(self.regex) |
| if not tool_match: |
| return None |
| |
| tool_pipe = tool_match.group(2) |
| tool_name = tool_match.group(4) |
| |
| if isinstance(self.command, FindTool): |
| command_str = self.command.resolve(config, search_dirs) |
| else: |
| command_str = str(self.command) |
| |
| if command_str: |
| if self.extra_args: |
| command_str = ' '.join([command_str] + self.extra_args) |
| else: |
| if self.unresolved == 'warn': |
| # Warn, but still provide a substitution. |
| config.lit_config.note( |
| 'Did not find ' + tool_name + ' in %s' % search_dirs) |
| command_str = os.path.join( |
| config.config.llvm_tools_dir, tool_name) |
| elif self.unresolved == 'fatal': |
| # The function won't even return in this case, this leads to |
| # sys.exit |
| config.lit_config.fatal( |
| 'Did not find ' + tool_name + ' in %s' % search_dirs) |
| elif self.unresolved == 'break': |
| # By returning a valid result with an empty command, the |
| # caller treats this as a failure. |
| pass |
| elif self.unresolved == 'ignore': |
| # By returning None, the caller just assumes there was no |
| # match in the first place. |
| return None |
| else: |
| raise 'Unexpected value for ToolSubst.unresolved' |
| if command_str: |
| self.was_resolved = True |
| return (self.regex, tool_pipe, command_str) |