| #!/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()) |