blob: 0ba49e70c113f30b811090a79ae6a507b939c38e [file] [log] [blame]
# 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"],
)