1*bb4ee6a4SAndroid Build Coastguard Worker#!/usr/bin/env python3 2*bb4ee6a4SAndroid Build Coastguard Worker# Copyright 2023 The ChromiumOS Authors 3*bb4ee6a4SAndroid Build Coastguard Worker# Use of this source code is governed by a BSD-style license that can be 4*bb4ee6a4SAndroid Build Coastguard Worker# found in the LICENSE file. 5*bb4ee6a4SAndroid Build Coastguard Worker 6*bb4ee6a4SAndroid Build Coastguard Workerimport argparse 7*bb4ee6a4SAndroid Build Coastguard Workerimport json 8*bb4ee6a4SAndroid Build Coastguard Workerimport os 9*bb4ee6a4SAndroid Build Coastguard Workerimport subprocess 10*bb4ee6a4SAndroid Build Coastguard Workerimport sys 11*bb4ee6a4SAndroid Build Coastguard Workerfrom itertools import chain, product, starmap 12*bb4ee6a4SAndroid Build Coastguard Workerfrom pathlib import Path 13*bb4ee6a4SAndroid Build Coastguard Workerfrom typing import Dict, Iterable, List, NamedTuple 14*bb4ee6a4SAndroid Build Coastguard Worker 15*bb4ee6a4SAndroid Build Coastguard Workerfrom impl.common import CROSVM_ROOT, Triple, verbose 16*bb4ee6a4SAndroid Build Coastguard Workerfrom impl.test_config import DO_NOT_BUILD_RISCV64 17*bb4ee6a4SAndroid Build Coastguard Worker 18*bb4ee6a4SAndroid Build Coastguard WorkerUSAGE = """\ 19*bb4ee6a4SAndroid Build Coastguard WorkerBuild crosvm with release (optimized) profile. 20*bb4ee6a4SAndroid Build Coastguard Worker 21*bb4ee6a4SAndroid Build Coastguard WorkerTo target local machine: 22*bb4ee6a4SAndroid Build Coastguard Worker 23*bb4ee6a4SAndroid Build Coastguard Worker $ ./tools/build_release 24*bb4ee6a4SAndroid Build Coastguard Worker 25*bb4ee6a4SAndroid Build Coastguard WorkerTo cross-compile for aarch64, armhf or windows you can use: 26*bb4ee6a4SAndroid Build Coastguard Worker 27*bb4ee6a4SAndroid Build Coastguard Worker $ ./tools/build_release --platform=aarch64 28*bb4ee6a4SAndroid Build Coastguard Worker $ ./tools/build_release --platform=armhf 29*bb4ee6a4SAndroid Build Coastguard Worker $ ./tools/build_release --platform=mingw64 30*bb4ee6a4SAndroid Build Coastguard Worker""" 31*bb4ee6a4SAndroid Build Coastguard Worker 32*bb4ee6a4SAndroid Build Coastguard Worker# We only need PGO for main binary, but for consistency, only exclude incompatible parts from PGO 33*bb4ee6a4SAndroid Build Coastguard WorkerPGO_EXCLUDE = ["crosvm_control"] 34*bb4ee6a4SAndroid Build Coastguard Worker 35*bb4ee6a4SAndroid Build Coastguard Worker 36*bb4ee6a4SAndroid Build Coastguard Workerclass Executable(NamedTuple): 37*bb4ee6a4SAndroid Build Coastguard Worker """Container for info about an executable generated by cargo build/test.""" 38*bb4ee6a4SAndroid Build Coastguard Worker 39*bb4ee6a4SAndroid Build Coastguard Worker binary_path: Path 40*bb4ee6a4SAndroid Build Coastguard Worker crate_name: str 41*bb4ee6a4SAndroid Build Coastguard Worker cargo_target: str 42*bb4ee6a4SAndroid Build Coastguard Worker kind: str 43*bb4ee6a4SAndroid Build Coastguard Worker is_test: bool 44*bb4ee6a4SAndroid Build Coastguard Worker is_fresh: bool 45*bb4ee6a4SAndroid Build Coastguard Worker 46*bb4ee6a4SAndroid Build Coastguard Worker @property 47*bb4ee6a4SAndroid Build Coastguard Worker def name(self): 48*bb4ee6a4SAndroid Build Coastguard Worker return f"{self.crate_name}:{self.cargo_target}" 49*bb4ee6a4SAndroid Build Coastguard Worker 50*bb4ee6a4SAndroid Build Coastguard Worker 51*bb4ee6a4SAndroid Build Coastguard Workerdef cargo( 52*bb4ee6a4SAndroid Build Coastguard Worker cargo_command: str, 53*bb4ee6a4SAndroid Build Coastguard Worker cwd: Path, 54*bb4ee6a4SAndroid Build Coastguard Worker flags: List[str], 55*bb4ee6a4SAndroid Build Coastguard Worker env: Dict[str, str], 56*bb4ee6a4SAndroid Build Coastguard Worker) -> Iterable[Executable]: 57*bb4ee6a4SAndroid Build Coastguard Worker """ 58*bb4ee6a4SAndroid Build Coastguard Worker Executes a cargo command and returns the list of test binaries generated. 59*bb4ee6a4SAndroid Build Coastguard Worker 60*bb4ee6a4SAndroid Build Coastguard Worker The build log will be hidden by default and only printed if the build 61*bb4ee6a4SAndroid Build Coastguard Worker fails. In VERBOSE mode the output will be streamed directly. 62*bb4ee6a4SAndroid Build Coastguard Worker 63*bb4ee6a4SAndroid Build Coastguard Worker Note: Exits the program if the build fails. 64*bb4ee6a4SAndroid Build Coastguard Worker """ 65*bb4ee6a4SAndroid Build Coastguard Worker message_format = "json-diagnostic-rendered-ansi" if sys.stdout.isatty() else "json" 66*bb4ee6a4SAndroid Build Coastguard Worker cmd = [ 67*bb4ee6a4SAndroid Build Coastguard Worker "cargo", 68*bb4ee6a4SAndroid Build Coastguard Worker cargo_command, 69*bb4ee6a4SAndroid Build Coastguard Worker f"--message-format={message_format}", 70*bb4ee6a4SAndroid Build Coastguard Worker *flags, 71*bb4ee6a4SAndroid Build Coastguard Worker ] 72*bb4ee6a4SAndroid Build Coastguard Worker if verbose(): 73*bb4ee6a4SAndroid Build Coastguard Worker print("$", " ".join(cmd)) 74*bb4ee6a4SAndroid Build Coastguard Worker process = subprocess.Popen( 75*bb4ee6a4SAndroid Build Coastguard Worker cmd, 76*bb4ee6a4SAndroid Build Coastguard Worker cwd=cwd, 77*bb4ee6a4SAndroid Build Coastguard Worker stdout=subprocess.PIPE, 78*bb4ee6a4SAndroid Build Coastguard Worker stderr=subprocess.STDOUT, 79*bb4ee6a4SAndroid Build Coastguard Worker text=True, 80*bb4ee6a4SAndroid Build Coastguard Worker env=env, 81*bb4ee6a4SAndroid Build Coastguard Worker ) 82*bb4ee6a4SAndroid Build Coastguard Worker 83*bb4ee6a4SAndroid Build Coastguard Worker messages: List[str] = [] 84*bb4ee6a4SAndroid Build Coastguard Worker 85*bb4ee6a4SAndroid Build Coastguard Worker # Read messages as cargo is running. 86*bb4ee6a4SAndroid Build Coastguard Worker assert process.stdout 87*bb4ee6a4SAndroid Build Coastguard Worker for line in iter(process.stdout.readline, ""): 88*bb4ee6a4SAndroid Build Coastguard Worker # any non-json line is a message to print 89*bb4ee6a4SAndroid Build Coastguard Worker if not line.startswith("{"): 90*bb4ee6a4SAndroid Build Coastguard Worker if verbose(): 91*bb4ee6a4SAndroid Build Coastguard Worker print(line.rstrip()) 92*bb4ee6a4SAndroid Build Coastguard Worker messages.append(line.rstrip()) 93*bb4ee6a4SAndroid Build Coastguard Worker continue 94*bb4ee6a4SAndroid Build Coastguard Worker json_line = json.loads(line) 95*bb4ee6a4SAndroid Build Coastguard Worker 96*bb4ee6a4SAndroid Build Coastguard Worker # 'message' type lines will be printed 97*bb4ee6a4SAndroid Build Coastguard Worker if json_line.get("message"): 98*bb4ee6a4SAndroid Build Coastguard Worker message = json_line.get("message").get("rendered") 99*bb4ee6a4SAndroid Build Coastguard Worker if verbose(): 100*bb4ee6a4SAndroid Build Coastguard Worker print(message) 101*bb4ee6a4SAndroid Build Coastguard Worker messages.append(message) 102*bb4ee6a4SAndroid Build Coastguard Worker 103*bb4ee6a4SAndroid Build Coastguard Worker # Collect info about test executables produced 104*bb4ee6a4SAndroid Build Coastguard Worker elif json_line.get("executable"): 105*bb4ee6a4SAndroid Build Coastguard Worker yield Executable( 106*bb4ee6a4SAndroid Build Coastguard Worker Path(json_line.get("executable")), 107*bb4ee6a4SAndroid Build Coastguard Worker crate_name=json_line.get("package_id", "").split(" ")[0], 108*bb4ee6a4SAndroid Build Coastguard Worker cargo_target=json_line.get("target").get("name"), 109*bb4ee6a4SAndroid Build Coastguard Worker kind=json_line.get("target").get("kind")[0], 110*bb4ee6a4SAndroid Build Coastguard Worker is_test=json_line.get("profile", {}).get("test", False), 111*bb4ee6a4SAndroid Build Coastguard Worker is_fresh=json_line.get("fresh", False), 112*bb4ee6a4SAndroid Build Coastguard Worker ) 113*bb4ee6a4SAndroid Build Coastguard Worker 114*bb4ee6a4SAndroid Build Coastguard Worker if process.wait() != 0: 115*bb4ee6a4SAndroid Build Coastguard Worker if not verbose(): 116*bb4ee6a4SAndroid Build Coastguard Worker for message in messages: 117*bb4ee6a4SAndroid Build Coastguard Worker print(message) 118*bb4ee6a4SAndroid Build Coastguard Worker sys.exit(-1) 119*bb4ee6a4SAndroid Build Coastguard Worker 120*bb4ee6a4SAndroid Build Coastguard Worker 121*bb4ee6a4SAndroid Build Coastguard Workerdef main(): 122*bb4ee6a4SAndroid Build Coastguard Worker parser = argparse.ArgumentParser(usage=USAGE) 123*bb4ee6a4SAndroid Build Coastguard Worker parser.add_argument( 124*bb4ee6a4SAndroid Build Coastguard Worker "--build-target", 125*bb4ee6a4SAndroid Build Coastguard Worker "--platform", 126*bb4ee6a4SAndroid Build Coastguard Worker "-p", 127*bb4ee6a4SAndroid Build Coastguard Worker help=( 128*bb4ee6a4SAndroid Build Coastguard Worker "Override the cargo triple to build. Shorthands are available: (x86_64, armhf, " 129*bb4ee6a4SAndroid Build Coastguard Worker + "aarch64, mingw64, msvc64)." 130*bb4ee6a4SAndroid Build Coastguard Worker ), 131*bb4ee6a4SAndroid Build Coastguard Worker ) 132*bb4ee6a4SAndroid Build Coastguard Worker parser.add_argument( 133*bb4ee6a4SAndroid Build Coastguard Worker "--json", 134*bb4ee6a4SAndroid Build Coastguard Worker action="store_true", 135*bb4ee6a4SAndroid Build Coastguard Worker help="Output in JSON instead of human readable format.", 136*bb4ee6a4SAndroid Build Coastguard Worker ) 137*bb4ee6a4SAndroid Build Coastguard Worker parser.add_argument("--strip", action="store_true", help="Strip output binaries") 138*bb4ee6a4SAndroid Build Coastguard Worker parser.add_argument( 139*bb4ee6a4SAndroid Build Coastguard Worker "--build-profile", help="Select compile profile, default to release.", default="release" 140*bb4ee6a4SAndroid Build Coastguard Worker ) 141*bb4ee6a4SAndroid Build Coastguard Worker pgo_group = parser.add_mutually_exclusive_group() 142*bb4ee6a4SAndroid Build Coastguard Worker pgo_group.add_argument( 143*bb4ee6a4SAndroid Build Coastguard Worker "--profile-generate", 144*bb4ee6a4SAndroid Build Coastguard Worker help="Target directory to generate profile when running, must use absolute path", 145*bb4ee6a4SAndroid Build Coastguard Worker ) 146*bb4ee6a4SAndroid Build Coastguard Worker pgo_group.add_argument( 147*bb4ee6a4SAndroid Build Coastguard Worker "--profile-use", help="Profile file used for PGO, must use absolute path" 148*bb4ee6a4SAndroid Build Coastguard Worker ) 149*bb4ee6a4SAndroid Build Coastguard Worker parser.add_argument("cargo_arguments", nargs="*", help="Extra arguments pass to cargo") 150*bb4ee6a4SAndroid Build Coastguard Worker 151*bb4ee6a4SAndroid Build Coastguard Worker args = parser.parse_args() 152*bb4ee6a4SAndroid Build Coastguard Worker 153*bb4ee6a4SAndroid Build Coastguard Worker if args.profile_generate and ( 154*bb4ee6a4SAndroid Build Coastguard Worker not os.path.isabs(args.profile_generate) or not os.path.isdir(args.profile_generate) 155*bb4ee6a4SAndroid Build Coastguard Worker ): 156*bb4ee6a4SAndroid Build Coastguard Worker raise ValueError("--profile-generate argument is not an absolute path to a folder") 157*bb4ee6a4SAndroid Build Coastguard Worker if args.profile_use and ( 158*bb4ee6a4SAndroid Build Coastguard Worker not os.path.isabs(args.profile_use) or not os.path.isfile(args.profile_use) 159*bb4ee6a4SAndroid Build Coastguard Worker ): 160*bb4ee6a4SAndroid Build Coastguard Worker raise ValueError("--profile-use argument is not an absolute path to a file") 161*bb4ee6a4SAndroid Build Coastguard Worker 162*bb4ee6a4SAndroid Build Coastguard Worker build_target = Triple.from_shorthand(args.build_target) if args.build_target else None 163*bb4ee6a4SAndroid Build Coastguard Worker build_target = build_target or Triple.host_default() 164*bb4ee6a4SAndroid Build Coastguard Worker 165*bb4ee6a4SAndroid Build Coastguard Worker exclude_args = [ 166*bb4ee6a4SAndroid Build Coastguard Worker f"--exclude={x}" for x in PGO_EXCLUDE if args.profile_generate or args.profile_use 167*bb4ee6a4SAndroid Build Coastguard Worker ] 168*bb4ee6a4SAndroid Build Coastguard Worker if build_target == Triple.from_shorthand("riscv64"): 169*bb4ee6a4SAndroid Build Coastguard Worker exclude_args += ["--exclude=" + s for s in DO_NOT_BUILD_RISCV64] 170*bb4ee6a4SAndroid Build Coastguard Worker 171*bb4ee6a4SAndroid Build Coastguard Worker features = build_target.feature_flag 172*bb4ee6a4SAndroid Build Coastguard Worker cargo_args = [ 173*bb4ee6a4SAndroid Build Coastguard Worker "--profile", 174*bb4ee6a4SAndroid Build Coastguard Worker args.build_profile, 175*bb4ee6a4SAndroid Build Coastguard Worker "--features=" + features, 176*bb4ee6a4SAndroid Build Coastguard Worker f"--target={build_target}", 177*bb4ee6a4SAndroid Build Coastguard Worker "--workspace", 178*bb4ee6a4SAndroid Build Coastguard Worker *exclude_args, 179*bb4ee6a4SAndroid Build Coastguard Worker *args.cargo_arguments, 180*bb4ee6a4SAndroid Build Coastguard Worker ] 181*bb4ee6a4SAndroid Build Coastguard Worker 182*bb4ee6a4SAndroid Build Coastguard Worker build_env = os.environ.copy() 183*bb4ee6a4SAndroid Build Coastguard Worker build_env.update(build_target.get_cargo_env()) 184*bb4ee6a4SAndroid Build Coastguard Worker build_env.setdefault("RUSTFLAGS", "") 185*bb4ee6a4SAndroid Build Coastguard Worker build_env["RUSTFLAGS"] += " -D warnings" 186*bb4ee6a4SAndroid Build Coastguard Worker if args.strip: 187*bb4ee6a4SAndroid Build Coastguard Worker build_env["RUSTFLAGS"] += " -C strip=symbols" 188*bb4ee6a4SAndroid Build Coastguard Worker if args.profile_generate: 189*bb4ee6a4SAndroid Build Coastguard Worker build_env["RUSTFLAGS"] += " -C profile-generate=" + args.profile_generate 190*bb4ee6a4SAndroid Build Coastguard Worker if args.profile_use: 191*bb4ee6a4SAndroid Build Coastguard Worker build_env["RUSTFLAGS"] += " -C profile-use=" + args.profile_use 192*bb4ee6a4SAndroid Build Coastguard Worker 193*bb4ee6a4SAndroid Build Coastguard Worker executables = list(cargo("build", CROSVM_ROOT, cargo_args, build_env)) 194*bb4ee6a4SAndroid Build Coastguard Worker 195*bb4ee6a4SAndroid Build Coastguard Worker if args.json: 196*bb4ee6a4SAndroid Build Coastguard Worker result = {} 197*bb4ee6a4SAndroid Build Coastguard Worker for exe in executables: 198*bb4ee6a4SAndroid Build Coastguard Worker assert exe.cargo_target not in result 199*bb4ee6a4SAndroid Build Coastguard Worker result[exe.cargo_target] = str(exe.binary_path) 200*bb4ee6a4SAndroid Build Coastguard Worker print(json.dumps(result)) 201*bb4ee6a4SAndroid Build Coastguard Worker else: 202*bb4ee6a4SAndroid Build Coastguard Worker print("Release binaries:") 203*bb4ee6a4SAndroid Build Coastguard Worker for exe in executables: 204*bb4ee6a4SAndroid Build Coastguard Worker print(f"Name: {exe.cargo_target}") 205*bb4ee6a4SAndroid Build Coastguard Worker print(f"Path: {str(exe.binary_path)}") 206*bb4ee6a4SAndroid Build Coastguard Worker print() 207*bb4ee6a4SAndroid Build Coastguard Worker 208*bb4ee6a4SAndroid Build Coastguard Worker 209*bb4ee6a4SAndroid Build Coastguard Workerif __name__ == "__main__": 210*bb4ee6a4SAndroid Build Coastguard Worker main() 211