1#!/usr/bin/env python3 2# -*- coding: utf-8 -*- 3# Copyright 2020 The ChromiumOS Authors 4# Use of this source code is governed by a BSD-style license that can be 5# found in the LICENSE file. 6 7"""Run full bisection test.""" 8 9 10import argparse 11import os 12import sys 13 14from cros_utils import command_executer 15 16 17TEST_DIR = "full_bisect_test" 18DEFAULT_BISECT_DIR = "/tmp/sysroot_bisect" 19 20 21def populate_good_files(top_dir, ce, bisect_dir=DEFAULT_BISECT_DIR): 22 # 'make clean' 23 work_dir = os.path.join(top_dir, TEST_DIR, "work") 24 cmd = "rm -f %s/*.o" % work_dir 25 status = ce.RunCommand(cmd) 26 if status != 0: 27 print("Error trying to clean out work directory: %s" % cmd) 28 return status 29 30 # set up the 'good' source files 31 script = os.path.join(top_dir, TEST_DIR, "make_sources_good.sh") 32 status = ce.RunCommand(script) 33 if status != 0: 34 print('Error setting up "good" source files: %s' % script) 35 return status 36 37 export_bisect = "export BISECT_DIR=%s; " % bisect_dir 38 # build the good source files 39 script_path = os.path.join(top_dir, TEST_DIR) 40 if os.path.exists("/usr/bin/x86_64-cros-linux-gnu-gcc"): 41 build_script = "chromeos_build.sh" 42 else: 43 build_script = "build.sh" 44 cmd = "%s export BISECT_STAGE=POPULATE_GOOD; pushd %s; ./%s; popd" % ( 45 export_bisect, 46 script_path, 47 build_script, 48 ) 49 status = ce.RunCommand(cmd) 50 return status 51 52 53def populate_bad_files(top_dir, ce, bisect_dir=DEFAULT_BISECT_DIR): 54 # 'make clean' 55 work_dir = os.path.join(top_dir, TEST_DIR, "work") 56 cmd = "rm -f %s/*.o" % work_dir 57 status = ce.RunCommand(cmd) 58 if status != 0: 59 print("Error trying to clean out work directory: %s" % cmd) 60 return status 61 62 # set up the 'bad' source files 63 script = os.path.join(top_dir, TEST_DIR, "make_sources_bad.sh") 64 status = ce.RunCommand(script) 65 if status != 0: 66 print('Error setting up "bad" source files: %s' % script) 67 return status 68 69 export_bisect = "export BISECT_DIR=%s; " % bisect_dir 70 # build the bad source files 71 script_path = os.path.join(top_dir, TEST_DIR) 72 if os.path.exists("/usr/bin/x86_64-cros-linux-gnu-gcc"): 73 build_script = "chromeos_build.sh" 74 else: 75 build_script = "build.sh" 76 cmd = "%s export BISECT_STAGE=POPULATE_BAD; pushd %s; ./%s ; popd" % ( 77 export_bisect, 78 script_path, 79 build_script, 80 ) 81 status = ce.RunCommand(cmd) 82 return status 83 84 85def run_main_bisection_test(top_dir, ce): 86 test_script = os.path.join(top_dir, TEST_DIR, "main-bisect-test.sh") 87 status = ce.RunCommand(test_script) 88 return status 89 90 91def verify_compiler_and_wrapper(): 92 # We don't need to do any special setup if running inside a ChromeOS 93 # chroot. 94 if os.path.exists("/usr/bin/x86_64-cros-linux-gnu-gcc"): 95 return True 96 97 message = """ 98*** IMPORTANT --- READ THIS CAREFULLY!! *** 99 100This test uses the command 'gcc' to compile the good/bad versions of the 101source program. BEFORE you can run this script you must make sure that 102your compiler wrapper is in the right place, with the right name, so that 103a call to 'gcc' will go through your compiler wrapper and "do the right 104thing". 105 106Is your compiler wrapper properly set up? [Y/n] 107""" 108 109 print(message) 110 inp = sys.stdin.readline() 111 inp = inp.strip() 112 inp = inp.lower() 113 return not inp or inp == "y" or inp == "yes" 114 115 116def Main(argv): 117 parser = argparse.ArgumentParser() 118 parser.add_argument( 119 "--dir", 120 dest="directory", 121 help="Bisection work tree, where good & bad object " 122 "files go. Default is /tmp/sysroot_bisect", 123 ) 124 125 options = parser.parse_args(argv) 126 127 # Make sure the compiler wrapper & soft links are properly set up. 128 wrapper_is_setup = verify_compiler_and_wrapper() 129 if not wrapper_is_setup: 130 print( 131 "Exiting now. Please re-run after you have set up the compiler " 132 "wrapper." 133 ) 134 return 0 135 136 # Make sure we're in the correct directory for running this test. 137 cwd = os.getcwd() 138 if not os.path.exists(os.path.join(cwd, "full_bisect_test")): 139 print( 140 "Error: Wrong directory. This script must be run from the top level" 141 " of the binary_search_tool tree (under toolchain_utils)." 142 ) 143 return 1 144 145 ce = command_executer.GetCommandExecuter() 146 bisect_dir = options.directory 147 if not bisect_dir: 148 bisect_dir = DEFAULT_BISECT_DIR 149 150 # Make sure BISECT_DIR is clean 151 if os.path.exists(bisect_dir): 152 cmd = "rm -Rf %s/*" % bisect_dir 153 retv = ce.RunCommand(cmd) 154 if retv != 0: 155 return retv 156 157 retv = populate_good_files(cwd, ce, bisect_dir) 158 if retv != 0: 159 return retv 160 161 retv = populate_bad_files(cwd, ce, bisect_dir) 162 if retv != 0: 163 return retv 164 165 # Set up good/bad work soft links 166 cmd = "rm -f %s/%s/good-objects; ln -s %s/good %s/%s/good-objects" % ( 167 cwd, 168 TEST_DIR, 169 bisect_dir, 170 cwd, 171 TEST_DIR, 172 ) 173 174 status = ce.RunCommand(cmd) 175 if status != 0: 176 print("Error executing: %s; exiting now." % cmd) 177 return status 178 179 cmd = "rm -f %s/%s/bad-objects; ln -s %s/bad %s/%s/bad-objects" % ( 180 cwd, 181 TEST_DIR, 182 bisect_dir, 183 cwd, 184 TEST_DIR, 185 ) 186 187 status = ce.RunCommand(cmd) 188 if status != 0: 189 print("Error executing: %s; exiting now." % cmd) 190 return status 191 192 retv = run_main_bisection_test(cwd, ce) 193 return retv 194 195 196if __name__ == "__main__": 197 retval = Main(sys.argv[1:]) 198 sys.exit(retval) 199