import argparse
import io
import os
import platform
import re
import subprocess
import sys
import tempfile
sys.path.append(
os.path.join(os.path.dirname(os.path.abspath(__file__)), os.pardir,
os.pardir, os.pardir, 'build'))
import action_helpers
RUSTC_VERSION_LINE = re.compile(r"(\w+): (.*)")
def rustc_name():
if platform.system() == 'Windows':
return "rustc.exe"
else:
return "rustc"
def host_triple(rustc_path):
args = [rustc_path, "-vV"]
known_vars = dict()
proc = subprocess.Popen(args, stdout=subprocess.PIPE)
for line in io.TextIOWrapper(proc.stdout, encoding="utf-8"):
m = RUSTC_VERSION_LINE.match(line.rstrip())
if m:
known_vars[m.group(1)] = m.group(2)
return known_vars["host"]
def set_cargo_cfg_target_env_variables(rustc_print_cfg_path, env):
with open(rustc_print_cfg_path, 'r') as file:
for line in file:
line = line.strip()
if "=" not in line: continue
key, value = line.split("=")
if key.startswith("target_"):
key = "CARGO_CFG_" + key.upper()
value = value.strip('"')
if key in env:
env[key] = env[key] + f",{value}"
else:
env[key] = value
RUSTC_CFG_LINE = re.compile("cargo::?rustc-cfg=(.*)")
def main():
parser = argparse.ArgumentParser(description='Run Rust build script.')
parser.add_argument('--build-script',
required=True,
help='build script to run')
parser.add_argument('--output',
required=True,
help='where to write output rustc flags')
parser.add_argument('--target', required=True, help='rust target triple')
parser.add_argument(
'--rustc-print-cfg-path',
required=True,
help='path to output from //build/rust/gni_impl:rustc_print_cfg')
parser.add_argument('--features', help='features', nargs='+')
parser.add_argument('--env', help='environment variable', nargs='+')
parser.add_argument('--rustflags',
help=('path to a file of newline-separated command line '
'flags for rustc'))
parser.add_argument('--rust-prefix', required=True, help='rust path prefix')
parser.add_argument('--generated-files', nargs='+', help='any generated file')
parser.add_argument('--out-dir', required=True, help='target out dir')
parser.add_argument('--src-dir', required=True, help='target source dir')
args = parser.parse_args()
rustc_path = os.path.join(args.rust_prefix, rustc_name())
with tempfile.TemporaryDirectory() as tempdir:
env = {} env["RUSTC"] = os.path.abspath(rustc_path)
env["OUT_DIR"] = tempdir
env["CARGO_MANIFEST_DIR"] = os.path.abspath(args.src_dir)
env["HOST"] = host_triple(rustc_path)
env["TARGET"] = args.target
set_cargo_cfg_target_env_variables(args.rustc_print_cfg_path, env)
if args.features:
for f in args.features:
feature_name = f.upper().replace("-", "_")
env["CARGO_FEATURE_%s" % feature_name] = "1"
if args.rustflags:
with open(args.rustflags) as flags:
for flag in flags:
if "-Copt-level" in flag:
(_, opt) = flag.split("=")
env["OPT_LEVEL"] = opt.rstrip()
flags.seek(0)
env["CARGO_ENCODED_RUSTFLAGS"] = '\x1f'.join(flags.readlines())
if args.env:
for e in args.env:
(k, v) = e.split("=")
env[k] = v
if "OPT_LEVEL" not in env:
env["OPT_LEVEL"] = "0"
if os.environ.get("RUST_BACKTRACE"):
env["RUST_BACKTRACE"] = os.environ.get("RUST_BACKTRACE")
if os.environ.get("RUST_LOG"):
env["RUST_LOG"] = os.environ.get("RUST_LOG")
proc = subprocess.run([os.path.abspath(args.build_script)],
env=env,
cwd=args.src_dir,
encoding='utf8',
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
if proc.stderr.rstrip():
print(proc.stderr.rstrip(), file=sys.stderr)
proc.check_returncode()
flags = ""
for line in proc.stdout.split("\n"):
m = RUSTC_CFG_LINE.match(line.rstrip())
if m:
flags = "%s--cfg\n%s\n" % (flags, m.group(1))
with action_helpers.atomic_output(args.output) as output:
output.write(flags.encode("utf-8"))
if args.generated_files:
for generated_file in args.generated_files:
in_path = os.path.join(tempdir, generated_file)
out_path = os.path.join(args.out_dir, generated_file)
out_dir = os.path.dirname(out_path)
if not os.path.exists(out_dir):
os.makedirs(out_dir)
with open(in_path, 'rb') as input:
with action_helpers.atomic_output(out_path) as output:
content = input.read()
output.write(content)
if __name__ == '__main__':
sys.exit(main())