| #!/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() | |
| + "-" | |
| + {"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() |