blob: 5330d1f3bb4ff9d6907a566c3f27d939927cf64c [file] [log] [blame]
#!/usr/bin/env python3
# Copyright 2022 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
'''Builds the Crubit tool.
Builds the Crubit tools for generating Rust/C++ bindings.
This script must be run after //tools/rust/build_rust.py as it uses the outputs
of that script in the compilation of Crubit. It uses:
- The LLVM and Clang libraries and headers in `RUST_HOST_LLVM_INSTALL_DIR`.
- The rust toolchain binaries and libraries in `RUST_TOOLCHAIN_OUT_DIR`.
This script:
- Clones the Abseil repository, checks out a defined revision.
- Builds Abseil with Cmake.
- Clones the Crubit repository, checks out a defined revision.
- Builds Crubit's rs_bindings_from_cc with Cargo.
- Adds rs_bindings_from_cc and the Crubit support libraries into the
toolchain package in `RUST_TOOLCHAIN_OUT_DIR`.
The cc_bindings_from_rs binary is not yet built, as there's no Cargo rules to build it yet.
'''
import argparse
import os
import platform
import shutil
import sys
from pathlib import Path
# Get variables and helpers from Clang update script
sys.path.append(
os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'clang',
'scripts'))
from build import (AddCMakeToPath, AddZlibToPath, CheckoutGitRepo,
DownloadDebianSysroot, RunCommand, THIRD_PARTY_DIR)
from update import (RmTree)
from build_rust import (RUST_HOST_LLVM_INSTALL_DIR)
from update_rust import (CHROMIUM_DIR, ABSL_REVISION, CRUBIT_REVISION,
RUST_TOOLCHAIN_OUT_DIR)
ABSL_GIT = 'https://github.com/abseil/abseil-cpp'
CRUBIT_GIT = 'https://github.com/google/crubit'
ABSL_SRC_DIR = os.path.join(CHROMIUM_DIR, 'third_party',
'rust-toolchain-intermediate', 'absl')
ABSL_INSTALL_DIR = os.path.join(ABSL_SRC_DIR, 'install')
CRUBIT_SRC_DIR = os.path.join(CHROMIUM_DIR, 'third_party',
'rust-toolchain-intermediate', 'crubit')
EXE = '.exe' if sys.platform == 'win32' else ''
def BuildAbsl(env, debug):
os.chdir(ABSL_SRC_DIR)
configure_cmd = [
'cmake',
'-B',
'out',
'-GNinja',
# Because Crubit is built with C++20.
'-DCMAKE_CXX_STANDARD=20',
f'-DCMAKE_INSTALL_PREFIX={ABSL_INSTALL_DIR}',
'-DABSL_PROPAGATE_CXX_STD=ON',
'-DABSL_BUILD_TESTING=OFF',
'-DABSL_USE_GOOGLETEST_HEAD=OFF',
# LLVM is built with static CRT. Make Abseil match it.
'-DABSL_MSVC_STATIC_RUNTIME=ON',
]
if not debug:
configure_cmd.append('-DCMAKE_BUILD_TYPE=Release')
RunCommand(configure_cmd, setenv=True, env=env)
build_cmd = ['cmake', '--build', 'out', '--target', 'all']
RunCommand(build_cmd, setenv=True, env=env)
install_cmd = ['cmake', '--install', 'out']
RunCommand(install_cmd, setenv=True, env=env)
os.chdir(CHROMIUM_DIR)
def BuildCrubit(env, debug):
os.chdir(CRUBIT_SRC_DIR)
CRUBIT_BINS = ['rs_bindings_from_cc']
build_cmd = ['cargo', 'build']
for bin in CRUBIT_BINS:
build_cmd += ['--bin', bin]
if not debug:
build_cmd.append('--release')
RunCommand(build_cmd, setenv=True, env=env)
print(f'Installing Crubit to {RUST_TOOLCHAIN_OUT_DIR} ...')
target_dir = os.path.join(CRUBIT_SRC_DIR, 'target',
'debug' if debug else 'release')
for bin in CRUBIT_BINS:
bin = bin + EXE
shutil.copy(os.path.join(target_dir, bin),
os.path.join(RUST_TOOLCHAIN_OUT_DIR, 'bin', bin))
support_build_dir = os.path.join(CRUBIT_SRC_DIR, 'support')
support_out_dir = os.path.join(RUST_TOOLCHAIN_OUT_DIR, 'lib', 'crubit')
if os.path.exists(support_out_dir):
RmTree(support_out_dir)
shutil.copytree(support_build_dir, support_out_dir)
os.chdir(CHROMIUM_DIR)
def main():
parser = argparse.ArgumentParser(
description='Build and package Crubit tools')
parser.add_argument(
'--skip-checkout',
action='store_true',
help=('skip checking out source code. Useful for trying local'
'changes'))
parser.add_argument('--debug',
action='store_true',
help=('build Crubit in debug mode'))
args, rest = parser.parse_known_args()
assert (not rest)
if not args.skip_checkout:
CheckoutGitRepo("absl", ABSL_GIT, ABSL_REVISION, ABSL_SRC_DIR)
CheckoutGitRepo("crubit", CRUBIT_GIT, CRUBIT_REVISION, CRUBIT_SRC_DIR)
if sys.platform.startswith('linux'):
arch = 'arm64' if platform.machine() == 'aarch64' else 'amd64'
sysroot = DownloadDebianSysroot(arch, args.skip_checkout)
llvm_bin_dir = os.path.join(RUST_HOST_LLVM_INSTALL_DIR, 'bin')
rust_bin_dir = os.path.join(RUST_TOOLCHAIN_OUT_DIR, 'bin')
AddCMakeToPath()
env = os.environ
path_trailing_sep = os.pathsep if env['PATH'] else ''
env['PATH'] = (f'{llvm_bin_dir}{os.pathsep}'
f'{rust_bin_dir}{path_trailing_sep}'
f'{env["PATH"]}')
if sys.platform == 'win32':
# CMake on Windows doesn't like depot_tools's ninja.bat wrapper.
ninja_dir = os.path.join(THIRD_PARTY_DIR, 'ninja')
env['PATH'] = f'{ninja_dir}{os.pathsep}{env["PATH"]}'
env['CXXFLAGS'] = ''
env['RUSTFLAGS'] = ''
if sys.platform == 'win32':
env['CC'] = 'clang-cl'
env['CXX'] = 'clang-cl'
else:
env['CC'] = 'clang'
env['CXX'] = 'clang++'
# We link with lld via clang, except on windows where we point to lld-link
# directly.
if sys.platform == 'win32':
env['RUSTFLAGS'] += f' -Clinker=lld-link'
else:
env['RUSTFLAGS'] += f' -Clinker=clang'
env['RUSTFLAGS'] += f' -Clink-arg=-fuse-ld=lld'
if sys.platform == 'win32':
# LLVM is built with static CRT. Make Rust match it.
env['RUSTFLAGS'] += f' -Ctarget-feature=+crt-static'
if sys.platform.startswith('linux'):
sysroot_flag = (f'--sysroot={sysroot}' if sysroot else '')
env['CXXFLAGS'] += f" {sysroot_flag}"
env['RUSTFLAGS'] += f" -Clink-arg={sysroot_flag}"
if sys.platform == 'darwin':
import subprocess
# The system/xcode compiler would find system SDK correctly, but
# the Clang we've built does not. See
# https://github.com/llvm/llvm-project/issues/45225
sdk_path = subprocess.check_output(['xcrun', '--show-sdk-path'],
text=True).rstrip()
env['CXXFLAGS'] += f' -isysroot {sdk_path}'
env['RUSTFLAGS'] += f' -Clink-arg=-isysroot -Clink-arg={sdk_path}'
if sys.platform == 'win32':
# LLVM depends on Zlib.
zlib_dir = AddZlibToPath(dry_run=args.skip_checkout)
env['CXXFLAGS'] += f' /I{zlib_dir}'
env['RUSTFLAGS'] += f' -Clink-arg=/LIBPATH:{zlib_dir}'
# Prevent deprecation warnings.
env['CXXFLAGS'] += ' /D_CRT_SECURE_NO_DEPRECATE'
BuildAbsl(env, args.debug)
env['ABSL_INCLUDE_PATH'] = os.path.join(ABSL_INSTALL_DIR, 'include')
env['ABSL_LIB_STATIC_PATH'] = os.path.join(ABSL_INSTALL_DIR, 'lib')
env['CLANG_INCLUDE_PATH'] = os.path.join(RUST_HOST_LLVM_INSTALL_DIR,
'include')
env['CLANG_LIB_STATIC_PATH'] = os.path.join(RUST_HOST_LLVM_INSTALL_DIR,
'lib')
BuildCrubit(env, args.debug)
return 0
if __name__ == '__main__':
sys.exit(main())