1*90c8c64dSAndroid Build Coastguard Worker#!/usr/bin/env python3 2*90c8c64dSAndroid Build Coastguard Worker# Copyright (C) 2023 The Android Open Source Project 3*90c8c64dSAndroid Build Coastguard Worker# 4*90c8c64dSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); 5*90c8c64dSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License. 6*90c8c64dSAndroid Build Coastguard Worker# You may obtain a copy of the License at 7*90c8c64dSAndroid Build Coastguard Worker# 8*90c8c64dSAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0 9*90c8c64dSAndroid Build Coastguard Worker# 10*90c8c64dSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 11*90c8c64dSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, 12*90c8c64dSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*90c8c64dSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and 14*90c8c64dSAndroid Build Coastguard Worker# limitations under the License. 15*90c8c64dSAndroid Build Coastguard Worker# 16*90c8c64dSAndroid Build Coastguard Worker"""Call cargo -v, parse its output, and generate a Trusty build system module. 17*90c8c64dSAndroid Build Coastguard Worker 18*90c8c64dSAndroid Build Coastguard WorkerUsage: Run this script in a crate workspace root directory. The Cargo.toml file 19*90c8c64dSAndroid Build Coastguard Workershould work at least for the host platform. 20*90c8c64dSAndroid Build Coastguard Worker 21*90c8c64dSAndroid Build Coastguard WorkerWithout other flags, "cargo2rulesmk.py --run" calls cargo clean, calls cargo 22*90c8c64dSAndroid Build Coastguard Workerbuild -v, and generates makefile rules. The cargo build only generates crates 23*90c8c64dSAndroid Build Coastguard Workerfor the host without test crates. 24*90c8c64dSAndroid Build Coastguard Worker 25*90c8c64dSAndroid Build Coastguard WorkerIf there are rustc warning messages, this script will add a warning comment to 26*90c8c64dSAndroid Build Coastguard Workerthe owner crate module in rules.mk. 27*90c8c64dSAndroid Build Coastguard Worker""" 28*90c8c64dSAndroid Build Coastguard Worker 29*90c8c64dSAndroid Build Coastguard Workerimport argparse 30*90c8c64dSAndroid Build Coastguard Workerimport glob 31*90c8c64dSAndroid Build Coastguard Workerimport json 32*90c8c64dSAndroid Build Coastguard Workerimport os 33*90c8c64dSAndroid Build Coastguard Workerimport os.path 34*90c8c64dSAndroid Build Coastguard Workerimport platform 35*90c8c64dSAndroid Build Coastguard Workerimport re 36*90c8c64dSAndroid Build Coastguard Workerimport shutil 37*90c8c64dSAndroid Build Coastguard Workerimport subprocess 38*90c8c64dSAndroid Build Coastguard Workerimport sys 39*90c8c64dSAndroid Build Coastguard Worker 40*90c8c64dSAndroid Build Coastguard Workerfrom typing import List 41*90c8c64dSAndroid Build Coastguard Worker 42*90c8c64dSAndroid Build Coastguard Worker 43*90c8c64dSAndroid Build Coastguard Workerassert "/development/scripts" in os.path.dirname(__file__) 44*90c8c64dSAndroid Build Coastguard WorkerTOP_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), "../..")) 45*90c8c64dSAndroid Build Coastguard Worker 46*90c8c64dSAndroid Build Coastguard Worker# Some Rust packages include extra unwanted crates. 47*90c8c64dSAndroid Build Coastguard Worker# This set contains all such excluded crate names. 48*90c8c64dSAndroid Build Coastguard WorkerEXCLUDED_CRATES = {"protobuf_bin_gen_rust_do_not_use"} 49*90c8c64dSAndroid Build Coastguard Worker 50*90c8c64dSAndroid Build Coastguard Worker 51*90c8c64dSAndroid Build Coastguard WorkerCUSTOM_MODULE_CRATES = { 52*90c8c64dSAndroid Build Coastguard Worker # This map tracks Rust crates that have special modules that 53*90c8c64dSAndroid Build Coastguard Worker # were not generated automatically by this script. Examples 54*90c8c64dSAndroid Build Coastguard Worker # include compiler builtins and other foundational libraries. 55*90c8c64dSAndroid Build Coastguard Worker # It also tracks crates tht are not under external/rust/crates. 56*90c8c64dSAndroid Build Coastguard Worker "compiler_builtins": "trusty/user/base/lib/libcompiler_builtins-rust", 57*90c8c64dSAndroid Build Coastguard Worker "core": "trusty/user/base/lib/libcore-rust", 58*90c8c64dSAndroid Build Coastguard Worker} 59*90c8c64dSAndroid Build Coastguard Worker 60*90c8c64dSAndroid Build Coastguard WorkerRENAME_STEM_MAP = { 61*90c8c64dSAndroid Build Coastguard Worker # This map includes all changes to the default rust module stem names, 62*90c8c64dSAndroid Build Coastguard Worker # which is used for output files when different from the module name. 63*90c8c64dSAndroid Build Coastguard Worker "protoc_gen_rust": "protoc-gen-rust", 64*90c8c64dSAndroid Build Coastguard Worker} 65*90c8c64dSAndroid Build Coastguard Worker 66*90c8c64dSAndroid Build Coastguard Worker# Header added to all generated rules.mk files. 67*90c8c64dSAndroid Build Coastguard WorkerRULES_MK_HEADER = ( 68*90c8c64dSAndroid Build Coastguard Worker "# This file is generated by cargo2rulesmk.py {args}.\n" 69*90c8c64dSAndroid Build Coastguard Worker + "# Do not modify this file as changes will be overridden on upgrade.\n\n" 70*90c8c64dSAndroid Build Coastguard Worker) 71*90c8c64dSAndroid Build Coastguard Worker 72*90c8c64dSAndroid Build Coastguard WorkerCARGO_OUT = "cargo.out" # Name of file to keep cargo build -v output. 73*90c8c64dSAndroid Build Coastguard Worker 74*90c8c64dSAndroid Build Coastguard Worker# This should be kept in sync with tools/external_updater/crates_updater.py. 75*90c8c64dSAndroid Build Coastguard WorkerERRORS_LINE = "Errors in " + CARGO_OUT + ":" 76*90c8c64dSAndroid Build Coastguard Worker 77*90c8c64dSAndroid Build Coastguard WorkerTARGET_TMP = "target.tmp" # Name of temporary output directory. 78*90c8c64dSAndroid Build Coastguard Worker 79*90c8c64dSAndroid Build Coastguard Worker# Message to be displayed when this script is called without the --run flag. 80*90c8c64dSAndroid Build Coastguard WorkerDRY_RUN_NOTE = ( 81*90c8c64dSAndroid Build Coastguard Worker "Dry-run: This script uses ./" 82*90c8c64dSAndroid Build Coastguard Worker + TARGET_TMP 83*90c8c64dSAndroid Build Coastguard Worker + " for output directory,\n" 84*90c8c64dSAndroid Build Coastguard Worker + "runs cargo clean, runs cargo build -v, saves output to ./cargo.out,\n" 85*90c8c64dSAndroid Build Coastguard Worker + "and writes to rules.mk in the current and subdirectories.\n\n" 86*90c8c64dSAndroid Build Coastguard Worker + "To do do all of the above, use the --run flag.\n" 87*90c8c64dSAndroid Build Coastguard Worker + "See --help for other flags, and more usage notes in this script.\n" 88*90c8c64dSAndroid Build Coastguard Worker) 89*90c8c64dSAndroid Build Coastguard Worker 90*90c8c64dSAndroid Build Coastguard Worker# Cargo -v output of a call to rustc. 91*90c8c64dSAndroid Build Coastguard WorkerRUSTC_PAT = re.compile("^ +Running `(.*\/)?rustc (.*)`$") 92*90c8c64dSAndroid Build Coastguard Worker 93*90c8c64dSAndroid Build Coastguard Worker# Cargo -vv output of a call to rustc could be split into multiple lines. 94*90c8c64dSAndroid Build Coastguard Worker# Assume that the first line will contain some CARGO_* env definition. 95*90c8c64dSAndroid Build Coastguard WorkerRUSTC_VV_PAT = re.compile("^ +Running `.*CARGO_.*=.*$") 96*90c8c64dSAndroid Build Coastguard Worker# The combined -vv output rustc command line pattern. 97*90c8c64dSAndroid Build Coastguard WorkerRUSTC_VV_CMD_ARGS = re.compile("^ *Running `.*CARGO_.*=.* (.*\/)?rustc (.*)`$") 98*90c8c64dSAndroid Build Coastguard Worker 99*90c8c64dSAndroid Build Coastguard Worker# Cargo -vv output of a "cc" or "ar" command; all in one line. 100*90c8c64dSAndroid Build Coastguard WorkerCC_AR_VV_PAT = re.compile(r'^\[([^ ]*)[^\]]*\] running:? "(cc|ar)" (.*)$') 101*90c8c64dSAndroid Build Coastguard Worker# Some package, such as ring-0.13.5, has pattern '... running "cc"'. 102*90c8c64dSAndroid Build Coastguard Worker 103*90c8c64dSAndroid Build Coastguard Worker# Rustc output of file location path pattern for a warning message. 104*90c8c64dSAndroid Build Coastguard WorkerWARNING_FILE_PAT = re.compile("^ *--> ([^:]*):[0-9]+") 105*90c8c64dSAndroid Build Coastguard Worker 106*90c8c64dSAndroid Build Coastguard Worker# cargo test --list output of the start of running a binary. 107*90c8c64dSAndroid Build Coastguard WorkerCARGO_TEST_LIST_START_PAT = re.compile(r"^\s*Running (.*) \(.*\)$") 108*90c8c64dSAndroid Build Coastguard Worker 109*90c8c64dSAndroid Build Coastguard Worker# cargo test --list output of the end of running a binary. 110*90c8c64dSAndroid Build Coastguard WorkerCARGO_TEST_LIST_END_PAT = re.compile(r"^(\d+) tests?, (\d+) benchmarks$") 111*90c8c64dSAndroid Build Coastguard Worker 112*90c8c64dSAndroid Build Coastguard WorkerCARGO2ANDROID_RUNNING_PAT = re.compile("^### Running: .*$") 113*90c8c64dSAndroid Build Coastguard Worker 114*90c8c64dSAndroid Build Coastguard Worker# Rust package name with suffix -d1.d2.d3(+.*)?. 115*90c8c64dSAndroid Build Coastguard WorkerVERSION_SUFFIX_PAT = re.compile( 116*90c8c64dSAndroid Build Coastguard Worker r"^(.*)-[0-9]+\.[0-9]+\.[0-9]+(?:-(alpha|beta)\.[0-9]+)?(?:\+.*)?$" 117*90c8c64dSAndroid Build Coastguard Worker) 118*90c8c64dSAndroid Build Coastguard Worker 119*90c8c64dSAndroid Build Coastguard Worker# Crate types corresponding to a C ABI library 120*90c8c64dSAndroid Build Coastguard WorkerC_LIBRARY_CRATE_TYPES = ["staticlib", "cdylib"] 121*90c8c64dSAndroid Build Coastguard Worker# Crate types corresponding to a Rust ABI library 122*90c8c64dSAndroid Build Coastguard WorkerRUST_LIBRARY_CRATE_TYPES = ["lib", "rlib", "dylib", "proc-macro"] 123*90c8c64dSAndroid Build Coastguard Worker# Crate types corresponding to a library 124*90c8c64dSAndroid Build Coastguard WorkerLIBRARY_CRATE_TYPES = C_LIBRARY_CRATE_TYPES + RUST_LIBRARY_CRATE_TYPES 125*90c8c64dSAndroid Build Coastguard Worker 126*90c8c64dSAndroid Build Coastguard Worker 127*90c8c64dSAndroid Build Coastguard Workerdef altered_stem(name): 128*90c8c64dSAndroid Build Coastguard Worker return RENAME_STEM_MAP[name] if (name in RENAME_STEM_MAP) else name 129*90c8c64dSAndroid Build Coastguard Worker 130*90c8c64dSAndroid Build Coastguard Worker 131*90c8c64dSAndroid Build Coastguard Workerdef is_build_crate_name(name): 132*90c8c64dSAndroid Build Coastguard Worker # We added special prefix to build script crate names. 133*90c8c64dSAndroid Build Coastguard Worker return name.startswith("build_script_") 134*90c8c64dSAndroid Build Coastguard Worker 135*90c8c64dSAndroid Build Coastguard Worker 136*90c8c64dSAndroid Build Coastguard Workerdef is_dependent_file_path(path): 137*90c8c64dSAndroid Build Coastguard Worker # Absolute or dependent '.../' paths are not main files of this crate. 138*90c8c64dSAndroid Build Coastguard Worker return path.startswith("/") or path.startswith(".../") 139*90c8c64dSAndroid Build Coastguard Worker 140*90c8c64dSAndroid Build Coastguard Worker 141*90c8c64dSAndroid Build Coastguard Workerdef get_module_name(crate): # to sort crates in a list 142*90c8c64dSAndroid Build Coastguard Worker return crate.module_name 143*90c8c64dSAndroid Build Coastguard Worker 144*90c8c64dSAndroid Build Coastguard Worker 145*90c8c64dSAndroid Build Coastguard Workerdef pkg2crate_name(s): 146*90c8c64dSAndroid Build Coastguard Worker return s.replace("-", "_").replace(".", "_") 147*90c8c64dSAndroid Build Coastguard Worker 148*90c8c64dSAndroid Build Coastguard Worker 149*90c8c64dSAndroid Build Coastguard Workerdef file_base_name(path): 150*90c8c64dSAndroid Build Coastguard Worker return os.path.splitext(os.path.basename(path))[0] 151*90c8c64dSAndroid Build Coastguard Worker 152*90c8c64dSAndroid Build Coastguard Worker 153*90c8c64dSAndroid Build Coastguard Workerdef test_base_name(path): 154*90c8c64dSAndroid Build Coastguard Worker return pkg2crate_name(file_base_name(path)) 155*90c8c64dSAndroid Build Coastguard Worker 156*90c8c64dSAndroid Build Coastguard Worker 157*90c8c64dSAndroid Build Coastguard Workerdef unquote(s): # remove quotes around str 158*90c8c64dSAndroid Build Coastguard Worker if s and len(s) > 1 and s[0] == s[-1] and s[0] in ('"', "'"): 159*90c8c64dSAndroid Build Coastguard Worker return s[1:-1] 160*90c8c64dSAndroid Build Coastguard Worker return s 161*90c8c64dSAndroid Build Coastguard Worker 162*90c8c64dSAndroid Build Coastguard Worker 163*90c8c64dSAndroid Build Coastguard Workerdef remove_version_suffix(s): # remove -d1.d2.d3 suffix 164*90c8c64dSAndroid Build Coastguard Worker if match := VERSION_SUFFIX_PAT.match(s): 165*90c8c64dSAndroid Build Coastguard Worker return match.group(1) 166*90c8c64dSAndroid Build Coastguard Worker return s 167*90c8c64dSAndroid Build Coastguard Worker 168*90c8c64dSAndroid Build Coastguard Worker 169*90c8c64dSAndroid Build Coastguard Workerdef short_out_name(pkg, s): # replace /.../pkg-*/out/* with .../out/* 170*90c8c64dSAndroid Build Coastguard Worker return re.sub("^/.*/" + pkg + "-[0-9a-f]*/out/", ".../out/", s) 171*90c8c64dSAndroid Build Coastguard Worker 172*90c8c64dSAndroid Build Coastguard Worker 173*90c8c64dSAndroid Build Coastguard Workerclass Crate(object): 174*90c8c64dSAndroid Build Coastguard Worker """Information of a Rust crate to collect/emit for a rules.mk module.""" 175*90c8c64dSAndroid Build Coastguard Worker 176*90c8c64dSAndroid Build Coastguard Worker def __init__(self, runner, outf_name): 177*90c8c64dSAndroid Build Coastguard Worker # Remembered global runner and its members. 178*90c8c64dSAndroid Build Coastguard Worker self.runner = runner 179*90c8c64dSAndroid Build Coastguard Worker self.debug = runner.args.debug 180*90c8c64dSAndroid Build Coastguard Worker self.cargo_dir = "" # directory of my Cargo.toml 181*90c8c64dSAndroid Build Coastguard Worker self.outf_name = outf_name # path to rules.mk 182*90c8c64dSAndroid Build Coastguard Worker self.outf = None # open file handle of outf_name during dump* 183*90c8c64dSAndroid Build Coastguard Worker self.has_warning = False 184*90c8c64dSAndroid Build Coastguard Worker # Trusty module properties derived from rustc parameters. 185*90c8c64dSAndroid Build Coastguard Worker self.module_name = "" 186*90c8c64dSAndroid Build Coastguard Worker self.defaults = "" # rust_defaults used by rust_test* modules 187*90c8c64dSAndroid Build Coastguard Worker self.default_srcs = False # use 'srcs' defined in self.defaults 188*90c8c64dSAndroid Build Coastguard Worker self.root_pkg = "" # parent package name of a sub/test packge, from -L 189*90c8c64dSAndroid Build Coastguard Worker self.srcs = [] # main_src or merged multiple source files 190*90c8c64dSAndroid Build Coastguard Worker self.stem = "" # real base name of output file 191*90c8c64dSAndroid Build Coastguard Worker # Kept parsed status 192*90c8c64dSAndroid Build Coastguard Worker self.errors = "" # all errors found during parsing 193*90c8c64dSAndroid Build Coastguard Worker self.line_num = 1 # runner told input source line number 194*90c8c64dSAndroid Build Coastguard Worker self.line = "" # original rustc command line parameters 195*90c8c64dSAndroid Build Coastguard Worker # Parameters collected from rustc command line. 196*90c8c64dSAndroid Build Coastguard Worker self.crate_name = "" # follows --crate-name 197*90c8c64dSAndroid Build Coastguard Worker self.main_src = "" # follows crate_name parameter, shortened 198*90c8c64dSAndroid Build Coastguard Worker self.crate_types = [] # follows --crate-type 199*90c8c64dSAndroid Build Coastguard Worker self.cfgs = [] # follows --cfg, without feature= prefix 200*90c8c64dSAndroid Build Coastguard Worker self.features = [] # follows --cfg, name in 'feature="..."' 201*90c8c64dSAndroid Build Coastguard Worker self.codegens = [] # follows -C, some ignored 202*90c8c64dSAndroid Build Coastguard Worker self.static_libs = [] # e.g. -l static=host_cpuid 203*90c8c64dSAndroid Build Coastguard Worker self.shared_libs = [] # e.g. -l dylib=wayland-client, -l z 204*90c8c64dSAndroid Build Coastguard Worker self.cap_lints = "" # follows --cap-lints 205*90c8c64dSAndroid Build Coastguard Worker self.emit_list = "" # e.g., --emit=dep-info,metadata,link 206*90c8c64dSAndroid Build Coastguard Worker self.edition = "2015" # rustc default, e.g., --edition=2018 207*90c8c64dSAndroid Build Coastguard Worker self.target = "" # follows --target 208*90c8c64dSAndroid Build Coastguard Worker self.cargo_env_compat = True 209*90c8c64dSAndroid Build Coastguard Worker # Parameters collected from cargo metadata output 210*90c8c64dSAndroid Build Coastguard Worker self.dependencies = [] # crate dependencies output by `cargo metadata` 211*90c8c64dSAndroid Build Coastguard Worker self.feature_dependencies: dict[str, List[str]] = {} # maps features to 212*90c8c64dSAndroid Build Coastguard Worker # optional dependencies 213*90c8c64dSAndroid Build Coastguard Worker 214*90c8c64dSAndroid Build Coastguard Worker def write(self, s): 215*90c8c64dSAndroid Build Coastguard Worker """convenient way to output one line at a time with EOL.""" 216*90c8c64dSAndroid Build Coastguard Worker assert self.outf 217*90c8c64dSAndroid Build Coastguard Worker self.outf.write(s + "\n") 218*90c8c64dSAndroid Build Coastguard Worker 219*90c8c64dSAndroid Build Coastguard Worker def find_cargo_dir(self): 220*90c8c64dSAndroid Build Coastguard Worker """Deepest directory with Cargo.toml and contains the main_src.""" 221*90c8c64dSAndroid Build Coastguard Worker if not is_dependent_file_path(self.main_src): 222*90c8c64dSAndroid Build Coastguard Worker dir_name = os.path.dirname(self.main_src) 223*90c8c64dSAndroid Build Coastguard Worker while dir_name: 224*90c8c64dSAndroid Build Coastguard Worker if os.path.exists(dir_name + "/Cargo.toml"): 225*90c8c64dSAndroid Build Coastguard Worker self.cargo_dir = dir_name 226*90c8c64dSAndroid Build Coastguard Worker return 227*90c8c64dSAndroid Build Coastguard Worker dir_name = os.path.dirname(dir_name) 228*90c8c64dSAndroid Build Coastguard Worker 229*90c8c64dSAndroid Build Coastguard Worker def add_codegens_flag(self, flag): 230*90c8c64dSAndroid Build Coastguard Worker """Ignore options not used by Trusty build system""" 231*90c8c64dSAndroid Build Coastguard Worker # 'prefer-dynamic' may be set by library.mk 232*90c8c64dSAndroid Build Coastguard Worker # 'embed-bitcode' is ignored; we might control LTO with other flags 233*90c8c64dSAndroid Build Coastguard Worker # 'codegen-units' is set globally in engine.mk 234*90c8c64dSAndroid Build Coastguard Worker # 'relocation-model' and 'target-feature=+reserve-x18' may be set by 235*90c8c64dSAndroid Build Coastguard Worker # common_flags.mk 236*90c8c64dSAndroid Build Coastguard Worker if not ( 237*90c8c64dSAndroid Build Coastguard Worker flag.startswith("codegen-units=") 238*90c8c64dSAndroid Build Coastguard Worker or flag.startswith("debuginfo=") 239*90c8c64dSAndroid Build Coastguard Worker or flag.startswith("embed-bitcode=") 240*90c8c64dSAndroid Build Coastguard Worker or flag.startswith("extra-filename=") 241*90c8c64dSAndroid Build Coastguard Worker or flag.startswith("incremental=") 242*90c8c64dSAndroid Build Coastguard Worker or flag.startswith("metadata=") 243*90c8c64dSAndroid Build Coastguard Worker or flag.startswith("relocation-model=") 244*90c8c64dSAndroid Build Coastguard Worker or flag == "prefer-dynamic" 245*90c8c64dSAndroid Build Coastguard Worker or flag == "target-feature=+reserve-x18" 246*90c8c64dSAndroid Build Coastguard Worker ): 247*90c8c64dSAndroid Build Coastguard Worker self.codegens.append(flag) 248*90c8c64dSAndroid Build Coastguard Worker 249*90c8c64dSAndroid Build Coastguard Worker def get_dependencies(self): 250*90c8c64dSAndroid Build Coastguard Worker """Use output from cargo metadata to determine crate dependencies""" 251*90c8c64dSAndroid Build Coastguard Worker cargo_metadata = subprocess.run( 252*90c8c64dSAndroid Build Coastguard Worker [ 253*90c8c64dSAndroid Build Coastguard Worker self.runner.cargo_path, 254*90c8c64dSAndroid Build Coastguard Worker "metadata", 255*90c8c64dSAndroid Build Coastguard Worker "--no-deps", 256*90c8c64dSAndroid Build Coastguard Worker "--format-version", 257*90c8c64dSAndroid Build Coastguard Worker "1", 258*90c8c64dSAndroid Build Coastguard Worker ], 259*90c8c64dSAndroid Build Coastguard Worker cwd=os.path.abspath(self.cargo_dir), 260*90c8c64dSAndroid Build Coastguard Worker stdout=subprocess.PIPE, 261*90c8c64dSAndroid Build Coastguard Worker check=False, 262*90c8c64dSAndroid Build Coastguard Worker ) 263*90c8c64dSAndroid Build Coastguard Worker if cargo_metadata.returncode: 264*90c8c64dSAndroid Build Coastguard Worker self.errors += ( 265*90c8c64dSAndroid Build Coastguard Worker "ERROR: unable to get cargo metadata to determine " 266*90c8c64dSAndroid Build Coastguard Worker f"dependencies; return code {cargo_metadata.returncode}\n" 267*90c8c64dSAndroid Build Coastguard Worker ) 268*90c8c64dSAndroid Build Coastguard Worker else: 269*90c8c64dSAndroid Build Coastguard Worker metadata_json = json.loads(cargo_metadata.stdout) 270*90c8c64dSAndroid Build Coastguard Worker 271*90c8c64dSAndroid Build Coastguard Worker for package in metadata_json["packages"]: 272*90c8c64dSAndroid Build Coastguard Worker # package names containing '-' are changed to '_' in crate_name 273*90c8c64dSAndroid Build Coastguard Worker if package["name"].replace("-", "_") == self.crate_name: 274*90c8c64dSAndroid Build Coastguard Worker self.dependencies = package["dependencies"] 275*90c8c64dSAndroid Build Coastguard Worker for feat, props in package["features"].items(): 276*90c8c64dSAndroid Build Coastguard Worker feat_deps = [ 277*90c8c64dSAndroid Build Coastguard Worker d[4:] for d in props if d.startswith("dep:") 278*90c8c64dSAndroid Build Coastguard Worker ] 279*90c8c64dSAndroid Build Coastguard Worker if feat_deps and feat in self.feature_dependencies: 280*90c8c64dSAndroid Build Coastguard Worker self.feature_dependencies[feat].extend(feat_deps) 281*90c8c64dSAndroid Build Coastguard Worker else: 282*90c8c64dSAndroid Build Coastguard Worker self.feature_dependencies[feat] = feat_deps 283*90c8c64dSAndroid Build Coastguard Worker break 284*90c8c64dSAndroid Build Coastguard Worker else: # package name not found in metadata 285*90c8c64dSAndroid Build Coastguard Worker if is_build_crate_name(self.crate_name): 286*90c8c64dSAndroid Build Coastguard Worker print( 287*90c8c64dSAndroid Build Coastguard Worker "### WARNING: unable to determine dependencies for " 288*90c8c64dSAndroid Build Coastguard Worker + f"{self.crate_name} from cargo metadata" 289*90c8c64dSAndroid Build Coastguard Worker ) 290*90c8c64dSAndroid Build Coastguard Worker 291*90c8c64dSAndroid Build Coastguard Worker def parse(self, line_num, line): 292*90c8c64dSAndroid Build Coastguard Worker """Find important rustc arguments to convert to makefile rules.""" 293*90c8c64dSAndroid Build Coastguard Worker self.line_num = line_num 294*90c8c64dSAndroid Build Coastguard Worker self.line = line 295*90c8c64dSAndroid Build Coastguard Worker args = [unquote(l) for l in line.split()] 296*90c8c64dSAndroid Build Coastguard Worker i = 0 297*90c8c64dSAndroid Build Coastguard Worker # Loop through every argument of rustc. 298*90c8c64dSAndroid Build Coastguard Worker while i < len(args): 299*90c8c64dSAndroid Build Coastguard Worker arg = args[i] 300*90c8c64dSAndroid Build Coastguard Worker if arg == "--crate-name": 301*90c8c64dSAndroid Build Coastguard Worker i += 1 302*90c8c64dSAndroid Build Coastguard Worker self.crate_name = args[i] 303*90c8c64dSAndroid Build Coastguard Worker elif arg == "--crate-type": 304*90c8c64dSAndroid Build Coastguard Worker i += 1 305*90c8c64dSAndroid Build Coastguard Worker # cargo calls rustc with multiple --crate-type flags. 306*90c8c64dSAndroid Build Coastguard Worker # rustc can accept: 307*90c8c64dSAndroid Build Coastguard Worker # --crate-type [bin|lib|rlib|dylib|cdylib|staticlib|proc-macro] 308*90c8c64dSAndroid Build Coastguard Worker self.crate_types.append(args[i]) 309*90c8c64dSAndroid Build Coastguard Worker elif arg == "--test": 310*90c8c64dSAndroid Build Coastguard Worker self.crate_types.append("test") 311*90c8c64dSAndroid Build Coastguard Worker elif arg == "--target": 312*90c8c64dSAndroid Build Coastguard Worker i += 1 313*90c8c64dSAndroid Build Coastguard Worker self.target = args[i] 314*90c8c64dSAndroid Build Coastguard Worker elif arg == "--cfg": 315*90c8c64dSAndroid Build Coastguard Worker i += 1 316*90c8c64dSAndroid Build Coastguard Worker if args[i].startswith("feature="): 317*90c8c64dSAndroid Build Coastguard Worker self.features.append( 318*90c8c64dSAndroid Build Coastguard Worker unquote(args[i].replace("feature=", "")) 319*90c8c64dSAndroid Build Coastguard Worker ) 320*90c8c64dSAndroid Build Coastguard Worker else: 321*90c8c64dSAndroid Build Coastguard Worker self.cfgs.append(args[i]) 322*90c8c64dSAndroid Build Coastguard Worker elif arg == "--extern": 323*90c8c64dSAndroid Build Coastguard Worker i += 1 324*90c8c64dSAndroid Build Coastguard Worker pass # ignored; get all dependencies from cargo metadata 325*90c8c64dSAndroid Build Coastguard Worker elif arg == "-C": # codegen options 326*90c8c64dSAndroid Build Coastguard Worker i += 1 327*90c8c64dSAndroid Build Coastguard Worker self.add_codegens_flag(args[i]) 328*90c8c64dSAndroid Build Coastguard Worker elif arg.startswith("-C"): 329*90c8c64dSAndroid Build Coastguard Worker # cargo has been passing "-C <xyz>" flag to rustc, 330*90c8c64dSAndroid Build Coastguard Worker # but newer cargo could pass '-Cembed-bitcode=no' to rustc. 331*90c8c64dSAndroid Build Coastguard Worker self.add_codegens_flag(arg[2:]) 332*90c8c64dSAndroid Build Coastguard Worker elif arg == "--cap-lints": 333*90c8c64dSAndroid Build Coastguard Worker i += 1 334*90c8c64dSAndroid Build Coastguard Worker self.cap_lints = args[i] 335*90c8c64dSAndroid Build Coastguard Worker elif arg == "-L": 336*90c8c64dSAndroid Build Coastguard Worker i += 1 337*90c8c64dSAndroid Build Coastguard Worker if args[i].startswith("dependency=") and args[i].endswith( 338*90c8c64dSAndroid Build Coastguard Worker "/deps" 339*90c8c64dSAndroid Build Coastguard Worker ): 340*90c8c64dSAndroid Build Coastguard Worker if "/" + TARGET_TMP + "/" in args[i]: 341*90c8c64dSAndroid Build Coastguard Worker self.root_pkg = re.sub( 342*90c8c64dSAndroid Build Coastguard Worker "^.*/", 343*90c8c64dSAndroid Build Coastguard Worker "", 344*90c8c64dSAndroid Build Coastguard Worker re.sub("/" + TARGET_TMP + "/.*/deps$", "", args[i]), 345*90c8c64dSAndroid Build Coastguard Worker ) 346*90c8c64dSAndroid Build Coastguard Worker else: 347*90c8c64dSAndroid Build Coastguard Worker self.root_pkg = re.sub( 348*90c8c64dSAndroid Build Coastguard Worker "^.*/", 349*90c8c64dSAndroid Build Coastguard Worker "", 350*90c8c64dSAndroid Build Coastguard Worker re.sub("/[^/]+/[^/]+/deps$", "", args[i]), 351*90c8c64dSAndroid Build Coastguard Worker ) 352*90c8c64dSAndroid Build Coastguard Worker self.root_pkg = remove_version_suffix(self.root_pkg) 353*90c8c64dSAndroid Build Coastguard Worker elif arg == "-l": 354*90c8c64dSAndroid Build Coastguard Worker i += 1 355*90c8c64dSAndroid Build Coastguard Worker if args[i].startswith("static="): 356*90c8c64dSAndroid Build Coastguard Worker self.static_libs.append(re.sub("static=", "", args[i])) 357*90c8c64dSAndroid Build Coastguard Worker elif args[i].startswith("dylib="): 358*90c8c64dSAndroid Build Coastguard Worker self.shared_libs.append(re.sub("dylib=", "", args[i])) 359*90c8c64dSAndroid Build Coastguard Worker else: 360*90c8c64dSAndroid Build Coastguard Worker self.shared_libs.append(args[i]) 361*90c8c64dSAndroid Build Coastguard Worker elif arg in ("--out-dir", "--color"): # ignored 362*90c8c64dSAndroid Build Coastguard Worker i += 1 363*90c8c64dSAndroid Build Coastguard Worker elif arg.startswith("--error-format=") or arg.startswith("--json="): 364*90c8c64dSAndroid Build Coastguard Worker pass # ignored 365*90c8c64dSAndroid Build Coastguard Worker elif arg.startswith("--emit="): 366*90c8c64dSAndroid Build Coastguard Worker self.emit_list = arg.replace("--emit=", "") 367*90c8c64dSAndroid Build Coastguard Worker elif arg.startswith("--edition="): 368*90c8c64dSAndroid Build Coastguard Worker self.edition = arg.replace("--edition=", "") 369*90c8c64dSAndroid Build Coastguard Worker elif arg.startswith("-Aclippy") or arg.startswith("-Wclippy"): 370*90c8c64dSAndroid Build Coastguard Worker pass # TODO: emit these flags in rules.mk 371*90c8c64dSAndroid Build Coastguard Worker elif arg.startswith("-W"): 372*90c8c64dSAndroid Build Coastguard Worker pass # ignored 373*90c8c64dSAndroid Build Coastguard Worker elif arg.startswith("-Z"): 374*90c8c64dSAndroid Build Coastguard Worker pass # ignore unstable flags 375*90c8c64dSAndroid Build Coastguard Worker elif arg.startswith("-D"): 376*90c8c64dSAndroid Build Coastguard Worker pass # TODO: emit these flags in rules.mk 377*90c8c64dSAndroid Build Coastguard Worker elif not arg.startswith("-"): 378*90c8c64dSAndroid Build Coastguard Worker # shorten imported crate main source paths like $HOME/.cargo/ 379*90c8c64dSAndroid Build Coastguard Worker # registry/src/github.com-1ecc6299db9ec823/memchr-2.3.3/src/ 380*90c8c64dSAndroid Build Coastguard Worker # lib.rs 381*90c8c64dSAndroid Build Coastguard Worker self.main_src = re.sub( 382*90c8c64dSAndroid Build Coastguard Worker r"^/[^ ]*/registry/src/", ".../", args[i] 383*90c8c64dSAndroid Build Coastguard Worker ) 384*90c8c64dSAndroid Build Coastguard Worker self.main_src = re.sub( 385*90c8c64dSAndroid Build Coastguard Worker r"^\.\.\./github.com-[0-9a-f]*/", ".../", self.main_src 386*90c8c64dSAndroid Build Coastguard Worker ) 387*90c8c64dSAndroid Build Coastguard Worker self.find_cargo_dir() 388*90c8c64dSAndroid Build Coastguard Worker if self.cargo_dir: # for a subdirectory 389*90c8c64dSAndroid Build Coastguard Worker if ( 390*90c8c64dSAndroid Build Coastguard Worker self.runner.args.no_subdir 391*90c8c64dSAndroid Build Coastguard Worker ): # all .mk content to /dev/null 392*90c8c64dSAndroid Build Coastguard Worker self.outf_name = "/dev/null" 393*90c8c64dSAndroid Build Coastguard Worker elif not self.runner.args.onefile: 394*90c8c64dSAndroid Build Coastguard Worker # Write to rules.mk in the subdirectory with Cargo.toml. 395*90c8c64dSAndroid Build Coastguard Worker self.outf_name = self.cargo_dir + "/rules.mk" 396*90c8c64dSAndroid Build Coastguard Worker self.main_src = self.main_src[len(self.cargo_dir) + 1 :] 397*90c8c64dSAndroid Build Coastguard Worker 398*90c8c64dSAndroid Build Coastguard Worker else: 399*90c8c64dSAndroid Build Coastguard Worker self.errors += "ERROR: unknown " + arg + "\n" 400*90c8c64dSAndroid Build Coastguard Worker i += 1 401*90c8c64dSAndroid Build Coastguard Worker if not self.crate_name: 402*90c8c64dSAndroid Build Coastguard Worker self.errors += "ERROR: missing --crate-name\n" 403*90c8c64dSAndroid Build Coastguard Worker if not self.main_src: 404*90c8c64dSAndroid Build Coastguard Worker self.errors += "ERROR: missing main source file\n" 405*90c8c64dSAndroid Build Coastguard Worker else: 406*90c8c64dSAndroid Build Coastguard Worker self.srcs.append(self.main_src) 407*90c8c64dSAndroid Build Coastguard Worker if not self.crate_types: 408*90c8c64dSAndroid Build Coastguard Worker # Treat "--cfg test" as "--test" 409*90c8c64dSAndroid Build Coastguard Worker if "test" in self.cfgs: 410*90c8c64dSAndroid Build Coastguard Worker self.crate_types.append("test") 411*90c8c64dSAndroid Build Coastguard Worker else: 412*90c8c64dSAndroid Build Coastguard Worker self.errors += "ERROR: missing --crate-type or --test\n" 413*90c8c64dSAndroid Build Coastguard Worker elif len(self.crate_types) > 1: 414*90c8c64dSAndroid Build Coastguard Worker if "test" in self.crate_types: 415*90c8c64dSAndroid Build Coastguard Worker self.errors += ( 416*90c8c64dSAndroid Build Coastguard Worker "ERROR: cannot handle both --crate-type and --test\n" 417*90c8c64dSAndroid Build Coastguard Worker ) 418*90c8c64dSAndroid Build Coastguard Worker if "lib" in self.crate_types and "rlib" in self.crate_types: 419*90c8c64dSAndroid Build Coastguard Worker self.errors += ( 420*90c8c64dSAndroid Build Coastguard Worker "ERROR: cannot generate both lib and rlib crate types\n" 421*90c8c64dSAndroid Build Coastguard Worker ) 422*90c8c64dSAndroid Build Coastguard Worker if not self.root_pkg: 423*90c8c64dSAndroid Build Coastguard Worker self.root_pkg = self.crate_name 424*90c8c64dSAndroid Build Coastguard Worker 425*90c8c64dSAndroid Build Coastguard Worker # get the package dependencies by running cargo metadata 426*90c8c64dSAndroid Build Coastguard Worker if not self.skip_crate(): 427*90c8c64dSAndroid Build Coastguard Worker self.get_dependencies() 428*90c8c64dSAndroid Build Coastguard Worker self.cfgs = sorted(set(self.cfgs)) 429*90c8c64dSAndroid Build Coastguard Worker self.features = sorted(set(self.features)) 430*90c8c64dSAndroid Build Coastguard Worker self.codegens = sorted(set(self.codegens)) 431*90c8c64dSAndroid Build Coastguard Worker self.static_libs = sorted(set(self.static_libs)) 432*90c8c64dSAndroid Build Coastguard Worker self.shared_libs = sorted(set(self.shared_libs)) 433*90c8c64dSAndroid Build Coastguard Worker self.crate_types = sorted(set(self.crate_types)) 434*90c8c64dSAndroid Build Coastguard Worker self.module_name = self.stem 435*90c8c64dSAndroid Build Coastguard Worker return self 436*90c8c64dSAndroid Build Coastguard Worker 437*90c8c64dSAndroid Build Coastguard Worker def dump_line(self): 438*90c8c64dSAndroid Build Coastguard Worker self.write("\n// Line " + str(self.line_num) + " " + self.line) 439*90c8c64dSAndroid Build Coastguard Worker 440*90c8c64dSAndroid Build Coastguard Worker def feature_list(self): 441*90c8c64dSAndroid Build Coastguard Worker """Return a string of main_src + "feature_list".""" 442*90c8c64dSAndroid Build Coastguard Worker pkg = self.main_src 443*90c8c64dSAndroid Build Coastguard Worker if pkg.startswith(".../"): # keep only the main package name 444*90c8c64dSAndroid Build Coastguard Worker pkg = re.sub("/.*", "", pkg[4:]) 445*90c8c64dSAndroid Build Coastguard Worker elif pkg.startswith("/"): # use relative path for a local package 446*90c8c64dSAndroid Build Coastguard Worker pkg = os.path.relpath(pkg) 447*90c8c64dSAndroid Build Coastguard Worker if not self.features: 448*90c8c64dSAndroid Build Coastguard Worker return pkg 449*90c8c64dSAndroid Build Coastguard Worker return pkg + ' "' + ",".join(self.features) + '"' 450*90c8c64dSAndroid Build Coastguard Worker 451*90c8c64dSAndroid Build Coastguard Worker def dump_skip_crate(self, kind): 452*90c8c64dSAndroid Build Coastguard Worker if self.debug: 453*90c8c64dSAndroid Build Coastguard Worker self.write("\n// IGNORED: " + kind + " " + self.main_src) 454*90c8c64dSAndroid Build Coastguard Worker return self 455*90c8c64dSAndroid Build Coastguard Worker 456*90c8c64dSAndroid Build Coastguard Worker def skip_crate(self): 457*90c8c64dSAndroid Build Coastguard Worker """Return crate_name or a message if this crate should be skipped.""" 458*90c8c64dSAndroid Build Coastguard Worker if ( 459*90c8c64dSAndroid Build Coastguard Worker is_build_crate_name(self.crate_name) 460*90c8c64dSAndroid Build Coastguard Worker or self.crate_name in EXCLUDED_CRATES 461*90c8c64dSAndroid Build Coastguard Worker ): 462*90c8c64dSAndroid Build Coastguard Worker return self.crate_name 463*90c8c64dSAndroid Build Coastguard Worker if is_dependent_file_path(self.main_src): 464*90c8c64dSAndroid Build Coastguard Worker return "dependent crate" 465*90c8c64dSAndroid Build Coastguard Worker return "" 466*90c8c64dSAndroid Build Coastguard Worker 467*90c8c64dSAndroid Build Coastguard Worker def dump(self): 468*90c8c64dSAndroid Build Coastguard Worker """Dump all error/debug/module code to the output rules.mk file.""" 469*90c8c64dSAndroid Build Coastguard Worker self.runner.init_rules_file(self.outf_name) 470*90c8c64dSAndroid Build Coastguard Worker with open(self.outf_name, "a", encoding="utf-8") as outf: 471*90c8c64dSAndroid Build Coastguard Worker self.outf = outf 472*90c8c64dSAndroid Build Coastguard Worker if self.errors: 473*90c8c64dSAndroid Build Coastguard Worker self.dump_line() 474*90c8c64dSAndroid Build Coastguard Worker self.write(self.errors) 475*90c8c64dSAndroid Build Coastguard Worker elif self.skip_crate(): 476*90c8c64dSAndroid Build Coastguard Worker self.dump_skip_crate(self.skip_crate()) 477*90c8c64dSAndroid Build Coastguard Worker else: 478*90c8c64dSAndroid Build Coastguard Worker if self.debug: 479*90c8c64dSAndroid Build Coastguard Worker self.dump_debug_info() 480*90c8c64dSAndroid Build Coastguard Worker self.dump_trusty_module() 481*90c8c64dSAndroid Build Coastguard Worker self.outf = None 482*90c8c64dSAndroid Build Coastguard Worker 483*90c8c64dSAndroid Build Coastguard Worker def dump_debug_info(self): 484*90c8c64dSAndroid Build Coastguard Worker """Dump parsed data, when cargo2rulesmk is called with --debug.""" 485*90c8c64dSAndroid Build Coastguard Worker 486*90c8c64dSAndroid Build Coastguard Worker def dump(name, value): 487*90c8c64dSAndroid Build Coastguard Worker self.write(f"//{name:>12} = {value}") 488*90c8c64dSAndroid Build Coastguard Worker 489*90c8c64dSAndroid Build Coastguard Worker def opt_dump(name, value): 490*90c8c64dSAndroid Build Coastguard Worker if value: 491*90c8c64dSAndroid Build Coastguard Worker dump(name, value) 492*90c8c64dSAndroid Build Coastguard Worker 493*90c8c64dSAndroid Build Coastguard Worker def dump_list(fmt, values): 494*90c8c64dSAndroid Build Coastguard Worker for v in values: 495*90c8c64dSAndroid Build Coastguard Worker self.write(fmt % v) 496*90c8c64dSAndroid Build Coastguard Worker 497*90c8c64dSAndroid Build Coastguard Worker self.dump_line() 498*90c8c64dSAndroid Build Coastguard Worker dump("module_name", self.module_name) 499*90c8c64dSAndroid Build Coastguard Worker dump("crate_name", self.crate_name) 500*90c8c64dSAndroid Build Coastguard Worker dump("crate_types", self.crate_types) 501*90c8c64dSAndroid Build Coastguard Worker dump("main_src", self.main_src) 502*90c8c64dSAndroid Build Coastguard Worker dump("has_warning", self.has_warning) 503*90c8c64dSAndroid Build Coastguard Worker opt_dump("target", self.target) 504*90c8c64dSAndroid Build Coastguard Worker opt_dump("edition", self.edition) 505*90c8c64dSAndroid Build Coastguard Worker opt_dump("emit_list", self.emit_list) 506*90c8c64dSAndroid Build Coastguard Worker opt_dump("cap_lints", self.cap_lints) 507*90c8c64dSAndroid Build Coastguard Worker dump_list("// cfg = %s", self.cfgs) 508*90c8c64dSAndroid Build Coastguard Worker dump_list("// cfg = 'feature \"%s\"'", self.features) 509*90c8c64dSAndroid Build Coastguard Worker # TODO(chh): escape quotes in self.features, but not in other dump_list 510*90c8c64dSAndroid Build Coastguard Worker dump_list("// codegen = %s", self.codegens) 511*90c8c64dSAndroid Build Coastguard Worker dump_list("// -l static = %s", self.static_libs) 512*90c8c64dSAndroid Build Coastguard Worker dump_list("// -l (dylib) = %s", self.shared_libs) 513*90c8c64dSAndroid Build Coastguard Worker 514*90c8c64dSAndroid Build Coastguard Worker def dump_trusty_module(self): 515*90c8c64dSAndroid Build Coastguard Worker """Dump one or more module definitions, depending on crate_types.""" 516*90c8c64dSAndroid Build Coastguard Worker if len(self.crate_types) > 1: 517*90c8c64dSAndroid Build Coastguard Worker if "test" in self.crate_types: 518*90c8c64dSAndroid Build Coastguard Worker self.write("\nERROR: multiple crate types cannot include test type") 519*90c8c64dSAndroid Build Coastguard Worker return 520*90c8c64dSAndroid Build Coastguard Worker 521*90c8c64dSAndroid Build Coastguard Worker if "lib" in self.crate_types: 522*90c8c64dSAndroid Build Coastguard Worker print(f"### WARNING: crate {self.crate_name} has multiple " 523*90c8c64dSAndroid Build Coastguard Worker f"crate types ({str(self.crate_types)}). Treating as 'lib'") 524*90c8c64dSAndroid Build Coastguard Worker self.crate_types = ["lib"] 525*90c8c64dSAndroid Build Coastguard Worker else: 526*90c8c64dSAndroid Build Coastguard Worker self.write("\nERROR: don't know how to handle crate types of " 527*90c8c64dSAndroid Build Coastguard Worker f"crate {self.crate_name}: {str(self.crate_types)}") 528*90c8c64dSAndroid Build Coastguard Worker return 529*90c8c64dSAndroid Build Coastguard Worker 530*90c8c64dSAndroid Build Coastguard Worker self.dump_single_type_trusty_module() 531*90c8c64dSAndroid Build Coastguard Worker 532*90c8c64dSAndroid Build Coastguard Worker def dump_srcs_list(self): 533*90c8c64dSAndroid Build Coastguard Worker """Dump the srcs list, for defaults or regular modules.""" 534*90c8c64dSAndroid Build Coastguard Worker if len(self.srcs) > 1: 535*90c8c64dSAndroid Build Coastguard Worker srcs = sorted(set(self.srcs)) # make a copy and dedup 536*90c8c64dSAndroid Build Coastguard Worker else: 537*90c8c64dSAndroid Build Coastguard Worker srcs = [self.main_src] 538*90c8c64dSAndroid Build Coastguard Worker self.write("MODULE_SRCS := \\") 539*90c8c64dSAndroid Build Coastguard Worker for src in srcs: 540*90c8c64dSAndroid Build Coastguard Worker self.write(f"\t$(LOCAL_DIR)/{src} \\") 541*90c8c64dSAndroid Build Coastguard Worker self.write("") 542*90c8c64dSAndroid Build Coastguard Worker 543*90c8c64dSAndroid Build Coastguard Worker # add rust file generated by build.rs to MODULE_SRCDEPS, if any 544*90c8c64dSAndroid Build Coastguard Worker # TODO(perlarsen): is there a need to support more than one output file? 545*90c8c64dSAndroid Build Coastguard Worker if srcdeps := [ 546*90c8c64dSAndroid Build Coastguard Worker f for f in self.runner.build_out_files if f.endswith(".rs") 547*90c8c64dSAndroid Build Coastguard Worker ]: 548*90c8c64dSAndroid Build Coastguard Worker assert len(srcdeps) == 1 549*90c8c64dSAndroid Build Coastguard Worker outfile = srcdeps.pop() 550*90c8c64dSAndroid Build Coastguard Worker lines = [ 551*90c8c64dSAndroid Build Coastguard Worker f"OUT_FILE := $(call TOBUILDDIR,$(MODULE))/{outfile}", 552*90c8c64dSAndroid Build Coastguard Worker f"$(OUT_FILE): $(MODULE)/out/{outfile}", 553*90c8c64dSAndroid Build Coastguard Worker "\t@echo copying $< to $@", 554*90c8c64dSAndroid Build Coastguard Worker "\t@$(MKDIR)", 555*90c8c64dSAndroid Build Coastguard Worker "\tcp $< $@", 556*90c8c64dSAndroid Build Coastguard Worker "", 557*90c8c64dSAndroid Build Coastguard Worker "MODULE_RUST_ENV += OUT_DIR=$(dir $(OUT_FILE))", 558*90c8c64dSAndroid Build Coastguard Worker "", 559*90c8c64dSAndroid Build Coastguard Worker "MODULE_SRCDEPS := $(OUT_FILE)", 560*90c8c64dSAndroid Build Coastguard Worker ] 561*90c8c64dSAndroid Build Coastguard Worker self.write("\n".join(lines)) 562*90c8c64dSAndroid Build Coastguard Worker 563*90c8c64dSAndroid Build Coastguard Worker def dump_single_type_trusty_module(self): 564*90c8c64dSAndroid Build Coastguard Worker """Dump one simple Trusty module, which has only one crate_type.""" 565*90c8c64dSAndroid Build Coastguard Worker crate_type = self.crate_types[0] 566*90c8c64dSAndroid Build Coastguard Worker assert crate_type != "test" 567*90c8c64dSAndroid Build Coastguard Worker self.dump_one_trusty_module(crate_type) 568*90c8c64dSAndroid Build Coastguard Worker 569*90c8c64dSAndroid Build Coastguard Worker def dump_one_trusty_module(self, crate_type): 570*90c8c64dSAndroid Build Coastguard Worker """Dump one Trusty module definition.""" 571*90c8c64dSAndroid Build Coastguard Worker if crate_type in ["test", "bin"]: # TODO: support test crates 572*90c8c64dSAndroid Build Coastguard Worker print( 573*90c8c64dSAndroid Build Coastguard Worker f"### WARNING: ignoring {crate_type} crate: {self.crate_name}") 574*90c8c64dSAndroid Build Coastguard Worker return 575*90c8c64dSAndroid Build Coastguard Worker if self.codegens: # TODO: support crates that require codegen flags 576*90c8c64dSAndroid Build Coastguard Worker print( 577*90c8c64dSAndroid Build Coastguard Worker f"ERROR: {self.crate_name} uses unexpected codegen flags: " + 578*90c8c64dSAndroid Build Coastguard Worker str(self.codegens) 579*90c8c64dSAndroid Build Coastguard Worker ) 580*90c8c64dSAndroid Build Coastguard Worker return 581*90c8c64dSAndroid Build Coastguard Worker 582*90c8c64dSAndroid Build Coastguard Worker self.dump_core_properties() 583*90c8c64dSAndroid Build Coastguard Worker if not self.defaults: 584*90c8c64dSAndroid Build Coastguard Worker self.dump_edition_flags_libs() 585*90c8c64dSAndroid Build Coastguard Worker 586*90c8c64dSAndroid Build Coastguard Worker # NOTE: a crate may list the same dependency as required and optional 587*90c8c64dSAndroid Build Coastguard Worker library_deps = set() 588*90c8c64dSAndroid Build Coastguard Worker for dependency in self.dependencies: 589*90c8c64dSAndroid Build Coastguard Worker if dependency["kind"] in ["dev", "build"]: 590*90c8c64dSAndroid Build Coastguard Worker continue 591*90c8c64dSAndroid Build Coastguard Worker name = ( 592*90c8c64dSAndroid Build Coastguard Worker rename 593*90c8c64dSAndroid Build Coastguard Worker if (rename := dependency["rename"]) 594*90c8c64dSAndroid Build Coastguard Worker else dependency["name"] 595*90c8c64dSAndroid Build Coastguard Worker ) 596*90c8c64dSAndroid Build Coastguard Worker if dependency["target"]: 597*90c8c64dSAndroid Build Coastguard Worker print( 598*90c8c64dSAndroid Build Coastguard Worker f"### WARNING: ignoring target-specific dependency: {name}") 599*90c8c64dSAndroid Build Coastguard Worker continue 600*90c8c64dSAndroid Build Coastguard Worker path = CUSTOM_MODULE_CRATES.get( 601*90c8c64dSAndroid Build Coastguard Worker name, f"external/rust/crates/{name}" 602*90c8c64dSAndroid Build Coastguard Worker ) 603*90c8c64dSAndroid Build Coastguard Worker if dependency["optional"]: 604*90c8c64dSAndroid Build Coastguard Worker if not any( 605*90c8c64dSAndroid Build Coastguard Worker name in self.feature_dependencies.get(f, []) 606*90c8c64dSAndroid Build Coastguard Worker for f in self.features 607*90c8c64dSAndroid Build Coastguard Worker ): 608*90c8c64dSAndroid Build Coastguard Worker continue 609*90c8c64dSAndroid Build Coastguard Worker library_deps.add(path) 610*90c8c64dSAndroid Build Coastguard Worker if library_deps: 611*90c8c64dSAndroid Build Coastguard Worker self.write("MODULE_LIBRARY_DEPS := \\") 612*90c8c64dSAndroid Build Coastguard Worker for path in sorted(library_deps): 613*90c8c64dSAndroid Build Coastguard Worker self.write(f"\t{path} \\") 614*90c8c64dSAndroid Build Coastguard Worker self.write("") 615*90c8c64dSAndroid Build Coastguard Worker if crate_type == "test" and not self.default_srcs: 616*90c8c64dSAndroid Build Coastguard Worker raise NotImplementedError("Crates with test data are not supported") 617*90c8c64dSAndroid Build Coastguard Worker 618*90c8c64dSAndroid Build Coastguard Worker assert crate_type in LIBRARY_CRATE_TYPES 619*90c8c64dSAndroid Build Coastguard Worker self.write("include make/library.mk") 620*90c8c64dSAndroid Build Coastguard Worker 621*90c8c64dSAndroid Build Coastguard Worker def dump_edition_flags_libs(self): 622*90c8c64dSAndroid Build Coastguard Worker if self.edition: 623*90c8c64dSAndroid Build Coastguard Worker self.write(f"MODULE_RUST_EDITION := {self.edition}") 624*90c8c64dSAndroid Build Coastguard Worker if self.features or self.cfgs: 625*90c8c64dSAndroid Build Coastguard Worker self.write("MODULE_RUSTFLAGS += \\") 626*90c8c64dSAndroid Build Coastguard Worker for feature in self.features: 627*90c8c64dSAndroid Build Coastguard Worker self.write(f"\t--cfg 'feature=\"{feature}\"' \\") 628*90c8c64dSAndroid Build Coastguard Worker for cfg in self.cfgs: 629*90c8c64dSAndroid Build Coastguard Worker self.write(f"\t--cfg '{cfg}' \\") 630*90c8c64dSAndroid Build Coastguard Worker self.write("") 631*90c8c64dSAndroid Build Coastguard Worker 632*90c8c64dSAndroid Build Coastguard Worker if self.static_libs or self.shared_libs: 633*90c8c64dSAndroid Build Coastguard Worker print("### WARNING: Crates with depend on static or shared " 634*90c8c64dSAndroid Build Coastguard Worker "libraries are not supported") 635*90c8c64dSAndroid Build Coastguard Worker 636*90c8c64dSAndroid Build Coastguard Worker def main_src_basename_path(self): 637*90c8c64dSAndroid Build Coastguard Worker return re.sub("/", "_", re.sub(".rs$", "", self.main_src)) 638*90c8c64dSAndroid Build Coastguard Worker 639*90c8c64dSAndroid Build Coastguard Worker def test_module_name(self): 640*90c8c64dSAndroid Build Coastguard Worker """Return a unique name for a test module.""" 641*90c8c64dSAndroid Build Coastguard Worker # root_pkg+(_host|_device) + '_test_'+source_file_name 642*90c8c64dSAndroid Build Coastguard Worker suffix = self.main_src_basename_path() 643*90c8c64dSAndroid Build Coastguard Worker return self.root_pkg + "_test_" + suffix 644*90c8c64dSAndroid Build Coastguard Worker 645*90c8c64dSAndroid Build Coastguard Worker def dump_core_properties(self): 646*90c8c64dSAndroid Build Coastguard Worker """Dump the module header, name, stem, etc.""" 647*90c8c64dSAndroid Build Coastguard Worker self.write("LOCAL_DIR := $(GET_LOCAL_DIR)") 648*90c8c64dSAndroid Build Coastguard Worker self.write("MODULE := $(LOCAL_DIR)") 649*90c8c64dSAndroid Build Coastguard Worker self.write(f"MODULE_CRATE_NAME := {self.crate_name}") 650*90c8c64dSAndroid Build Coastguard Worker 651*90c8c64dSAndroid Build Coastguard Worker # Trusty's module system only supports bin, rlib, and proc-macro so map 652*90c8c64dSAndroid Build Coastguard Worker # lib->rlib 653*90c8c64dSAndroid Build Coastguard Worker if self.crate_types != ["lib"]: 654*90c8c64dSAndroid Build Coastguard Worker crate_types = set( 655*90c8c64dSAndroid Build Coastguard Worker "rlib" if ct == "lib" else ct for ct in self.crate_types 656*90c8c64dSAndroid Build Coastguard Worker ) 657*90c8c64dSAndroid Build Coastguard Worker self.write(f'MODULE_RUST_CRATE_TYPES := {" ".join(crate_types)}') 658*90c8c64dSAndroid Build Coastguard Worker 659*90c8c64dSAndroid Build Coastguard Worker if not self.default_srcs: 660*90c8c64dSAndroid Build Coastguard Worker self.dump_srcs_list() 661*90c8c64dSAndroid Build Coastguard Worker 662*90c8c64dSAndroid Build Coastguard Worker if hasattr(self.runner.args, "module_add_implicit_deps"): 663*90c8c64dSAndroid Build Coastguard Worker if hasattr(self.runner.args, "module_add_implicit_deps_reason"): 664*90c8c64dSAndroid Build Coastguard Worker self.write(self.runner.args.module_add_implicit_deps_reason) 665*90c8c64dSAndroid Build Coastguard Worker 666*90c8c64dSAndroid Build Coastguard Worker if self.runner.args.module_add_implicit_deps in [True, "yes"]: 667*90c8c64dSAndroid Build Coastguard Worker self.write("MODULE_ADD_IMPLICIT_DEPS := true") 668*90c8c64dSAndroid Build Coastguard Worker elif self.runner.args.module_add_implicit_deps in [False, "no"]: 669*90c8c64dSAndroid Build Coastguard Worker self.write("MODULE_ADD_IMPLICIT_DEPS := false") 670*90c8c64dSAndroid Build Coastguard Worker else: 671*90c8c64dSAndroid Build Coastguard Worker sys.exit( 672*90c8c64dSAndroid Build Coastguard Worker "ERROR: invalid value for module_add_implicit_deps: " + 673*90c8c64dSAndroid Build Coastguard Worker str(self.runner.args.module_add_implicit_deps) 674*90c8c64dSAndroid Build Coastguard Worker ) 675*90c8c64dSAndroid Build Coastguard Worker 676*90c8c64dSAndroid Build Coastguard Worker 677*90c8c64dSAndroid Build Coastguard Workerclass Runner(object): 678*90c8c64dSAndroid Build Coastguard Worker """Main class to parse cargo -v output and print Trusty makefile modules.""" 679*90c8c64dSAndroid Build Coastguard Worker 680*90c8c64dSAndroid Build Coastguard Worker def __init__(self, args): 681*90c8c64dSAndroid Build Coastguard Worker self.mk_files = set() # Remember all Trusty module files. 682*90c8c64dSAndroid Build Coastguard Worker self.root_pkg = "" # name of package in ./Cargo.toml 683*90c8c64dSAndroid Build Coastguard Worker # Saved flags, modes, and data. 684*90c8c64dSAndroid Build Coastguard Worker self.args = args 685*90c8c64dSAndroid Build Coastguard Worker self.dry_run = not args.run 686*90c8c64dSAndroid Build Coastguard Worker self.skip_cargo = args.skipcargo 687*90c8c64dSAndroid Build Coastguard Worker self.cargo_path = "./cargo" # path to cargo, will be set later 688*90c8c64dSAndroid Build Coastguard Worker self.checked_out_files = False # to check only once 689*90c8c64dSAndroid Build Coastguard Worker self.build_out_files = [] # output files generated by build.rs 690*90c8c64dSAndroid Build Coastguard Worker self.crates: List[Crate] = [] 691*90c8c64dSAndroid Build Coastguard Worker self.warning_files = set() 692*90c8c64dSAndroid Build Coastguard Worker # Keep a unique mapping from (module name) to crate 693*90c8c64dSAndroid Build Coastguard Worker self.name_owners = {} 694*90c8c64dSAndroid Build Coastguard Worker # Save and dump all errors from cargo to rules.mk. 695*90c8c64dSAndroid Build Coastguard Worker self.errors = "" 696*90c8c64dSAndroid Build Coastguard Worker self.test_errors = "" 697*90c8c64dSAndroid Build Coastguard Worker self.setup_cargo_path() 698*90c8c64dSAndroid Build Coastguard Worker # Default action is cargo clean, followed by build or user given actions 699*90c8c64dSAndroid Build Coastguard Worker if args.cargo: 700*90c8c64dSAndroid Build Coastguard Worker self.cargo = ["clean"] + args.cargo 701*90c8c64dSAndroid Build Coastguard Worker else: 702*90c8c64dSAndroid Build Coastguard Worker default_target = "--target x86_64-unknown-linux-gnu" 703*90c8c64dSAndroid Build Coastguard Worker # Use the same target for both host and default device builds. 704*90c8c64dSAndroid Build Coastguard Worker # Same target is used as default in host x86_64 Android compilation. 705*90c8c64dSAndroid Build Coastguard Worker # Note: b/169872957, prebuilt cargo failed to build vsock 706*90c8c64dSAndroid Build Coastguard Worker # on x86_64-unknown-linux-musl systems. 707*90c8c64dSAndroid Build Coastguard Worker self.cargo = ["clean", "build " + default_target] 708*90c8c64dSAndroid Build Coastguard Worker if args.tests: 709*90c8c64dSAndroid Build Coastguard Worker self.cargo.append("build --tests " + default_target) 710*90c8c64dSAndroid Build Coastguard Worker self.empty_tests = set() 711*90c8c64dSAndroid Build Coastguard Worker self.empty_unittests = False 712*90c8c64dSAndroid Build Coastguard Worker 713*90c8c64dSAndroid Build Coastguard Worker def setup_cargo_path(self): 714*90c8c64dSAndroid Build Coastguard Worker """Find cargo in the --cargo_bin or prebuilt rust bin directory.""" 715*90c8c64dSAndroid Build Coastguard Worker if self.args.cargo_bin: 716*90c8c64dSAndroid Build Coastguard Worker self.cargo_path = os.path.join(self.args.cargo_bin, "cargo") 717*90c8c64dSAndroid Build Coastguard Worker if not os.path.isfile(self.cargo_path): 718*90c8c64dSAndroid Build Coastguard Worker sys.exit("ERROR: cannot find cargo in " + self.args.cargo_bin) 719*90c8c64dSAndroid Build Coastguard Worker print("INFO: using cargo in " + self.args.cargo_bin) 720*90c8c64dSAndroid Build Coastguard Worker return 721*90c8c64dSAndroid Build Coastguard Worker 722*90c8c64dSAndroid Build Coastguard Worker # We have only tested this on Linux. 723*90c8c64dSAndroid Build Coastguard Worker if platform.system() != "Linux": 724*90c8c64dSAndroid Build Coastguard Worker sys.exit( 725*90c8c64dSAndroid Build Coastguard Worker "ERROR: this script has only been tested on Linux with cargo." 726*90c8c64dSAndroid Build Coastguard Worker ) 727*90c8c64dSAndroid Build Coastguard Worker 728*90c8c64dSAndroid Build Coastguard Worker # Assuming that this script is in development/scripts 729*90c8c64dSAndroid Build Coastguard Worker env_setup_sh = os.path.join( 730*90c8c64dSAndroid Build Coastguard Worker TOP_DIR, "trusty/vendor/google/aosp/scripts/envsetup.sh" 731*90c8c64dSAndroid Build Coastguard Worker ) 732*90c8c64dSAndroid Build Coastguard Worker if not os.path.exists(env_setup_sh): 733*90c8c64dSAndroid Build Coastguard Worker sys.exit("ERROR: missing " + env_setup_sh) 734*90c8c64dSAndroid Build Coastguard Worker rust_version = self.find_rust_version(env_setup_sh) 735*90c8c64dSAndroid Build Coastguard Worker self.cargo_path = os.path.join( 736*90c8c64dSAndroid Build Coastguard Worker TOP_DIR, f"prebuilts/rust/linux-x86/{rust_version}/bin/cargo" 737*90c8c64dSAndroid Build Coastguard Worker ) 738*90c8c64dSAndroid Build Coastguard Worker 739*90c8c64dSAndroid Build Coastguard Worker if not os.path.isfile(self.cargo_path): 740*90c8c64dSAndroid Build Coastguard Worker sys.exit( 741*90c8c64dSAndroid Build Coastguard Worker "ERROR: no cargo at " 742*90c8c64dSAndroid Build Coastguard Worker + self.cargo_path 743*90c8c64dSAndroid Build Coastguard Worker + "; consider using the --cargo_bin= flag." 744*90c8c64dSAndroid Build Coastguard Worker ) 745*90c8c64dSAndroid Build Coastguard Worker 746*90c8c64dSAndroid Build Coastguard Worker if self.args.verbose: 747*90c8c64dSAndroid Build Coastguard Worker print(f"### INFO: using cargo from {self.cargo_path}") 748*90c8c64dSAndroid Build Coastguard Worker 749*90c8c64dSAndroid Build Coastguard Worker def find_rust_version(self, env_setup_sh): 750*90c8c64dSAndroid Build Coastguard Worker """find the Rust version used by Trusty from envsetup.sh""" 751*90c8c64dSAndroid Build Coastguard Worker 752*90c8c64dSAndroid Build Coastguard Worker version_pat = re.compile(r"prebuilts/rust/linux-x86/([0-9]+\.[0-9]+\..+)/bin") 753*90c8c64dSAndroid Build Coastguard Worker 754*90c8c64dSAndroid Build Coastguard Worker with open(env_setup_sh) as fh: 755*90c8c64dSAndroid Build Coastguard Worker for line in fh.readlines(): 756*90c8c64dSAndroid Build Coastguard Worker if line.lstrip().startswith("export RUST_BINDIR"): 757*90c8c64dSAndroid Build Coastguard Worker if not (result := version_pat.search(line)): 758*90c8c64dSAndroid Build Coastguard Worker sys.exit("ERROR: failed to parse rust version " 759*90c8c64dSAndroid Build Coastguard Worker + "from RUST_BINDIR in envsetup.sh: " 760*90c8c64dSAndroid Build Coastguard Worker + line 761*90c8c64dSAndroid Build Coastguard Worker ) 762*90c8c64dSAndroid Build Coastguard Worker version = result.group(1) 763*90c8c64dSAndroid Build Coastguard Worker 764*90c8c64dSAndroid Build Coastguard Worker if self.args.verbose: 765*90c8c64dSAndroid Build Coastguard Worker print(f"### INFO: using rust version {version}") 766*90c8c64dSAndroid Build Coastguard Worker 767*90c8c64dSAndroid Build Coastguard Worker return version 768*90c8c64dSAndroid Build Coastguard Worker 769*90c8c64dSAndroid Build Coastguard Worker sys.exit("ERROR: failed to parse {env_setup_sh}; is RUST_BINDIR exported?") 770*90c8c64dSAndroid Build Coastguard Worker 771*90c8c64dSAndroid Build Coastguard Worker def find_out_files(self): 772*90c8c64dSAndroid Build Coastguard Worker # list1 has build.rs output for normal crates 773*90c8c64dSAndroid Build Coastguard Worker list1 = glob.glob( 774*90c8c64dSAndroid Build Coastguard Worker TARGET_TMP + "/*/*/build/" + self.root_pkg + "-*/out/*" 775*90c8c64dSAndroid Build Coastguard Worker ) 776*90c8c64dSAndroid Build Coastguard Worker # list2 has build.rs output for proc-macro crates 777*90c8c64dSAndroid Build Coastguard Worker list2 = glob.glob(TARGET_TMP + "/*/build/" + self.root_pkg + "-*/out/*") 778*90c8c64dSAndroid Build Coastguard Worker return list1 + list2 779*90c8c64dSAndroid Build Coastguard Worker 780*90c8c64dSAndroid Build Coastguard Worker def copy_out_files(self): 781*90c8c64dSAndroid Build Coastguard Worker """Copy build.rs output files to ./out and set up build_out_files.""" 782*90c8c64dSAndroid Build Coastguard Worker if self.checked_out_files: 783*90c8c64dSAndroid Build Coastguard Worker return 784*90c8c64dSAndroid Build Coastguard Worker self.checked_out_files = True 785*90c8c64dSAndroid Build Coastguard Worker cargo_out_files = self.find_out_files() 786*90c8c64dSAndroid Build Coastguard Worker out_files = set() 787*90c8c64dSAndroid Build Coastguard Worker if cargo_out_files: 788*90c8c64dSAndroid Build Coastguard Worker os.makedirs("out", exist_ok=True) 789*90c8c64dSAndroid Build Coastguard Worker for path in cargo_out_files: 790*90c8c64dSAndroid Build Coastguard Worker file_name = path.split("/")[-1] 791*90c8c64dSAndroid Build Coastguard Worker out_files.add(file_name) 792*90c8c64dSAndroid Build Coastguard Worker shutil.copy(path, "out/" + file_name) 793*90c8c64dSAndroid Build Coastguard Worker self.build_out_files = sorted(out_files) 794*90c8c64dSAndroid Build Coastguard Worker 795*90c8c64dSAndroid Build Coastguard Worker def has_used_out_dir(self): 796*90c8c64dSAndroid Build Coastguard Worker """Returns true if env!("OUT_DIR") is found.""" 797*90c8c64dSAndroid Build Coastguard Worker return 0 == os.system( 798*90c8c64dSAndroid Build Coastguard Worker "grep -rl --exclude build.rs --include \\*.rs" 799*90c8c64dSAndroid Build Coastguard Worker + " 'env!(\"OUT_DIR\")' * > /dev/null" 800*90c8c64dSAndroid Build Coastguard Worker ) 801*90c8c64dSAndroid Build Coastguard Worker 802*90c8c64dSAndroid Build Coastguard Worker def init_rules_file(self, name): 803*90c8c64dSAndroid Build Coastguard Worker # name could be rules.mk or sub_dir_path/rules.mk 804*90c8c64dSAndroid Build Coastguard Worker if name not in self.mk_files: 805*90c8c64dSAndroid Build Coastguard Worker self.mk_files.add(name) 806*90c8c64dSAndroid Build Coastguard Worker with open(name, "w", encoding="utf-8") as outf: 807*90c8c64dSAndroid Build Coastguard Worker print_args = sys.argv[1:].copy() 808*90c8c64dSAndroid Build Coastguard Worker if "--cargo_bin" in print_args: 809*90c8c64dSAndroid Build Coastguard Worker index = print_args.index("--cargo_bin") 810*90c8c64dSAndroid Build Coastguard Worker del print_args[index : index + 2] 811*90c8c64dSAndroid Build Coastguard Worker outf.write(RULES_MK_HEADER.format(args=" ".join(print_args))) 812*90c8c64dSAndroid Build Coastguard Worker 813*90c8c64dSAndroid Build Coastguard Worker def find_root_pkg(self): 814*90c8c64dSAndroid Build Coastguard Worker """Read name of [package] in ./Cargo.toml.""" 815*90c8c64dSAndroid Build Coastguard Worker if not os.path.exists("./Cargo.toml"): 816*90c8c64dSAndroid Build Coastguard Worker return 817*90c8c64dSAndroid Build Coastguard Worker with open("./Cargo.toml", "r", encoding="utf-8") as inf: 818*90c8c64dSAndroid Build Coastguard Worker pkg_section = re.compile(r"^ *\[package\]") 819*90c8c64dSAndroid Build Coastguard Worker name = re.compile('^ *name *= * "([^"]*)"') 820*90c8c64dSAndroid Build Coastguard Worker in_pkg = False 821*90c8c64dSAndroid Build Coastguard Worker for line in inf: 822*90c8c64dSAndroid Build Coastguard Worker if in_pkg: 823*90c8c64dSAndroid Build Coastguard Worker if match := name.match(line): 824*90c8c64dSAndroid Build Coastguard Worker self.root_pkg = match.group(1) 825*90c8c64dSAndroid Build Coastguard Worker break 826*90c8c64dSAndroid Build Coastguard Worker else: 827*90c8c64dSAndroid Build Coastguard Worker in_pkg = pkg_section.match(line) is not None 828*90c8c64dSAndroid Build Coastguard Worker 829*90c8c64dSAndroid Build Coastguard Worker def run_cargo(self): 830*90c8c64dSAndroid Build Coastguard Worker """Calls cargo -v and save its output to ./cargo.out.""" 831*90c8c64dSAndroid Build Coastguard Worker if self.skip_cargo: 832*90c8c64dSAndroid Build Coastguard Worker return self 833*90c8c64dSAndroid Build Coastguard Worker cargo_toml = "./Cargo.toml" 834*90c8c64dSAndroid Build Coastguard Worker cargo_out = "./cargo.out" 835*90c8c64dSAndroid Build Coastguard Worker 836*90c8c64dSAndroid Build Coastguard Worker # Do not use Cargo.lock, because Trusty makefile rules are designed 837*90c8c64dSAndroid Build Coastguard Worker # to run with the latest available vendored crates in Trusty. 838*90c8c64dSAndroid Build Coastguard Worker cargo_lock = "./Cargo.lock" 839*90c8c64dSAndroid Build Coastguard Worker cargo_lock_saved = "./cargo.lock.saved" 840*90c8c64dSAndroid Build Coastguard Worker had_cargo_lock = os.path.exists(cargo_lock) 841*90c8c64dSAndroid Build Coastguard Worker if not os.access(cargo_toml, os.R_OK): 842*90c8c64dSAndroid Build Coastguard Worker print("ERROR: Cannot find or read", cargo_toml) 843*90c8c64dSAndroid Build Coastguard Worker return self 844*90c8c64dSAndroid Build Coastguard Worker if not self.dry_run: 845*90c8c64dSAndroid Build Coastguard Worker if os.path.exists(cargo_out): 846*90c8c64dSAndroid Build Coastguard Worker os.remove(cargo_out) 847*90c8c64dSAndroid Build Coastguard Worker if not self.args.use_cargo_lock and had_cargo_lock: # save it 848*90c8c64dSAndroid Build Coastguard Worker os.rename(cargo_lock, cargo_lock_saved) 849*90c8c64dSAndroid Build Coastguard Worker cmd_tail_target = " --target-dir " + TARGET_TMP 850*90c8c64dSAndroid Build Coastguard Worker cmd_tail_redir = " >> " + cargo_out + " 2>&1" 851*90c8c64dSAndroid Build Coastguard Worker # set up search PATH for cargo to find the correct rustc 852*90c8c64dSAndroid Build Coastguard Worker saved_path = os.environ["PATH"] 853*90c8c64dSAndroid Build Coastguard Worker os.environ["PATH"] = os.path.dirname(self.cargo_path) + ":" + saved_path 854*90c8c64dSAndroid Build Coastguard Worker # Add [workspace] to Cargo.toml if it is not there. 855*90c8c64dSAndroid Build Coastguard Worker added_workspace = False 856*90c8c64dSAndroid Build Coastguard Worker cargo_toml_lines = None 857*90c8c64dSAndroid Build Coastguard Worker if self.args.add_workspace: 858*90c8c64dSAndroid Build Coastguard Worker with open(cargo_toml, "r", encoding="utf-8") as in_file: 859*90c8c64dSAndroid Build Coastguard Worker cargo_toml_lines = in_file.readlines() 860*90c8c64dSAndroid Build Coastguard Worker found_workspace = "[workspace]\n" in cargo_toml_lines 861*90c8c64dSAndroid Build Coastguard Worker if found_workspace: 862*90c8c64dSAndroid Build Coastguard Worker print("### WARNING: found [workspace] in Cargo.toml") 863*90c8c64dSAndroid Build Coastguard Worker else: 864*90c8c64dSAndroid Build Coastguard Worker with open(cargo_toml, "a", encoding="utf-8") as out_file: 865*90c8c64dSAndroid Build Coastguard Worker out_file.write("\n\n[workspace]\n") 866*90c8c64dSAndroid Build Coastguard Worker added_workspace = True 867*90c8c64dSAndroid Build Coastguard Worker if self.args.verbose: 868*90c8c64dSAndroid Build Coastguard Worker print("### INFO: added [workspace] to Cargo.toml") 869*90c8c64dSAndroid Build Coastguard Worker features = "" 870*90c8c64dSAndroid Build Coastguard Worker for c in self.cargo: 871*90c8c64dSAndroid Build Coastguard Worker features = "" 872*90c8c64dSAndroid Build Coastguard Worker if c != "clean": 873*90c8c64dSAndroid Build Coastguard Worker if self.args.features is not None: 874*90c8c64dSAndroid Build Coastguard Worker features = " --no-default-features" 875*90c8c64dSAndroid Build Coastguard Worker if self.args.features: 876*90c8c64dSAndroid Build Coastguard Worker features += " --features " + self.args.features 877*90c8c64dSAndroid Build Coastguard Worker cmd_v_flag = " -vv " if self.args.vv else " -v " 878*90c8c64dSAndroid Build Coastguard Worker cmd = self.cargo_path + cmd_v_flag 879*90c8c64dSAndroid Build Coastguard Worker cmd += c + features + cmd_tail_target + cmd_tail_redir 880*90c8c64dSAndroid Build Coastguard Worker if c != "clean": 881*90c8c64dSAndroid Build Coastguard Worker rustflags = self.args.rustflags if self.args.rustflags else "" 882*90c8c64dSAndroid Build Coastguard Worker # linting issues shouldn't prevent us from generating rules.mk 883*90c8c64dSAndroid Build Coastguard Worker rustflags = f'RUSTFLAGS="{rustflags} --cap-lints allow" ' 884*90c8c64dSAndroid Build Coastguard Worker cmd = rustflags + cmd 885*90c8c64dSAndroid Build Coastguard Worker self.run_cmd(cmd, cargo_out) 886*90c8c64dSAndroid Build Coastguard Worker if self.args.tests: 887*90c8c64dSAndroid Build Coastguard Worker cmd = ( 888*90c8c64dSAndroid Build Coastguard Worker self.cargo_path 889*90c8c64dSAndroid Build Coastguard Worker + " test" 890*90c8c64dSAndroid Build Coastguard Worker + features 891*90c8c64dSAndroid Build Coastguard Worker + cmd_tail_target 892*90c8c64dSAndroid Build Coastguard Worker + " -- --list" 893*90c8c64dSAndroid Build Coastguard Worker + cmd_tail_redir 894*90c8c64dSAndroid Build Coastguard Worker ) 895*90c8c64dSAndroid Build Coastguard Worker self.run_cmd(cmd, cargo_out) 896*90c8c64dSAndroid Build Coastguard Worker if added_workspace: # restore original Cargo.toml 897*90c8c64dSAndroid Build Coastguard Worker with open(cargo_toml, "w", encoding="utf-8") as out_file: 898*90c8c64dSAndroid Build Coastguard Worker assert cargo_toml_lines 899*90c8c64dSAndroid Build Coastguard Worker out_file.writelines(cargo_toml_lines) 900*90c8c64dSAndroid Build Coastguard Worker if self.args.verbose: 901*90c8c64dSAndroid Build Coastguard Worker print("### INFO: restored original Cargo.toml") 902*90c8c64dSAndroid Build Coastguard Worker os.environ["PATH"] = saved_path 903*90c8c64dSAndroid Build Coastguard Worker if not self.dry_run: 904*90c8c64dSAndroid Build Coastguard Worker if not had_cargo_lock: # restore to no Cargo.lock state 905*90c8c64dSAndroid Build Coastguard Worker if os.path.exists(cargo_lock): 906*90c8c64dSAndroid Build Coastguard Worker os.remove(cargo_lock) 907*90c8c64dSAndroid Build Coastguard Worker elif not self.args.use_cargo_lock: # restore saved Cargo.lock 908*90c8c64dSAndroid Build Coastguard Worker os.rename(cargo_lock_saved, cargo_lock) 909*90c8c64dSAndroid Build Coastguard Worker return self 910*90c8c64dSAndroid Build Coastguard Worker 911*90c8c64dSAndroid Build Coastguard Worker def run_cmd(self, cmd, cargo_out): 912*90c8c64dSAndroid Build Coastguard Worker if self.dry_run: 913*90c8c64dSAndroid Build Coastguard Worker print("Dry-run skip:", cmd) 914*90c8c64dSAndroid Build Coastguard Worker else: 915*90c8c64dSAndroid Build Coastguard Worker if self.args.verbose: 916*90c8c64dSAndroid Build Coastguard Worker print("Running:", cmd) 917*90c8c64dSAndroid Build Coastguard Worker with open(cargo_out, "a+", encoding="utf-8") as out_file: 918*90c8c64dSAndroid Build Coastguard Worker out_file.write("### Running: " + cmd + "\n") 919*90c8c64dSAndroid Build Coastguard Worker ret = os.system(cmd) 920*90c8c64dSAndroid Build Coastguard Worker if ret != 0: 921*90c8c64dSAndroid Build Coastguard Worker print( 922*90c8c64dSAndroid Build Coastguard Worker "*** There was an error while running cargo. " 923*90c8c64dSAndroid Build Coastguard Worker + f"See the {cargo_out} file for details." 924*90c8c64dSAndroid Build Coastguard Worker ) 925*90c8c64dSAndroid Build Coastguard Worker 926*90c8c64dSAndroid Build Coastguard Worker def apply_patch(self): 927*90c8c64dSAndroid Build Coastguard Worker """Apply local patch file if it is given.""" 928*90c8c64dSAndroid Build Coastguard Worker if self.args.patch: 929*90c8c64dSAndroid Build Coastguard Worker if self.dry_run: 930*90c8c64dSAndroid Build Coastguard Worker print("Dry-run skip patch file:", self.args.patch) 931*90c8c64dSAndroid Build Coastguard Worker else: 932*90c8c64dSAndroid Build Coastguard Worker if not os.path.exists(self.args.patch): 933*90c8c64dSAndroid Build Coastguard Worker self.append_to_rules( 934*90c8c64dSAndroid Build Coastguard Worker "ERROR cannot find patch file: " + self.args.patch 935*90c8c64dSAndroid Build Coastguard Worker ) 936*90c8c64dSAndroid Build Coastguard Worker return self 937*90c8c64dSAndroid Build Coastguard Worker if self.args.verbose: 938*90c8c64dSAndroid Build Coastguard Worker print( 939*90c8c64dSAndroid Build Coastguard Worker "### INFO: applying local patch file:", self.args.patch 940*90c8c64dSAndroid Build Coastguard Worker ) 941*90c8c64dSAndroid Build Coastguard Worker subprocess.run( 942*90c8c64dSAndroid Build Coastguard Worker [ 943*90c8c64dSAndroid Build Coastguard Worker "patch", 944*90c8c64dSAndroid Build Coastguard Worker "-s", 945*90c8c64dSAndroid Build Coastguard Worker "--no-backup-if-mismatch", 946*90c8c64dSAndroid Build Coastguard Worker "./rules.mk", 947*90c8c64dSAndroid Build Coastguard Worker self.args.patch, 948*90c8c64dSAndroid Build Coastguard Worker ], 949*90c8c64dSAndroid Build Coastguard Worker check=True, 950*90c8c64dSAndroid Build Coastguard Worker ) 951*90c8c64dSAndroid Build Coastguard Worker return self 952*90c8c64dSAndroid Build Coastguard Worker 953*90c8c64dSAndroid Build Coastguard Worker def gen_rules(self): 954*90c8c64dSAndroid Build Coastguard Worker """Parse cargo.out and generate Trusty makefile rules""" 955*90c8c64dSAndroid Build Coastguard Worker if self.dry_run: 956*90c8c64dSAndroid Build Coastguard Worker print("Dry-run skip: read", CARGO_OUT, "write rules.mk") 957*90c8c64dSAndroid Build Coastguard Worker elif os.path.exists(CARGO_OUT): 958*90c8c64dSAndroid Build Coastguard Worker self.find_root_pkg() 959*90c8c64dSAndroid Build Coastguard Worker if self.args.copy_out: 960*90c8c64dSAndroid Build Coastguard Worker self.copy_out_files() 961*90c8c64dSAndroid Build Coastguard Worker elif self.find_out_files() and self.has_used_out_dir(): 962*90c8c64dSAndroid Build Coastguard Worker print( 963*90c8c64dSAndroid Build Coastguard Worker "WARNING: " 964*90c8c64dSAndroid Build Coastguard Worker + self.root_pkg 965*90c8c64dSAndroid Build Coastguard Worker + " has cargo output files; " 966*90c8c64dSAndroid Build Coastguard Worker + "please rerun with the --copy-out flag." 967*90c8c64dSAndroid Build Coastguard Worker ) 968*90c8c64dSAndroid Build Coastguard Worker with open(CARGO_OUT, "r", encoding="utf-8") as cargo_out: 969*90c8c64dSAndroid Build Coastguard Worker self.parse(cargo_out, "rules.mk") 970*90c8c64dSAndroid Build Coastguard Worker self.crates.sort(key=get_module_name) 971*90c8c64dSAndroid Build Coastguard Worker for crate in self.crates: 972*90c8c64dSAndroid Build Coastguard Worker crate.dump() 973*90c8c64dSAndroid Build Coastguard Worker if self.errors: 974*90c8c64dSAndroid Build Coastguard Worker self.append_to_rules("\n" + ERRORS_LINE + "\n" + self.errors) 975*90c8c64dSAndroid Build Coastguard Worker if self.test_errors: 976*90c8c64dSAndroid Build Coastguard Worker self.append_to_rules( 977*90c8c64dSAndroid Build Coastguard Worker "\n// Errors when listing tests:\n" + self.test_errors 978*90c8c64dSAndroid Build Coastguard Worker ) 979*90c8c64dSAndroid Build Coastguard Worker return self 980*90c8c64dSAndroid Build Coastguard Worker 981*90c8c64dSAndroid Build Coastguard Worker def add_crate(self, crate: Crate): 982*90c8c64dSAndroid Build Coastguard Worker """Append crate to list unless it meets criteria for being skipped.""" 983*90c8c64dSAndroid Build Coastguard Worker if crate.skip_crate(): 984*90c8c64dSAndroid Build Coastguard Worker if self.args.debug: # include debug info of all crates 985*90c8c64dSAndroid Build Coastguard Worker self.crates.append(crate) 986*90c8c64dSAndroid Build Coastguard Worker elif crate.crate_types == set(["bin"]): 987*90c8c64dSAndroid Build Coastguard Worker print("WARNING: skipping binary crate: " + crate.crate_name) 988*90c8c64dSAndroid Build Coastguard Worker else: 989*90c8c64dSAndroid Build Coastguard Worker self.crates.append(crate) 990*90c8c64dSAndroid Build Coastguard Worker 991*90c8c64dSAndroid Build Coastguard Worker def find_warning_owners(self): 992*90c8c64dSAndroid Build Coastguard Worker """For each warning file, find its owner crate.""" 993*90c8c64dSAndroid Build Coastguard Worker missing_owner = False 994*90c8c64dSAndroid Build Coastguard Worker for f in self.warning_files: 995*90c8c64dSAndroid Build Coastguard Worker cargo_dir = "" # find lowest crate, with longest path 996*90c8c64dSAndroid Build Coastguard Worker owner = None # owner crate of this warning 997*90c8c64dSAndroid Build Coastguard Worker for c in self.crates: 998*90c8c64dSAndroid Build Coastguard Worker if f.startswith(c.cargo_dir + "/") and len(cargo_dir) < len( 999*90c8c64dSAndroid Build Coastguard Worker c.cargo_dir 1000*90c8c64dSAndroid Build Coastguard Worker ): 1001*90c8c64dSAndroid Build Coastguard Worker cargo_dir = c.cargo_dir 1002*90c8c64dSAndroid Build Coastguard Worker owner = c 1003*90c8c64dSAndroid Build Coastguard Worker if owner: 1004*90c8c64dSAndroid Build Coastguard Worker owner.has_warning = True 1005*90c8c64dSAndroid Build Coastguard Worker else: 1006*90c8c64dSAndroid Build Coastguard Worker missing_owner = True 1007*90c8c64dSAndroid Build Coastguard Worker if missing_owner and os.path.exists("Cargo.toml"): 1008*90c8c64dSAndroid Build Coastguard Worker # owner is the root cargo, with empty cargo_dir 1009*90c8c64dSAndroid Build Coastguard Worker for c in self.crates: 1010*90c8c64dSAndroid Build Coastguard Worker if not c.cargo_dir: 1011*90c8c64dSAndroid Build Coastguard Worker c.has_warning = True 1012*90c8c64dSAndroid Build Coastguard Worker 1013*90c8c64dSAndroid Build Coastguard Worker def rustc_command(self, n, rustc_line, line, outf_name): 1014*90c8c64dSAndroid Build Coastguard Worker """Process a rustc command line from cargo -vv output.""" 1015*90c8c64dSAndroid Build Coastguard Worker # cargo build -vv output can have multiple lines for a rustc command 1016*90c8c64dSAndroid Build Coastguard Worker # due to '\n' in strings for environment variables. 1017*90c8c64dSAndroid Build Coastguard Worker # strip removes leading spaces and '\n' at the end 1018*90c8c64dSAndroid Build Coastguard Worker new_rustc = (rustc_line.strip() + line) if rustc_line else line 1019*90c8c64dSAndroid Build Coastguard Worker # Use an heuristic to detect the completions of a multi-line command. 1020*90c8c64dSAndroid Build Coastguard Worker # This might fail for some very rare case, but easy to fix manually. 1021*90c8c64dSAndroid Build Coastguard Worker if not line.endswith("`\n") or (new_rustc.count("`") % 2) != 0: 1022*90c8c64dSAndroid Build Coastguard Worker return new_rustc 1023*90c8c64dSAndroid Build Coastguard Worker if match := RUSTC_VV_CMD_ARGS.match(new_rustc): 1024*90c8c64dSAndroid Build Coastguard Worker args = match.group(2) 1025*90c8c64dSAndroid Build Coastguard Worker self.add_crate(Crate(self, outf_name).parse(n, args)) 1026*90c8c64dSAndroid Build Coastguard Worker else: 1027*90c8c64dSAndroid Build Coastguard Worker self.assert_empty_vv_line(new_rustc) 1028*90c8c64dSAndroid Build Coastguard Worker return "" 1029*90c8c64dSAndroid Build Coastguard Worker 1030*90c8c64dSAndroid Build Coastguard Worker def append_to_rules(self, line): 1031*90c8c64dSAndroid Build Coastguard Worker self.init_rules_file("rules.mk") 1032*90c8c64dSAndroid Build Coastguard Worker with open("rules.mk", "a", encoding="utf-8") as outf: 1033*90c8c64dSAndroid Build Coastguard Worker outf.write(line) 1034*90c8c64dSAndroid Build Coastguard Worker 1035*90c8c64dSAndroid Build Coastguard Worker def assert_empty_vv_line(self, line): 1036*90c8c64dSAndroid Build Coastguard Worker if line: # report error if line is not empty 1037*90c8c64dSAndroid Build Coastguard Worker self.append_to_rules("ERROR -vv line: " + line) 1038*90c8c64dSAndroid Build Coastguard Worker return "" 1039*90c8c64dSAndroid Build Coastguard Worker 1040*90c8c64dSAndroid Build Coastguard Worker def add_empty_test(self, name): 1041*90c8c64dSAndroid Build Coastguard Worker if name.startswith("unittests"): 1042*90c8c64dSAndroid Build Coastguard Worker self.empty_unittests = True 1043*90c8c64dSAndroid Build Coastguard Worker else: 1044*90c8c64dSAndroid Build Coastguard Worker self.empty_tests.add(name) 1045*90c8c64dSAndroid Build Coastguard Worker 1046*90c8c64dSAndroid Build Coastguard Worker def should_ignore_test(self, src): 1047*90c8c64dSAndroid Build Coastguard Worker # cargo test outputs the source file for integration tests but 1048*90c8c64dSAndroid Build Coastguard Worker # "unittests" for unit tests. To figure out to which crate this 1049*90c8c64dSAndroid Build Coastguard Worker # corresponds, we check if the current source file is the main source of 1050*90c8c64dSAndroid Build Coastguard Worker # a non-test crate, e.g., a library or a binary. 1051*90c8c64dSAndroid Build Coastguard Worker return ( 1052*90c8c64dSAndroid Build Coastguard Worker src in self.args.test_blocklist 1053*90c8c64dSAndroid Build Coastguard Worker or src in self.empty_tests 1054*90c8c64dSAndroid Build Coastguard Worker or ( 1055*90c8c64dSAndroid Build Coastguard Worker self.empty_unittests 1056*90c8c64dSAndroid Build Coastguard Worker and src 1057*90c8c64dSAndroid Build Coastguard Worker in [ 1058*90c8c64dSAndroid Build Coastguard Worker c.main_src for c in self.crates if c.crate_types != ["test"] 1059*90c8c64dSAndroid Build Coastguard Worker ] 1060*90c8c64dSAndroid Build Coastguard Worker ) 1061*90c8c64dSAndroid Build Coastguard Worker ) 1062*90c8c64dSAndroid Build Coastguard Worker 1063*90c8c64dSAndroid Build Coastguard Worker def parse(self, inf, outf_name): 1064*90c8c64dSAndroid Build Coastguard Worker """Parse rustc, test, and warning messages in input file.""" 1065*90c8c64dSAndroid Build Coastguard Worker n = 0 # line number 1066*90c8c64dSAndroid Build Coastguard Worker # We read the file in two passes, where the first simply checks for 1067*90c8c64dSAndroid Build Coastguard Worker # empty tests. Otherwise we would add and merge tests before seeing 1068*90c8c64dSAndroid Build Coastguard Worker # they're empty. 1069*90c8c64dSAndroid Build Coastguard Worker cur_test_name = None 1070*90c8c64dSAndroid Build Coastguard Worker for line in inf: 1071*90c8c64dSAndroid Build Coastguard Worker if match := CARGO_TEST_LIST_START_PAT.match(line): 1072*90c8c64dSAndroid Build Coastguard Worker cur_test_name = match.group(1) 1073*90c8c64dSAndroid Build Coastguard Worker elif cur_test_name and ( 1074*90c8c64dSAndroid Build Coastguard Worker match := CARGO_TEST_LIST_END_PAT.match(line) 1075*90c8c64dSAndroid Build Coastguard Worker ): 1076*90c8c64dSAndroid Build Coastguard Worker if int(match.group(1)) + int(match.group(2)) == 0: 1077*90c8c64dSAndroid Build Coastguard Worker self.add_empty_test(cur_test_name) 1078*90c8c64dSAndroid Build Coastguard Worker cur_test_name = None 1079*90c8c64dSAndroid Build Coastguard Worker inf.seek(0) 1080*90c8c64dSAndroid Build Coastguard Worker prev_warning = False # true if the previous line was warning: ... 1081*90c8c64dSAndroid Build Coastguard Worker rustc_line = "" # previous line(s) matching RUSTC_VV_PAT 1082*90c8c64dSAndroid Build Coastguard Worker in_tests = False 1083*90c8c64dSAndroid Build Coastguard Worker for line in inf: 1084*90c8c64dSAndroid Build Coastguard Worker n += 1 1085*90c8c64dSAndroid Build Coastguard Worker if line.startswith("warning: "): 1086*90c8c64dSAndroid Build Coastguard Worker prev_warning = True 1087*90c8c64dSAndroid Build Coastguard Worker rustc_line = self.assert_empty_vv_line(rustc_line) 1088*90c8c64dSAndroid Build Coastguard Worker continue 1089*90c8c64dSAndroid Build Coastguard Worker new_rustc = "" 1090*90c8c64dSAndroid Build Coastguard Worker if match := RUSTC_PAT.match(line): 1091*90c8c64dSAndroid Build Coastguard Worker args_line = match.group(2) 1092*90c8c64dSAndroid Build Coastguard Worker self.add_crate(Crate(self, outf_name).parse(n, args_line)) 1093*90c8c64dSAndroid Build Coastguard Worker self.assert_empty_vv_line(rustc_line) 1094*90c8c64dSAndroid Build Coastguard Worker elif rustc_line or RUSTC_VV_PAT.match(line): 1095*90c8c64dSAndroid Build Coastguard Worker new_rustc = self.rustc_command(n, rustc_line, line, outf_name) 1096*90c8c64dSAndroid Build Coastguard Worker elif CC_AR_VV_PAT.match(line): 1097*90c8c64dSAndroid Build Coastguard Worker raise NotImplementedError("$CC or $AR commands not supported") 1098*90c8c64dSAndroid Build Coastguard Worker elif prev_warning and (match := WARNING_FILE_PAT.match(line)): 1099*90c8c64dSAndroid Build Coastguard Worker self.assert_empty_vv_line(rustc_line) 1100*90c8c64dSAndroid Build Coastguard Worker fpath = match.group(1) 1101*90c8c64dSAndroid Build Coastguard Worker if fpath[0] != "/": # ignore absolute path 1102*90c8c64dSAndroid Build Coastguard Worker self.warning_files.add(fpath) 1103*90c8c64dSAndroid Build Coastguard Worker elif line.startswith("error: ") or line.startswith("error[E"): 1104*90c8c64dSAndroid Build Coastguard Worker if not self.args.ignore_cargo_errors: 1105*90c8c64dSAndroid Build Coastguard Worker if in_tests: 1106*90c8c64dSAndroid Build Coastguard Worker self.test_errors += "// " + line 1107*90c8c64dSAndroid Build Coastguard Worker else: 1108*90c8c64dSAndroid Build Coastguard Worker self.errors += line 1109*90c8c64dSAndroid Build Coastguard Worker elif CARGO2ANDROID_RUNNING_PAT.match(line): 1110*90c8c64dSAndroid Build Coastguard Worker in_tests = "cargo test" in line and "--list" in line 1111*90c8c64dSAndroid Build Coastguard Worker prev_warning = False 1112*90c8c64dSAndroid Build Coastguard Worker rustc_line = new_rustc 1113*90c8c64dSAndroid Build Coastguard Worker self.find_warning_owners() 1114*90c8c64dSAndroid Build Coastguard Worker 1115*90c8c64dSAndroid Build Coastguard Worker 1116*90c8c64dSAndroid Build Coastguard Workerdef get_parser(): 1117*90c8c64dSAndroid Build Coastguard Worker """Parse main arguments.""" 1118*90c8c64dSAndroid Build Coastguard Worker parser = argparse.ArgumentParser("cargo2rulesmk") 1119*90c8c64dSAndroid Build Coastguard Worker parser.add_argument( 1120*90c8c64dSAndroid Build Coastguard Worker "--add_workspace", 1121*90c8c64dSAndroid Build Coastguard Worker action="store_true", 1122*90c8c64dSAndroid Build Coastguard Worker default=False, 1123*90c8c64dSAndroid Build Coastguard Worker help=( 1124*90c8c64dSAndroid Build Coastguard Worker "append [workspace] to Cargo.toml before calling cargo," 1125*90c8c64dSAndroid Build Coastguard Worker + " to treat current directory as root of package source;" 1126*90c8c64dSAndroid Build Coastguard Worker + " otherwise the relative source file path in generated" 1127*90c8c64dSAndroid Build Coastguard Worker + " rules.mk file will be from the parent directory." 1128*90c8c64dSAndroid Build Coastguard Worker ), 1129*90c8c64dSAndroid Build Coastguard Worker ) 1130*90c8c64dSAndroid Build Coastguard Worker parser.add_argument( 1131*90c8c64dSAndroid Build Coastguard Worker "--cargo", 1132*90c8c64dSAndroid Build Coastguard Worker action="append", 1133*90c8c64dSAndroid Build Coastguard Worker metavar="args_string", 1134*90c8c64dSAndroid Build Coastguard Worker help=( 1135*90c8c64dSAndroid Build Coastguard Worker "extra cargo build -v args in a string, " 1136*90c8c64dSAndroid Build Coastguard Worker + "each --cargo flag calls cargo build -v once" 1137*90c8c64dSAndroid Build Coastguard Worker ), 1138*90c8c64dSAndroid Build Coastguard Worker ) 1139*90c8c64dSAndroid Build Coastguard Worker parser.add_argument( 1140*90c8c64dSAndroid Build Coastguard Worker "--cargo_bin", 1141*90c8c64dSAndroid Build Coastguard Worker type=str, 1142*90c8c64dSAndroid Build Coastguard Worker help="use cargo in the cargo_bin directory instead of the prebuilt one", 1143*90c8c64dSAndroid Build Coastguard Worker ) 1144*90c8c64dSAndroid Build Coastguard Worker parser.add_argument( 1145*90c8c64dSAndroid Build Coastguard Worker "--copy-out", 1146*90c8c64dSAndroid Build Coastguard Worker action="store_true", 1147*90c8c64dSAndroid Build Coastguard Worker default=False, 1148*90c8c64dSAndroid Build Coastguard Worker help=( 1149*90c8c64dSAndroid Build Coastguard Worker "only for root directory, " 1150*90c8c64dSAndroid Build Coastguard Worker + "copy build.rs output to ./out/* and declare source deps " 1151*90c8c64dSAndroid Build Coastguard Worker + "for ./out/*.rs; for crates with code pattern: " 1152*90c8c64dSAndroid Build Coastguard Worker + 'include!(concat!(env!("OUT_DIR"), "/<some_file>.rs"))' 1153*90c8c64dSAndroid Build Coastguard Worker ), 1154*90c8c64dSAndroid Build Coastguard Worker ) 1155*90c8c64dSAndroid Build Coastguard Worker parser.add_argument( 1156*90c8c64dSAndroid Build Coastguard Worker "--debug", 1157*90c8c64dSAndroid Build Coastguard Worker action="store_true", 1158*90c8c64dSAndroid Build Coastguard Worker default=False, 1159*90c8c64dSAndroid Build Coastguard Worker help="dump debug info into rules.mk", 1160*90c8c64dSAndroid Build Coastguard Worker ) 1161*90c8c64dSAndroid Build Coastguard Worker parser.add_argument( 1162*90c8c64dSAndroid Build Coastguard Worker "--features", 1163*90c8c64dSAndroid Build Coastguard Worker type=str, 1164*90c8c64dSAndroid Build Coastguard Worker help=( 1165*90c8c64dSAndroid Build Coastguard Worker "pass features to cargo build, " 1166*90c8c64dSAndroid Build Coastguard Worker + "empty string means no default features" 1167*90c8c64dSAndroid Build Coastguard Worker ), 1168*90c8c64dSAndroid Build Coastguard Worker ) 1169*90c8c64dSAndroid Build Coastguard Worker parser.add_argument( 1170*90c8c64dSAndroid Build Coastguard Worker "--ignore-cargo-errors", 1171*90c8c64dSAndroid Build Coastguard Worker action="store_true", 1172*90c8c64dSAndroid Build Coastguard Worker default=False, 1173*90c8c64dSAndroid Build Coastguard Worker help="do not append cargo/rustc error messages to rules.mk", 1174*90c8c64dSAndroid Build Coastguard Worker ) 1175*90c8c64dSAndroid Build Coastguard Worker parser.add_argument( 1176*90c8c64dSAndroid Build Coastguard Worker "--no-subdir", 1177*90c8c64dSAndroid Build Coastguard Worker action="store_true", 1178*90c8c64dSAndroid Build Coastguard Worker default=False, 1179*90c8c64dSAndroid Build Coastguard Worker help="do not output anything for sub-directories", 1180*90c8c64dSAndroid Build Coastguard Worker ) 1181*90c8c64dSAndroid Build Coastguard Worker parser.add_argument( 1182*90c8c64dSAndroid Build Coastguard Worker "--onefile", 1183*90c8c64dSAndroid Build Coastguard Worker action="store_true", 1184*90c8c64dSAndroid Build Coastguard Worker default=False, 1185*90c8c64dSAndroid Build Coastguard Worker help=( 1186*90c8c64dSAndroid Build Coastguard Worker "output all into one ./rules.mk, default will generate " 1187*90c8c64dSAndroid Build Coastguard Worker + "one rules.mk per Cargo.toml in subdirectories" 1188*90c8c64dSAndroid Build Coastguard Worker ), 1189*90c8c64dSAndroid Build Coastguard Worker ) 1190*90c8c64dSAndroid Build Coastguard Worker parser.add_argument( 1191*90c8c64dSAndroid Build Coastguard Worker "--patch", 1192*90c8c64dSAndroid Build Coastguard Worker type=str, 1193*90c8c64dSAndroid Build Coastguard Worker help="apply the given patch file to generated ./rules.mk", 1194*90c8c64dSAndroid Build Coastguard Worker ) 1195*90c8c64dSAndroid Build Coastguard Worker parser.add_argument( 1196*90c8c64dSAndroid Build Coastguard Worker "--run", 1197*90c8c64dSAndroid Build Coastguard Worker action="store_true", 1198*90c8c64dSAndroid Build Coastguard Worker default=False, 1199*90c8c64dSAndroid Build Coastguard Worker help="run it, default is dry-run", 1200*90c8c64dSAndroid Build Coastguard Worker ) 1201*90c8c64dSAndroid Build Coastguard Worker parser.add_argument("--rustflags", type=str, help="passing flags to rustc") 1202*90c8c64dSAndroid Build Coastguard Worker parser.add_argument( 1203*90c8c64dSAndroid Build Coastguard Worker "--skipcargo", 1204*90c8c64dSAndroid Build Coastguard Worker action="store_true", 1205*90c8c64dSAndroid Build Coastguard Worker default=False, 1206*90c8c64dSAndroid Build Coastguard Worker help="skip cargo command, parse cargo.out, and generate ./rules.mk", 1207*90c8c64dSAndroid Build Coastguard Worker ) 1208*90c8c64dSAndroid Build Coastguard Worker parser.add_argument( 1209*90c8c64dSAndroid Build Coastguard Worker "--tests", 1210*90c8c64dSAndroid Build Coastguard Worker action="store_true", 1211*90c8c64dSAndroid Build Coastguard Worker default=False, 1212*90c8c64dSAndroid Build Coastguard Worker help="run cargo build --tests after normal build", 1213*90c8c64dSAndroid Build Coastguard Worker ) 1214*90c8c64dSAndroid Build Coastguard Worker parser.add_argument( 1215*90c8c64dSAndroid Build Coastguard Worker "--use-cargo-lock", 1216*90c8c64dSAndroid Build Coastguard Worker action="store_true", 1217*90c8c64dSAndroid Build Coastguard Worker default=False, 1218*90c8c64dSAndroid Build Coastguard Worker help=( 1219*90c8c64dSAndroid Build Coastguard Worker "run cargo build with existing Cargo.lock " 1220*90c8c64dSAndroid Build Coastguard Worker + "(used when some latest dependent crates failed)" 1221*90c8c64dSAndroid Build Coastguard Worker ), 1222*90c8c64dSAndroid Build Coastguard Worker ) 1223*90c8c64dSAndroid Build Coastguard Worker parser.add_argument( 1224*90c8c64dSAndroid Build Coastguard Worker "--test-data", 1225*90c8c64dSAndroid Build Coastguard Worker nargs="*", 1226*90c8c64dSAndroid Build Coastguard Worker default=[], 1227*90c8c64dSAndroid Build Coastguard Worker help=( 1228*90c8c64dSAndroid Build Coastguard Worker "Add the given file to the given test's data property. " 1229*90c8c64dSAndroid Build Coastguard Worker + "Usage: test-path=data-path" 1230*90c8c64dSAndroid Build Coastguard Worker ), 1231*90c8c64dSAndroid Build Coastguard Worker ) 1232*90c8c64dSAndroid Build Coastguard Worker parser.add_argument( 1233*90c8c64dSAndroid Build Coastguard Worker "--dependency-blocklist", 1234*90c8c64dSAndroid Build Coastguard Worker nargs="*", 1235*90c8c64dSAndroid Build Coastguard Worker default=[], 1236*90c8c64dSAndroid Build Coastguard Worker help="Do not emit the given dependencies (without lib prefixes).", 1237*90c8c64dSAndroid Build Coastguard Worker ) 1238*90c8c64dSAndroid Build Coastguard Worker parser.add_argument( 1239*90c8c64dSAndroid Build Coastguard Worker "--test-blocklist", 1240*90c8c64dSAndroid Build Coastguard Worker nargs="*", 1241*90c8c64dSAndroid Build Coastguard Worker default=[], 1242*90c8c64dSAndroid Build Coastguard Worker help=( 1243*90c8c64dSAndroid Build Coastguard Worker "Do not emit the given tests. " 1244*90c8c64dSAndroid Build Coastguard Worker + "Pass the path to the test file to exclude." 1245*90c8c64dSAndroid Build Coastguard Worker ), 1246*90c8c64dSAndroid Build Coastguard Worker ) 1247*90c8c64dSAndroid Build Coastguard Worker parser.add_argument( 1248*90c8c64dSAndroid Build Coastguard Worker "--cfg-blocklist", 1249*90c8c64dSAndroid Build Coastguard Worker nargs="*", 1250*90c8c64dSAndroid Build Coastguard Worker default=[], 1251*90c8c64dSAndroid Build Coastguard Worker help="Do not emit the given cfg.", 1252*90c8c64dSAndroid Build Coastguard Worker ) 1253*90c8c64dSAndroid Build Coastguard Worker parser.add_argument( 1254*90c8c64dSAndroid Build Coastguard Worker "--verbose", 1255*90c8c64dSAndroid Build Coastguard Worker action="store_true", 1256*90c8c64dSAndroid Build Coastguard Worker default=False, 1257*90c8c64dSAndroid Build Coastguard Worker help="echo executed commands", 1258*90c8c64dSAndroid Build Coastguard Worker ) 1259*90c8c64dSAndroid Build Coastguard Worker parser.add_argument( 1260*90c8c64dSAndroid Build Coastguard Worker "--vv", 1261*90c8c64dSAndroid Build Coastguard Worker action="store_true", 1262*90c8c64dSAndroid Build Coastguard Worker default=False, 1263*90c8c64dSAndroid Build Coastguard Worker help="run cargo with -vv instead of default -v", 1264*90c8c64dSAndroid Build Coastguard Worker ) 1265*90c8c64dSAndroid Build Coastguard Worker parser.add_argument( 1266*90c8c64dSAndroid Build Coastguard Worker "--dump-config-and-exit", 1267*90c8c64dSAndroid Build Coastguard Worker type=str, 1268*90c8c64dSAndroid Build Coastguard Worker help=( 1269*90c8c64dSAndroid Build Coastguard Worker "Dump command-line arguments (minus this flag) to a config file and" 1270*90c8c64dSAndroid Build Coastguard Worker " exit. This is intended to help migrate from command line options " 1271*90c8c64dSAndroid Build Coastguard Worker "to config files." 1272*90c8c64dSAndroid Build Coastguard Worker ), 1273*90c8c64dSAndroid Build Coastguard Worker ) 1274*90c8c64dSAndroid Build Coastguard Worker parser.add_argument( 1275*90c8c64dSAndroid Build Coastguard Worker "--config", 1276*90c8c64dSAndroid Build Coastguard Worker type=str, 1277*90c8c64dSAndroid Build Coastguard Worker help=( 1278*90c8c64dSAndroid Build Coastguard Worker "Load command-line options from the given config file. Options in " 1279*90c8c64dSAndroid Build Coastguard Worker "this file will override those passed on the command line." 1280*90c8c64dSAndroid Build Coastguard Worker ), 1281*90c8c64dSAndroid Build Coastguard Worker ) 1282*90c8c64dSAndroid Build Coastguard Worker return parser 1283*90c8c64dSAndroid Build Coastguard Worker 1284*90c8c64dSAndroid Build Coastguard Worker 1285*90c8c64dSAndroid Build Coastguard Workerdef parse_args(parser): 1286*90c8c64dSAndroid Build Coastguard Worker """Parses command-line options.""" 1287*90c8c64dSAndroid Build Coastguard Worker args = parser.parse_args() 1288*90c8c64dSAndroid Build Coastguard Worker # Use the values specified in a config file if one was found. 1289*90c8c64dSAndroid Build Coastguard Worker if args.config: 1290*90c8c64dSAndroid Build Coastguard Worker with open(args.config, "r", encoding="utf-8") as f: 1291*90c8c64dSAndroid Build Coastguard Worker config = json.load(f) 1292*90c8c64dSAndroid Build Coastguard Worker args_dict = vars(args) 1293*90c8c64dSAndroid Build Coastguard Worker for arg in config: 1294*90c8c64dSAndroid Build Coastguard Worker args_dict[arg.replace("-", "_")] = config[arg] 1295*90c8c64dSAndroid Build Coastguard Worker return args 1296*90c8c64dSAndroid Build Coastguard Worker 1297*90c8c64dSAndroid Build Coastguard Worker 1298*90c8c64dSAndroid Build Coastguard Workerdef dump_config(parser, args): 1299*90c8c64dSAndroid Build Coastguard Worker """Writes the non-default command-line options to the specified file.""" 1300*90c8c64dSAndroid Build Coastguard Worker args_dict = vars(args) 1301*90c8c64dSAndroid Build Coastguard Worker # Filter out the arguments that have their default value. 1302*90c8c64dSAndroid Build Coastguard Worker # Also filter certain "temporary" arguments. 1303*90c8c64dSAndroid Build Coastguard Worker non_default_args = {} 1304*90c8c64dSAndroid Build Coastguard Worker for arg in args_dict: 1305*90c8c64dSAndroid Build Coastguard Worker if ( 1306*90c8c64dSAndroid Build Coastguard Worker args_dict[arg] != parser.get_default(arg) 1307*90c8c64dSAndroid Build Coastguard Worker and arg != "dump_config_and_exit" 1308*90c8c64dSAndroid Build Coastguard Worker and arg != "config" 1309*90c8c64dSAndroid Build Coastguard Worker and arg != "cargo_bin" 1310*90c8c64dSAndroid Build Coastguard Worker ): 1311*90c8c64dSAndroid Build Coastguard Worker non_default_args[arg.replace("_", "-")] = args_dict[arg] 1312*90c8c64dSAndroid Build Coastguard Worker # Write to the specified file. 1313*90c8c64dSAndroid Build Coastguard Worker with open(args.dump_config_and_exit, "w", encoding="utf-8") as f: 1314*90c8c64dSAndroid Build Coastguard Worker json.dump(non_default_args, f, indent=2, sort_keys=True) 1315*90c8c64dSAndroid Build Coastguard Worker 1316*90c8c64dSAndroid Build Coastguard Worker 1317*90c8c64dSAndroid Build Coastguard Workerdef main(): 1318*90c8c64dSAndroid Build Coastguard Worker parser = get_parser() 1319*90c8c64dSAndroid Build Coastguard Worker args = parse_args(parser) 1320*90c8c64dSAndroid Build Coastguard Worker if not args.run: # default is dry-run 1321*90c8c64dSAndroid Build Coastguard Worker print(DRY_RUN_NOTE) 1322*90c8c64dSAndroid Build Coastguard Worker if args.dump_config_and_exit: 1323*90c8c64dSAndroid Build Coastguard Worker dump_config(parser, args) 1324*90c8c64dSAndroid Build Coastguard Worker else: 1325*90c8c64dSAndroid Build Coastguard Worker Runner(args).run_cargo().gen_rules().apply_patch() 1326*90c8c64dSAndroid Build Coastguard Worker 1327*90c8c64dSAndroid Build Coastguard Worker 1328*90c8c64dSAndroid Build Coastguard Workerif __name__ == "__main__": 1329*90c8c64dSAndroid Build Coastguard Worker main() 1330