Skip to content

Commit f355ec9

Browse files
danakjAravind Vasudevan
authored andcommitted
Build and ship bindgen along with the Rust toolchain
Remove bindgen and its dependencies from //third_party/rust, and have the GN scripts point to the binary from the toolchain package. This depends on a new Rust toolchain being built and updating the FALLBACK_REVISION to point to it, or the bindgen binary will simply go missing. Bug: 1426886 Change-Id: I7ed5061c8ad0df30722be4406b73bc386ce75715 Cq-Include-Trybots: luci.chromium.try:android-rust-arm32-rel,android-rust-arm64-dbg,android-rust-arm64-rel,linux-rust-x64-dbg,linux-rust-x64-rel Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4362520 Reviewed-by: Collin Baker <[email protected]> Auto-Submit: danakj <[email protected]> Commit-Queue: Collin Baker <[email protected]> Cr-Commit-Position: refs/heads/main@{#1124972} NOKEYCHECK=True GitOrigin-RevId: b82362661f1fac1954ba59580b7b4945c939215d
1 parent c636f50 commit f355ec9

File tree

4 files changed

+320
-58
lines changed

4 files changed

+320
-58
lines changed

build_bindgen.py

Lines changed: 258 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,258 @@
1+
#!/usr/bin/env python3
2+
# Copyright 2023 The Chromium Authors
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 bindgen tool.'''
6+
7+
import argparse
8+
import collections
9+
import os
10+
import platform
11+
import shutil
12+
import subprocess
13+
import sys
14+
15+
from build_rust import (CARGO_HOME_DIR, CIPD_DOWNLOAD_URL, FetchBetaPackage,
16+
InstallBetaPackage, RustTargetTriple,
17+
RUST_CROSS_TARGET_LLVM_INSTALL_DIR,
18+
RUST_HOST_LLVM_INSTALL_DIR)
19+
from update_rust import (RUST_REVISION, RUST_TOOLCHAIN_OUT_DIR,
20+
THIRD_PARTY_DIR)
21+
22+
# Get variables and helpers from Clang update script
23+
sys.path.append(
24+
os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'clang',
25+
'scripts'))
26+
27+
from build import (CheckoutGitRepo, DownloadAndUnpack, LLVM_BUILD_TOOLS_DIR,
28+
MaybeDownloadHostGcc, RunCommand)
29+
from update import (RmTree)
30+
31+
# The git hash to use. This is the `v0.60.0` tag.
32+
BINDGEN_GIT_VERSION = '355181134094202e0caae60c1fbf145d8e6ca84b'
33+
# TODO(crbug.com/1428298): Mirror to Git-on-Borg.
34+
BINDGEN_GIT_REPO = 'https://github.com/rust-lang/rust-bindgen'
35+
36+
BINDGEN_SRC_DIR = os.path.join(THIRD_PARTY_DIR, 'rust-toolchain-intermediate',
37+
'bindgen-src')
38+
BINDGEN_HOST_BUILD_DIR = os.path.join(THIRD_PARTY_DIR,
39+
'rust-toolchain-intermediate',
40+
'bindgen-host-build')
41+
BINDGEN_CROSS_TARGET_BUILD_DIR = os.path.join(THIRD_PARTY_DIR,
42+
'rust-toolchain-intermediate',
43+
'bindgen-target-build')
44+
45+
NCURSESW_CIPD_LINUX_AMD_PATH = 'infra/3pp/static_libs/ncursesw/linux-amd64'
46+
NCURSESW_CIPD_LINUX_AMD_VERSION = '6.0.chromium.1'
47+
48+
RUST_BETA_SYSROOT_DIR = os.path.join(THIRD_PARTY_DIR,
49+
'rust-toolchain-intermediate',
50+
'beta-sysroot')
51+
52+
EXE = '.exe' if sys.platform == 'win32' else ''
53+
54+
55+
def FetchNcurseswLibrary():
56+
assert sys.platform.startswith('linux')
57+
ncursesw_dir = os.path.join(LLVM_BUILD_TOOLS_DIR, 'ncursesw')
58+
ncursesw_url = (f'{CIPD_DOWNLOAD_URL}/{NCURSESW_CIPD_LINUX_AMD_PATH}'
59+
f'/+/version:2@{NCURSESW_CIPD_LINUX_AMD_VERSION}')
60+
61+
if os.path.exists(ncursesw_dir):
62+
RmTree(ncursesw_dir)
63+
DownloadAndUnpack(ncursesw_url, ncursesw_dir, is_known_zip=True)
64+
return ncursesw_dir
65+
66+
67+
def main():
68+
parser = argparse.ArgumentParser(description='Build and package bindgen')
69+
parser.add_argument(
70+
'--skip-checkout',
71+
action='store_true',
72+
help='skip downloading the git repo. Useful for trying local changes')
73+
parser.add_argument('--build-mac-arm',
74+
action='store_true',
75+
help='Build arm binaries. Only valid on macOS.')
76+
args, rest = parser.parse_known_args()
77+
78+
if args.build_mac_arm and sys.platform != 'darwin':
79+
print('--build-mac-arm only valid on macOS')
80+
return 1
81+
if args.build_mac_arm and platform.machine() == 'arm64':
82+
print('--build-mac-arm only valid on intel to cross-build arm')
83+
return 1
84+
85+
args.gcc_toolchain = None
86+
if sys.platform.startswith('linux'):
87+
# Fetch GCC package to build against same libstdc++ as Clang. This
88+
# function will only download it if necessary, and it will set the
89+
# `args.gcc_toolchain` if so.
90+
MaybeDownloadHostGcc(args)
91+
92+
ncursesw_dir = None
93+
if sys.platform.startswith('linux'):
94+
ncursesw_dir = FetchNcurseswLibrary()
95+
96+
if args.build_mac_arm:
97+
# When cross-compiling, the binaries in RUST_TOOLCHAIN_OUT_DIR are not
98+
# usable on this machine, so we have to fetch them. We install them,
99+
# along with the host and target stdlib to RUST_BETA_SYSROOT_DIR.
100+
if os.path.exists(RUST_BETA_SYSROOT_DIR):
101+
RmTree(RUST_BETA_SYSROOT_DIR)
102+
InstallBetaPackage(FetchBetaPackage('cargo', RUST_REVISION),
103+
RUST_BETA_SYSROOT_DIR)
104+
InstallBetaPackage(FetchBetaPackage('rustc', RUST_REVISION),
105+
RUST_BETA_SYSROOT_DIR)
106+
InstallBetaPackage(
107+
FetchBetaPackage('rust-std',
108+
RUST_REVISION,
109+
triple=RustTargetTriple(None)),
110+
RUST_BETA_SYSROOT_DIR)
111+
InstallBetaPackage(
112+
FetchBetaPackage('rust-std',
113+
RUST_REVISION,
114+
triple=RustTargetTriple(args.build_mac_arm)),
115+
RUST_BETA_SYSROOT_DIR)
116+
cargo_bin = os.path.join(RUST_BETA_SYSROOT_DIR, 'bin', f'cargo{EXE}')
117+
rustc_bin = os.path.join(RUST_BETA_SYSROOT_DIR, 'bin', f'rustc{EXE}')
118+
119+
if not os.path.exists(cargo_bin):
120+
print(f'Missing cargo at {cargo_bin}. The sysroot was not setup '
121+
'correctly?')
122+
sys.exit(1)
123+
if not os.path.exists(rustc_bin):
124+
print(f'Missing rustc at {rustc_bin}. The sysroot was not setup '
125+
'correctly?')
126+
sys.exit(1)
127+
else:
128+
cargo_bin = os.path.join(RUST_TOOLCHAIN_OUT_DIR, 'bin', f'cargo{EXE}')
129+
rustc_bin = os.path.join(RUST_TOOLCHAIN_OUT_DIR, 'bin', f'rustc{EXE}')
130+
131+
if not os.path.exists(cargo_bin):
132+
print(
133+
f'Missing cargo at {cargo_bin}. The build_bindgen.py '
134+
f'script expects to be run after build_rust.py is run as '
135+
f'the build_rust.py script builds cargo that is needed here.')
136+
sys.exit(1)
137+
if not os.path.exists(rustc_bin):
138+
print(
139+
f'Missing rustc at {rustc_bin}. The build_bindgen.py '
140+
f'script expects to be run after build_rust.py is run as '
141+
f'the build_rust.py script builds rustc that is needed here.')
142+
sys.exit(1)
143+
144+
clang_bins_dir = os.path.join(RUST_HOST_LLVM_INSTALL_DIR, 'bin')
145+
if args.build_mac_arm:
146+
llvm_dir = RUST_CROSS_TARGET_LLVM_INSTALL_DIR
147+
build_dir = BINDGEN_CROSS_TARGET_BUILD_DIR
148+
else:
149+
llvm_dir = RUST_HOST_LLVM_INSTALL_DIR
150+
build_dir = BINDGEN_HOST_BUILD_DIR
151+
152+
if not os.path.exists(os.path.join(llvm_dir, 'bin', f'llvm-config{EXE}')):
153+
print(f'Missing llvm-config in {llvm_dir}. The build_bindgen.py '
154+
f'script expects to be run after build_rust.py is run as '
155+
f'the build_rust.py script produces the LLVM libraries that '
156+
f'are needed here.')
157+
sys.exit(1)
158+
159+
if not args.skip_checkout:
160+
CheckoutGitRepo("bindgen", BINDGEN_GIT_REPO, BINDGEN_GIT_VERSION,
161+
BINDGEN_SRC_DIR)
162+
163+
print(f'Building bindgen in {build_dir} ...')
164+
if os.path.exists(build_dir):
165+
RmTree(build_dir)
166+
167+
env = collections.defaultdict(str, os.environ)
168+
# Cargo normally stores files in $HOME. Override this.
169+
env['CARGO_HOME'] = CARGO_HOME_DIR
170+
171+
# Use a rustc we deterministically provide, not a system one.
172+
env['RUSTC'] = rustc_bin
173+
174+
# Use the LLVM libs and clang compiler from the rustc build.
175+
env['LLVM_CONFIG_PATH'] = os.path.join(llvm_dir, 'bin', 'llvm-config')
176+
if sys.platform == 'win32':
177+
env['LIBCLANG_PATH'] = os.path.join(llvm_dir, 'bin')
178+
else:
179+
env['LIBCLANG_PATH'] = os.path.join(llvm_dir, 'lib')
180+
env['LIBCLANG_STATIC_PATH'] = os.path.join(llvm_dir, 'lib')
181+
env['CC'] = os.path.join(clang_bins_dir, 'clang')
182+
env['CXX'] = os.path.join(clang_bins_dir, 'clang++')
183+
184+
# Windows uses lld-link for MSVC compat. Otherwise, we use lld via clang.
185+
if sys.platform == 'win32':
186+
linker = os.path.join(clang_bins_dir, 'lld-link')
187+
else:
188+
linker = os.path.join(clang_bins_dir, 'clang')
189+
env['LDFLAGS'] += ' -fuse-ld=lld'
190+
env['RUSTFLAGS'] += ' -Clink-arg=-fuse-ld=lld'
191+
env['LD'] = linker
192+
env['RUSTFLAGS'] += f' -Clinker={linker}'
193+
194+
if args.gcc_toolchain:
195+
# We use these flags to avoid linking with the system libstdc++.
196+
gcc_toolchain_flag = f'--gcc-toolchain={args.gcc_toolchain}'
197+
env['CFLAGS'] += f' {gcc_toolchain_flag}'
198+
env['CXXFLAGS'] += f' {gcc_toolchain_flag}'
199+
env['LDFLAGS'] += f' {gcc_toolchain_flag}'
200+
env['RUSTFLAGS'] += f' -Clink-arg={gcc_toolchain_flag}'
201+
if ncursesw_dir:
202+
env['CFLAGS'] += f' -I{ncursesw_dir}/include'
203+
env['CXXFLAGS'] += f' -I{ncursesw_dir}/include'
204+
env['LDFLAGS'] += f' -L{ncursesw_dir}/lib'
205+
env['RUSTFLAGS'] += f' -Clink-arg=-L{ncursesw_dir}/lib'
206+
207+
if sys.platform == 'darwin':
208+
# The system/xcode compiler would find system SDK correctly, but
209+
# the Clang we've built does not. See
210+
# https://github.com/llvm/llvm-project/issues/45225
211+
sdk_path = subprocess.check_output(['xcrun', '--show-sdk-path'],
212+
text=True).rstrip()
213+
env['CFLAGS'] += f' -isysroot {sdk_path}'
214+
env['CXXFLAGS'] += f' -isysroot {sdk_path}'
215+
env['LDFLAGS'] += f' -isysroot {sdk_path}'
216+
env['RUSTFLAGS'] += f' -Clink-arg=-isysroot -Clink-arg={sdk_path}'
217+
218+
cargo_args = [
219+
'build',
220+
f'--manifest-path={BINDGEN_SRC_DIR}/Cargo.toml',
221+
f'--target-dir={build_dir}',
222+
f'--target={RustTargetTriple(args.build_mac_arm)}',
223+
f'--no-default-features',
224+
f'--features=clap,logging',
225+
'--release',
226+
'--bin',
227+
'bindgen',
228+
]
229+
RunCommand([cargo_bin] + cargo_args, msvc_arch='x64', env=env)
230+
231+
install_dir = os.path.join(RUST_TOOLCHAIN_OUT_DIR)
232+
print(f'Installing bindgen to {install_dir} ...')
233+
234+
shutil.copy(
235+
os.path.join(build_dir, RustTargetTriple(args.build_mac_arm),
236+
'release', f'bindgen{EXE}'),
237+
os.path.join(install_dir, 'bin'))
238+
if sys.platform == 'win32':
239+
shutil.copy(os.path.join(llvm_dir, 'bin', f'libclang.dll'),
240+
os.path.join(install_dir, 'bin'))
241+
elif sys.platform == 'darwin':
242+
shutil.copy(os.path.join(llvm_dir, 'lib', f'libclang.dylib'),
243+
os.path.join(install_dir, 'lib'))
244+
else:
245+
# Can't replace symlinks so remove existing ones.
246+
for filename in os.listdir(os.path.join(install_dir, 'lib')):
247+
if filename.startswith('libclang.so'):
248+
os.remove(os.path.join(install_dir, 'lib', filename))
249+
for filename in os.listdir(os.path.join(llvm_dir, 'lib')):
250+
if filename.startswith('libclang.so'):
251+
shutil.copy(os.path.join(llvm_dir, 'lib', filename),
252+
os.path.join(install_dir, 'lib'),
253+
follow_symlinks=False)
254+
return 0
255+
256+
257+
if __name__ == '__main__':
258+
sys.exit(main())

0 commit comments

Comments
 (0)