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