]> git.proxmox.com Git - rustc.git/blame - src/bootstrap/configure.py
New upstream version 1.68.2+dfsg1
[rustc.git] / src / bootstrap / configure.py
CommitLineData
ea8adc8c 1#!/usr/bin/env python
ea8adc8c
XL
2
3# ignore-tidy-linelength
4
abe05a73 5from __future__ import absolute_import, division, print_function
ea8adc8c
XL
6import sys
7import os
8rust_dir = os.path.dirname(os.path.abspath(__file__))
9rust_dir = os.path.dirname(rust_dir)
10rust_dir = os.path.dirname(rust_dir)
11sys.path.append(os.path.join(rust_dir, "src", "bootstrap"))
12import bootstrap
13
abe05a73
XL
14
15class Option(object):
ea8adc8c
XL
16 def __init__(self, name, rustbuild, desc, value):
17 self.name = name
18 self.rustbuild = rustbuild
19 self.desc = desc
20 self.value = value
21
abe05a73 22
ea8adc8c
XL
23options = []
24
abe05a73 25
ea8adc8c
XL
26def o(*args):
27 options.append(Option(*args, value=False))
28
abe05a73 29
ea8adc8c
XL
30def v(*args):
31 options.append(Option(*args, value=True))
32
abe05a73 33
064997fb 34o("debug", "rust.debug", "enables debugging environment; does not affect optimization of bootstrapped code")
ea8adc8c
XL
35o("docs", "build.docs", "build standard library documentation")
36o("compiler-docs", "build.compiler-docs", "build compiler documentation")
37o("optimize-tests", "rust.optimize-tests", "build tests with optimizations")
94b46f34 38o("verbose-tests", "rust.verbose-tests", "enable verbose output when running tests")
ea8adc8c
XL
39o("ccache", "llvm.ccache", "invoke gcc/clang via ccache to reuse object files between builds")
40o("sccache", None, "invoke gcc/clang via sccache to reuse object files between builds")
41o("local-rust", None, "use an installed rustc rather than downloading a snapshot")
42v("local-rust-root", None, "set prefix for local rust binary")
43o("local-rebuild", "build.local-rebuild", "assume local-rust matches the current version, for rebuilds; implies local-rust, and is implied if local-rust already matches the current version")
44o("llvm-static-stdcpp", "llvm.static-libstdcpp", "statically link to libstdc++ for LLVM")
45o("llvm-link-shared", "llvm.link-shared", "prefer shared linking to LLVM (llvm-config --link-shared)")
46o("rpath", "rust.rpath", "build rpaths into rustc itself")
47o("llvm-version-check", "llvm.version-check", "check if the LLVM version is supported, build anyway")
6522a427 48o("codegen-tests", "rust.codegen-tests", "run the tests/codegen tests")
ea8adc8c
XL
49o("option-checking", None, "complain about unrecognized options in this configure script")
50o("ninja", "llvm.ninja", "build LLVM using the Ninja generator (for MSVC, requires building in the correct environment)")
51o("locked-deps", "build.locked-deps", "force Cargo.lock to be up to date")
52o("vendor", "build.vendor", "enable usage of vendored Rust crates")
6a06907d 53o("sanitizers", "build.sanitizers", "build the sanitizer runtimes (asan, lsan, msan, tsan, hwasan)")
ea8adc8c 54o("dist-src", "rust.dist-src", "when building tarballs enables building a source tarball")
0bf4aa26 55o("cargo-native-static", "build.cargo-native-static", "static native libraries in cargo")
ea8adc8c 56o("profiler", "build.profiler", "build the profiler runtime")
0531ce1d 57o("full-tools", None, "enable all tools")
a1dfa0c6 58o("lld", "rust.lld", "build lld")
94222f64 59o("clang", "llvm.clang", "build clang")
0bf4aa26 60o("missing-tools", "dist.missing-tools", "allow failures when building tools")
dfeec247 61o("use-libcxx", "llvm.use-libcxx", "build LLVM with libc++")
74b04a01 62o("control-flow-guard", "rust.control-flow-guard", "Enable Control Flow Guard")
ea8adc8c 63
74b04a01
XL
64v("llvm-cflags", "llvm.cflags", "build LLVM with these extra compiler flags")
65v("llvm-cxxflags", "llvm.cxxflags", "build LLVM with these extra compiler flags")
66v("llvm-ldflags", "llvm.ldflags", "build LLVM with these extra linker flags")
9fa01778 67
29967ef6 68v("llvm-libunwind", "rust.llvm-libunwind", "use LLVM libunwind")
532ac7d7 69
ea8adc8c
XL
70# Optimization and debugging options. These may be overridden by the release
71# channel, etc.
ea8adc8c
XL
72o("optimize-llvm", "llvm.optimize", "build optimized LLVM")
73o("llvm-assertions", "llvm.assertions", "build LLVM with assertions")
94222f64 74o("llvm-plugins", "llvm.plugins", "build LLVM with plugin interface")
ea8adc8c 75o("debug-assertions", "rust.debug-assertions", "build with debugging assertions")
c295e0f8 76o("debug-assertions-std", "rust.debug-assertions-std", "build the standard library with debugging assertions")
94222f64 77o("overflow-checks", "rust.overflow-checks", "build with overflow checks")
c295e0f8 78o("overflow-checks-std", "rust.overflow-checks-std", "build the standard library with overflow checks")
ea8adc8c 79o("llvm-release-debuginfo", "llvm.release-debuginfo", "build LLVM with debugger metadata")
dc9dc135
XL
80v("debuginfo-level", "rust.debuginfo-level", "debuginfo level for Rust code")
81v("debuginfo-level-rustc", "rust.debuginfo-level-rustc", "debuginfo level for the compiler")
82v("debuginfo-level-std", "rust.debuginfo-level-std", "debuginfo level for the standard library")
83v("debuginfo-level-tools", "rust.debuginfo-level-tools", "debuginfo level for the tools")
84v("debuginfo-level-tests", "rust.debuginfo-level-tests", "debuginfo level for the test suites run with compiletest")
ff7c6d11 85v("save-toolstates", "rust.save-toolstates", "save build and test status of external tools into this file")
ea8adc8c
XL
86
87v("prefix", "install.prefix", "set installation prefix")
88v("localstatedir", "install.localstatedir", "local state directory")
89v("datadir", "install.datadir", "install data")
90v("sysconfdir", "install.sysconfdir", "install system configuration files")
91v("infodir", "install.infodir", "install additional info")
92v("libdir", "install.libdir", "install libraries")
93v("mandir", "install.mandir", "install man pages in PATH")
94v("docdir", "install.docdir", "install documentation in PATH")
95v("bindir", "install.bindir", "install binaries")
96
97v("llvm-root", None, "set LLVM root")
0bf4aa26
XL
98v("llvm-config", None, "set path to llvm-config")
99v("llvm-filecheck", None, "set path to LLVM's FileCheck utility")
ea8adc8c 100v("python", "build.python", "set path to python")
ea8adc8c
XL
101v("android-cross-path", "target.arm-linux-androideabi.android-ndk",
102 "Android NDK standalone path (deprecated)")
103v("i686-linux-android-ndk", "target.i686-linux-android.android-ndk",
104 "i686-linux-android NDK standalone path")
105v("arm-linux-androideabi-ndk", "target.arm-linux-androideabi.android-ndk",
106 "arm-linux-androideabi NDK standalone path")
107v("armv7-linux-androideabi-ndk", "target.armv7-linux-androideabi.android-ndk",
108 "armv7-linux-androideabi NDK standalone path")
0731742a
XL
109v("thumbv7neon-linux-androideabi-ndk", "target.thumbv7neon-linux-androideabi.android-ndk",
110 "thumbv7neon-linux-androideabi NDK standalone path")
ea8adc8c
XL
111v("aarch64-linux-android-ndk", "target.aarch64-linux-android.android-ndk",
112 "aarch64-linux-android NDK standalone path")
113v("x86_64-linux-android-ndk", "target.x86_64-linux-android.android-ndk",
114 "x86_64-linux-android NDK standalone path")
115v("musl-root", "target.x86_64-unknown-linux-musl.musl-root",
116 "MUSL root installation directory (deprecated)")
117v("musl-root-x86_64", "target.x86_64-unknown-linux-musl.musl-root",
118 "x86_64-unknown-linux-musl install directory")
2c00a5a8
XL
119v("musl-root-i586", "target.i586-unknown-linux-musl.musl-root",
120 "i586-unknown-linux-musl install directory")
ea8adc8c
XL
121v("musl-root-i686", "target.i686-unknown-linux-musl.musl-root",
122 "i686-unknown-linux-musl install directory")
123v("musl-root-arm", "target.arm-unknown-linux-musleabi.musl-root",
124 "arm-unknown-linux-musleabi install directory")
125v("musl-root-armhf", "target.arm-unknown-linux-musleabihf.musl-root",
126 "arm-unknown-linux-musleabihf install directory")
83c7162d
XL
127v("musl-root-armv5te", "target.armv5te-unknown-linux-musleabi.musl-root",
128 "armv5te-unknown-linux-musleabi install directory")
416331ca
XL
129v("musl-root-armv7", "target.armv7-unknown-linux-musleabi.musl-root",
130 "armv7-unknown-linux-musleabi install directory")
131v("musl-root-armv7hf", "target.armv7-unknown-linux-musleabihf.musl-root",
ea8adc8c
XL
132 "armv7-unknown-linux-musleabihf install directory")
133v("musl-root-aarch64", "target.aarch64-unknown-linux-musl.musl-root",
134 "aarch64-unknown-linux-musl install directory")
2c00a5a8
XL
135v("musl-root-mips", "target.mips-unknown-linux-musl.musl-root",
136 "mips-unknown-linux-musl install directory")
137v("musl-root-mipsel", "target.mipsel-unknown-linux-musl.musl-root",
138 "mipsel-unknown-linux-musl install directory")
e74abb32
XL
139v("musl-root-mips64", "target.mips64-unknown-linux-muslabi64.musl-root",
140 "mips64-unknown-linux-muslabi64 install directory")
141v("musl-root-mips64el", "target.mips64el-unknown-linux-muslabi64.musl-root",
142 "mips64el-unknown-linux-muslabi64 install directory")
ea8adc8c
XL
143v("qemu-armhf-rootfs", "target.arm-unknown-linux-gnueabihf.qemu-rootfs",
144 "rootfs in qemu testing, you probably don't want to use this")
145v("qemu-aarch64-rootfs", "target.aarch64-unknown-linux-gnu.qemu-rootfs",
146 "rootfs in qemu testing, you probably don't want to use this")
f035d41b
XL
147v("qemu-riscv64-rootfs", "target.riscv64gc-unknown-linux-gnu.qemu-rootfs",
148 "rootfs in qemu testing, you probably don't want to use this")
ea8adc8c
XL
149v("experimental-targets", "llvm.experimental-targets",
150 "experimental LLVM targets to build")
151v("release-channel", "rust.channel", "the name of the release channel to build")
fc512014 152v("release-description", "rust.description", "optional descriptive string for version output")
5869c6ff
XL
153v("dist-compression-formats", None,
154 "comma-separated list of compression formats to use")
ea8adc8c 155
abe05a73 156# Used on systems where "cc" is unavailable
ea8adc8c 157v("default-linker", "rust.default-linker", "the default linker")
ea8adc8c
XL
158
159# Many of these are saved below during the "writing configuration" step
160# (others are conditionally saved).
161o("manage-submodules", "build.submodules", "let the build manage the git submodules")
064997fb 162o("full-bootstrap", "build.full-bootstrap", "build three compilers instead of two (not recommended except for testing reproducible builds)")
ea8adc8c
XL
163o("extended", "build.extended", "build an extended rust tool set")
164
83c7162d 165v("tools", None, "List of extended tools will be installed")
136023e0 166v("codegen-backends", None, "List of codegen backends to build")
ea8adc8c
XL
167v("build", "build.build", "GNUs ./configure syntax LLVM build triple")
168v("host", None, "GNUs ./configure syntax LLVM host triples")
169v("target", None, "GNUs ./configure syntax LLVM target triples")
170
171v("set", None, "set arbitrary key/value pairs in TOML configuration")
172
abe05a73 173
ea8adc8c
XL
174def p(msg):
175 print("configure: " + msg)
176
abe05a73 177
ea8adc8c
XL
178def err(msg):
179 print("configure: error: " + msg)
180 sys.exit(1)
181
abe05a73 182
ea8adc8c
XL
183if '--help' in sys.argv or '-h' in sys.argv:
184 print('Usage: ./configure [options]')
185 print('')
186 print('Options')
187 for option in options:
188 if 'android' in option.name:
189 # no one needs to know about these obscure options
190 continue
191 if option.value:
192 print('\t{:30} {}'.format('--{}=VAL'.format(option.name), option.desc))
193 else:
194 print('\t{:30} {}'.format('--enable-{}'.format(option.name), option.desc))
195 print('')
196 print('This configure script is a thin configuration shim over the true')
197 print('configuration system, `config.toml`. You can explore the comments')
198 print('in `config.toml.example` next to this configure script to see')
199 print('more information about what each option is. Additionally you can')
200 print('pass `--set` as an argument to set arbitrary key/value pairs')
201 print('in the TOML configuration if desired')
202 print('')
203 print('Also note that all options which take `--enable` can similarly')
204 print('be passed with `--disable-foo` to forcibly disable the option')
205 sys.exit(0)
206
207# Parse all command line arguments into one of these three lists, handling
208# boolean and value-based options separately
209unknown_args = []
210need_value_args = []
211known_args = {}
212
213p("processing command line")
214i = 1
215while i < len(sys.argv):
216 arg = sys.argv[i]
217 i += 1
218 if not arg.startswith('--'):
219 unknown_args.append(arg)
220 continue
221
222 found = False
223 for option in options:
224 value = None
225 if option.value:
226 keyval = arg[2:].split('=', 1)
227 key = keyval[0]
228 if option.name != key:
229 continue
230
231 if len(keyval) > 1:
232 value = keyval[1]
233 elif i < len(sys.argv):
234 value = sys.argv[i]
235 i += 1
236 else:
237 need_value_args.append(arg)
238 continue
239 else:
240 if arg[2:] == 'enable-' + option.name:
241 value = True
242 elif arg[2:] == 'disable-' + option.name:
243 value = False
244 else:
245 continue
246
247 found = True
abe05a73 248 if option.name not in known_args:
ea8adc8c
XL
249 known_args[option.name] = []
250 known_args[option.name].append((option, value))
251 break
252
253 if not found:
254 unknown_args.append(arg)
255p("")
256
abe05a73
XL
257# Note: here and a few other places, we use [-1] to apply the *last* value
258# passed. But if option-checking is enabled, then the known_args loop will
259# also assert that options are only passed once.
260option_checking = ('option-checking' not in known_args
261 or known_args['option-checking'][-1][1])
262if option_checking:
ea8adc8c
XL
263 if len(unknown_args) > 0:
264 err("Option '" + unknown_args[0] + "' is not recognized")
265 if len(need_value_args) > 0:
266 err("Option '{0}' needs a value ({0}=val)".format(need_value_args[0]))
267
268# Parse all known arguments into a configuration structure that reflects the
269# TOML we're going to write out
270config = {}
271
abe05a73 272
ea8adc8c
XL
273def build():
274 if 'build' in known_args:
abe05a73 275 return known_args['build'][-1][1]
29967ef6 276 return bootstrap.default_build_triple(verbose=False)
ea8adc8c 277
abe05a73 278
ea8adc8c 279def set(key, value):
5e7ed085
FG
280 if isinstance(value, list):
281 # Remove empty values, which value.split(',') tends to generate.
282 value = [v for v in value if v]
283
abe05a73
XL
284 s = "{:20} := {}".format(key, value)
285 if len(s) < 70:
286 p(s)
287 else:
288 p(s[:70] + " ...")
289
290 arr = config
291 parts = key.split('.')
292 for i, part in enumerate(parts):
293 if i == len(parts) - 1:
294 arr[part] = value
295 else:
296 if part not in arr:
297 arr[part] = {}
298 arr = arr[part]
299
ea8adc8c
XL
300
301for key in known_args:
302 # The `set` option is special and can be passed a bunch of times
303 if key == 'set':
304 for option, value in known_args[key]:
305 keyval = value.split('=', 1)
306 if len(keyval) == 1 or keyval[1] == "true":
307 value = True
308 elif keyval[1] == "false":
309 value = False
310 else:
311 value = keyval[1]
312 set(keyval[0], value)
313 continue
314
315 # Ensure each option is only passed once
316 arr = known_args[key]
abe05a73 317 if option_checking and len(arr) > 1:
ea8adc8c 318 err("Option '{}' provided more than once".format(key))
abe05a73 319 option, value = arr[-1]
ea8adc8c
XL
320
321 # If we have a clear avenue to set our value in rustbuild, do so
322 if option.rustbuild is not None:
323 set(option.rustbuild, value)
324 continue
325
326 # Otherwise we're a "special" option and need some extra handling, so do
327 # that here.
328 if option.name == 'sccache':
329 set('llvm.ccache', 'sccache')
330 elif option.name == 'local-rust':
331 for path in os.environ['PATH'].split(os.pathsep):
332 if os.path.exists(path + '/rustc'):
333 set('build.rustc', path + '/rustc')
334 break
335 for path in os.environ['PATH'].split(os.pathsep):
336 if os.path.exists(path + '/cargo'):
337 set('build.cargo', path + '/cargo')
338 break
339 elif option.name == 'local-rust-root':
340 set('build.rustc', value + '/bin/rustc')
341 set('build.cargo', value + '/bin/cargo')
342 elif option.name == 'llvm-root':
343 set('target.{}.llvm-config'.format(build()), value + '/bin/llvm-config')
0bf4aa26
XL
344 elif option.name == 'llvm-config':
345 set('target.{}.llvm-config'.format(build()), value)
346 elif option.name == 'llvm-filecheck':
347 set('target.{}.llvm-filecheck'.format(build()), value)
83c7162d
XL
348 elif option.name == 'tools':
349 set('build.tools', value.split(','))
136023e0
XL
350 elif option.name == 'codegen-backends':
351 set('rust.codegen-backends', value.split(','))
ea8adc8c
XL
352 elif option.name == 'host':
353 set('build.host', value.split(','))
354 elif option.name == 'target':
355 set('build.target', value.split(','))
0531ce1d 356 elif option.name == 'full-tools':
e74abb32 357 set('rust.codegen-backends', ['llvm'])
0531ce1d 358 set('rust.lld', True)
8faf50e0 359 set('rust.llvm-tools', True)
0531ce1d 360 set('build.extended', True)
ea8adc8c
XL
361 elif option.name == 'option-checking':
362 # this was handled above
363 pass
5869c6ff
XL
364 elif option.name == 'dist-compression-formats':
365 set('dist.compression-formats', value.split(','))
ea8adc8c
XL
366 else:
367 raise RuntimeError("unhandled option {}".format(option.name))
368
369set('build.configure-args', sys.argv[1:])
370
371# "Parse" the `config.toml.example` file into the various sections, and we'll
372# use this as a template of a `config.toml` to write out which preserves
373# all the various comments and whatnot.
374#
375# Note that the `target` section is handled separately as we'll duplicate it
b7449926 376# per configured target, so there's a bit of special handling for that here.
ea8adc8c
XL
377sections = {}
378cur_section = None
379sections[None] = []
380section_order = [None]
381targets = {}
382
383for line in open(rust_dir + '/config.toml.example').read().split("\n"):
384 if line.startswith('['):
385 cur_section = line[1:-1]
386 if cur_section.startswith('target'):
387 cur_section = 'target'
388 elif '.' in cur_section:
389 raise RuntimeError("don't know how to deal with section: {}".format(cur_section))
390 sections[cur_section] = [line]
391 section_order.append(cur_section)
392 else:
393 sections[cur_section].append(line)
394
395# Fill out the `targets` array by giving all configured targets a copy of the
396# `target` section we just loaded from the example config
397configured_targets = [build()]
398if 'build' in config:
399 if 'host' in config['build']:
400 configured_targets += config['build']['host']
401 if 'target' in config['build']:
402 configured_targets += config['build']['target']
403if 'target' in config:
404 for target in config['target']:
405 configured_targets.append(target)
406for target in configured_targets:
407 targets[target] = sections['target'][:]
6522a427
EL
408 # For `.` to be valid TOML, it needs to be quoted. But `bootstrap.py` doesn't use a proper TOML parser and fails to parse the target.
409 # Avoid using quotes unless it's necessary.
410 targets[target][0] = targets[target][0].replace("x86_64-unknown-linux-gnu", "'{}'".format(target) if "." in target else target)
ea8adc8c 411
abe05a73 412
a1dfa0c6 413def is_number(value):
74b04a01
XL
414 try:
415 float(value)
416 return True
417 except ValueError:
418 return False
419
a1dfa0c6 420
ea8adc8c 421# Here we walk through the constructed configuration we have from the parsed
abe05a73 422# command line arguments. We then apply each piece of configuration by
ea8adc8c
XL
423# basically just doing a `sed` to change the various configuration line to what
424# we've got configure.
425def to_toml(value):
426 if isinstance(value, bool):
427 if value:
428 return "true"
429 else:
430 return "false"
431 elif isinstance(value, list):
432 return '[' + ', '.join(map(to_toml, value)) + ']'
433 elif isinstance(value, str):
a1dfa0c6
XL
434 # Don't put quotes around numeric values
435 if is_number(value):
436 return value
437 else:
438 return "'" + value + "'"
ea8adc8c 439 else:
abe05a73
XL
440 raise RuntimeError('no toml')
441
ea8adc8c
XL
442
443def configure_section(lines, config):
444 for key in config:
445 value = config[key]
446 found = False
447 for i, line in enumerate(lines):
448 if not line.startswith('#' + key + ' = '):
449 continue
450 found = True
451 lines[i] = "{} = {}".format(key, to_toml(value))
452 break
453 if not found:
cdc7bbd5
XL
454 # These are used by rpm, but aren't accepted by x.py.
455 # Give a warning that they're ignored, but not a hard error.
456 if key in ["infodir", "localstatedir"]:
457 print("warning: {} will be ignored".format(key))
458 else:
459 raise RuntimeError("failed to find config line for {}".format(key))
ea8adc8c 460
abe05a73 461
ea8adc8c
XL
462for section_key in config:
463 section_config = config[section_key]
abe05a73
XL
464 if section_key not in sections:
465 raise RuntimeError("config key {} not in sections".format(section_key))
ea8adc8c
XL
466
467 if section_key == 'target':
468 for target in section_config:
469 configure_section(targets[target], section_config[target])
470 else:
471 configure_section(sections[section_key], section_config)
472
473# Now that we've built up our `config.toml`, write it all out in the same
474# order that we read it in.
475p("")
476p("writing `config.toml` in current directory")
8faf50e0 477with bootstrap.output('config.toml') as f:
ea8adc8c
XL
478 for section in section_order:
479 if section == 'target':
480 for target in targets:
481 for line in targets[target]:
482 f.write(line + "\n")
483 else:
484 for line in sections[section]:
485 f.write(line + "\n")
486
8faf50e0 487with bootstrap.output('Makefile') as f:
ea8adc8c
XL
488 contents = os.path.join(rust_dir, 'src', 'bootstrap', 'mk', 'Makefile.in')
489 contents = open(contents).read()
490 contents = contents.replace("$(CFG_SRC_DIR)", rust_dir + '/')
491 contents = contents.replace("$(CFG_PYTHON)", sys.executable)
492 f.write(contents)
493
ea8adc8c 494p("")
abe05a73 495p("run `python {}/x.py --help`".format(rust_dir))