blob: 3c617eafe536fd49bd841bd662f4c1645299fc2b [file] [log] [blame] [edit]
#!/usr/bin/env fuchsia-vendored-python
#
# Copyright 2018 The Fuchsia Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import hashlib
import os
import platform
import re
from functools import lru_cache
from pathlib import Path
ROOT_PATH = Path(os.environ.get("FUCHSIA_DIR", ""))
FX_PATH = ROOT_PATH / "scripts" / "fx"
FUCHSIA_BUILD_DIR = Path(os.environ.get("FUCHSIA_BUILD_DIR", ""))
PREBUILT_DIR = ROOT_PATH / "prebuilt"
PREBUILT_THIRD_PARTY_DIR = PREBUILT_DIR / "third_party"
HOST_PLATFORM = (
platform.system().lower().replace("darwin", "mac")
+ "-"
+ {"x86_64": "x64", "aarch64": "arm64", "arm64": "arm64"}[
platform.machine()
]
)
class GnTarget:
def __init__(self, gn_target, fuchsia_dir=None):
build_label_regex = get_build_label_regex()
match = re.match(build_label_regex, gn_target)
if match is None:
print(f"Invalid GN label '{gn_target}'")
raise ValueError(gn_target)
path, name, toolchain = match.group(1, 3, 5)
if fuchsia_dir is None:
fuchsia_dir = ROOT_PATH
if path.startswith("//"):
path = fuchsia_dir / Path(path[2:])
else:
path = Path(path).resolve()
if name is None:
name = path.name
self.label_path = path.relative_to(fuchsia_dir)
self.label_name = name
self.explicit_toolchain = toolchain
def __str__(self):
return self.gn_target
@property
def ninja_target(self):
"""The canonical GN label of this target, minus the leading '//'."""
return (
str(self.label_path) + ":" + self.label_name + self.toolchain_suffix
)
def __actual_ninja_target(self):
"""The canonical GN label of the ".actual" target, minus the leading '//'."""
label_name = self.label_name
if not label_name.endswith(".actual"):
label_name += ".actual"
return str(self.label_path) + ":" + label_name + self.toolchain_suffix
@property
def gn_target(self):
"""The canonical GN label of this target, including the leading '//'."""
return "//" + self.ninja_target
@property
def toolchain_suffix(self):
"""The GN path suffix for this target's toolchain, if it is not the default."""
if (
self.explicit_toolchain is None
or "fuchsia" in self.explicit_toolchain
):
return ""
return "({})".format(self.explicit_toolchain)
@property
def src_path(self):
"""The path to the directory containing this target's BUILD.gn file."""
return ROOT_PATH / self.label_path
def gen_dir(self, build_dir=None):
"""The path to the directory containing this target's generated files."""
tc = self.explicit_toolchain
build_dir = build_dir or FUCHSIA_BUILD_DIR
default = default_toolchain(build_dir)
return (
build_dir
/ (tc.split(":")[-1] if tc and tc != default else "")
/ "gen"
/ self.label_path
)
def manifest_path(self, build_dir=None):
"""The path to Cargo.toml for this target."""
if build_dir is None:
build_dir = FUCHSIA_BUILD_DIR
hashed_gn_path = hashlib.sha1(
self.__actual_ninja_target().encode("utf-8")
).hexdigest()
return Path(build_dir) / "cargo" / hashed_gn_path / "Cargo.toml"
@lru_cache
def get_build_label_regex():
"""get a regular expression for parsing build target labels"""
# [\w-] is a valid GN name. We also accept '/' and '.' in paths.
# For the toolchain suffix, we take the whole label name at once, so we allow ':'.
build_label_regex = (
r"([\w/.-]*)" + r"(:([+\w.-]+))?" + r"(\(([\w./:+-]+)\))?$"
)
# Here are some examples of matching labels
assert (
re.match(
build_label_regex,
"//third_party/rust_crates:zstd-v0_11_2+zstd_1_5_2.rustdoc(//build/toolchain/fuchsia:x64)",
)
is not None
)
assert re.match(build_label_regex, "//src/lib/fuchsia-async") is not None
assert (
re.match(build_label_regex, "//build/rust/tests:clippy_test")
is not None
)
return re.compile(build_label_regex)
@lru_cache
def default_toolchain(build_dir):
return open(build_dir / "default_toolchain_name.txt").read()