blob: ce4da6cca18917a83e00e62f07ec385e4012b802 [file] [log] [blame]
#!/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())