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