| # Copyright 2021 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. |
| |
| """Recipe for building and uploading a cargo project's main binary to CIPD.""" |
| |
| from PB.recipes.fuchsia.contrib.cargo_build import InputProperties |
| |
| DEPS = [ |
| "fuchsia/cas_util", |
| "fuchsia/cipd_util", |
| "fuchsia/git_checkout", |
| "fuchsia/macos_sdk", |
| "fuchsia/platform_util", |
| "fuchsia/toolchain", |
| "recipe_engine/cipd", |
| "recipe_engine/context", |
| "recipe_engine/file", |
| "recipe_engine/path", |
| "recipe_engine/platform", |
| "recipe_engine/properties", |
| "recipe_engine/step", |
| ] |
| |
| PROPERTIES = InputProperties |
| |
| # we need clang for some package's buildscripts |
| CLANG_PKG = ("fuchsia/third_party/clang/${platform}", "integration") |
| # TODO(fxbug.dev/73442) use `integration` instead of `latest` for the rust package |
| RUST_HOST_PKG = ("fuchsia/third_party/rust/host/${platform}", "latest") |
| |
| |
| def RunSteps(api, props): |
| cipd_dir = api.path.start_dir.join("cipd") |
| host_platform = api.cipd_util.platform_name |
| host_triple = api.toolchain.PLATFORM_TO_TRIPLE[host_platform].replace( |
| "arm64-apple-darwin", "aarch64-apple-darwin" |
| ) |
| with api.context(infra_steps=True): |
| pkgs = api.cipd.EnsureFile() |
| for pkg in [CLANG_PKG, RUST_HOST_PKG]: |
| pkgs.add_package(*pkg) |
| |
| # Add the Rust target package based on the current host |
| pkgs.add_package(f"fuchsia/third_party/rust/target/{host_triple}", "latest") |
| # Add gnu make, which some build scripts unfortunately depend on |
| pkgs.add_package("fuchsia/third_party/make/${platform}", "version:4.3") |
| if api.platform.is_linux: |
| pkgs.add_package( |
| "fuchsia/third_party/sysroot/linux", "integration", "sysroot" |
| ) |
| |
| api.cipd.ensure(cipd_dir, pkgs) |
| |
| src_dir, revision = api.git_checkout(props.remote) |
| |
| install_dir = api.path.start_dir.join("install") |
| tmp_dir = api.path.start_dir.join("tmp") |
| api.file.ensure_directory("ensure tmp directory", tmp_dir) |
| |
| additional_env = { |
| "CC": tmp_dir.join("cc-wrapper"), |
| "CXX": tmp_dir.join("cxx-wrapper"), |
| "AR": cipd_dir.join("bin", "llvm-ar"), |
| "ASM": tmp_dir.join("asm-wrapper"), |
| "RANLIB": cipd_dir.join("bin", "llvm-ranlib"), |
| "LD": tmp_dir.join("linker-wrapper"), |
| } |
| with api.step.nest("build"), api.macos_sdk(), api.context( |
| cwd=src_dir, |
| env_prefixes={"PATH": [cipd_dir.join("bin")]}, |
| env=additional_env, |
| ): |
| target_platform = api.platform_util.host |
| sysroot = get_sysroot(api, cipd_dir, target_platform) |
| |
| # Prepare all the wrapper scripts |
| with api.step.nest("set up wrapper scripts"): |
| # pairs of executable |
| wrapped_executables = [ |
| ("cc-wrapper", cipd_dir.join("bin", "clang")), |
| ("cxx-wrapper", cipd_dir.join("bin", "clang++")), |
| ("asm-wrapper", cipd_dir.join("bin", "clang")), |
| ] |
| |
| for pair in wrapped_executables: |
| (name, binary) = pair |
| path = tmp_dir.join(name) |
| api.file.write_text( |
| f"write wrapper {name}", |
| path, |
| f'#!/bin/bash\nexec {binary} --sysroot={sysroot} "$@"', |
| ) |
| api.file.chmod(f"make {name} executable", path, "0755") |
| |
| linker_wrapper_path = tmp_dir.join("linker-wrapper") |
| api.file.write_text( |
| "write wrapper linker-wrapper", |
| linker_wrapper_path, |
| f'#!/bin/bash\nexec {binary} --sysroot={sysroot} "$@"', |
| ) |
| api.file.chmod( |
| "make linker-wrapper executable", linker_wrapper_path, "0755" |
| ) |
| |
| if api.platform.is_linux: |
| with api.step.nest("linux-specific linker/cargo config setup"): |
| # generate linker script |
| linker_script_path = tmp_dir.join("linker-script") |
| linker = cipd_dir.join("bin", "clang++") |
| sysroot = cipd_dir.join("sysroot") |
| api.file.write_text( |
| "write linker script", |
| linker_script_path, |
| f'#!/bin/bash\nexec {linker} --sysroot={sysroot} -static-libstdc++ "$@"', |
| ) |
| api.file.chmod( |
| "make linker script executable", linker_script_path, "0755" |
| ) |
| |
| # generate config.toml to specify linker script with sysroot |
| cargo_config_dir = api.path.start_dir.join(".cargo") |
| api.file.ensure_directory("ensure .cargo directory", cargo_config_dir) |
| cargo_config_path = cargo_config_dir.join("config.toml") |
| api.file.write_text( |
| "write cargo config.toml", |
| cargo_config_path, |
| f'[target.{host_triple}]\nlinker = "{linker_script_path}"', |
| ) |
| |
| cargo_args = [ |
| "cargo", |
| "build", |
| "--release", |
| "--bin", |
| props.bin_name, |
| ] |
| if props.features: |
| cargo_args += ["--features", ",".join(props.features)] |
| api.step("cargo build", cargo_args) |
| |
| api.file.ensure_directory("ensure the install directory exists", install_dir) |
| api.file.move( |
| "move binary to install directory", |
| src_dir.join("target/release/" + props.bin_name), |
| install_dir.join(props.bin_name), |
| ) |
| |
| if props.dry_run: |
| api.cas_util.upload(install_dir, output_property="isolated") |
| else: |
| api.cipd_util.upload_package( |
| props.cipd_package, |
| install_dir, |
| search_tag={"git_revision": revision}, |
| ) |
| |
| |
| def get_sysroot(api, cipd_dir, platform): |
| if platform.is_linux: |
| return cipd_dir.join("sysroot") |
| if platform.is_mac: |
| return api.macos_sdk.sysroot |
| raise api.step.StepFailure("unsupported platform") # pragma: no cover |
| |
| |
| def GenTests(api): |
| test_remote = ( |
| "https://fuchsia.googlesource.com/third_party/github.com/rust-lang/rust-bindgen" |
| ) |
| test_bin = "bindgen" |
| test_cipd = "fuchsia/third_party/rust_bindgen/${platform}" |
| yield api.test("ci") + api.platform.name("linux") + api.properties( |
| remote=test_remote, |
| bin_name=test_bin, |
| cipd_package=test_cipd, |
| dry_run=True, |
| ) |
| yield api.test("prod") + api.platform.name("mac") + api.properties( |
| remote=test_remote, |
| bin_name=test_bin, |
| cipd_package=test_cipd, |
| dry_run=False, |
| features=["bogus-feature-for-testing", "second-fake-feature"], |
| ) |