blob: 1b3084289c70807bb8f6255246c1fd8921d9120b [file] [log] [blame]
# Copyright (C) 2019 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Handles generation of config.toml for the rustc build."""
import argparse
import os
from pathlib import Path
import subprocess
import sys
from typing import Any, Tuple, Union
import build_platform
from paths import *
from utils import instantiate_template, instantiate_template_file, instantiate_template_exec
#
# Constants
#
HOST_TARGETS_DEFAULT: list[str] = [
"x86_64-unknown-linux-gnu",
"i686-unknown-linux-gnu",
"x86_64-unknown-linux-musl",
"i686-unknown-linux-musl",
"x86_64-pc-windows-gnu",
]
BARE_TARGETS_DEFAULT: list[str] = [
"aarch64-unknown-none",
"armv7a-none-eabi",
"riscv32i-unknown-none-elf",
"riscv32imc-unknown-none-elf",
# Added for b/301288222
"x86_64-unknown-uefi",
"i686-unknown-uefi",
"aarch64-unknown-uefi",
]
DEVICE_TARGET_AND_ARCH: dict[str, str] = {
"aarch64-linux-android": "aarch64",
"armv7-linux-androideabi": "arm",
"x86_64-linux-android": "x86_64",
"i686-linux-android": "i386",
}
# rustc replaces these triples with other targets when invoking clang. To
# avoid confusion we won't emit `--target=<triple>` flags into the compiler and
# linker wrappers.
RUSTC_TRANSLATED_TRIPLES: list[str] = [
"x86_64-unknown-uefi",
"i686-unknown-uefi",
"aarch64-unknown-uefi",
]
DEVICE_TARGETS_DEFAULT: list[str] = list(DEVICE_TARGET_AND_ARCH.keys())
ANDROID_TARGET_VERSION: str = "31"
_CMD = ".cmd" if build_platform.is_windows() else ""
BARE_CC_WRAPPER_TEMPLATE: Path = TEMPLATES_PATH / f"bare_cc_wrapper{_CMD}.template"
BARE_LINKER_WRAPPER_TEMPLATE: Path = TEMPLATES_PATH / f"bare_linker_wrapper{_CMD}.template"
BARE_TARGET_TEMPLATE: Path = TEMPLATES_PATH / "bare_target.template"
CONFIG_TOML_TEMPLATE: Path = TEMPLATES_PATH / "config.toml.template"
DEVICE_CC_WRAPPER_TEMPLATE: Path = TEMPLATES_PATH / f"device_cc_wrapper{_CMD}.template"
DEVICE_LINKER_WRAPPER_TEMPLATE: Path = TEMPLATES_PATH / f"device_linker_wrapper{_CMD}.template"
DEVICE_TARGET_TEMPLATE: Path = TEMPLATES_PATH / "device_target.template"
HOST_CC_WRAPPER_TEMPLATE: Path = TEMPLATES_PATH / f"host_cc_wrapper{_CMD}.template"
HOST_CXX_WRAPPER_TEMPLATE: Path = TEMPLATES_PATH / f"host_cxx_wrapper{_CMD}.template"
HOST_LINKER_WRAPPER_TEMPLATE: Path = TEMPLATES_PATH / f"host_linker_wrapper{_CMD}.template"
HOST_TARGET_TEMPLATE: Path = TEMPLATES_PATH / "host_target.template"
#
# Helper functions
#
def vp_counters_flags(num_counters: int) -> str:
return f"-mllvm -vp-counters-per-site={num_counters}"
def apply_target_flags(target: str, cc_flags: list[str], cxx_flags: list[str], ld_flags: list[str], android_version: str = "", escape: bool = True) -> Tuple[str, str, str]:
if target in RUSTC_TRANSLATED_TRIPLES:
target_flag = []
else:
target_flag = [f"--target={target}{android_version}"]
cc_flags_str = " ".join(
target_flag +
TARGET_COMMON_FLAGS.get(target, []) +
TARGET_CC_FLAGS.get(target, []) +
cc_flags)
cxx_flags_str = " ".join(
target_flag +
TARGET_COMMON_FLAGS.get(target, []) +
TARGET_CC_FLAGS.get(target, []) +
TARGET_CXX_FLAGS.get(target, []) +
cxx_flags)
ld_flags_str = " ".join(
target_flag +
TARGET_COMMON_FLAGS.get(target, []) +
TARGET_LD_FLAGS.get(target, []) +
ld_flags)
if escape:
cc_flags_str = cc_flags_str.replace("$", "\\$")
cxx_flags_str = cxx_flags_str.replace("$", "\\$")
ld_flags_str = ld_flags_str.replace("$", "\\$")
return (cc_flags_str, cxx_flags_str, ld_flags_str)
def darwin_sysroot() -> str:
if build_platform.is_darwin():
# Apple removed the normal sysroot at / on Mojave+, so we need
# to go hunt for it on OSX
# On pre-Mojave, this command will output the empty string.
output = subprocess.check_output(
["xcrun", "--sdk", "macosx", "--show-sdk-path"])
return output.rstrip().decode("utf-8")
return ""
def print_flags(target: str, cc_flags: str, cxx_flags: str, ld_flags: str) -> None:
print(f"Compiler/linker flags for {target}")
print(f"CC Flags: {cc_flags}")
if cxx_flags:
print(f"CXX Flags: {cxx_flags}")
print(f"LD Flags: {ld_flags}\n")
def get_wrapper_paths(target: str) -> Tuple[Path, Path, Path]:
return (
OUT_PATH_WRAPPERS / f"clang-{target}{_CMD}",
OUT_PATH_WRAPPERS / f"clang++-{target}{_CMD}",
OUT_PATH_WRAPPERS / f"linker-{target}{_CMD}",
)
#
# Target configuration
#
def host_config(target: str, cc_flags: list[str], cxx_flags: list[str], ld_flags: list[str], env: dict[str, str]) -> str:
cc_wrapper_name, cxx_wrapper_name, ld_wrapper_name = get_wrapper_paths(target)
cc_flags_str, cxx_flags_str, ld_flags_str = apply_target_flags(target, cc_flags, cxx_flags, ld_flags)
print_flags(target, cc_flags_str, cxx_flags_str, ld_flags_str)
envified_target = target.replace("-", "_")
env[f"CC_{envified_target}"] = cc_wrapper_name.as_posix()
env[f"CXX_{envified_target}"] = cxx_wrapper_name.as_posix()
env[f"LD_{envified_target}"] = ld_wrapper_name.as_posix()
env[f"RANLIB_{envified_target}"] = RANLIB_PATH.as_posix()
instantiate_template_exec(
HOST_CC_WRAPPER_TEMPLATE,
cc_wrapper_name,
real_cc=CC_PATH,
cc_flags=cc_flags_str)
instantiate_template_exec(
HOST_CXX_WRAPPER_TEMPLATE,
cxx_wrapper_name,
real_cxx=CXX_PATH,
cxx_flags=cxx_flags_str)
instantiate_template_exec(
HOST_LINKER_WRAPPER_TEMPLATE,
ld_wrapper_name,
real_cc=CC_PATH,
ld_flags=ld_flags_str)
return instantiate_template(
HOST_TARGET_TEMPLATE,
target=target,
cc=cc_wrapper_name.as_posix(),
cxx=cxx_wrapper_name.as_posix(),
llvm_config=LLVM_CONFIG_PATH.as_posix(),
linker=ld_wrapper_name.as_posix(),
ar=AR_PATH.as_posix(),
ranlib=RANLIB_PATH.as_posix(),
musl_root=f"musl-root = \"{HOST_SYSROOTS[target]}\"" if "musl" in target else "")
def bare_config(target: str, cc_flags: list[str], ld_flags: list[str], env: dict[str, str]) -> str:
cc_wrapper_name, _, ld_wrapper_name = get_wrapper_paths(target)
cc_flags_str, _, ld_flags_str = apply_target_flags(target, cc_flags, [], ld_flags)
print_flags(target, cc_flags_str, "", ld_flags_str)
envified_target = target.replace("-", "_")
env[f"CC_{envified_target}"] = cc_wrapper_name.as_posix()
env[f"LD_{envified_target}"] = ld_wrapper_name.as_posix()
instantiate_template_exec(
BARE_CC_WRAPPER_TEMPLATE,
cc_wrapper_name,
real_cc=CC_PATH,
cc_flags=cc_flags_str)
instantiate_template_exec(
BARE_LINKER_WRAPPER_TEMPLATE,
ld_wrapper_name,
real_cc=CC_PATH,
ld_flags=ld_flags_str)
return instantiate_template(
BARE_TARGET_TEMPLATE,
target=target,
cc=cc_wrapper_name.as_posix(),
cxx=cc_wrapper_name.as_posix(),
linker=ld_wrapper_name.as_posix(),
ar=AR_PATH.as_posix())
def device_config(target: str, cc_flags: list[str], ld_flags: list[str], env: dict[str, str]) -> str:
cc_wrapper_name, _, ld_wrapper_name = get_wrapper_paths(target)
cc_flags_str, _, ld_flags_str = apply_target_flags(
target, cc_flags, [], ld_flags, android_version=ANDROID_TARGET_VERSION)
print_flags(target, cc_flags_str, "", ld_flags_str)
envified_target = target.replace("-", "_")
env[f"CC_{envified_target}"] = cc_wrapper_name.as_posix()
env[f"LD_{envified_target}"] = ld_wrapper_name.as_posix()
instantiate_template_exec(
DEVICE_CC_WRAPPER_TEMPLATE,
cc_wrapper_name,
real_cc=CC_PATH,
cc_flags=cc_flags_str)
instantiate_template_exec(
DEVICE_LINKER_WRAPPER_TEMPLATE,
ld_wrapper_name,
real_cc=CC_PATH,
ld_flags=ld_flags_str)
return instantiate_template(
DEVICE_TARGET_TEMPLATE,
target=target,
cc=cc_wrapper_name.as_posix(),
cxx=cc_wrapper_name.as_posix(),
linker=ld_wrapper_name.as_posix(),
ar=AR_PATH.as_posix())
#
# Main configuration
#
CC_FLAG_PIC: str = "-fpic"
LD_FLAG_PIC: str = "-Wl,-mllvm,--relocation-model=pic"
LD_FLAG_USE_LLD: str = "-fuse-ld=lld"
LD_OLD_DTAGS: str = "-Wl,--disable-new-dtags"
LD_FLAG_RPATH: str = f"-Wl,-rpath,{build_platform.rpath_origin()}/../lib64"
MACOSX_VERSION_FLAG: str = "-mmacosx-version-min=10.14"
HOST_SYSROOTS: dict[str, str] = {
"x86_64-unknown-linux-gnu": GCC_SYSROOT_PATH.as_posix(),
"i686-unknown-linux-gnu": GCC_SYSROOT_PATH.as_posix(),
"x86_64-apple-darwin": darwin_sysroot(),
"x86_64-unknown-linux-musl": MUSL_SYSROOT64_PATH.as_posix(),
"i686-unknown-linux-musl": MUSL_SYSROOT32_PATH.as_posix(),
"x86_64-pc-windows-gnu": MINGW_SYSROOT_PATH.as_posix(),
}
TARGET_COMMON_FLAGS: dict[str, list[str]] = {}
for arch, sysroot in HOST_SYSROOTS.items():
sysroot_flag = f"--sysroot={sysroot}"
if arch in TARGET_COMMON_FLAGS:
TARGET_COMMON_FLAGS[arch].append(sysroot_flag)
else:
TARGET_COMMON_FLAGS[arch] = [sysroot_flag]
TARGET_CC_FLAGS: dict[str, list[str]] = {
"x86_64-apple-darwin": ["-D_LIBCPP_AVAILABILITY_HAS_NO_VERBOSE_ABORT=1"],
"x86_64-unknown-linux-musl": ["-D_LIBCPP_HAS_MUSL_LIBC"],
"i686-unknown-linux-musl": ["-D_LIBCPP_HAS_MUSL_LIBC"],
}
TARGET_CXX_FLAGS: dict[str, list[str]] = {}
HOST_LINUX_LD_FLAGS: list[str] = [
LD_FLAG_USE_LLD,
"--rtlib=compiler-rt",
# Rely on rust.llvm-libunwind="in-tree" in config.toml to link host
# binaries against the in-tree built LLVM libunwind. The version of
# libunwind in our prebuilts is for devices only.
#"-lunwind",
f"-B{GCC_LIBGCC_PATH.as_posix()}",
f"-L{GCC_LIBGCC_PATH.as_posix()}",
f"-L{GCC_LIB_PATH.as_posix()}",
f"-L{LLVM_CXX_RUNTIME_PATH_HOST.as_posix()}",
LD_OLD_DTAGS,
LD_FLAG_RPATH,
]
HOST_WINDOWS_LDFLAGS: list[str] = [
LD_FLAG_USE_LLD,
# "--rtlib=compiler-rt",
f"-B{MINGW_LIBGCC_PATH.as_posix()}",
f"-L{MINGW_LIBGCC_PATH.as_posix()}",
f"-L{MINGW_LIB_PATH.as_posix()}",
f"-L{LLVM_CXX_RUNTIME_PATH_WINDOWS.as_posix()}",
]
TARGET_LD_FLAGS: dict[str, list[str]] = {
# When performing LTO, the LLVM IR generator doesn't know about these
# target specific symbols. By telling the linker about them ahead of time
# we avoid an error when they are encountered when the native code is
# emitted. See b/201551165 for more information.
"armv7-linux-androideabi": [
"-u __aeabi_uidiv",
"-u __aeabi_idiv0",
LD_OLD_DTAGS,
LD_FLAG_RPATH,
],
"x86_64-unknown-linux-gnu": HOST_LINUX_LD_FLAGS,
"i686-unknown-linux-gnu": HOST_LINUX_LD_FLAGS,
"x86_64-apple-darwin": [
f"-L{LLVM_CXX_RUNTIME_PATH_HOST}",
LD_FLAG_RPATH,
],
"x86_64-unknown-linux-musl": [
LD_FLAG_USE_LLD,
"--rtlib=compiler-rt",
f"-L{LLVM_CXX_RUNTIME_PATH_LINUX_MUSL}",
f"-L{MUSL_SYSROOT64_PATH.as_posix()}/lib",
LD_OLD_DTAGS,
LD_FLAG_RPATH,
],
"i686-unknown-linux-musl": [
LD_FLAG_USE_LLD,
"--rtlib=compiler-rt",
f"-L{LLVM_CXX_RUNTIME_PATH_LINUX_MUSL}",
f"-L{MUSL_SYSROOT32_PATH.as_posix()}/lib",
LD_OLD_DTAGS,
LD_FLAG_RPATH,
],
"x86_64-pc-windows-gnu": HOST_WINDOWS_LDFLAGS,
}
MUSL_RUSTFLAGS: list[str] = [
# Rust defaults to using its own crt objects when targeting musl, but we
# want to use the ones from the sysroot with the embedded dynamic
# linker. It defaults to no when targeting glibc, darwin or android.
"-Clink-self-contained=no",
]
BTI_RUSTFLAGS_X86: list[str] = [
"-Zcf-protection=branch",
]
BTI_RUSTFLAGS_AARCH64: list[str] = [
"-Zbranch-protection=bti",
]
TARGET_RUSTFLAGS: dict[str, list[str]] = {
"x86_64-unknown-linux-musl": MUSL_RUSTFLAGS,
"i686-unknown-linux-musl": MUSL_RUSTFLAGS,
"aarch64-unknown-none": BTI_RUSTFLAGS_AARCH64,
"aarch64-unknown-linux-gnu": BTI_RUSTFLAGS_AARCH64,
"aarch64-linux-android": BTI_RUSTFLAGS_AARCH64,
"x86_64-unknown-linux-gnu": BTI_RUSTFLAGS_X86,
"riscv64-linux-android": ["-C target-feature=+V,+Zba,+Zbb,+Zbs"],
}
def configure(args: argparse.Namespace, env: dict[str, str]) -> None:
"""Generates config.toml and compiler wrappers for the rustc build."""
#
# Update environment variables
#
path: list[Union[Path, str]] = [
PYTHON_PATH.parent,
RUST_HOST_STAGE0_PATH / "bin",
CMAKE_PREBUILT_PATH / "bin",
NINJA_PREBUILT_PATH,
BUILD_TOOLS_PREBUILT_MULTICALL,
BUILD_TOOLS_PREBUILT_BIN_PATH,
OUT_PATH_BIN_LINKS,
]
# Continue to use the system search paths on Darwin.
if build_platform.is_darwin():
path.append(env["PATH"])
if build_platform.is_windows():
path.extend([
GIT_USR_BIN_PATH, # So we can find sh.exe
MINGW_LIB_PATH.parent / "bin",
MINGW_LIB_PATH.parent / "lib",
])
env["PATH"] = os.pathsep.join([str(p) for p in path])
# System libraries are still required to build the Mac and Windows
# toolchains.
if build_platform.is_linux():
if "LIBRARY_PATH" in env:
del env["LIBRARY_PATH"]
# Use LD_LIBRARY_PATH to tell the build system where to find libc++.so.1
# without polluting the rpath of the produced artifacts.
if not build_platform.is_windows():
env["LD_LIBRARY_PATH"] = LLVM_CXX_RUNTIME_PATH_HOST.as_posix()
# Tell the rust bootstrap system where to place its final products
env["DESTDIR"] = OUT_PATH_PACKAGE.as_posix()
# Tell pkg-config where to find metadata
env["PKG_CONFIG_PATH"] = GCC_PKG_CONFIG_PATH.as_posix()
# By default, the lzma-sys crate links against the system's liblzma.so.
# This causes Cargo to propagate a dependency to the system library
# directory to all of the libraries that depend on lzma-sys.
#
# Setting this property causes the crate to build a static liblzma.a and
# link against that.
env["LZMA_API_STATIC"] = "1"
# Ensure libz is compiled from in-tree source.
env["LIBZ_SYS_STATIC"] = "1"
# Explicitly set the host AR path; this is required to build the
# openssl-src crate.
env["AR"] = AR_PATH.as_posix()
#
# Select the targets
#
host_targets: list[str] = [args.host]
if build_platform.is_linux():
if not args.host_multilibs:
# Make sure that a compiler for the host triple can be found
if args.host != build_platform.triple():
host_targets.append(build_platform.triple())
else:
for t in HOST_TARGETS_DEFAULT:
if t != args.host:
host_targets.append(t)
bare_targets: list[str] = []
if args.bare_targets:
bare_targets = BARE_TARGETS_DEFAULT
device_targets: list[str] = []
if args.device_targets:
device_targets = DEVICE_TARGETS_DEFAULT
all_targets: list[str] = host_targets + bare_targets + device_targets
#
# Flag set definitions
#
common_cc_flags = []
# `-fuse-ld=lld` will cause Clang to use the prebuilt version of LLD. This
# is not desired on Darwin hosts as only the system linker can successfully
# link binaries for the platform. As such this flag is not included here
# and is instead listed in `bare_ld_flags`, `device_ld_flags` and specific
# host target flags.
common_ld_flags = []
host_common_flags = []
host_cc_flags = [CC_FLAG_PIC]
# All flags from host_cc_flags will be added to host_cxx_flags
host_cxx_flags = [
"--stdlib=libc++",
f"-I{CXXSTD_PATH.as_posix()}",
]
host_ld_flags = [
LD_FLAG_PIC,
]
bare_cc_flags: list[str] = []
bare_ld_flags: list[str] = [LD_FLAG_USE_LLD]
device_common_flags = [f"--sysroot={(args.ndk_path / NDK_LLVM_PATH_SUFFIX / NDK_SYSROOT_PATH_SUFFIX).as_posix()}"]
device_cc_flags = [CC_FLAG_PIC]
# No need to pass `--rtlib=compiler-rt -lunwind` arguments here because NDK
# r23+ only has compiler-rt
device_ld_flags = [
LD_FLAG_USE_LLD,
LD_FLAG_PIC,
]
llvm_common_flags = []
llvm_cc_flags: list[str] = []
llvm_ld_flags = []
env_cflags: list[str] = []
env_rustflags: list[str] = [
"-Crelocation-model=pic",
f"-Cdlltool={DLLTOOL_PATH}",
] + ([] if args.verbose else ["-Awarnings"])
env_rustflags_bootstrap: list[str] = []
env_rustflags_not_bootstrap: list[str] = []
env_rustdocflags: list[str] = [
# For some reason, rustdoc needs a linker.
f"-Clinker={get_wrapper_paths(args.host)[2]}"
]
#
# Build platform based configuration
#
if build_platform.is_darwin():
host_common_flags.append(MACOSX_VERSION_FLAG)
# The Linux build of clang has some architecture-specific libraries, and it knows how
# to find them. The Windows build doesn't have these, and so it doesn't know how to find
# libunwind.a. So, when building on Windows, we need to point to the right directory in
# in the Linux build of clang.
if build_platform.is_windows():
for target, arch in DEVICE_TARGET_AND_ARCH.items():
unwind_path = DEVICE_LIB_PATH / arch
if not unwind_path.is_dir():
raise RuntimeError(f"{unwind_path} is not a directory")
flag = f"-L{unwind_path.as_posix()}"
if target in TARGET_LD_FLAGS:
TARGET_LD_FLAGS[target].append(flag)
else:
TARGET_LD_FLAGS[target] = [flag]
#
# Command-line based configuration
#
# LTO
llvm_lto_config = "false"
rust_lto_config = "thin-local"
if args.lto == "thin":
llvm_lto_config = "true"
rust_lto_config = "thin"
# PGO
llvm_pgo_config: str = ""
rustc_pgo_config: str = ""
if args.profile_generate != None:
profile_name_llvm = PROFILE_SUBDIR_LLVM if args.llvm_linkage == "shared" else PROFILE_SUBDIR_RUST
llvm_cc_flags.append(vp_counters_flags(16))
llvm_cc_flags.append("-Wno-unused-command-line-argument")
env_rustflags.append("-Cllvm-args=-vp-counters-per-site=16")
llvm_pgo_config = f"profile-generate = \"{args.profile_generate / profile_name_llvm}\""
rustc_pgo_config = f"profile-generate = \"{args.profile_generate / PROFILE_SUBDIR_RUST}\""
elif args.profile_use != None:
# LLVM
profile_path_llvm: Path = args.profile_use / PROFILE_NAME_LLVM_CS
if not profile_path_llvm.exists():
profile_path_llvm = args.profile_use / PROFILE_NAME_LLVM
if profile_path_llvm.exists():
llvm_pgo_config = f"profile-use = \"{profile_path_llvm}\""
# Rust
profile_path_rust: Path = args.profile_use / PROFILE_NAME_RUST
if profile_path_rust.exists():
rustc_pgo_config = f"profile-use = \"{profile_path_rust}\""
if not (profile_path_llvm.exists() or profile_path_rust.exists()):
sys.exit(f"No profiles found in specified directory: {args.profile_use}")
if args.cs_profile_generate != None:
# TODO: The vp-counters-per-site value needs to be tuned to eliminate
# warnings about the inability to allocate counters during
# context-sensitive profiling.
if args.llvm_linkage == "shared":
profile_path = args.cs_profile_generate / PROFILE_SUBDIR_LLVM_CS
llvm_common_flags += [
f"-fcs-profile-generate={profile_path}",
vp_counters_flags(32),
]
else: # args.llvm_linkage == "static"
if args.lto == None:
raise RuntimeError("Context-sensitive PGO with static LLVM linkage requires LTO to be enabled")
profile_path = args.cs_profile_generate / PROFILE_SUBDIR_RUST
llvm_common_flags += [
f"-fcs-profile-generate={profile_path}",
vp_counters_flags(32),
]
llvm_ld_flags += [
" -Wl,--lto-cs-profile-generate",
f"-Wl,--lto-cs-profile-file={profile_path}",
]
env_rustflags += [
f"-C link-arg=-fcs-profile-generate={profile_path}",
" -C link-arg=-Wl,--lto-cs-profile-generate",
f"-C link-arg=-Wl,--lto-cs-profile-file={profile_path}"
]
# Misc.
if args.emit_relocs:
for target in HOST_TARGETS_DEFAULT:
# "-Wl,--emit-relocs" is not supported on Windows targets
if "linux" in target:
TARGET_LD_FLAGS[target].append("-Wl,--emit-relocs")
if args.gc_sections and build_platform.is_linux():
common_cc_flags += ["-ffunction-sections", "-fdata-sections"]
common_ld_flags.append("-Wl,--gc-sections")
if args.cgu1:
env_rustflags.append("-Ccodegen-units=1")
llvm_link_shared = "true" if args.llvm_linkage == "shared" else "false"
# Coalesce flags
host_cc_flags = common_cc_flags + host_common_flags + host_cc_flags
host_cxx_flags = host_cc_flags + host_cxx_flags
host_ld_flags = common_ld_flags + host_common_flags + host_ld_flags
bare_cc_flags = common_cc_flags + bare_cc_flags
bare_ld_flags = common_ld_flags + bare_ld_flags
device_cc_flags = common_cc_flags + device_common_flags + device_cc_flags
device_ld_flags = common_ld_flags + device_common_flags + device_ld_flags
llvm_cc_flags_str = " ".join(llvm_common_flags + llvm_cc_flags)
llvm_ld_flags_str = " ".join(
host_ld_flags +
llvm_common_flags +
llvm_ld_flags)
env["CFLAGS"] = " ".join(env_cflags)
env["RUSTFLAGS_BOOTSTRAP"] = " ".join(env_rustflags + env_rustflags_bootstrap)
env["RUSTFLAGS_NOT_BOOTSTRAP"] = " ".join(env_rustflags + env_rustflags_not_bootstrap)
env["RUSTDOCFLAGS"] = " ".join(env_rustdocflags)
# Display final flag strings (and set some straggling env vars)
print()
print("Compiler/Linker Flags")
print()
print(f"env PATH: {env['PATH']}")
print(f"env LIBRARY_PATH: {env.get('LIBRARY_PATH', '')}")
print()
print(f"env CFLAGS : {env['CFLAGS']}")
print(f"env RUSTFLAGS_BOOTSTRAP : {env['RUSTFLAGS_BOOTSTRAP']}")
print(f"env RUSTFLAGS_NOT_BOOTSTRAP: {env['RUSTFLAGS_NOT_BOOTSTRAP']}")
print()
print(f"LLVM CC Flags: {llvm_cc_flags_str}")
print(f"LLVM LD Flags: {llvm_ld_flags_str}")
print()
# The LLVM build needs different linker flags for x86_64-unknown-linux-gnu and
# x86_64-unknown-linux-musl when cross-compiling host musl tools. The LLVM
# build never uses the linker wrapper, it runs the compiler wrappers to link
# instead, so the target-specific linker flags can't go in the wrappers. It
# only has a single field in config.toml for all architectures. The only way
# to pass target-specific linker flags to LLVM is to use LDFLAGS_<triple>
# environment variables.
for target in host_targets:
env_var_name = "LDFLAGS_" + target.replace("-", "_")
env[env_var_name] = " ".join(
TARGET_COMMON_FLAGS[target] +
TARGET_LD_FLAGS[target])
print(f"env {env_var_name} = {env[env_var_name]}")
print()
for target, flags in TARGET_RUSTFLAGS.items():
if target in all_targets:
key = f"CARGO_TARGET_{target.replace('-', '_').upper()}_RUSTFLAGS"
env[key] = " ".join(flags)
print(f"env {key}: {env[key]}")
print()
#
# Instantiate wrappers
#
host_configs = "\n".join(
[host_config(target, host_cc_flags, host_cxx_flags, host_ld_flags, env) for target in host_targets])
bare_configs = "\n".join(
[bare_config(target, bare_cc_flags, bare_ld_flags, env) for target in bare_targets])
device_configs = "\n".join(
[device_config(target, device_cc_flags, device_ld_flags, env) for target in device_targets])
quoted_target_list = ",".join([f'\"{target}\"' for target in all_targets])
#
# Print Environment
#
print()
print("Environment Variables")
for key, val in sorted(env.items()):
print(f"\t{key} => {val}")
print()
instantiate_template_file(
CONFIG_TOML_TEMPLATE,
OUT_PATH_RUST_SOURCE / "config.toml",
llvm_link_shared=llvm_link_shared,
llvm_cflags=llvm_cc_flags_str,
llvm_cxxflags=llvm_cc_flags_str,
llvm_ldflags=llvm_ld_flags_str,
llvm_lto_config=llvm_lto_config,
llvm_pgo_config=llvm_pgo_config,
stage0_host_triple=RUST_STAGE0_TRIPLE,
new_host_triple=args.host,
all_targets=quoted_target_list,
cargo=CARGO_PATH.as_posix(),
rustc=RUSTC_PATH.as_posix(),
python=PYTHON_PATH.as_posix(),
verbose=1 if args.verbose else 0,
description=f"\"Android Rust Toolchain version {args.build_name}\"",
rust_lto_config=rust_lto_config,
rust_pgo_config=rustc_pgo_config,
host_configs=host_configs,
bare_configs=bare_configs,
device_configs=device_configs)