]> git.lizzy.rs Git - rust.git/blob - src/bootstrap/configure.py
run EndRegion when unwinding otherwise-empty scopes
[rust.git] / src / bootstrap / configure.py
1 #!/usr/bin/env python
2 # Copyright 2017 The Rust Project Developers. See the COPYRIGHT
3 # file at the top-level directory of this distribution and at
4 # http://rust-lang.org/COPYRIGHT.
5 #
6 # Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
7 # http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
8 # <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
9 # option. This file may not be copied, modified, or distributed
10 # except according to those terms.
11
12 # ignore-tidy-linelength
13
14 import sys
15 import os
16 rust_dir = os.path.dirname(os.path.abspath(__file__))
17 rust_dir = os.path.dirname(rust_dir)
18 rust_dir = os.path.dirname(rust_dir)
19 sys.path.append(os.path.join(rust_dir, "src", "bootstrap"))
20 import bootstrap
21
22
23 class Option:
24     def __init__(self, name, rustbuild, desc, value):
25         self.name = name
26         self.rustbuild = rustbuild
27         self.desc = desc
28         self.value = value
29
30
31 options = []
32
33
34 def o(*args):
35     options.append(Option(*args, value=False))
36
37
38 def v(*args):
39     options.append(Option(*args, value=True))
40
41
42 o("debug", "rust.debug", "debug mode; disables optimization unless `--enable-optimize` given")
43 o("docs", "build.docs", "build standard library documentation")
44 o("compiler-docs", "build.compiler-docs", "build compiler documentation")
45 o("optimize-tests", "rust.optimize-tests", "build tests with optimizations")
46 o("test-miri", "rust.test-miri", "run miri's test suite")
47 o("debuginfo-tests", "rust.debuginfo-tests", "build tests with debugger metadata")
48 o("quiet-tests", "rust.quiet-tests", "enable quieter output when running tests")
49 o("ccache", "llvm.ccache", "invoke gcc/clang via ccache to reuse object files between builds")
50 o("sccache", None, "invoke gcc/clang via sccache to reuse object files between builds")
51 o("local-rust", None, "use an installed rustc rather than downloading a snapshot")
52 v("local-rust-root", None, "set prefix for local rust binary")
53 o("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")
54 o("llvm-static-stdcpp", "llvm.static-libstdcpp", "statically link to libstdc++ for LLVM")
55 o("llvm-link-shared", "llvm.link-shared", "prefer shared linking to LLVM (llvm-config --link-shared)")
56 o("rpath", "rust.rpath", "build rpaths into rustc itself")
57 o("llvm-version-check", "llvm.version-check", "check if the LLVM version is supported, build anyway")
58 o("codegen-tests", "rust.codegen-tests", "run the src/test/codegen tests")
59 o("option-checking", None, "complain about unrecognized options in this configure script")
60 o("ninja", "llvm.ninja", "build LLVM using the Ninja generator (for MSVC, requires building in the correct environment)")
61 o("locked-deps", "build.locked-deps", "force Cargo.lock to be up to date")
62 o("vendor", "build.vendor", "enable usage of vendored Rust crates")
63 o("sanitizers", "build.sanitizers", "build the sanitizer runtimes (asan, lsan, msan, tsan)")
64 o("dist-src", "rust.dist-src", "when building tarballs enables building a source tarball")
65 o("cargo-openssl-static", "build.openssl-static", "static openssl in cargo")
66 o("profiler", "build.profiler", "build the profiler runtime")
67
68 # Optimization and debugging options. These may be overridden by the release
69 # channel, etc.
70 o("optimize", "rust.optimize", "build optimized rust code")
71 o("optimize-llvm", "llvm.optimize", "build optimized LLVM")
72 o("llvm-assertions", "llvm.assertions", "build LLVM with assertions")
73 o("debug-assertions", "rust.debug-assertions", "build with debugging assertions")
74 o("llvm-release-debuginfo", "llvm.release-debuginfo", "build LLVM with debugger metadata")
75 o("debuginfo", "rust.debuginfo", "build with debugger metadata")
76 o("debuginfo-lines", "rust.debuginfo-lines", "build with line number debugger metadata")
77 o("debuginfo-only-std", "rust.debuginfo-only-std", "build only libstd with debugging information")
78 o("debug-jemalloc", "rust.debug-jemalloc", "build jemalloc with --enable-debug --enable-fill")
79
80 v("prefix", "install.prefix", "set installation prefix")
81 v("localstatedir", "install.localstatedir", "local state directory")
82 v("datadir", "install.datadir", "install data")
83 v("sysconfdir", "install.sysconfdir", "install system configuration files")
84 v("infodir", "install.infodir", "install additional info")
85 v("libdir", "install.libdir", "install libraries")
86 v("mandir", "install.mandir", "install man pages in PATH")
87 v("docdir", "install.docdir", "install documentation in PATH")
88 v("bindir", "install.bindir", "install binaries")
89
90 v("llvm-root", None, "set LLVM root")
91 v("python", "build.python", "set path to python")
92 v("jemalloc-root", None, "set directory where libjemalloc_pic.a is located")
93 v("android-cross-path", "target.arm-linux-androideabi.android-ndk",
94   "Android NDK standalone path (deprecated)")
95 v("i686-linux-android-ndk", "target.i686-linux-android.android-ndk",
96   "i686-linux-android NDK standalone path")
97 v("arm-linux-androideabi-ndk", "target.arm-linux-androideabi.android-ndk",
98   "arm-linux-androideabi NDK standalone path")
99 v("armv7-linux-androideabi-ndk", "target.armv7-linux-androideabi.android-ndk",
100   "armv7-linux-androideabi NDK standalone path")
101 v("aarch64-linux-android-ndk", "target.aarch64-linux-android.android-ndk",
102   "aarch64-linux-android NDK standalone path")
103 v("x86_64-linux-android-ndk", "target.x86_64-linux-android.android-ndk",
104   "x86_64-linux-android NDK standalone path")
105 v("musl-root", "target.x86_64-unknown-linux-musl.musl-root",
106   "MUSL root installation directory (deprecated)")
107 v("musl-root-x86_64", "target.x86_64-unknown-linux-musl.musl-root",
108   "x86_64-unknown-linux-musl install directory")
109 v("musl-root-i686", "target.i686-unknown-linux-musl.musl-root",
110   "i686-unknown-linux-musl install directory")
111 v("musl-root-arm", "target.arm-unknown-linux-musleabi.musl-root",
112   "arm-unknown-linux-musleabi install directory")
113 v("musl-root-armhf", "target.arm-unknown-linux-musleabihf.musl-root",
114   "arm-unknown-linux-musleabihf install directory")
115 v("musl-root-armv7", "target.armv7-unknown-linux-musleabihf.musl-root",
116   "armv7-unknown-linux-musleabihf install directory")
117 v("musl-root-aarch64", "target.aarch64-unknown-linux-musl.musl-root",
118   "aarch64-unknown-linux-musl install directory")
119 v("qemu-armhf-rootfs", "target.arm-unknown-linux-gnueabihf.qemu-rootfs",
120   "rootfs in qemu testing, you probably don't want to use this")
121 v("qemu-aarch64-rootfs", "target.aarch64-unknown-linux-gnu.qemu-rootfs",
122   "rootfs in qemu testing, you probably don't want to use this")
123 v("experimental-targets", "llvm.experimental-targets",
124   "experimental LLVM targets to build")
125 v("release-channel", "rust.channel", "the name of the release channel to build")
126
127 # Used on systems where "cc" is unavailable
128 v("default-linker", "rust.default-linker", "the default linker")
129
130 # Many of these are saved below during the "writing configuration" step
131 # (others are conditionally saved).
132 o("manage-submodules", "build.submodules", "let the build manage the git submodules")
133 o("jemalloc", "rust.use-jemalloc", "build liballoc with jemalloc")
134 o("full-bootstrap", "build.full-bootstrap", "build three compilers instead of two")
135 o("extended", "build.extended", "build an extended rust tool set")
136
137 v("build", "build.build", "GNUs ./configure syntax LLVM build triple")
138 v("host", None, "GNUs ./configure syntax LLVM host triples")
139 v("target", None, "GNUs ./configure syntax LLVM target triples")
140
141 v("set", None, "set arbitrary key/value pairs in TOML configuration")
142
143
144 def p(msg):
145     print("configure: " + msg)
146
147
148 def err(msg):
149     print("configure: error: " + msg)
150     sys.exit(1)
151
152
153 if '--help' in sys.argv or '-h' in sys.argv:
154     print('Usage: ./configure [options]')
155     print('')
156     print('Options')
157     for option in options:
158         if 'android' in option.name:
159             # no one needs to know about these obscure options
160             continue
161         if option.value:
162             print('\t{:30} {}'.format('--{}=VAL'.format(option.name), option.desc))
163         else:
164             print('\t{:30} {}'.format('--enable-{}'.format(option.name), option.desc))
165     print('')
166     print('This configure script is a thin configuration shim over the true')
167     print('configuration system, `config.toml`. You can explore the comments')
168     print('in `config.toml.example` next to this configure script to see')
169     print('more information about what each option is. Additionally you can')
170     print('pass `--set` as an argument to set arbitrary key/value pairs')
171     print('in the TOML configuration if desired')
172     print('')
173     print('Also note that all options which take `--enable` can similarly')
174     print('be passed with `--disable-foo` to forcibly disable the option')
175     sys.exit(0)
176
177 # Parse all command line arguments into one of these three lists, handling
178 # boolean and value-based options separately
179 unknown_args = []
180 need_value_args = []
181 known_args = {}
182
183 p("processing command line")
184 i = 1
185 while i < len(sys.argv):
186     arg = sys.argv[i]
187     i += 1
188     if not arg.startswith('--'):
189         unknown_args.append(arg)
190         continue
191
192     found = False
193     for option in options:
194         value = None
195         if option.value:
196             keyval = arg[2:].split('=', 1)
197             key = keyval[0]
198             if option.name != key:
199                 continue
200
201             if len(keyval) > 1:
202                 value = keyval[1]
203             elif i < len(sys.argv):
204                 value = sys.argv[i]
205                 i += 1
206             else:
207                 need_value_args.append(arg)
208                 continue
209         else:
210             if arg[2:] == 'enable-' + option.name:
211                 value = True
212             elif arg[2:] == 'disable-' + option.name:
213                 value = False
214             else:
215                 continue
216
217         found = True
218         if option.name not in known_args:
219             known_args[option.name] = []
220         known_args[option.name].append((option, value))
221         break
222
223     if not found:
224         unknown_args.append(arg)
225 p("")
226
227 if 'option-checking' not in known_args or known_args['option-checking'][1]:
228     if len(unknown_args) > 0:
229         err("Option '" + unknown_args[0] + "' is not recognized")
230     if len(need_value_args) > 0:
231         err("Option '{0}' needs a value ({0}=val)".format(need_value_args[0]))
232
233 # Parse all known arguments into a configuration structure that reflects the
234 # TOML we're going to write out
235 config = {}
236
237
238 def build():
239     if 'build' in known_args:
240         return known_args['build'][0][1]
241     return bootstrap.default_build_triple()
242
243
244 def set(key, value):
245     s = "{:20} := {}".format(key, value)
246     if len(s) < 70:
247         p(s)
248     else:
249         p(s[:70] + " ...")
250
251     arr = config
252     parts = key.split('.')
253     for i, part in enumerate(parts):
254         if i == len(parts) - 1:
255             arr[part] = value
256         else:
257             if part not in arr:
258                 arr[part] = {}
259             arr = arr[part]
260
261
262 for key in known_args:
263     # The `set` option is special and can be passed a bunch of times
264     if key == 'set':
265         for option, value in known_args[key]:
266             keyval = value.split('=', 1)
267             if len(keyval) == 1 or keyval[1] == "true":
268                 value = True
269             elif keyval[1] == "false":
270                 value = False
271             else:
272                 value = keyval[1]
273             set(keyval[0], value)
274         continue
275
276     # Ensure each option is only passed once
277     arr = known_args[key]
278     if len(arr) > 1:
279         err("Option '{}' provided more than once".format(key))
280     option, value = arr[0]
281
282     # If we have a clear avenue to set our value in rustbuild, do so
283     if option.rustbuild is not None:
284         set(option.rustbuild, value)
285         continue
286
287     # Otherwise we're a "special" option and need some extra handling, so do
288     # that here.
289     if option.name == 'sccache':
290         set('llvm.ccache', 'sccache')
291     elif option.name == 'local-rust':
292         for path in os.environ['PATH'].split(os.pathsep):
293             if os.path.exists(path + '/rustc'):
294                 set('build.rustc', path + '/rustc')
295                 break
296         for path in os.environ['PATH'].split(os.pathsep):
297             if os.path.exists(path + '/cargo'):
298                 set('build.cargo', path + '/cargo')
299                 break
300     elif option.name == 'local-rust-root':
301         set('build.rustc', value + '/bin/rustc')
302         set('build.cargo', value + '/bin/cargo')
303     elif option.name == 'llvm-root':
304         set('target.{}.llvm-config'.format(build()), value + '/bin/llvm-config')
305     elif option.name == 'jemalloc-root':
306         set('target.{}.jemalloc'.format(build()), value + '/libjemalloc_pic.a')
307     elif option.name == 'host':
308         set('build.host', value.split(','))
309     elif option.name == 'target':
310         set('build.target', value.split(','))
311     elif option.name == 'option-checking':
312         # this was handled above
313         pass
314     else:
315         raise RuntimeError("unhandled option {}".format(option.name))
316
317 set('build.configure-args', sys.argv[1:])
318
319 # "Parse" the `config.toml.example` file into the various sections, and we'll
320 # use this as a template of a `config.toml` to write out which preserves
321 # all the various comments and whatnot.
322 #
323 # Note that the `target` section is handled separately as we'll duplicate it
324 # per configure dtarget, so there's a bit of special handling for that here.
325 sections = {}
326 cur_section = None
327 sections[None] = []
328 section_order = [None]
329 targets = {}
330
331 for line in open(rust_dir + '/config.toml.example').read().split("\n"):
332     if line.startswith('['):
333         cur_section = line[1:-1]
334         if cur_section.startswith('target'):
335             cur_section = 'target'
336         elif '.' in cur_section:
337             raise RuntimeError("don't know how to deal with section: {}".format(cur_section))
338         sections[cur_section] = [line]
339         section_order.append(cur_section)
340     else:
341         sections[cur_section].append(line)
342
343 # Fill out the `targets` array by giving all configured targets a copy of the
344 # `target` section we just loaded from the example config
345 configured_targets = [build()]
346 if 'build' in config:
347     if 'host' in config['build']:
348         configured_targets += config['build']['host']
349     if 'target' in config['build']:
350         configured_targets += config['build']['target']
351 if 'target' in config:
352     for target in config['target']:
353         configured_targets.append(target)
354 for target in configured_targets:
355     targets[target] = sections['target'][:]
356     targets[target][0] = targets[target][0].replace("x86_64-unknown-linux-gnu", target)
357
358
359 # Here we walk through the constructed configuration we have from the parsed
360 # command line arguments. We then apply each piece of configuration by
361 # basically just doing a `sed` to change the various configuration line to what
362 # we've got configure.
363 def to_toml(value):
364     if isinstance(value, bool):
365         if value:
366             return "true"
367         else:
368             return "false"
369     elif isinstance(value, list):
370         return '[' + ', '.join(map(to_toml, value)) + ']'
371     elif isinstance(value, str):
372         return "'" + value + "'"
373     else:
374         raise RuntimeError('no toml')
375
376
377 def configure_section(lines, config):
378     for key in config:
379         value = config[key]
380         found = False
381         for i, line in enumerate(lines):
382             if not line.startswith('#' + key + ' = '):
383                 continue
384             found = True
385             lines[i] = "{} = {}".format(key, to_toml(value))
386             break
387         if not found:
388             raise RuntimeError("failed to find config line for {}".format(key))
389
390
391 for section_key in config:
392     section_config = config[section_key]
393     if section_key not in sections:
394         raise RuntimeError("config key {} not in sections".format(section_key))
395
396     if section_key == 'target':
397         for target in section_config:
398             configure_section(targets[target], section_config[target])
399     else:
400         configure_section(sections[section_key], section_config)
401
402 # Now that we've built up our `config.toml`, write it all out in the same
403 # order that we read it in.
404 p("")
405 p("writing `config.toml` in current directory")
406 with open('config.toml', 'w') as f:
407     for section in section_order:
408         if section == 'target':
409             for target in targets:
410                 for line in targets[target]:
411                     f.write(line + "\n")
412         else:
413             for line in sections[section]:
414                 f.write(line + "\n")
415
416 with open('Makefile', 'w') as f:
417     contents = os.path.join(rust_dir, 'src', 'bootstrap', 'mk', 'Makefile.in')
418     contents = open(contents).read()
419     contents = contents.replace("$(CFG_SRC_DIR)", rust_dir + '/')
420     contents = contents.replace("$(CFG_PYTHON)", sys.executable)
421     f.write(contents)
422
423 p("")
424 p("run `python {}/x.py --help`".format(rust_dir))
425 p("")