| OLD | NEW |
| (Empty) | |
| 1 #!/usr/bin/env python |
| 2 # |
| 3 # Copyright 2017 The Chromium Authors. All rights reserved. |
| 4 # Use of this source code is governed by a BSD-style license that can be |
| 5 # found in the LICENSE file. |
| 6 |
| 7 """Packages a user.bootfs for a Fuchsia QEMU image, pulling in the runtime |
| 8 dependencies of a test binary, and then uses QEMU from the Fuchsia SDK to run |
| 9 it.""" |
| 10 |
| 11 import argparse |
| 12 import os |
| 13 import subprocess |
| 14 import sys |
| 15 import tempfile |
| 16 |
| 17 |
| 18 DIR_SOURCE_ROOT = os.path.abspath( |
| 19 os.path.join(os.path.dirname(__file__), os.pardir, os.pardir)) |
| 20 SDK_ROOT = os.path.join(DIR_SOURCE_ROOT, 'third_party', 'fuchsia-sdk') |
| 21 |
| 22 |
| 23 def MakeTargetImageName(common_prefix, output_directory, location): |
| 24 assert output_directory.startswith(common_prefix) |
| 25 output_dir_no_common_prefix = output_directory[len(common_prefix):] |
| 26 assert location.startswith(common_prefix) |
| 27 loc = location[len(common_prefix):] |
| 28 if loc.startswith(output_dir_no_common_prefix): |
| 29 loc = loc[len(output_dir_no_common_prefix)+1:] |
| 30 return loc |
| 31 |
| 32 |
| 33 def AddToManifest(manifest_file, target_name, source, mapper): |
| 34 if os.path.isdir(source): |
| 35 files = [os.path.join(dp, f) for dp, dn, fn in os.walk(source) for f in fn] |
| 36 for f in files: |
| 37 # We pass None as the mapper because this should never recurse a 2nd time. |
| 38 AddToManifest(manifest_file, mapper(f), f, None) |
| 39 elif os.path.exists(source): |
| 40 manifest_file.write('%s=%s\n' % (target_name, source)) |
| 41 else: |
| 42 raise Exception('%s does not exist' % source) |
| 43 |
| 44 |
| 45 def BuildBootfs(output_directory, runtime_deps_path, test_name, gtest_filter): |
| 46 with open(runtime_deps_path) as f: |
| 47 lines = f.readlines() |
| 48 |
| 49 locations_to_add = [os.path.abspath(os.path.join(output_directory, x.strip())) |
| 50 for x in lines] |
| 51 # TODO(scottmg): This is a hokey way to get the test binary. We need to ask |
| 52 # gn (or something) for the binary in addition to the runtime deps. |
| 53 locations_to_add.append( |
| 54 os.path.abspath(os.path.join(output_directory, test_name))) |
| 55 |
| 56 common_prefix = os.path.commonprefix(locations_to_add) |
| 57 target_source_pairs = zip( |
| 58 [MakeTargetImageName(common_prefix, output_directory, loc) |
| 59 for loc in locations_to_add], |
| 60 locations_to_add) |
| 61 |
| 62 # Add extra .so's that are required for running to system/lib |
| 63 sysroot_libs = [ |
| 64 'libc++abi.so.1', |
| 65 'libc++.so.2', |
| 66 'libunwind.so.1', |
| 67 ] |
| 68 sysroot_lib_path = os.path.join(SDK_ROOT, 'sysroot', 'x86_64-fuchsia', 'lib') |
| 69 for lib in sysroot_libs: |
| 70 target_source_pairs.append( |
| 71 ('lib/' + lib, os.path.join(sysroot_lib_path, lib))) |
| 72 |
| 73 # Generate a little script that runs the test binaries and then shuts down |
| 74 # QEMU. |
| 75 autorun_file = tempfile.NamedTemporaryFile() |
| 76 autorun_file.write('#!/bin/sh\n') |
| 77 autorun_file.write('echo \'Starting test run...\'\n') |
| 78 assert os.path.basename(test_name) == 'base_unittests' |
| 79 autorun_file.write('/system/base_unittests') |
| 80 if gtest_filter: |
| 81 autorun_file.write(' --gtest_filter=' + gtest_filter) |
| 82 autorun_file.write('\n') |
| 83 autorun_file.write('dm poweroff\n') |
| 84 autorun_file.flush() |
| 85 os.chmod(autorun_file.name, 0750) |
| 86 target_source_pairs.append(('autorun', autorun_file.name)) |
| 87 |
| 88 # Generate an initial.config for application_manager that tells it to run |
| 89 # our autorun script with sh. |
| 90 initial_config_file = tempfile.NamedTemporaryFile() |
| 91 initial_config_file.write('''{ |
| 92 "initial-apps": [ |
| 93 [ "file:///boot/bin/sh", "/system/autorun" ] |
| 94 ] |
| 95 } |
| 96 ''') |
| 97 initial_config_file.flush() |
| 98 target_source_pairs.append(('data/application_manager/initial.config', |
| 99 initial_config_file.name)) |
| 100 |
| 101 manifest_file = tempfile.NamedTemporaryFile() |
| 102 bootfs_name = runtime_deps_path + '.bootfs' |
| 103 |
| 104 manifest_file.file.write('%s:\n' % bootfs_name) |
| 105 for target, source in target_source_pairs: |
| 106 AddToManifest(manifest_file.file, target, source, |
| 107 lambda x: MakeTargetImageName( |
| 108 common_prefix, output_directory, x)) |
| 109 |
| 110 mkbootfs_path = os.path.join(SDK_ROOT, 'tools', 'mkbootfs') |
| 111 |
| 112 manifest_file.flush() |
| 113 subprocess.check_call( |
| 114 [mkbootfs_path, '-o', bootfs_name, |
| 115 '--target=boot', os.path.join(SDK_ROOT, 'bootdata.bin'), |
| 116 '--target=system', manifest_file.name, |
| 117 ]) |
| 118 print 'Wrote bootfs to', bootfs_name |
| 119 return bootfs_name |
| 120 |
| 121 |
| 122 def main(): |
| 123 parser = argparse.ArgumentParser() |
| 124 parser.add_argument('--output-directory', |
| 125 type=os.path.realpath, |
| 126 help=('Path to the directory in which build files are' |
| 127 ' located (must include build type).')) |
| 128 parser.add_argument('--runtime-deps-path', |
| 129 type=os.path.realpath, |
| 130 help='Runtime data dependency file from GN.') |
| 131 parser.add_argument('--test-name', |
| 132 type=os.path.realpath, |
| 133 help='Name of the the test') |
| 134 parser.add_argument('--gtest_filter', |
| 135 help='GTest filter to use in place of any default') |
| 136 args = parser.parse_args() |
| 137 |
| 138 bootfs = BuildBootfs(args.output_directory, args.runtime_deps_path, |
| 139 args.test_name, args.gtest_filter) |
| 140 |
| 141 qemu_path = os.path.join(SDK_ROOT, 'qemu', 'bin', 'qemu-system-x86_64') |
| 142 |
| 143 qemu_popen = subprocess.Popen( |
| 144 [qemu_path, '-m', '2048', '-nographic', '-net', 'none', '-smp', '4', |
| 145 '-machine', 'q35', '-kernel', |
| 146 os.path.join(SDK_ROOT, 'kernel', 'magenta.bin'), |
| 147 '-cpu', 'Haswell,+smap,-check', '-initrd', bootfs, |
| 148 '-append', 'TERM=xterm-256color'], |
| 149 stdout=subprocess.PIPE) |
| 150 output = subprocess.Popen(['/work/fuchsia/magenta/scripts/symbolize', |
| 151 os.path.basename(args.test_name), |
| 152 '--build-dir=' + os.path.join(SDK_ROOT, 'kernel', 'debug'), |
| 153 '--build-dir=' + args.output_directory], stdin=qemu_popen.stdout) |
| 154 qemu_popen.wait() |
| 155 output.wait() |
| 156 |
| 157 return 0 |
| 158 |
| 159 |
| 160 if __name__ == '__main__': |
| 161 sys.exit(main()) |
| OLD | NEW |