'''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
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',
'-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',
'-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':
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++'
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':
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
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':
zlib_dir = AddZlibToPath(dry_run=args.skip_checkout)
env['CXXFLAGS'] += f' /I{zlib_dir}'
env['RUSTFLAGS'] += f' -Clink-arg=/LIBPATH:{zlib_dir}'
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())