| #!/usr/bin/env python3 |
| # |
| # Copyright (C) 2022 The Android Open Source Project |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| |
| import argparse |
| import inspect |
| import os |
| from pathlib import Path |
| import re |
| import sys |
| import tempfile |
| |
| import context |
| |
| import android_rust.build_platform as build_platform |
| from android_rust.paths import ( |
| DIST_PATH_DEFAULT, |
| OUT_PATH_PROFILES, |
| PROFILE_SUBDIR_BOLT, |
| ) |
| from android_rust.toolchains import CLANG_TOOLCHAIN_HOST, ClangToolchain, RustToolchain, export_profiles |
| from android_rust.utils import ( |
| TERM_RED, |
| TEST_VERSION_NUMBER, |
| ExtantPath, |
| ResolvedPath, |
| ScriptException, |
| archive_extract, |
| is_archive, |
| prepare_prebuilts, |
| print_colored, |
| run_build_target, |
| ) |
| |
| |
| RUST_PROFILES_NAME_PATTERN = re.compile(r"rust-profraw-(\S*)\.tar\.xz") |
| |
| # |
| # Program logic |
| # |
| |
| |
| def parse_args() -> argparse.Namespace: |
| parser = argparse.ArgumentParser(description=inspect.getdoc(sys.modules[__name__])) |
| |
| prebuilt_group = parser.add_mutually_exclusive_group(required=True) |
| prebuilt_group.add_argument( |
| "--prebuilt-path", |
| type=ExtantPath, |
| help="Path to either the build artifact or the directory that contains it") |
| prebuilt_group.add_argument( |
| "--reuse-prebuilt", |
| action="store_true", |
| help="Re-use the prebuilt in the test directory (prebuilts/rust/linux-x86/9.99.9)") |
| |
| parser.add_argument( |
| "--target", type=str, default="aosp_cf_x86_64_phone", help="Device target to build for") |
| parser.add_argument( |
| "--variant", |
| type=str, |
| default="userdebug", |
| choices=[ |
| "eng", |
| "user", |
| "userdebug", |
| ], |
| help="Set the build target variant") |
| parser.add_argument( |
| "--release", |
| type=str, |
| default="trunk_staging", |
| choices=[ |
| "next", |
| "trunk", |
| "trunk_food", |
| "trunk_staging", |
| ], |
| help="Set the Android release name") |
| parser.add_argument( |
| "--dist", |
| "-d", |
| dest="dist_path", |
| type=ResolvedPath, |
| default=DIST_PATH_DEFAULT, |
| help="Where to place distributable artifacts") |
| parser.add_argument( |
| "--clean", |
| "-c", |
| action=argparse.BooleanOptionalAction, |
| default=False, |
| help="Run the clean step before testing the compiler") |
| parser.add_argument( |
| "--lint", |
| action=argparse.BooleanOptionalAction, |
| default=False, |
| help="Enable/disable Clippy lints when building Android platform code") |
| parser.add_argument( |
| "--clang-prebuilt", |
| type=ExtantPath, |
| default=CLANG_TOOLCHAIN_HOST, |
| help="Path to Clang toolchain that will be used to merge profile data") |
| |
| parser.add_argument( |
| "--all-rust", |
| action=argparse.BooleanOptionalAction, |
| default=False, |
| help="Build all Rust targets available for the product") |
| parser.add_argument( |
| "--image", |
| action=argparse.BooleanOptionalAction, |
| default=False, |
| help="Build an image as part of the compiler test") |
| parser.add_argument( |
| "--test-targets", |
| action=argparse.BooleanOptionalAction, |
| default=False, |
| help="Build the targets necessary to run tests in EngProd") |
| parser.add_argument( |
| "--rustdoc", |
| action=argparse.BooleanOptionalAction, |
| default=False, |
| help="Build all rustdoc targets") |
| parser.add_argument( |
| "--custom-targets", |
| nargs="+", |
| help="Targets to build in addition to those required by other flags") |
| |
| pgo_group = parser.add_mutually_exclusive_group() |
| pgo_group.add_argument( |
| "--profile-generate", |
| type=Path, |
| nargs="?", |
| const=OUT_PATH_PROFILES, |
| help="Path where instrumented prebuilts will place their profiles") |
| pgo_group.add_argument( |
| "--cs-profile-generate", |
| type=Path, |
| nargs="?", |
| const=OUT_PATH_PROFILES, |
| help="Path were context-sensitive instrumented prebuilts will place their profiles") |
| pgo_group.add_argument( |
| "--bolt-profile-generate", |
| type=Path, |
| nargs="?", |
| const=OUT_PATH_PROFILES, |
| help="Path where BOLT instrumented prebuilts will place their profiles") |
| |
| args = parser.parse_args() |
| if args.bolt_profile_generate: |
| args.bolt_profile_generate = (args.bolt_profile_generate / PROFILE_SUBDIR_BOLT).resolve() |
| |
| return args |
| |
| |
| def ensure_bolt_profile_dir(profile_dir: Path) -> None: |
| if profile_dir: |
| print(f"Making BOLT profile directory: {profile_dir}") |
| profile_dir.mkdir(exist_ok=True, parents=True) |
| |
| |
| def initialize_clang_prebuilt(args: argparse.Namespace) -> None: |
| if isinstance(args.clang_prebuilt, Path): |
| if is_archive(args.clang_prebuilt): |
| extract_dir = Path(tempfile.mkdtemp(prefix="clang-prebuilt-")) |
| print(f"Extracting Clang archive to {extract_dir}") |
| archive_extract(args.clang_prebuilt, extract_dir, strip_components=1) |
| args.clang_prebuilt = extract_dir |
| |
| args.clang_prebuilt = ClangToolchain(args.clang_prebuilt, host=build_platform.system()) |
| |
| |
| def main() -> None: |
| args = parse_args() |
| |
| if not (args.all_rust or args.rustdoc or args.image or args.test_targets or args.custom_targets): |
| sys.exit( |
| "One or more tests flags must be set: --all-rust, --rustdoc, --image, --test-targets, or --custom-targets") |
| |
| initialize_clang_prebuilt(args) |
| |
| toolchain_dir = prepare_prebuilts(args.prebuilt_path, args.reuse_prebuilt) |
| test_toolchain = RustToolchain(toolchain_dir) |
| env = os.environ.copy() |
| if args.lint is False: |
| env["SOONG_DISABLE_CLIPPY"] = "true" |
| |
| common_args = { |
| "device_target": args.target, |
| "release_name": args.release, |
| "device_target_variant": args.variant, |
| "prebuilt_version": TEST_VERSION_NUMBER, |
| "env": env, |
| } |
| |
| try: |
| if args.clean: |
| run_build_target("clean", **common_args) |
| |
| ensure_bolt_profile_dir(args.bolt_profile_generate) |
| |
| if args.all_rust: |
| print("Building Rust targets") |
| run_build_target(["rust"], **common_args) |
| |
| if args.rustdoc: |
| print("Building Rustdocs targets") |
| run_build_target(["rustdoc"], **common_args) |
| |
| if args.image: |
| print("Building Android image") |
| run_build_target(["droid", "dist"], **common_args) |
| |
| if args.test_targets: |
| # Build the targets necessary for running tests in EngProd |
| print("Building Android test targets") |
| run_build_target([ |
| "dist", |
| "continuous_instrumentation_tests", |
| "continuous_native_tests", |
| "device-tests", |
| "platform_tests", |
| ], |
| **common_args) # yapf: disable |
| |
| if args.custom_targets: |
| print(f"Building custom targets: {' '.join(args.custom_targets)}") |
| run_build_target(args.custom_targets, **common_args) |
| |
| finally: |
| export_profiles( |
| args.clang_prebuilt, |
| args.profile_generate or args.cs_profile_generate or args.bolt_profile_generate, |
| args.dist_path, |
| test_toolchain.get_version()) |
| |
| |
| if __name__ == "__main__": |
| try: |
| main() |
| |
| except (ScriptException, argparse.ArgumentTypeError) as err: |
| print_colored(str(err), TERM_RED) |
| sys.exit(1) |