Lukasz Anforowicz | a394bbd | 2022-06-21 18:21:06 | [diff] [blame] | 1 | #!/usr/bin/env python3 |
Avi Drissman | dfd88085 | 2022-09-15 20:11:09 | [diff] [blame] | 2 | # Copyright 2022 The Chromium Authors |
Lukasz Anforowicz | a394bbd | 2022-06-21 18:21:06 | [diff] [blame] | 3 | # Use of this source code is governed by a BSD-style license that can be |
| 4 | # found in the LICENSE file. |
| 5 | '''Builds the Crubit tool. |
| 6 | |
danakj | 9a318f6 | 2024-10-01 17:56:39 | [diff] [blame] | 7 | Builds the Crubit tools for generating Rust/C++ bindings. |
Lukasz Anforowicz | a394bbd | 2022-06-21 18:21:06 | [diff] [blame] | 8 | |
danakj | 9a318f6 | 2024-10-01 17:56:39 | [diff] [blame] | 9 | This script must be run after //tools/rust/build_rust.py as it uses the outputs |
| 10 | of that script in the compilation of Crubit. It uses: |
| 11 | - The LLVM and Clang libraries and headers in `RUST_HOST_LLVM_INSTALL_DIR`. |
| 12 | - The rust toolchain binaries and libraries in `RUST_TOOLCHAIN_OUT_DIR`. |
| 13 | |
| 14 | This script: |
| 15 | - Clones the Abseil repository, checks out a defined revision. |
| 16 | - Builds Abseil with Cmake. |
| 17 | - Clones the Crubit repository, checks out a defined revision. |
| 18 | - Builds Crubit's rs_bindings_from_cc with Cargo. |
| 19 | - Adds rs_bindings_from_cc and the Crubit support libraries into the |
| 20 | toolchain package in `RUST_TOOLCHAIN_OUT_DIR`. |
| 21 | |
| 22 | The cc_bindings_from_rs binary is not yet built, as there's no Cargo rules to build it yet. |
Lukasz Anforowicz | a394bbd | 2022-06-21 18:21:06 | [diff] [blame] | 23 | ''' |
| 24 | |
| 25 | import argparse |
Lukasz Anforowicz | a394bbd | 2022-06-21 18:21:06 | [diff] [blame] | 26 | import os |
danakj | fd4dee7 | 2023-01-05 14:42:24 | [diff] [blame] | 27 | import platform |
Lukasz Anforowicz | a394bbd | 2022-06-21 18:21:06 | [diff] [blame] | 28 | import shutil |
Lukasz Anforowicz | a394bbd | 2022-06-21 18:21:06 | [diff] [blame] | 29 | import sys |
| 30 | |
| 31 | from pathlib import Path |
| 32 | |
| 33 | # Get variables and helpers from Clang update script |
| 34 | sys.path.append( |
| 35 | os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'clang', |
| 36 | 'scripts')) |
| 37 | |
danakj | 9a318f6 | 2024-10-01 17:56:39 | [diff] [blame] | 38 | from build import (AddCMakeToPath, AddZlibToPath, CheckoutGitRepo, |
| 39 | DownloadDebianSysroot, RunCommand, THIRD_PARTY_DIR) |
| 40 | from update import (RmTree) |
Lukasz Anforowicz | a394bbd | 2022-06-21 18:21:06 | [diff] [blame] | 41 | |
danakj | 9a318f6 | 2024-10-01 17:56:39 | [diff] [blame] | 42 | from build_rust import (RUST_HOST_LLVM_INSTALL_DIR) |
| 43 | from update_rust import (CHROMIUM_DIR, ABSL_REVISION, CRUBIT_REVISION, |
| 44 | RUST_TOOLCHAIN_OUT_DIR) |
Lukasz Anforowicz | a394bbd | 2022-06-21 18:21:06 | [diff] [blame] | 45 | |
danakj | 9a318f6 | 2024-10-01 17:56:39 | [diff] [blame] | 46 | ABSL_GIT = 'https://github.com/abseil/abseil-cpp' |
| 47 | CRUBIT_GIT = 'https://github.com/google/crubit' |
| 48 | |
| 49 | ABSL_SRC_DIR = os.path.join(CHROMIUM_DIR, 'third_party', |
| 50 | 'rust-toolchain-intermediate', 'absl') |
| 51 | ABSL_INSTALL_DIR = os.path.join(ABSL_SRC_DIR, 'install') |
| 52 | CRUBIT_SRC_DIR = os.path.join(CHROMIUM_DIR, 'third_party', |
| 53 | 'rust-toolchain-intermediate', 'crubit') |
| 54 | |
| 55 | EXE = '.exe' if sys.platform == 'win32' else '' |
Lukasz Anforowicz | a394bbd | 2022-06-21 18:21:06 | [diff] [blame] | 56 | |
| 57 | |
danakj | 9a318f6 | 2024-10-01 17:56:39 | [diff] [blame] | 58 | def BuildAbsl(env, debug): |
| 59 | os.chdir(ABSL_SRC_DIR) |
danakj | fd4dee7 | 2023-01-05 14:42:24 | [diff] [blame] | 60 | |
danakj | 9a318f6 | 2024-10-01 17:56:39 | [diff] [blame] | 61 | configure_cmd = [ |
| 62 | 'cmake', |
| 63 | '-B', |
| 64 | 'out', |
| 65 | '-GNinja', |
| 66 | # Because Crubit is built with C++20. |
| 67 | '-DCMAKE_CXX_STANDARD=20', |
| 68 | f'-DCMAKE_INSTALL_PREFIX={ABSL_INSTALL_DIR}', |
| 69 | '-DABSL_PROPAGATE_CXX_STD=ON', |
| 70 | '-DABSL_BUILD_TESTING=OFF', |
| 71 | '-DABSL_USE_GOOGLETEST_HEAD=OFF', |
| 72 | # LLVM is built with static CRT. Make Abseil match it. |
| 73 | '-DABSL_MSVC_STATIC_RUNTIME=ON', |
Lukasz Anforowicz | a394bbd | 2022-06-21 18:21:06 | [diff] [blame] | 74 | ] |
danakj | 9a318f6 | 2024-10-01 17:56:39 | [diff] [blame] | 75 | if not debug: |
| 76 | configure_cmd.append('-DCMAKE_BUILD_TYPE=Release') |
Lukasz Anforowicz | a394bbd | 2022-06-21 18:21:06 | [diff] [blame] | 77 | |
danakj | 9a318f6 | 2024-10-01 17:56:39 | [diff] [blame] | 78 | RunCommand(configure_cmd, setenv=True, env=env) |
| 79 | build_cmd = ['cmake', '--build', 'out', '--target', 'all'] |
| 80 | RunCommand(build_cmd, setenv=True, env=env) |
| 81 | install_cmd = ['cmake', '--install', 'out'] |
| 82 | RunCommand(install_cmd, setenv=True, env=env) |
Lukasz Anforowicz | 17a2339 | 2022-07-06 17:26:18 | [diff] [blame] | 83 | |
danakj | 9a318f6 | 2024-10-01 17:56:39 | [diff] [blame] | 84 | os.chdir(CHROMIUM_DIR) |
Lukasz Anforowicz | a394bbd | 2022-06-21 18:21:06 | [diff] [blame] | 85 | |
| 86 | |
danakj | 9a318f6 | 2024-10-01 17:56:39 | [diff] [blame] | 87 | def BuildCrubit(env, debug): |
| 88 | os.chdir(CRUBIT_SRC_DIR) |
Lukasz Anforowicz | 401dc9c | 2022-10-20 18:45:00 | [diff] [blame] | 89 | |
danakj | 9a318f6 | 2024-10-01 17:56:39 | [diff] [blame] | 90 | CRUBIT_BINS = ['rs_bindings_from_cc'] |
Lukasz Anforowicz | 401dc9c | 2022-10-20 18:45:00 | [diff] [blame] | 91 | |
danakj | 9a318f6 | 2024-10-01 17:56:39 | [diff] [blame] | 92 | build_cmd = ['cargo', 'build'] |
| 93 | for bin in CRUBIT_BINS: |
| 94 | build_cmd += ['--bin', bin] |
| 95 | if not debug: |
| 96 | build_cmd.append('--release') |
| 97 | RunCommand(build_cmd, setenv=True, env=env) |
Lukasz Anforowicz | 401dc9c | 2022-10-20 18:45:00 | [diff] [blame] | 98 | |
danakj | 9a318f6 | 2024-10-01 17:56:39 | [diff] [blame] | 99 | print(f'Installing Crubit to {RUST_TOOLCHAIN_OUT_DIR} ...') |
| 100 | target_dir = os.path.join(CRUBIT_SRC_DIR, 'target', |
| 101 | 'debug' if debug else 'release') |
| 102 | for bin in CRUBIT_BINS: |
| 103 | bin = bin + EXE |
| 104 | shutil.copy(os.path.join(target_dir, bin), |
| 105 | os.path.join(RUST_TOOLCHAIN_OUT_DIR, 'bin', bin)) |
Lukasz Anforowicz | 401dc9c | 2022-10-20 18:45:00 | [diff] [blame] | 106 | |
danakj | 9a318f6 | 2024-10-01 17:56:39 | [diff] [blame] | 107 | support_build_dir = os.path.join(CRUBIT_SRC_DIR, 'support') |
| 108 | support_out_dir = os.path.join(RUST_TOOLCHAIN_OUT_DIR, 'lib', 'crubit') |
| 109 | if os.path.exists(support_out_dir): |
| 110 | RmTree(support_out_dir) |
| 111 | shutil.copytree(support_build_dir, support_out_dir) |
Lukasz Anforowicz | 401dc9c | 2022-10-20 18:45:00 | [diff] [blame] | 112 | |
danakj | 9a318f6 | 2024-10-01 17:56:39 | [diff] [blame] | 113 | os.chdir(CHROMIUM_DIR) |
Lukasz Anforowicz | 401dc9c | 2022-10-20 18:45:00 | [diff] [blame] | 114 | |
| 115 | |
Lukasz Anforowicz | a394bbd | 2022-06-21 18:21:06 | [diff] [blame] | 116 | def main(): |
| 117 | parser = argparse.ArgumentParser( |
| 118 | description='Build and package Crubit tools') |
Lukasz Anforowicz | 401dc9c | 2022-10-20 18:45:00 | [diff] [blame] | 119 | parser.add_argument( |
Lukasz Anforowicz | a394bbd | 2022-06-21 18:21:06 | [diff] [blame] | 120 | '--skip-checkout', |
| 121 | action='store_true', |
danakj | 9a318f6 | 2024-10-01 17:56:39 | [diff] [blame] | 122 | help=('skip checking out source code. Useful for trying local' |
| 123 | 'changes')) |
| 124 | parser.add_argument('--debug', |
| 125 | action='store_true', |
| 126 | help=('build Crubit in debug mode')) |
Lukasz Anforowicz | a394bbd | 2022-06-21 18:21:06 | [diff] [blame] | 127 | args, rest = parser.parse_known_args() |
danakj | 9a318f6 | 2024-10-01 17:56:39 | [diff] [blame] | 128 | assert (not rest) |
Lukasz Anforowicz | a394bbd | 2022-06-21 18:21:06 | [diff] [blame] | 129 | |
| 130 | if not args.skip_checkout: |
danakj | 9a318f6 | 2024-10-01 17:56:39 | [diff] [blame] | 131 | CheckoutGitRepo("absl", ABSL_GIT, ABSL_REVISION, ABSL_SRC_DIR) |
| 132 | CheckoutGitRepo("crubit", CRUBIT_GIT, CRUBIT_REVISION, CRUBIT_SRC_DIR) |
| 133 | if sys.platform.startswith('linux'): |
| 134 | arch = 'arm64' if platform.machine() == 'aarch64' else 'amd64' |
| 135 | sysroot = DownloadDebianSysroot(arch, args.skip_checkout) |
Lukasz Anforowicz | a394bbd | 2022-06-21 18:21:06 | [diff] [blame] | 136 | |
danakj | 9a318f6 | 2024-10-01 17:56:39 | [diff] [blame] | 137 | llvm_bin_dir = os.path.join(RUST_HOST_LLVM_INSTALL_DIR, 'bin') |
| 138 | rust_bin_dir = os.path.join(RUST_TOOLCHAIN_OUT_DIR, 'bin') |
Lukasz Anforowicz | 401dc9c | 2022-10-20 18:45:00 | [diff] [blame] | 139 | |
danakj | 9a318f6 | 2024-10-01 17:56:39 | [diff] [blame] | 140 | AddCMakeToPath() |
Lukasz Anforowicz | 401dc9c | 2022-10-20 18:45:00 | [diff] [blame] | 141 | |
danakj | 9a318f6 | 2024-10-01 17:56:39 | [diff] [blame] | 142 | env = os.environ |
| 143 | |
| 144 | path_trailing_sep = os.pathsep if env['PATH'] else '' |
| 145 | env['PATH'] = (f'{llvm_bin_dir}{os.pathsep}' |
| 146 | f'{rust_bin_dir}{path_trailing_sep}' |
| 147 | f'{env["PATH"]}') |
| 148 | |
| 149 | if sys.platform == 'win32': |
| 150 | # CMake on Windows doesn't like depot_tools's ninja.bat wrapper. |
| 151 | ninja_dir = os.path.join(THIRD_PARTY_DIR, 'ninja') |
| 152 | env['PATH'] = f'{ninja_dir}{os.pathsep}{env["PATH"]}' |
| 153 | |
| 154 | env['CXXFLAGS'] = '' |
| 155 | env['RUSTFLAGS'] = '' |
| 156 | |
| 157 | if sys.platform == 'win32': |
| 158 | env['CC'] = 'clang-cl' |
| 159 | env['CXX'] = 'clang-cl' |
| 160 | else: |
| 161 | env['CC'] = 'clang' |
| 162 | env['CXX'] = 'clang++' |
| 163 | |
| 164 | # We link with lld via clang, except on windows where we point to lld-link |
| 165 | # directly. |
| 166 | if sys.platform == 'win32': |
| 167 | env['RUSTFLAGS'] += f' -Clinker=lld-link' |
| 168 | else: |
| 169 | env['RUSTFLAGS'] += f' -Clinker=clang' |
| 170 | env['RUSTFLAGS'] += f' -Clink-arg=-fuse-ld=lld' |
| 171 | |
| 172 | if sys.platform == 'win32': |
| 173 | # LLVM is built with static CRT. Make Rust match it. |
| 174 | env['RUSTFLAGS'] += f' -Ctarget-feature=+crt-static' |
| 175 | |
| 176 | if sys.platform.startswith('linux'): |
| 177 | sysroot_flag = (f'--sysroot={sysroot}' if sysroot else '') |
| 178 | env['CXXFLAGS'] += f" {sysroot_flag}" |
| 179 | env['RUSTFLAGS'] += f" -Clink-arg={sysroot_flag}" |
| 180 | |
| 181 | if sys.platform == 'darwin': |
| 182 | import subprocess |
| 183 | # The system/xcode compiler would find system SDK correctly, but |
| 184 | # the Clang we've built does not. See |
| 185 | # https://github.com/llvm/llvm-project/issues/45225 |
| 186 | sdk_path = subprocess.check_output(['xcrun', '--show-sdk-path'], |
| 187 | text=True).rstrip() |
| 188 | env['CXXFLAGS'] += f' -isysroot {sdk_path}' |
| 189 | env['RUSTFLAGS'] += f' -Clink-arg=-isysroot -Clink-arg={sdk_path}' |
| 190 | |
| 191 | if sys.platform == 'win32': |
| 192 | # LLVM depends on Zlib. |
| 193 | zlib_dir = AddZlibToPath(dry_run=args.skip_checkout) |
| 194 | env['CXXFLAGS'] += f' /I{zlib_dir}' |
| 195 | env['RUSTFLAGS'] += f' -Clink-arg=/LIBPATH:{zlib_dir}' |
| 196 | # Prevent deprecation warnings. |
| 197 | env['CXXFLAGS'] += ' /D_CRT_SECURE_NO_DEPRECATE' |
| 198 | |
| 199 | BuildAbsl(env, args.debug) |
| 200 | |
| 201 | env['ABSL_INCLUDE_PATH'] = os.path.join(ABSL_INSTALL_DIR, 'include') |
| 202 | env['ABSL_LIB_STATIC_PATH'] = os.path.join(ABSL_INSTALL_DIR, 'lib') |
| 203 | env['CLANG_INCLUDE_PATH'] = os.path.join(RUST_HOST_LLVM_INSTALL_DIR, |
| 204 | 'include') |
| 205 | env['CLANG_LIB_STATIC_PATH'] = os.path.join(RUST_HOST_LLVM_INSTALL_DIR, |
| 206 | 'lib') |
| 207 | |
| 208 | BuildCrubit(env, args.debug) |
Lukasz Anforowicz | a394bbd | 2022-06-21 18:21:06 | [diff] [blame] | 209 | |
| 210 | return 0 |
| 211 | |
| 212 | |
| 213 | if __name__ == '__main__': |
| 214 | sys.exit(main()) |