blob: 4489b7b843eef55a9c9916e846155ace281c3a8c [file] [log] [blame]
#!/usr/bin/env python3
# Copyright 2019 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.
from collections import OrderedDict
from os import path, getcwd
import argparse
import json
import platform
import sys
DEFAULT_TOOLS = [
"cargo",
"rustfmt",
"cargo-fmt",
"clippy",
"src",
"rust-demangler",
"llvm-tools",
"rust-analyzer",
"rustdoc",
]
FUCHSIA_TRIPLE_TO_ARCH = {
"aarch64-fuchsia": "arm64",
"riscv64gc-unknown-fuchsia": "riscv64",
"x86_64-fuchsia": "x64",
}
FUCHSIA_TRIPLES = list(FUCHSIA_TRIPLE_TO_ARCH.keys())
FUCHSIA_RUNTIME_TARGETS = [
("aarch64-fuchsia", "aarch64-unknown-fuchsia"),
("riscv64gc-unknown-fuchsia", "riscv64-unknown-fuchsia"),
("x86_64-fuchsia", "x86_64-unknown-fuchsia"),
]
CMAKE_SETTINGS = """
cflags = "{cflags}"
cxxflags = "{cxxflags}"
ldflags = "{ldflags}"
"""
BOOTSTRAP_CONFIG = """
# Use our own beta compiler as stage0 for bootstrapping, rather than downloading
cargo = "{beta}/bin/cargo"
rustc = "{beta}/bin/rustc"
rustfmt = "{beta}/bin/rustfmt"
"""
BUILD_CONFIG = """
changelog-seen = 2
[llvm]
optimize = true
thin-lto = {thinlto}
ccache = {gomacc_quote}
ninja = true
targets = "AArch64;ARM;RISCV;WebAssembly;X86"
{cmake_settings}
use-libcxx = true
# TODO(https://github.com/rust-lang/rust/issues/94983)
# We shouldn't have to set this to false to enable statically linking libc++
static-libstdcpp = false
[build]
target = [{target}]
{host_triple}
build-dir = "fuchsia-build"
docs = false
extended = true
cargo-native-static = true
tools = [{tools}]
{bootstrap}
[install]
prefix = "{prefix}"
sysconfdir = "etc"
[rust]
optimize = true
codegen-units-std = 1
channel = "nightly"
lld = false
llvm-libunwind = "in-tree"
jemalloc = {jemalloc}
lto = "thin"
# Enable full debuginfo for libstd.
debuginfo-level-std = 2
[dist]
"""
TARGET_CONFIG = """
[target.{triple}]
cc = "{cc}"
cxx = "{cxx}"
ar = "{ar}"
ranlib = "{ranlib}"
linker = "{linker}"
profiler = {profiler}
"""
def clang_tool(args, tool):
return path.join(args.clang_prefix, "bin", tool) + (".exe" if args.is_win else "")
def generate_config_toml(args):
targets = args.targets.split(",")
if args.is_win:
# don't build fuchsia targets on windows
pass
elif args.is_mac:
# TODO(https://fxbug.dev/126336): fix riscv64gc-unknown-fuchsia build on mac
targets += [t for t in FUCHSIA_TRIPLES if t != "riscv64gc-unknown-fuchsia"]
else:
targets += FUCHSIA_TRIPLES
tools = args.tools.split(",")
def string_list(items):
return ", ".join('"%s"' % item for item in items)
cmake_fragment = (
'build-config = { CMAKE_SYSROOT="%s" }' % args.host_sysroot
if args.is_win
else CMAKE_SETTINGS.format(
cflags="--sysroot=%s" % args.host_sysroot,
cxxflags="--sysroot=%s -stdlib=libc++" % args.host_sysroot,
ldflags="--sysroot=%s" % args.host_sysroot
+ (
" -L%s" % path.join(args.clang_prefix, "lib")
if args.is_mac
else " -static-libstdc++"
),
)
)
config_toml = BUILD_CONFIG.format(
prefix=args.prefix,
jemalloc=str(not args.is_win).lower(),
gomacc_quote=('"%s"' % path.join(args.goma_dir, "gomacc"))
if args.goma_dir
else "false",
cmake_settings=cmake_fragment,
thinlto=str(args.thinlto).lower(),
target=string_list(targets),
tools=string_list(tools),
# For windows specify that host is msvc not mingw
host_triple='build = "x86_64-pc-windows-msvc"' if args.is_win else "",
bootstrap=BOOTSTRAP_CONFIG.format(beta=args.beta) if args.beta else "",
)
for target in targets:
cc = clang_tool(args, "clang")
cxx = clang_tool(args, "clang++")
linker = clang_tool(args, "clang++")
ar = clang_tool(args, "llvm-ar")
if "fuchsia" in target:
linker = clang_tool(args, "ld.lld")
elif "windows" in target:
cc = cxx = clang_tool(args, "clang-cl")
linker = clang_tool(args, "lld-link")
ar = clang_tool(args, "llvm-lib")
config_toml += TARGET_CONFIG.format(
triple=target,
cc=cc,
cxx=cxx,
ar=ar,
ranlib=clang_tool(args, "llvm-ranlib"),
linker=linker,
# Enabling the profiler for wasm caused the build to fail, so we
# disable it for now.
profiler="false" if "wasm" in target else "true",
)
print(config_toml.replace("\\", "/"))
def generate_env(args):
env = OrderedDict()
env["RUST_BACKTRACE"] = 1
if args.revision:
env["CFG_VERSION"] = args.revision
# Configure Fuchsia targets.
for target, gn_arch in list(FUCHSIA_TRIPLE_TO_ARCH.items()):
triple_lower = target.replace("-", "_").lower()
triple_upper = triple_lower.upper()
clang_target = target.replace("riscv64gc", "riscv64")
env["CC_%s" % triple_lower] = clang_tool(args, "clang")
env["CXX_%s" % triple_lower] = clang_tool(args, "clang++")
env["CFLAGS_%s" % triple_lower] = "--target=%s --sysroot=%s -I%s" % (
clang_target,
path.join(args.sdk_dir, "arch", gn_arch, "sysroot"),
path.join(args.sdk_dir, "pkg", "fdio", "include"),
)
env["CXXFLAGS_%s" % triple_lower] = "--target=%s --sysroot=%s -I%s" % (
clang_target,
path.join(args.sdk_dir, "arch", gn_arch, "sysroot"),
path.join(args.sdk_dir, "pkg", "fdio", "include"),
)
env["LDFLAGS_%s" % triple_lower] = (
"--target=%s --sysroot=%s -L%s"
% (
clang_target,
path.join(args.sdk_dir, "arch", gn_arch, "sysroot"),
path.join(args.sdk_dir, "arch", gn_arch, "lib"),
) # TODO(https://fxbug.dev/117949): Remove "--undefined-version" logic when issue resolved upstream.
+ " --undefined-version"
)
env["CARGO_TARGET_%s_AR" % triple_upper] = clang_tool(args, "llvm-ar")
env["CARGO_TARGET_%s_RUSTFLAGS" % triple_upper] = " ".join(
[
"-Clink-arg=--sysroot=%s"
% path.join(args.sdk_dir, "arch", gn_arch, "sysroot"),
"-Lnative=%s/lib" % path.join(args.sdk_dir, "arch", gn_arch, "sysroot"),
"-Lnative=%s" % path.join(args.sdk_dir, "arch", gn_arch, "lib"),
"-Cpanic=abort",
"-Cforce-unwind-tables=yes",
]
# TODO(https://fxbug.dev/117949): Remove "--undefined-version" logic when issue resolved upstream.
+ ["-Clink-arg=--undefined-version"]
)
target_sysroots = {
"aarch64-unknown-linux-gnu": args.linux_arm64_sysroot,
"x86_64-unknown-linux-gnu": args.linux_amd64_sysroot,
}
if args.darwin_sysroot:
target_sysroots.update({"aarch64-apple-darwin": args.darwin_sysroot})
target_sysroots.update({"x86_64-apple-darwin": args.darwin_sysroot})
if args.win_sysroot:
target_sysroots.update({"x86_64-pc-windows-msvc": args.win_sysroot})
# Configure non-Fuchsia target sysroots.
for target in args.targets.split(","):
# These are the only targets we define a sysroot for.
if not ("linux" in target or "apple" in target):
continue
sysroot = target_sysroots[target]
triple_lower = target.replace("-", "_").lower()
triple_upper = triple_lower.upper()
env["CC_%s" % triple_lower] = clang_tool(args, "clang")
env["CXX_%s" % triple_lower] = clang_tool(args, "clang++")
env["CFLAGS_%s" % triple_lower] = " ".join(
["--target=" + target, "--sysroot=" + sysroot]
# TODO(https://fxbug.dev/69260): Find a longer-term solution.
+ (["-mno-outline-atomics"] if "aarch64" in target else [])
)
env["CXXFLAGS_%s" % triple_lower] = "--target=%s --sysroot=%s" % (
target,
sysroot,
)
env["LDFLAGS_%s" % triple_lower] = (
"--target=%s --sysroot=%s"
% (
target,
sysroot,
)
+ (" -fuse-ld=lld" if "apple" not in target else "")
# TODO(https://fxbug.dev/117949): Remove "--undefined-version" logic when issue resolved upstream.
+ (" -Wl,--undefined-version" if "apple" not in target else "")
)
env["CARGO_TARGET_%s_AR" % triple_upper] = clang_tool(args, "llvm-ar")
env["CARGO_TARGET_%s_RUSTFLAGS" % triple_upper] = " ".join(
["-Clink-arg=--target=%s" % target, "-Clink-arg=--sysroot=%s" % sysroot]
+ (["-Clink-arg=-fuse-ld=lld"] if "apple" not in target else [])
# TODO(https://fxbug.dev/117949): Remove "--undefined-version" logic when issue resolved upstream.
+ (["-Clink-arg=-Wl,--undefined-version"] if "apple" not in target else [])
)
# This flag is unstable; see https://fxbug.dev/108610 for details.
env["CARGOFLAGS"] = "-Ztarget-applies-to-host"
for key, val in list(env.items()):
if args.eval:
print('export {}="{}"'.format(key, val).replace("\\", "/"))
else:
print("{}={}".format(key, val).replace("\\", "/"))
# pylint: disable=unused-argument
def generate_runtimes_spec(args):
"""
Unused argument `args` required to preserve usage pattern:
```
parser_env.set_defaults(func=generate_env)
parser_runtime.set_defaults(func=generate_runtimes_spec)
args = parser.parse_args()
args.func(args)
```
"""
runtimes = []
for dynlink_flags in [[], ["-Cprefer-dynamic"]]:
for targets in FUCHSIA_RUNTIME_TARGETS:
if args.is_mac and targets[0] == "riscv64gc-unknown-fuchsia":
# TODO(https://fxbug.dev/126336): fix riscv64gc-unknown-fuchsia build on mac
continue
runtime = []
if dynlink_flags:
for lib in ["libstd", "libtest"]:
runtime.append(
{
# The runtimes module will expand this wildcard
# (it must match exactly one file.)
"dist": "rustlib/%s/lib/%s-*.so" % (targets[0], lib),
"name": lib,
}
)
runtimes.append(
{
"target": targets,
"rustflags": dynlink_flags,
"runtime": runtime,
}
)
print(json.dumps(runtimes))
def main():
is_mac = platform.system() == "Darwin"
is_win = platform.system() == "Windows"
default_targets = [
"x86_64-unknown-linux-gnu",
"aarch64-unknown-linux-gnu",
"wasm32-unknown-unknown",
"thumbv7m-none-eabi",
]
if is_mac:
default_targets.append("aarch64-apple-darwin")
default_targets.append("x86_64-apple-darwin")
if is_win:
default_targets = ["x86_64-pc-windows-msvc"]
parser = argparse.ArgumentParser()
parser.set_defaults(is_mac=is_mac)
parser.set_defaults(is_win=is_win)
subparsers = parser.add_subparsers()
parser_config = subparsers.add_parser("config_toml")
parser_env = subparsers.add_parser("environment")
parser_runtime = subparsers.add_parser("runtime")
for subcommand in [parser_config, parser_env]:
subcommand.add_argument(
"--targets",
default=",".join(default_targets),
help="comma-separated list of targets to build for, in addition to Fuchsia",
)
subcommand.add_argument(
"--clang-prefix", help="path to clang toolchain", required=True
)
parser_config.add_argument("--prefix", help="installation prefix", required=True)
parser_config.add_argument(
"--host-sysroot", help="path to host sysroot", required=True
)
parser_config.add_argument("--goma-dir", help="path to goma", required=False)
parser_config.add_argument(
"--beta", help="path to beta toolchain, will download from upstream by default"
)
parser_config.add_argument(
"--thinlto",
default=not (is_mac or is_win),
action="store_true",
help="enable thinlto",
)
parser_config.add_argument(
"--tools",
help="comma-separated list of tools to build",
default=",".join(DEFAULT_TOOLS),
)
parser_config.set_defaults(func=generate_config_toml)
parser_env.add_argument("--source", help="rust source path", default=getcwd())
parser_env.add_argument("--sdk-dir", help="path to Fuchsia SDK", required=True)
parser_env.add_argument("--linux-amd64-sysroot", help="path to Linux amd64 sysroot")
parser_env.add_argument("--linux-arm64-sysroot", help="path to Linux arm64 sysroot")
parser_env.add_argument(
"--darwin-sysroot", help="path to Darwin sysroot, if building on Mac"
)
parser_env.add_argument(
"--win-sysroot", help="path to Windows sysroot, if building on Windows"
)
parser_env.add_argument("--revision", help="git commit of Rust repository")
parser_env.add_argument(
"--eval",
default=False,
action="store_true",
help="format output for evaluating in a terminal",
)
parser_env.set_defaults(func=generate_env)
parser_runtime.set_defaults(func=generate_runtimes_spec)
args = parser.parse_args()
args.func(args)
return 0
if __name__ == "__main__":
sys.exit(main())