'''Assembles a Rust toolchain in-tree linked against the LLVM revision
specified in //tools/clang/scripts/update.py.
Builds a Rust toolchain bootstrapped from an untrusted rustc build.
Rust has an official boostrapping build. At a high level:
1. A "stage 0" Rust is downloaded from Rust's official server. This
is one major release before the version being built. E.g. if building trunk
the latest beta is downloaded. If building stable 1.57.0, stage0 is stable
1.56.1.
2. Stage 0 libstd is built. This is different than the libstd downloaded above.
3. Stage 1 rustc is built with rustc from (1) and libstd from (2)
2. Stage 1 libstd is built with stage 1 rustc. Later artifacts built with
stage 1 rustc are built with stage 1 libstd.
Further stages are possible and continue as expected. Additionally, the build
can be extensively customized. See for details:
https://rustc-dev-guide.rust-lang.org/building/bootstrapping.html
This script clones the Rust repository, checks it out to a defined revision,
builds LLVM and Clang via //tools/clang/scripts/build.py, then builds rustc and
libstd against it. Clang is included in the build for libclang, which is needed
for building and shipping bindgen.
Ideally our build would begin with our own trusted stage0 rustc. As it is
simpler, for now we use an official build.
TODO(crbug.com/40196262): Do a proper 3-stage build
'''
import argparse
import base64
import collections
import hashlib
import json
import platform
import os
import re
import shutil
import string
import subprocess
import sys
import urllib
from pathlib import Path
THIS_DIR = os.path.dirname(__file__)
sys.path.append(
os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'clang',
'scripts'))
from build import (AddCMakeToPath, AddZlibToPath, CheckoutGitRepo, CopyFile,
DownloadDebianSysroot, GetLibXml2Dirs, GitCherryPick,
GitRevert, LLVM_DIR, IsGitAncestorToHead,
LLVM_BUILD_TOOLS_DIR, RunCommand)
from update import (CHROMIUM_DIR, DownloadAndUnpack, EnsureDirExists,
GetDefaultHostOs, RmTree, ReadStampFile, WriteStampFile,
UpdatePackage, STAMP_FILENAME as LLVM_STAMP_FILENAME,
FORCE_HEAD_REVISION_FILENAME as
LLVM_FORCE_HEAD_REVISION_FILENAME)
from update_rust import (RUST_REVISION, RUST_TOOLCHAIN_OUT_DIR,
STAGE0_JSON_SHA256, THIRD_PARTY_DIR, VERSION_SRC_PATH,
GetRustClangRevision)
from package import TeeCmd
EXCLUDED_TESTS = [
os.path.join('tests', 'codegen-llvm', 'common_prim_int_ptr.rs'),
os.path.join('tests', 'codegen-llvm', 'enum', 'enum-discriminant-eq.rs'),
os.path.join('tests', 'codegen-llvm', 'issues',
'issue-122600-ptr-discriminant-update.rs'),
os.path.join('tests', 'codegen-llvm', 'vec_pop_push_noop.rs'),
os.path.join('tests', 'codegen-llvm', 'vecdeque_pop_push.rs'),
os.path.join('tests', 'codegen-llvm', 'simd-intrinsic', 'simd-intrinsic-generic-scatter.rs'),
os.path.join('tests', 'codegen-llvm', 'simd-intrinsic', 'simd-intrinsic-generic-gather.rs'),
os.path.join('tests', 'codegen-llvm', 'simd-intrinsic', 'simd-intrinsic-generic-masked-store.rs'),
os.path.join('tests', 'codegen-llvm', 'simd-intrinsic', 'simd-intrinsic-generic-masked-load.rs'),
]
EXCLUDED_TESTS_WINDOWS = [
os.path.join('tests', 'ui', 'sanitizer', 'asan_odr_windows.rs'),
os.path.join('tests', 'ui', 'process', 'win-command-child-path.rs'),
os.path.join('tests', 'ui', 'asm', 'x86_64', 'may_unwind.rs'),
]
EXCLUDED_TESTS_MAC = [
]
EXCLUDED_TESTS_MAC_ARM64 = [
]
CLANG_SCRIPTS_DIR = os.path.join(CHROMIUM_DIR, 'tools', 'clang', 'scripts')
RUST_GIT_URL = ('https://chromium.googlesource.com/external/' +
'github.com/rust-lang/rust')
RUST_SRC_DIR = os.path.join(THIRD_PARTY_DIR, 'rust-src')
RUST_BUILD_DIR = os.path.join(RUST_SRC_DIR, 'build')
RUST_BOOTSTRAP_DIST_RS = os.path.join(RUST_SRC_DIR, 'src', 'bootstrap',
'dist.rs')
STAGE0_JSON_PATH = os.path.join(RUST_SRC_DIR, 'src', 'stage0')
CARGO_HOME_DIR = os.path.join(RUST_SRC_DIR, 'cargo-home')
RUST_SRC_VERSION_FILE_PATH = os.path.join(RUST_SRC_DIR, 'src', 'version')
RUST_SRC_GIT_COMMIT_INFO_FILE_PATH = os.path.join(RUST_SRC_DIR,
'git-commit-info')
RUST_TOOLCHAIN_LIB_DIR = os.path.join(RUST_TOOLCHAIN_OUT_DIR, 'lib')
RUST_TOOLCHAIN_SRC_DIST_DIR = os.path.join(RUST_TOOLCHAIN_LIB_DIR, 'rustlib',
'src', 'rust')
RUST_CONFIG_TEMPLATE_PATH = os.path.join(
os.path.dirname(os.path.abspath(__file__)), 'config.toml.template')
RUST_CARGO_CONFIG_TEMPLATE_PATH = os.path.join(
os.path.dirname(os.path.abspath(__file__)), 'cargo-config.toml.template')
RUST_HOST_LLVM_BUILD_DIR = os.path.join(CHROMIUM_DIR, 'third_party',
'rust-toolchain-intermediate',
'llvm-host-build')
RUST_HOST_LLVM_INSTALL_DIR = os.path.join(CHROMIUM_DIR, 'third_party',
'rust-toolchain-intermediate',
'llvm-host-install')
RUST_BETA_SYSROOT_DIR = os.path.join(THIRD_PARTY_DIR,
'rust-toolchain-intermediate',
'beta-sysroot')
CIPD_DOWNLOAD_URL = f'https://chrome-infra-packages.appspot.com/dl'
OPENSSL_CIPD_LINUX_AMD_PATH = 'infra/3pp/static_libs/openssl/linux-amd64'
OPENSSL_CIPD_LINUX_AMD_VERSION = '1.1.1j.chromium.2'
OPENSSL_CIPD_MAC_AMD_PATH = 'infra/3pp/static_libs/openssl/mac-amd64'
OPENSSL_CIPD_MAC_AMD_VERSION = '1.1.1j.chromium.2'
OPENSSL_CIPD_MAC_ARM_PATH = 'infra/3pp/static_libs/openssl/mac-arm64'
OPENSSL_CIPD_MAC_ARM_VERSION = '1.1.1j.chromium.2'
if sys.platform == 'win32':
LD_PATH_FLAG = '/LIBPATH:'
else:
LD_PATH_FLAG = '-L'
BUILD_TARGETS = [
'library/proc_macro', 'library/std', 'src/tools/cargo', 'src/tools/clippy',
'src/tools/rustfmt'
]
TEST_SUITES = [
'library/std',
'tests/codegen-llvm',
'tests/ui',
]
def InstallRustBetaSysroot(rust_git_hash, target_triples):
if os.path.exists(RUST_BETA_SYSROOT_DIR):
RmTree(RUST_BETA_SYSROOT_DIR)
InstallBetaPackage(FetchBetaPackage('cargo', rust_git_hash),
RUST_BETA_SYSROOT_DIR)
InstallBetaPackage(FetchBetaPackage('rustc', rust_git_hash),
RUST_BETA_SYSROOT_DIR)
for t in target_triples:
InstallBetaPackage(
FetchBetaPackage('rust-std', rust_git_hash, triple=t),
RUST_BETA_SYSROOT_DIR)
def AddOpenSSLToEnv():
"""Download OpenSSL, and add to OPENSSL_DIR."""
ssl_dir = os.path.join(LLVM_BUILD_TOOLS_DIR, 'openssl')
if sys.platform == 'darwin':
if platform.machine() == 'arm64':
ssl_url = (f'{CIPD_DOWNLOAD_URL}/{OPENSSL_CIPD_MAC_ARM_PATH}'
f'/+/version:2@{OPENSSL_CIPD_MAC_ARM_VERSION}')
else:
ssl_url = (f'{CIPD_DOWNLOAD_URL}/{OPENSSL_CIPD_MAC_AMD_PATH}'
f'/+/version:2@{OPENSSL_CIPD_MAC_AMD_VERSION}')
elif sys.platform == 'win32':
ssl_url = (f'{CIPD_DOWNLOAD_URL}/{OPENSSL_CIPD_WIN_AMD_PATH}'
f'/+/version:2@{OPENSSL_CIPD_WIN_AMD_VERSION}')
else:
ssl_url = (f'{CIPD_DOWNLOAD_URL}/{OPENSSL_CIPD_LINUX_AMD_PATH}'
f'/+/version:2@{OPENSSL_CIPD_LINUX_AMD_VERSION}')
if os.path.exists(ssl_dir):
RmTree(ssl_dir)
DownloadAndUnpack(ssl_url, ssl_dir, is_known_zip=True)
os.environ['OPENSSL_DIR'] = ssl_dir
return ssl_dir
def VerifyStage0JsonHash(stage0_json_url=None):
hasher = hashlib.sha256()
if stage0_json_url:
print(stage0_json_url)
base64_text = urllib.request.urlopen(stage0_json_url).read().decode(
"utf-8")
stage0 = base64.b64decode(base64_text)
hasher.update(stage0)
else:
with open(STAGE0_JSON_PATH, 'rb') as input:
hasher.update(input.read())
actual_hash = hasher.hexdigest()
if actual_hash == STAGE0_JSON_SHA256:
return
print('src/stage0 hash is different than expected!')
print('Expected hash: ' + STAGE0_JSON_SHA256)
print('Actual hash: ' + actual_hash)
sys.exit(1)
def FetchBetaPackage(name, rust_git_hash, triple=None):
'''Downloads the beta package specified for the compiler build
If `triple` is not specified, it downloads a package for the current
machine's architecture.
Unpacks the package and returns the path to root of the package.
'''
triple = triple if triple else RustTargetTriple()
filename = f'{name}-beta-{triple}'
STAGE0_JSON_URL = (
'https://chromium.googlesource.com/external/github.com/'
'rust-lang/rust/+/{GIT_HASH}/src/stage0?format=TEXT')
base64_text = urllib.request.urlopen(
STAGE0_JSON_URL.format(GIT_HASH=rust_git_hash)).read().decode("utf-8")
stage0 = base64.b64decode(base64_text).decode("utf-8")
lines = stage0.splitlines()
for l in lines:
if l.startswith('dist_server='):
server = l.split('=')[1]
if (filename + '.tar.gz') in l:
package_tgz = l.split('=')[0]
DownloadAndUnpack(f'{server}/{package_tgz}', LLVM_BUILD_TOOLS_DIR)
return os.path.join(LLVM_BUILD_TOOLS_DIR, filename)
def InstallBetaPackage(package_dir, install_dir):
cmd = []
if sys.platform == 'win32':
install_dir = os.path.relpath(install_dir).replace('\\', '/')
where = subprocess.check_output(['where.exe', 'sh'], text=True)
sh_exe = where.splitlines()[0]
cmd += [sh_exe]
cmd += [
os.path.join(package_dir, 'install.sh'),
f'--destdir={install_dir}',
f'--prefix=',
]
if sys.platform.startswith('linux'):
cmd += ['--disable-ldconfig']
RunCommand(cmd)
def VendorForStdlib(cargo_bin):
'''Runs `cargo vendor` to pull down standard library dependencies.'''
os.chdir(RUST_SRC_DIR)
vendor_env = os.environ
vendor_env['RUSTC_BOOTSTRAP'] = '1'
vendor_cmd = [
cargo_bin, 'vendor', '--manifest-path', 'library/Cargo.toml',
'--locked', '--versioned-dirs', 'library/vendor'
]
RunWithRetry(vendor_cmd, 'cargo vendor')
os.chdir(CHROMIUM_DIR)
def RunWithRetry(command, name):
'''Run a command, retrying a few times then aborting if it fails.'''
for i in range(0, 3):
if RunCommand(command, fail_hard=False):
return
elif i < 2:
print(f'failed {name}, retrying...')
else:
sys.exit(1)
class XPy:
''' Runner for x.py, Rust's build script. Holds shared state between x.py
runs. '''
def __init__(self, zlib_path, libxml2_dirs, debian_sysroot, verbose):
self._debian_sysroot = debian_sysroot
self._env = collections.defaultdict(str, os.environ)
self._verbose = verbose
self._llvm_bins_path = os.path.join(RUST_HOST_LLVM_INSTALL_DIR, 'bin')
ENV_FLAGS = [
'CFLAGS',
'CXXFLAGS',
'LDFLAGS',
'RUSTFLAGS_BOOTSTRAP',
'RUSTFLAGS_NOT_BOOTSTRAP',
'RUSTDOCFLAGS',
]
self._env = collections.defaultdict(str, os.environ)
for f in ENV_FLAGS:
self._env.setdefault(f, '')
if sys.platform == 'win32':
self._env['AR'] = os.path.join(self._llvm_bins_path,
'llvm-lib.exe')
self._env['CC'] = os.path.join(self._llvm_bins_path,
'clang-cl.exe')
self._env['CXX'] = os.path.join(self._llvm_bins_path,
'clang-cl.exe')
self._env['LD'] = os.path.join(self._llvm_bins_path,
'lld-link.exe')
else:
self._env['AR'] = os.path.join(self._llvm_bins_path, 'llvm-ar')
self._env['CC'] = os.path.join(self._llvm_bins_path, 'clang')
self._env['CXX'] = os.path.join(self._llvm_bins_path, 'clang++')
self._env['LD'] = os.path.join(self._llvm_bins_path, 'clang')
if sys.platform == 'darwin':
sdk_path = subprocess.check_output(['xcrun', '--show-sdk-path'],
text=True).rstrip()
self._env['CFLAGS'] += f' -isysroot {sdk_path}'
self._env['CXXFLAGS'] += f' -isysroot {sdk_path}'
self._env['LDFLAGS'] += f' -isysroot {sdk_path}'
self._env['RUSTFLAGS_BOOTSTRAP'] += (
f' -Clink-arg=-isysroot -Clink-arg={sdk_path}')
self._env['RUSTFLAGS_NOT_BOOTSTRAP'] += (
f' -Clink-arg=-isysroot -Clink-arg={sdk_path}')
self._env['SDKROOT'] = sdk_path
if zlib_path:
self._env['CFLAGS'] += f' -I{zlib_path}'
self._env['CXXFLAGS'] += f' -I{zlib_path}'
self._env['LDFLAGS'] += f' {LD_PATH_FLAG}{zlib_path}'
self._env['RUSTFLAGS_BOOTSTRAP'] += (
f' -Clink-arg={LD_PATH_FLAG}{zlib_path}')
self._env['RUSTFLAGS_NOT_BOOTSTRAP'] += (
f' -Clink-arg={LD_PATH_FLAG}{zlib_path}')
if libxml2_dirs:
self._env['CFLAGS'] += f' -I{libxml2_dirs.include_dir}'
self._env['CXXFLAGS'] += f' -I{libxml2_dirs.include_dir}'
self._env['LDFLAGS'] += f' {LD_PATH_FLAG}{libxml2_dirs.lib_dir}'
self._env['RUSTFLAGS_BOOTSTRAP'] += (
f' -Clink-arg={LD_PATH_FLAG}{libxml2_dirs.lib_dir}')
self._env['RUSTFLAGS_NOT_BOOTSTRAP'] += (
f' -Clink-arg={LD_PATH_FLAG}{libxml2_dirs.lib_dir}')
if debian_sysroot:
sysroot_cflag = f'--sysroot={debian_sysroot}'
self._env['CFLAGS'] += f' {sysroot_cflag}'
self._env['CXXFLAGS'] += f' {sysroot_cflag}'
self._env['LDFLAGS'] += f' {sysroot_cflag}'
self._env['RUSTFLAGS_BOOTSTRAP'] += f' -Clink-arg={sysroot_cflag}'
self._env[
'RUSTFLAGS_NOT_BOOTSTRAP'] += f' -Clink-arg={sysroot_cflag}'
self._env['PKG_CONFIG_SYSROOT_DIR'] = debian_sysroot
self._env[
'PKG_CONFIG_LIBDIR'] = debian_sysroot + '/usr/lib/pkgconfig'
self._env['LZMA_API_STATIC'] = '1'
if sys.platform != 'win32':
self._env['RUSTFLAGS_BOOTSTRAP'] += ' -Clink-arg=-fuse-ld=lld'
self._env['RUSTFLAGS_NOT_BOOTSTRAP'] += ' -Clink-arg=-fuse-ld=lld'
if sys.platform.startswith('linux'):
self._env['RUSTFLAGS_BOOTSTRAP'] += (
' -Clink-arg=-Wl,--undefined-version')
self._env['RUSTFLAGS_NOT_BOOTSTRAP'] += (
' -Clink-arg=-Wl,--undefined-version')
self._env['RUSTDOCFLAGS'] += f' -Clinker={self._env["LD"]}'
self._env['CARGO_HOME'] = CARGO_HOME_DIR
self._env['GITHUB_ACTIONS'] = 'true'
def configure(self):
with open(RUST_CONFIG_TEMPLATE_PATH, 'r') as input:
template = string.Template(input.read())
def quote_string(s: str):
return s.replace('\\', '\\\\').replace('"', '\\"')
subs = {}
subs['INSTALL_DIR'] = quote_string(str(RUST_TOOLCHAIN_OUT_DIR))
subs['LLVM_BIN'] = quote_string(str(self._llvm_bins_path))
subs['PACKAGE_VERSION'] = GetRustClangRevision()
if RUST_REVISION == 'ab71ee7a9214c2793108a41efb065aa77aeb7326':
subs['CHANGELOG_SEEN'] = '''\
# Suppress x.py warning about configuration changes
changelog-seen = 2'''
else:
subs['CHANGELOG_SEEN'] = ''
with open(os.path.join(RUST_SRC_DIR, 'config.toml'), 'w') as output:
output.write(template.substitute(subs))
if self._debian_sysroot:
with open(RUST_CARGO_CONFIG_TEMPLATE_PATH, 'r') as input:
template = string.Template(input.read())
subs = {}
subs['DEBIAN_SYSROOT'] = quote_string(str(self._debian_sysroot))
if not os.path.exists(CARGO_HOME_DIR):
os.makedirs(CARGO_HOME_DIR)
with open(os.path.join(CARGO_HOME_DIR, 'config.toml'),
'w') as output:
output.write(template.substitute(subs))
def run(self, sub, args):
''' Run x.py subcommand with specified args. '''
os.chdir(RUST_SRC_DIR)
cmd = [sys.executable, 'x.py', sub]
if self._verbose and self._verbose > 0:
cmd.append('-' + self._verbose * 'v')
RunCommand(cmd + args, setenv=True, env=self._env)
os.chdir(CHROMIUM_DIR)
def get_env(self):
''' The environment variables set for x.py invocations, as a dict. '''
return self._env
def GetTestArgs():
args = TEST_SUITES
for excluded in EXCLUDED_TESTS:
args.append('--exclude')
args.append(excluded)
if sys.platform == 'win32':
for excluded in EXCLUDED_TESTS_WINDOWS:
args.append('--exclude')
args.append(excluded)
if sys.platform == 'darwin':
for excluded in EXCLUDED_TESTS_MAC:
args.append('--exclude')
args.append(excluded)
if sys.platform == 'darwin' and platform.machine() == 'arm64':
for excluded in EXCLUDED_TESTS_MAC_ARM64:
args.append('--exclude')
args.append(excluded)
return args
def MakeVersionStamp(rust_hash, rust_force_head_revision,
llvm_force_head_revision):
with open(RUST_SRC_VERSION_FILE_PATH) as version_file:
rust_version = version_file.readline().rstrip()
if rust_force_head_revision or llvm_force_head_revision:
if llvm_force_head_revision:
llvm_stamp_file = os.path.join(RUST_HOST_LLVM_BUILD_DIR, '..',
LLVM_FORCE_HEAD_REVISION_FILENAME)
else:
llvm_stamp_file = os.path.join(RUST_HOST_LLVM_BUILD_DIR,
LLVM_STAMP_FILENAME)
package_version = f'{rust_hash}-0-{ReadStampFile(llvm_stamp_file)}'
else:
package_version = GetRustClangRevision()
return (f'rustc {rust_version} {rust_hash}'
f' ({package_version} chromium)\n')
def GetLatestRustCommit():
"""Get the latest commit hash in the LLVM monorepo."""
url = (
'https://chromium.googlesource.com/external/' +
'github.com/rust-lang/rust/+/refs/heads/main?format=JSON'
)
main = json.loads(
urllib.request.urlopen(url).read().decode("utf-8").replace(")]}'", ""))
return main['commit']
def RustTargetTriple():
if sys.platform == 'darwin':
if platform.machine() == 'arm64':
return 'aarch64-apple-darwin'
else:
return 'x86_64-apple-darwin'
elif sys.platform == 'win32':
return 'x86_64-pc-windows-msvc'
else:
return 'x86_64-unknown-linux-gnu'
def BuildLLVMLibraries(skip_build, llvm_force_head_revision):
if not skip_build:
print(f'Building the host LLVM in {RUST_HOST_LLVM_BUILD_DIR}...')
build_cmd = [
sys.executable,
os.path.join(CLANG_SCRIPTS_DIR, 'build.py'),
'--disable-asserts',
'--no-tools',
'--no-runtimes',
'--pic',
'--with-ml-inliner-model=',
'--without-zstd',
]
if llvm_force_head_revision:
build_cmd.append('--llvm-force-head-revision')
if sys.platform.startswith('linux'):
build_cmd.append('--without-android')
build_cmd.append('--without-fuchsia')
RunCommand(build_cmd + [
'--build-dir', RUST_HOST_LLVM_BUILD_DIR, '--install-dir',
RUST_HOST_LLVM_INSTALL_DIR
])
def GitMoveSubmoduleBranch(root_git, submodule, branch):
print(f'Moving git submodule {submodule} to branch "{branch}"')
os.chdir(RUST_SRC_DIR)
RunCommand(
['git', 'submodule', 'set-branch', '--branch', branch, submodule])
os.chdir(os.path.join(RUST_SRC_DIR, *submodule.split('/')))
RunCommand([
'git', 'config', 'remote.origin.fetch',
f'+refs/heads/{branch}:refs/remotes/origin/{branch}'
])
os.chdir(RUST_SRC_DIR)
RunCommand(
['git', 'submodule', 'update', '--remote', '--depth', '1', submodule])
RunCommand([
'git', 'commit', '-m',
f'Chromium: Moved submodule {submodule} to branch {branch}',
'.gitmodules', submodule
],
fail_hard=False)
os.chdir(CHROMIUM_DIR)
def GitApplyCherryPicks():
print('Applying cherry-picks...')
GitCherryPick(RUST_SRC_DIR, 'f9c040b7318f86e54fc57119ba5e0664df117600',
'https://github.com/rust-lang/rust.git')
print('Finished applying cherry-picks.')
def main():
parser = argparse.ArgumentParser(
description='Build and package Rust toolchain')
parser.add_argument('-v',
'--verbose',
action='count',
help='run subcommands with verbosity')
parser.add_argument(
'--verify-stage0-hash',
action='store_true',
help=
'checkout Rust, verify the stage0 hash, then quit without building. '
'Will print the actual hash if different than expected.')
parser.add_argument(
'--dump-env',
action='store_true',
help=
'dump all environment variables set for x.py to a file `rust-build-env`'
)
parser.add_argument('--skip-checkout',
action='store_true',
help='do not create or update any checkouts')
parser.add_argument('--sync-for-gnrt',
action='store_true',
help='sync checkout and deps for gnrt run then quit.')
parser.add_argument('--skip-clean',
action='store_true',
help='skip x.py clean step')
parser.add_argument(
'--skip-llvm-build',
action='store_true',
help='do not build LLVM, presuming build_rust.py was '
'already run and the LLVM libs are thus already present.')
parser.add_argument('--skip-test',
action='store_true',
help='skip running rustc and libstd tests')
parser.add_argument('--skip-install',
action='store_true',
help='do not install to RUST_TOOLCHAIN_OUT_DIR')
parser.add_argument(
'--preserve-gcs-signature',
action='store_true',
help='By default, this script removes gcs hash files '
'so that third_party/llvm-build is clobbered on the next'
'run of gclient sync. This disables that, so that the'
'directory will be preserved when syncing. Useful for'
'local development.')
parser.add_argument('--rust-force-head-revision',
action='store_true',
help='build the latest revision')
parser.add_argument(
'--prepare-run-xpy',
action='store_true',
help='set up the build directory to use --run-xpy subsequently. For '
'debugging.')
parser.add_argument(
'--run-xpy',
action='store_true',
help='run x.py command in configured Rust checkout. Quits after '
'running specified command, skipping all normal build steps. For '
'debugging. Running x.py directly will not set the appropriate env '
'variables nor update config.toml')
parser.add_argument(
'--llvm-force-head-revision',
action='store_true',
help='Checkout and build against the most recent llvm revision,'
'rather than the one specified in tools/clang/scripts/update.py')
parser.add_argument(
'--build-bindgen',
action='store_true',
help='After building rust, also build bindgen using build_bindgen.py')
parser.add_argument(
'--build-crubit',
action='store_true',
help='After building rust, also build crubit using build_crubit.py')
parser.add_argument(
'--gnrt-stdlib',
action='store_true',
help='After building rust, also generate stdlib GN rules using '
'gnrt_stdlib.py')
parser.add_argument('--entire-toolchain',
action='store_true',
help='Build rust and the rest of the rust toolchain. '
'Equivalent to --build-bindgen --build-crubit '
'--gnrt-stdlib')
if sys.platform == 'win32':
parser.add_argument('--sh', help='path to the sh.exe to use')
args, rest = parser.parse_known_args()
if args.entire_toolchain:
args.build_bindgen = True
args.build_crubit = True
args.gnrt_stdlib = True
if sys.platform == 'win32':
if args.sh:
assert args.sh.endswith('sh.exe')
p = os.environ['PATH']
shdir = os.path.dirname(args.sh)
os.environ['PATH'] = f'{shdir};{p}'
where = subprocess.check_output(['where.exe', 'sh'], text=True)
if '\\gnubby\\' in where.splitlines()[0]:
print("WARNING: It looks like you have gnubby sh.exe in your ")
print(" PATH, but it does not support normalized paths of the ")
print(" form `/c/foo` and will fail at the install step. Put the ")
print(" sh.exe from the Git installation into your PATH first ")
print(" when running this script or use --sh to specify the path ")
print(" to sh.exe.")
print("where sh.exe:")
print(where)
return 1
debian_sysroot = None
if sys.platform.startswith('linux') and not args.sync_for_gnrt:
debian_sysroot = DownloadDebianSysroot('amd64', args.skip_checkout)
if sys.platform == 'win32':
zlib_path = AddZlibToPath(dry_run=args.skip_checkout)
else:
zlib_path = None
if sys.platform == 'win32':
libxml2_dirs = GetLibXml2Dirs()
else:
libxml2_dirs = None
if (sys.platform != 'win32' and not args.sync_for_gnrt):
AddOpenSSLToEnv()
xpy = XPy(zlib_path, libxml2_dirs, debian_sysroot, args.verbose)
if args.dump_env:
with open('rust-build-env', 'w') as f:
for name, val in xpy.get_env().items():
print(f'{name}={val}', file=f)
if args.run_xpy:
config_path = os.path.join(RUST_SRC_DIR, 'config.toml')
assert os.path.exists(config_path)
assert os.path.isfile(config_path)
if rest[0] == '--':
rest = rest[1:]
xpy.run(rest[0], rest[1:])
return 0
else:
assert not rest
if sys.platform == 'win32':
RunCommand(['curl', '-I', 'https://static.rust-lang.org'])
if args.rust_force_head_revision:
assert not args.skip_checkout
checkout_revision = GetLatestRustCommit()
else:
checkout_revision = RUST_REVISION
if not args.skip_checkout:
if args.verify_stage0_hash:
VerifyStage0JsonHash(
'https://chromium.googlesource.com/external/github.com/'
'rust-lang/rust/+/{}/src/stage0?format=TEXT'.format(
checkout_revision))
return 0
CheckoutGitRepo('Rust', RUST_GIT_URL, checkout_revision, RUST_SRC_DIR)
path = FetchBetaPackage('cargo', checkout_revision)
if sys.platform == 'win32':
cargo_bin = os.path.join(path, 'cargo', 'bin', 'cargo.exe')
else:
cargo_bin = os.path.join(path, 'cargo', 'bin', 'cargo')
submod_cmd = [
'git', '-C', RUST_SRC_DIR, 'submodule', 'update', '--init',
'--recursive', '--depth', '1'
]
RunWithRetry(submod_cmd, 'git submodule')
GitApplyCherryPicks()
bootstrap_cargo = os.path.join(RUST_SRC_DIR, 'src', 'bootstrap',
'Cargo.toml')
with open(bootstrap_cargo, 'r') as f:
lines = f.readlines()
with open(bootstrap_cargo, 'w') as f:
for l in lines:
if l.strip('\n') != 'debug = 0':
f.write(l)
VendorForStdlib(cargo_bin)
if args.sync_for_gnrt:
return 0
if not args.rust_force_head_revision:
VerifyStage0JsonHash()
if args.verify_stage0_hash:
return 0
BuildLLVMLibraries(args.skip_llvm_build, args.llvm_force_head_revision)
AddCMakeToPath()
xpy.configure()
if args.prepare_run_xpy:
return 0
target_triple = RustTargetTriple()
xpy_args = ['--build', target_triple]
if not args.skip_clean:
print('Clearing build directory...')
if os.path.exists(RUST_BUILD_DIR):
RmTree(RUST_BUILD_DIR)
if not args.skip_test:
print(f'Building stage 2 artifacts and running tests...')
xpy.run('test', ['--stage', '2'] + xpy_args + GetTestArgs())
if not args.skip_install:
print('Installing stage 2 artifacts...')
xpy.run('build', xpy_args + ['--stage', '2'] + BUILD_TARGETS)
if not args.skip_install:
print(f'Installing Rust to {RUST_TOOLCHAIN_OUT_DIR} ...')
if os.path.exists(RUST_TOOLCHAIN_OUT_DIR):
RmTree(RUST_TOOLCHAIN_OUT_DIR)
xpy.run('install', xpy_args + [])
WriteStampFile(
MakeVersionStamp(checkout_revision, args.rust_force_head_revision,
args.llvm_force_head_revision), VERSION_SRC_PATH,
args.preserve_gcs_signature)
with open(os.path.join(THIRD_PARTY_DIR,
f'rust-buildlog-{checkout_revision}.txt'),
'w',
encoding='utf-8') as log:
if args.build_bindgen:
print('Building bindgen...')
build_cmd = [
sys.executable,
os.path.join(THIS_DIR, 'build_bindgen.py')
]
TeeCmd(build_cmd, log)
if args.build_crubit:
print('Building crubit...')
build_cmd = [
sys.executable,
os.path.join(THIS_DIR, 'build_crubit.py')
]
TeeCmd(build_cmd, log, fail_hard=False)
if args.gnrt_stdlib:
print('Building gnrt...')
InstallRustBetaSysroot(checkout_revision, [RustTargetTriple()])
print('Beta sysroot installed.')
build_cmd = [
sys.executable,
os.path.join(THIS_DIR, 'gnrt_stdlib.py'), '--skip-prep'
]
TeeCmd(build_cmd, log)
return 0
if __name__ == '__main__':
sys.exit(main())