| from __future__ import print_function |
| |
| import os |
| import subprocess |
| |
| import subprocess_utils |
| |
| DRY_RUN = False |
| SQUELCH_STDERR = True |
| ECHO_CALLS = False |
| |
| |
| def br_call(args, dry_run=DRY_RUN, echo=ECHO_CALLS): |
| if dry_run or echo: |
| print('BRCALL: ' + ' '.join(args)) |
| if dry_run: |
| return {'exit_code': 0, 'fingerprint': ''} |
| return subprocess_utils.call_fingerprint(args, |
| echo_stderr=not SQUELCH_STDERR) |
| |
| |
| # We use this since our squelching of stderr can hide missing file errors. |
| def sanity_check_file_exists(f): |
| if not os.access(f, os.F_OK): |
| raise RuntimeError('Error! Could not find file: ' + f) |
| |
| |
| class SwiftTools(object): |
| """A utility class that enables users to easily find sil-tools without needing |
| to constantly reform paths to the build directory. Also provides safety by |
| asserting if one of the tools does not exist at the specified path""" |
| |
| def __init__(self, swift_build_dir): |
| self.swift_build_dir = swift_build_dir |
| |
| def _get_tool(self, name): |
| path = os.path.join(self.swift_build_dir, 'bin', name) |
| if not os.access(path, os.F_OK): |
| error_msg = "Error! {} does not exist at: {}".format(name, path) |
| raise RuntimeError(error_msg) |
| return path |
| |
| @property |
| def sil_nm(self): |
| """Return the path to sil-nm in the specified swift build directory. Throws a |
| runtime error if the tool does not exist""" |
| return self._get_tool('sil-nm') |
| |
| @property |
| def swiftc(self): |
| """Return the path to swiftc in the specified swift build directory. Throws a |
| runtime error if the tool does not exist""" |
| return self._get_tool('swiftc') |
| |
| @property |
| def sil_opt(self): |
| """Return the path to sil-opt in the specified swift build directory. Throws a |
| runtime error if the tool does not exist""" |
| return self._get_tool('sil-opt') |
| |
| @property |
| def sil_func_extractor(self): |
| """Return the path to sil-func-extractor in the specified swift build |
| directory. Throws a runtime error if the tool does not exist.""" |
| return self._get_tool('sil-func-extractor') |
| |
| @property |
| def sil_passpipeline_dumper(self): |
| """Return the path to sil-passpipeline-dumper in the specified swift build |
| directory. Throws a runtime error if the tool does not exist |
| |
| """ |
| return self._get_tool('sil-passpipeline-dumper') |
| |
| |
| def maybe_abspath(x): |
| if x is None: |
| return x |
| return os.path.abspath(x) |
| |
| |
| class SILToolInvokerConfig(object): |
| |
| def __init__(self, args): |
| self.module_cache = args.module_cache |
| self.sdk = args.sdk |
| self.target = args.target |
| self.resource_dir = maybe_abspath(args.resource_dir) |
| self.work_dir = maybe_abspath(args.work_dir) |
| self.module_name = args.module_name |
| |
| |
| class SILToolInvoker(object): |
| |
| def __init__(self, config, extra_args=None): |
| self.config = config |
| self.extra_args = extra_args or [] |
| |
| def base_args(self, emit_sib): |
| x = [self.tool] |
| if self.config.sdk is not None: |
| x.append("-sdk=%s" % self.config.sdk) |
| if self.config.target is not None: |
| x.append("-target=%s" % self.config.target) |
| if self.config.resource_dir is not None: |
| x.append("-resource-dir=%s" % self.config.resource_dir) |
| if self.config.module_cache is not None: |
| x.append("-module-cache-path=%s" % self.config.module_cache) |
| if self.config.module_name is not None: |
| x.append("-module-name=%s" % self.config.module_name) |
| if emit_sib: |
| x.append("-emit-sib") |
| return x |
| |
| @property |
| def tool(self): |
| raise RuntimeError('Abstract Method') |
| |
| |
| class SILConstantInputToolInvoker(SILToolInvoker): |
| |
| def __init__(self, config, tools, initial_input_file, extra_args): |
| SILToolInvoker.__init__(self, config, extra_args) |
| self.tools = tools |
| |
| # Start by creating our workdir if necessary |
| subprocess.check_call(["mkdir", "-p", self.config.work_dir]) |
| |
| # Then copy our input file into the work dir |
| base_input_file = os.path.basename(initial_input_file) |
| (base, ext) = os.path.splitext(base_input_file) |
| self.base_input_file_stem = base |
| self.base_input_file_ext = ".sib" |
| |
| # First emit an initial *.sib file. This ensures no matter if we have a |
| # *.swiftmodule, *.sil, or *.sib file, we are always using *.sib. |
| self.input_file = initial_input_file |
| sanity_check_file_exists(initial_input_file) |
| |
| def _invoke(self, *args, **kwargs): |
| raise RuntimeError('Abstract method') |
| |
| def get_suffixed_filename(self, suffix): |
| basename = self.base_input_file_stem + '_' + suffix |
| basename += self.base_input_file_ext |
| return os.path.join(self.config.work_dir, basename) |
| |
| |
| class SILOptInvoker(SILConstantInputToolInvoker): |
| |
| def __init__(self, config, tools, input_file, extra_args): |
| SILConstantInputToolInvoker.__init__(self, config, tools, input_file, |
| extra_args) |
| self.input_file = self.get_suffixed_filename('initial') |
| self._invoke(input_file, [], True, self.input_file) |
| |
| @property |
| def tool(self): |
| return self.tools.sil_opt |
| |
| def _cmdline(self, input_file, passes, emit_sib, output_file='-'): |
| assert(isinstance(emit_sib, bool)) |
| assert(isinstance(output_file, str)) |
| base_args = self.base_args(emit_sib) |
| sanity_check_file_exists(input_file) |
| base_args.extend([input_file, '-o', output_file]) |
| base_args.extend(self.extra_args) |
| base_args.extend(passes) |
| return base_args |
| |
| def _invoke(self, input_file, passes, emit_sib, output_filename): |
| cmdline = self._cmdline(input_file, passes, emit_sib, output_filename) |
| return br_call(cmdline) |
| |
| def invoke_with_passlist(self, passes, output_filename): |
| return self._invoke(self.input_file, passes, True, output_filename) |
| |
| def cmdline_with_passlist(self, passes): |
| return self._cmdline(self.input_file, passes, False) |
| |
| |
| class SILFuncExtractorInvoker(SILConstantInputToolInvoker): |
| |
| def __init__(self, config, tools, input_file): |
| SILConstantInputToolInvoker.__init__(self, config, tools, input_file, |
| []) |
| |
| @property |
| def tool(self): |
| return self.tools.sil_func_extractor |
| |
| def _cmdline(self, input_file, funclist_path, emit_sib, output_file='-', |
| invert=False): |
| assert(isinstance(emit_sib, bool)) |
| assert(isinstance(output_file, str)) |
| |
| sanity_check_file_exists(input_file) |
| sanity_check_file_exists(funclist_path) |
| assert(isinstance(funclist_path, str)) |
| base_args = self.base_args(emit_sib) |
| base_args.extend([input_file, '-o', output_file, |
| '-func-file=%s' % funclist_path]) |
| if invert: |
| base_args.append('-invert') |
| return base_args |
| |
| def _invoke(self, input_file, funclist_path, output_filename, |
| invert=False): |
| assert(isinstance(funclist_path, str)) |
| cmdline = self._cmdline(input_file, |
| funclist_path, |
| True, |
| output_filename, |
| invert) |
| return br_call(cmdline) |
| |
| def invoke_with_functions(self, funclist_path, output_filename, |
| invert=False): |
| assert(isinstance(funclist_path, str)) |
| return self._invoke(self.input_file, funclist_path, output_filename, |
| invert) |
| |
| |
| class SILNMInvoker(SILToolInvoker): |
| |
| def __init__(self, config, tools): |
| self.tools = tools |
| SILToolInvoker.__init__(self, config) |
| |
| @property |
| def tool(self): |
| return self.tools.sil_nm |
| |
| def get_symbols(self, input_file): |
| sanity_check_file_exists(input_file) |
| cmdline = self.base_args(emit_sib=False) |
| cmdline.append(input_file) |
| output = subprocess.check_output(cmdline) |
| for l in output.split("\n")[:-1]: |
| t = tuple(l.split(" ")) |
| assert(len(t) == 2) |
| yield t |