blob: 94d3efdafaa51c1490f49d013d431b3e058d20d0 [file] [log] [blame]
# Copyright 2017 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 Rust toolchain."""
from recipe_engine.config import Enum
from recipe_engine.recipe_api import Property
import re
DEPS = [
"fuchsia/buildbucket_util",
"fuchsia/cipd_platform",
"fuchsia/git",
"fuchsia/goma",
"fuchsia/macos_sdk",
"fuchsia/nullcontext",
"fuchsia/status_check",
"fuchsia/toolchain",
"fuchsia/upload",
"recipe_engine/cipd",
"recipe_engine/context",
"recipe_engine/file",
"recipe_engine/json",
"recipe_engine/path",
"recipe_engine/platform",
"recipe_engine/properties",
"recipe_engine/python",
"recipe_engine/raw_io",
"recipe_engine/step",
]
PACKAGES = ["rust", "rust_tools"]
PROPERTIES = {
"repository": Property(
kind=str,
help="Git repository URL",
default="https://fuchsia.googlesource.com/third_party/rust",
),
"branch": Property(kind=str, help="Git branch", default="refs/heads/master"),
"revision": Property(kind=str, help="Revision", default=None),
"package": Property(
kind=Enum(*PACKAGES), help="Which package to build", default="rust"
),
}
def RunSteps(api, repository, branch, revision, package):
use_goma = (
not api.platform.arch == "arm" and api.platform.bits == 64
) and not api.platform.is_win
if use_goma:
api.goma.ensure()
goma_context = api.goma.build_with_goma
else:
goma_context = api.nullcontext
if not revision:
revision = api.git.get_remote_branch_head(repository, branch)
host_platform = api.cipd_platform.name
use_breakpad = host_platform == "linux-amd64"
with api.step.nest("ensure_packages"):
with api.context(infra_steps=True):
pkgs = api.cipd.EnsureFile()
pkgs.add_package("infra/3pp/tools/cmake/${platform}", "version:3.13.5")
pkgs.add_package("infra/3pp/tools/ninja/${platform}", "version:1.9.0")
pkgs.add_package("infra/3pp/tools/swig/${platform}", "version:4.0.2")
pkgs.add_package("fuchsia/third_party/clang/${platform}", "integration")
pkgs.add_package("fuchsia/sysroot/linux-amd64", "latest", "linux-amd64")
pkgs.add_package("fuchsia/sysroot/linux-arm64", "latest", "linux-arm64")
# We don't have SDK for linux-arm64 or win, but we only need sysroot.
if (
api.platform.arch == "arm" and api.platform.bits == 64
) or api.platform.is_win:
pkgs.add_package("fuchsia/sdk/core/linux-amd64", "latest", "sdk")
else:
pkgs.add_package("fuchsia/sdk/core/${platform}", "latest", "sdk")
if use_breakpad:
pkgs.add_package(
"fuchsia/tools/breakpad/${platform}", "latest", "breakpad"
)
cipd_dir = api.path["start_dir"].join("cipd")
api.cipd.ensure(cipd_dir, pkgs)
sdk_dir = cipd_dir.join("sdk")
with api.context(infra_steps=True):
rust_dir = api.path["start_dir"].join("rust")
api.git.checkout(repository, rust_dir, ref=revision, recursive=True)
# build rust
staging_dir = api.path["start_dir"].join("staging")
build_dir = staging_dir.join("build")
api.file.ensure_directory("build", build_dir)
pkg_dir = staging_dir.join("rust")
api.file.ensure_directory("create pkg_dir", pkg_dir)
with api.macos_sdk(), goma_context():
if api.platform.name == "linux":
host_sysroot = cipd_dir.join(host_platform)
elif api.platform.name == "mac":
# TODO(fxbug.dev/3043): Eventually use our own hermetic sysroot as for Linux.
step_result = api.step(
"xcrun",
["xcrun", "--sdk", "macosx", "--show-sdk-path"],
stdout=api.raw_io.output(name="sdk-path", add_output_log=True),
step_test_data=lambda: api.raw_io.test_api.stream_output(
"/some/xcode/path"
),
)
host_sysroot = step_result.stdout.strip()
else: # pragma: no cover
assert False, "unsupported platform"
targets = [
"x86_64-unknown-linux-gnu",
"aarch64-unknown-linux-gnu",
"wasm32-unknown-unknown",
]
if api.platform.is_mac:
targets.append("x86_64-apple-darwin")
config_file = "config.toml"
api.python(
"generate config.toml",
api.resource("generate_config.py"),
args=[
"config_toml",
"--targets",
",".join(targets),
"--clang-prefix",
cipd_dir,
"--prefix",
pkg_dir,
"--host-sysroot",
host_sysroot,
]
+ (["--goma-dir", api.goma.goma_dir] if use_goma else [])
+ (["--extra-tools-only"] if package == "rust_tools" else []),
stdout=api.raw_io.output(leak_to=build_dir.join(config_file)),
)
env_data = api.python(
"generate environment",
api.resource("generate_config.py"),
args=[
"environment",
"--targets",
",".join(targets),
"--clang-prefix",
cipd_dir,
"--sdk-dir",
sdk_dir,
"--revision",
revision,
# TODO(tmandry): Switch to multiarch so these don't need to be separate
"--linux-amd64-sysroot",
cipd_dir.join("linux-amd64"),
"--linux-arm64-sysroot",
cipd_dir.join("linux-arm64"),
]
+ (["--darwin-sysroot", host_sysroot] if api.platform.is_mac else []),
stdout=api.raw_io.output(name="environment", add_output_log=True),
step_test_data=lambda: api.raw_io.test_api.stream_output(
"RUST_BACKTRACE=1"
),
)
env = {}
for line in env_data.stdout.splitlines():
key, value = line.split("=", 1)
env[key] = value
env_prefixes = {"PATH": [cipd_dir, cipd_dir.join("bin")]}
with api.context(cwd=build_dir, env=env, env_prefixes=env_prefixes):
api.python(
"rust install",
rust_dir.join("x.py"),
args=["install", "--config", config_file],
)
runtime_result = api.python(
"generate runtime spec",
api.resource("generate_config.py"),
args=["runtime"],
stdout=api.json.output(),
)
api.toolchain.strip_runtimes(
name="generate runtime.json",
spec=runtime_result.stdout,
path=pkg_dir.join("lib"),
build_id_subpath="debug/.build-id",
readelf=cipd_dir.join("bin", "llvm-readelf"),
objcopy=cipd_dir.join("bin", "llvm-objcopy"),
dump_syms=(
cipd_dir.join("breakpad", "dump_syms", "dump_syms")
if use_breakpad
else None
),
)
isolated = api.upload.upload_isolated(pkg_dir)
# package rust
step_result = api.step(
"rust version",
[pkg_dir.join("bin", "rustc"), "--version"],
stdout=api.raw_io.output(),
step_test_data=lambda: api.raw_io.test_api.stream_output(
"rustc 1.19.0-nightly (75b056812 2017-05-15)"
),
)
m = re.search(r"rustc ([0-9a-z.-]+)", step_result.stdout)
assert m, "Cannot determine Rust version"
version = m.group(1)
if not api.buildbucket_util.is_tryjob:
api.upload.cipd_package(
"fuchsia/third_party/%s/${platform}" % package,
pkg_dir,
[api.upload.DirectoryPath(pkg_dir)],
{"git_revision": revision},
repository=repository,
extra_tags={"version": version},
)
builders = {
"linux-amd64": (
"rust_toolchain.fuchsia-arm64-debug",
"rust_toolchain.fuchsia-arm64-release",
"rust_toolchain.fuchsia-x64-debug",
"rust_toolchain.fuchsia-x64-release",
),
"mac-amd64": ("rust_toolchain.fuchsia-host-mac",),
}
if package == "rust" and host_platform in builders:
# Do a full integration build. This will use the just-built toolchain
# to build all of Fuchsia to check whether there are any regressions.
api.toolchain.trigger_build(
"rust_toolchain",
repository,
revision,
isolated,
builders=builders[host_platform],
)
def GenTests(api):
revision = "75b05681239cb309a23fcb4f8864f177e5aa62da"
for platform in ("linux", "mac"):
for package in ("rust", "rust_tools"):
for arch in ("intel", "arm") if platform == "linux" else ("intel",):
yield (
api.status_check.test("%s_%s_%s" % (package, arch, platform))
+ api.platform.name(platform)
+ api.platform.arch(arch)
+ api.properties(package=package)
+ api.git.get_remote_branch_head("git ls-remote", revision)
+ api.step_data("generate runtime spec", stdout=api.json.output([]))
)
yield (
api.status_check.test("%s_%s_%s_new" % (package, arch, platform))
+ api.platform.name(platform)
+ api.platform.arch(arch)
+ api.properties(package=package)
+ api.git.get_remote_branch_head("git ls-remote", revision)
+ api.step_data("generate runtime spec", stdout=api.json.output([]))
+ api.step_data(
"cipd.cipd search fuchsia/third_party/%s/${platform} " % package
+ "git_revision:"
+ revision,
api.json.output({"result": []}),
)
)