| #!/usr/bin/env python |
| # utils/rth - Resilience test helper |
| # |
| # This source file is part of the Swift.org open source project |
| # |
| # Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors |
| # Licensed under Apache License v2.0 with Runtime Library Exception |
| # |
| # See https://swift.org/LICENSE.txt for license information |
| # See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors |
| |
| from __future__ import print_function |
| |
| import argparse |
| import os |
| import pipes |
| import shlex |
| import shutil |
| import subprocess |
| import sys |
| |
| VERBOSE = True |
| |
| |
| def verbose_print_command(command): |
| if VERBOSE: |
| print(" ".join(pipes.quote(c) for c in command)) |
| sys.stdout.flush() |
| |
| |
| class ResilienceTest(object): |
| |
| def __init__(self, target_build_swift, target_run, target_codesign, |
| tmp_dir, test_dir, test_src, lib_prefix, lib_suffix, |
| additional_compile_flags_library, |
| no_backward_deployment): |
| self.target_build_swift = shlex.split(target_build_swift) |
| self.target_run = shlex.split(target_run) |
| self.target_codesign = shlex.split(target_codesign) |
| self.tmp_dir = tmp_dir |
| self.test_dir = test_dir |
| self.test_src = test_src |
| self.lib_prefix = lib_prefix |
| self.lib_suffix = lib_suffix |
| self.additional_compile_flags_library = \ |
| shlex.split(additional_compile_flags_library) |
| |
| self.before_dir = os.path.join(self.tmp_dir, 'before') |
| self.after_dir = os.path.join(self.tmp_dir, 'after') |
| self.config_dir_map = {'BEFORE': self.before_dir, |
| 'AFTER': self.after_dir} |
| |
| self.lib_src_name = os.path.basename(self.test_src)[5:] |
| self.lib_name = self.lib_src_name[:-6] |
| self.lib_src = os.path.join(self.test_dir, 'Inputs', self.lib_src_name) |
| |
| self.no_backward_deployment = no_backward_deployment |
| |
| def run(self): |
| self.set_up() |
| self.compile_library() |
| self.compile_main() |
| self.link() |
| self.execute() |
| return 0 |
| |
| def set_up(self): |
| shutil.rmtree(self.tmp_dir, ignore_errors=True) |
| os.makedirs(self.after_dir) |
| os.makedirs(self.before_dir) |
| |
| def is_apple_platform(self): |
| return any('-apple-' in arg for arg in self.target_build_swift) |
| |
| def compile_library(self): |
| for config in self.config_dir_map: |
| lib_file = self.lib_prefix + self.lib_name + self.lib_suffix |
| output_dylib = os.path.join(self.config_dir_map[config], |
| lib_file) |
| compiler_flags = ['-emit-library', '-emit-module', |
| '-swift-version', '4', |
| '-Xfrontend', '-enable-resilience', |
| '-Xfrontend', '-enable-class-resilience', |
| '-D', config, |
| self.lib_src, |
| '-o', output_dylib] |
| if self.is_apple_platform(): |
| compiler_flags += ['-Xlinker', |
| '-install_name', |
| '-Xlinker', |
| os.path.join('@rpath', lib_file)] |
| |
| command = self.target_build_swift + \ |
| self.additional_compile_flags_library + compiler_flags |
| verbose_print_command(command) |
| returncode = subprocess.call(command) |
| assert returncode == 0, str(command) |
| |
| codesign_cmd = self.target_codesign + [output_dylib] |
| verbose_print_command(codesign_cmd) |
| returncode = subprocess.call(codesign_cmd) |
| assert returncode == 0, str(codesign_cmd) |
| |
| def compile_main(self): |
| for config in self.config_dir_map: |
| output_obj = os.path.join(self.config_dir_map[config], 'main.o') |
| compiler_flags = ['-D', config, '-c', self.test_src, |
| '-Xfrontend', '-enable-class-resilience', |
| '-I', self.config_dir_map[config], |
| '-o', output_obj] |
| command = self.target_build_swift + compiler_flags |
| verbose_print_command(command) |
| returncode = subprocess.call(command) |
| assert returncode == 0, str(command) |
| |
| def configs(self): |
| for config1 in self.config_dir_map: |
| for config2 in self.config_dir_map: |
| # --no-backward-deployment skips testing a new application |
| # linked against an old library. |
| if config1 == "BEFORE" and \ |
| config2 == "AFTER" and \ |
| self.no_backward_deployment: |
| continue |
| |
| yield (config1, config2) |
| |
| def link(self): |
| for config1, config2 in self.configs(): |
| config1_lower = config1.lower() |
| config2_lower = config2.lower() |
| output_obj = os.path.join(self.tmp_dir, |
| config1_lower + '_' + config2_lower) |
| if self.is_apple_platform(): |
| rpath_origin = '@executable_path' |
| else: |
| rpath_origin = '$ORIGIN' |
| |
| compiler_flags = [ |
| '-L', self.config_dir_map[config2], |
| '-l' + self.lib_name, |
| os.path.join(self.config_dir_map[config2], |
| 'main.o'), |
| '-Xlinker', '-rpath', '-Xlinker', |
| os.path.join(rpath_origin, |
| os.path.relpath(self.config_dir_map[config1], |
| self.tmp_dir)), |
| '-o', output_obj |
| ] |
| |
| command = self.target_build_swift + compiler_flags |
| verbose_print_command(command) |
| returncode = subprocess.call(command) |
| assert returncode == 0, str(command) |
| |
| def execute(self): |
| for config1, config2 in self.configs(): |
| config1_lower = config1.lower() |
| config2_lower = config2.lower() |
| output_obj = os.path.join(self.tmp_dir, |
| config1_lower + '_' + config2_lower) |
| command = self.target_run + [output_obj, self.tmp_dir] |
| verbose_print_command(command) |
| returncode = subprocess.call(command) |
| assert returncode == 0, str(command) |
| |
| |
| def main(): |
| parser = argparse.ArgumentParser(description='Resilience test helper') |
| parser.add_argument('--target-build-swift', required=True) |
| parser.add_argument('--target-run', required=True) |
| parser.add_argument('--target-codesign', default='echo') |
| parser.add_argument('--t', required=True) |
| parser.add_argument('--S', required=True) |
| parser.add_argument('--s', required=True) |
| parser.add_argument('--lib-prefix', required=True) |
| parser.add_argument('--lib-suffix', required=True) |
| parser.add_argument('--additional-compile-flags-library', default='') |
| parser.add_argument('--no-backward-deployment', default=False, |
| action='store_true') |
| |
| args = parser.parse_args() |
| |
| resilience_test = ResilienceTest(args.target_build_swift, args.target_run, |
| args.target_codesign, |
| args.t, args.S, args.s, args.lib_prefix, |
| args.lib_suffix, |
| args.additional_compile_flags_library, |
| args.no_backward_deployment) |
| |
| return resilience_test.run() |
| |
| |
| if __name__ == '__main__': |
| exit(main()) |