Skip to content

Commit 419590e

Browse files
authored
Implement a new approach to making recompile faster. (#13433)
Add a Python script which stubs out build configure steps, build cleaning, and makes various commands (e.g. mkdir) repeatable.
1 parent b036966 commit 419590e

File tree

2 files changed

+142
-0
lines changed

2 files changed

+142
-0
lines changed

infra/base-images/base-builder/Dockerfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@ COPY bazel_build_fuzz_tests \
181181
bash_parser.py \
182182
srcmap \
183183
write_labels.py \
184+
make_build_replayable.py \
184185
/usr/local/bin/
185186

186187
# TODO: Build this as part of a multi-stage build.
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
#!/usr/bin/env python3
2+
# Copyright 2025 Google LLC.
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
#!/usr/bin/env python
16+
import os
17+
import shutil
18+
19+
_REAL_SUFFIX = '.real'
20+
_WRAPPER_TEMPLATE = """#!/usr/bin/env python3
21+
22+
import sys
23+
import os
24+
25+
def main():
26+
target = sys.argv[0] + '.real'
27+
{contents}
28+
os.execv(target, sys.argv)
29+
30+
31+
if __name__ == '__main__':
32+
main()
33+
"""
34+
35+
36+
def create_wrapper(contents: str):
37+
return _WRAPPER_TEMPLATE.format(contents=contents)
38+
39+
40+
def main():
41+
dummy_script_content = '#!/bin/sh'
42+
dummy_scripts = [
43+
'/usr/bin/autoconf',
44+
'/usr/bin/autoheader',
45+
'/usr/bin/autom4te',
46+
'/usr/bin/automake',
47+
'/usr/bin/autopoint',
48+
'/usr/bin/autoreconf',
49+
'/usr/bin/autoscan',
50+
'/usr/bin/autoupdate',
51+
]
52+
53+
for script_path in dummy_scripts:
54+
with open(script_path, 'w') as f:
55+
f.write(dummy_script_content)
56+
os.chmod(script_path, 0o755)
57+
58+
files_to_move = (
59+
'/usr/bin/cmake',
60+
'/usr/local/bin/cmake',
61+
'/bin/sh',
62+
'/bin/bash',
63+
'/usr/bin/ln',
64+
'/usr/bin/make',
65+
'/usr/bin/meson',
66+
'/usr/bin/mkdir',
67+
'/usr/bin/zip',
68+
)
69+
70+
for src in files_to_move:
71+
if os.path.exists(src):
72+
shutil.move(src, src + _REAL_SUFFIX)
73+
74+
# Create a shell wrapper that stubs out `configure` and `autogen`.
75+
with open('/bin/sh', 'w') as f:
76+
f.write(
77+
create_wrapper("""
78+
if any(os.path.basename(arg) in ('configure', 'autogen.sh') for arg in sys.argv[1:]):
79+
sys.exit(0)
80+
"""))
81+
82+
shutil.copyfile('/bin/sh', '/bin/bash')
83+
84+
# Stub out `make clean`.
85+
with open('/usr/bin/make', 'w') as f:
86+
f.write(
87+
create_wrapper("""
88+
if any(arg == 'clean' for arg in sys.argv[1:]):
89+
sys.exit(0)
90+
"""))
91+
92+
# Stub out `meson setup`.
93+
with open('/usr/bin/meson', 'w') as f:
94+
f.write(
95+
create_wrapper("""
96+
if any(arg == 'setup' for arg in sys.argv[1:]):
97+
sys.exit(0)
98+
"""))
99+
100+
shutil.copyfile('/bin/sh', '/bin/bash')
101+
102+
# Stub out cmake, but allow cmake --build.
103+
with open('/usr/bin/cmake', 'w') as f:
104+
f.write(
105+
create_wrapper("""
106+
if not any(arg == '--build' for arg in sys.argv[1:]):
107+
sys.exit(0)
108+
"""))
109+
shutil.copyfile('/usr/bin/cmake', '/usr/local/bin/cmake')
110+
111+
# Add -p to mkdir calls to allow it to be run twice.
112+
with open('/usr/bin/mkdir', 'w') as f:
113+
f.write(
114+
create_wrapper("""
115+
if not any(arg == '-p' for arg in sys.argv[1:]):
116+
sys.argv.insert(1, '-p')
117+
"""))
118+
119+
# Don't zip something that already exists.
120+
with open('/usr/bin/zip', 'w') as f:
121+
f.write(
122+
create_wrapper("""
123+
if (any(arg.endswith('.zip') and os.path.exists(arg) for arg in sys.argv[1:])):
124+
sys.exit(0)
125+
"""))
126+
127+
# Add -f to ln.
128+
with open('/usr/bin/ln', 'w') as f:
129+
f.write(
130+
create_wrapper("""
131+
if not any(arg == '-f' for arg in sys.argv[1:]):
132+
sys.argv.insert(1, '-f')
133+
"""))
134+
135+
for file_path in files_to_move:
136+
if os.path.exists(file_path):
137+
os.chmod(file_path, 0o755)
138+
139+
140+
if __name__ == '__main__':
141+
main()

0 commit comments

Comments
 (0)