summaryrefslogtreecommitdiffstats
path: root/src/bootstrap/configure.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/bootstrap/configure.py')
-rwxr-xr-xsrc/bootstrap/configure.py440
1 files changed, 237 insertions, 203 deletions
diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py
index ab3d08292..abd28b400 100755
--- a/src/bootstrap/configure.py
+++ b/src/bootstrap/configure.py
@@ -44,7 +44,6 @@ o("local-rebuild", "build.local-rebuild", "assume local-rust matches the current
o("llvm-static-stdcpp", "llvm.static-libstdcpp", "statically link to libstdc++ for LLVM")
o("llvm-link-shared", "llvm.link-shared", "prefer shared linking to LLVM (llvm-config --link-shared)")
o("rpath", "rust.rpath", "build rpaths into rustc itself")
-o("llvm-version-check", "llvm.version-check", "check if the LLVM version is supported, build anyway")
o("codegen-tests", "rust.codegen-tests", "run the tests/codegen tests")
o("option-checking", None, "complain about unrecognized options in this configure script")
o("ninja", "llvm.ninja", "build LLVM using the Ninja generator (for MSVC, requires building in the correct environment)")
@@ -195,7 +194,7 @@ if '--help' in sys.argv or '-h' in sys.argv:
print('')
print('This configure script is a thin configuration shim over the true')
print('configuration system, `config.toml`. You can explore the comments')
- print('in `config.toml.example` next to this configure script to see')
+ print('in `config.example.toml` next to this configure script to see')
print('more information about what each option is. Additionally you can')
print('pass `--set` as an argument to set arbitrary key/value pairs')
print('in the TOML configuration if desired')
@@ -206,77 +205,78 @@ if '--help' in sys.argv or '-h' in sys.argv:
# Parse all command line arguments into one of these three lists, handling
# boolean and value-based options separately
-unknown_args = []
-need_value_args = []
-known_args = {}
-
-p("processing command line")
-i = 1
-while i < len(sys.argv):
- arg = sys.argv[i]
- i += 1
- if not arg.startswith('--'):
- unknown_args.append(arg)
- continue
-
- found = False
- for option in options:
- value = None
- if option.value:
- keyval = arg[2:].split('=', 1)
- key = keyval[0]
- if option.name != key:
- continue
+def parse_args(args):
+ unknown_args = []
+ need_value_args = []
+ known_args = {}
+
+ i = 0
+ while i < len(args):
+ arg = args[i]
+ i += 1
+ if not arg.startswith('--'):
+ unknown_args.append(arg)
+ continue
- if len(keyval) > 1:
- value = keyval[1]
- elif i < len(sys.argv):
- value = sys.argv[i]
- i += 1
- else:
- need_value_args.append(arg)
- continue
- else:
- if arg[2:] == 'enable-' + option.name:
- value = True
- elif arg[2:] == 'disable-' + option.name:
- value = False
+ found = False
+ for option in options:
+ value = None
+ if option.value:
+ keyval = arg[2:].split('=', 1)
+ key = keyval[0]
+ if option.name != key:
+ continue
+
+ if len(keyval) > 1:
+ value = keyval[1]
+ elif i < len(args):
+ value = args[i]
+ i += 1
+ else:
+ need_value_args.append(arg)
+ continue
else:
- continue
+ if arg[2:] == 'enable-' + option.name:
+ value = True
+ elif arg[2:] == 'disable-' + option.name:
+ value = False
+ else:
+ continue
+
+ found = True
+ if option.name not in known_args:
+ known_args[option.name] = []
+ known_args[option.name].append((option, value))
+ break
+
+ if not found:
+ unknown_args.append(arg)
+
+ # Note: here and a few other places, we use [-1] to apply the *last* value
+ # passed. But if option-checking is enabled, then the known_args loop will
+ # also assert that options are only passed once.
+ option_checking = ('option-checking' not in known_args
+ or known_args['option-checking'][-1][1])
+ if option_checking:
+ if len(unknown_args) > 0:
+ err("Option '" + unknown_args[0] + "' is not recognized")
+ if len(need_value_args) > 0:
+ err("Option '{0}' needs a value ({0}=val)".format(need_value_args[0]))
+
+ config = {}
+
+ set('build.configure-args', sys.argv[1:], config)
+ apply_args(known_args, option_checking, config)
+ return parse_example_config(known_args, config)
- found = True
- if option.name not in known_args:
- known_args[option.name] = []
- known_args[option.name].append((option, value))
- break
-
- if not found:
- unknown_args.append(arg)
-p("")
-
-# Note: here and a few other places, we use [-1] to apply the *last* value
-# passed. But if option-checking is enabled, then the known_args loop will
-# also assert that options are only passed once.
-option_checking = ('option-checking' not in known_args
- or known_args['option-checking'][-1][1])
-if option_checking:
- if len(unknown_args) > 0:
- err("Option '" + unknown_args[0] + "' is not recognized")
- if len(need_value_args) > 0:
- err("Option '{0}' needs a value ({0}=val)".format(need_value_args[0]))
-
-# Parse all known arguments into a configuration structure that reflects the
-# TOML we're going to write out
-config = {}
-
-
-def build():
+
+def build(known_args):
if 'build' in known_args:
return known_args['build'][-1][1]
return bootstrap.default_build_triple(verbose=False)
-def set(key, value):
+def set(key, value, config):
if isinstance(value, list):
# Remove empty values, which value.split(',') tends to generate.
value = [v for v in value if v]
@@ -298,122 +298,127 @@ def set(key, value):
arr = arr[part]
-for key in known_args:
- # The `set` option is special and can be passed a bunch of times
- if key == 'set':
- for option, value in known_args[key]:
- keyval = value.split('=', 1)
- if len(keyval) == 1 or keyval[1] == "true":
- value = True
- elif keyval[1] == "false":
- value = False
- else:
- value = keyval[1]
- set(keyval[0], value)
- continue
-
- # Ensure each option is only passed once
- arr = known_args[key]
- if option_checking and len(arr) > 1:
- err("Option '{}' provided more than once".format(key))
- option, value = arr[-1]
-
- # If we have a clear avenue to set our value in rustbuild, do so
- if option.rustbuild is not None:
- set(option.rustbuild, value)
- continue
-
- # Otherwise we're a "special" option and need some extra handling, so do
- # that here.
- if option.name == 'sccache':
- set('llvm.ccache', 'sccache')
- elif option.name == 'local-rust':
- for path in os.environ['PATH'].split(os.pathsep):
- if os.path.exists(path + '/rustc'):
- set('build.rustc', path + '/rustc')
- break
- for path in os.environ['PATH'].split(os.pathsep):
- if os.path.exists(path + '/cargo'):
- set('build.cargo', path + '/cargo')
- break
- elif option.name == 'local-rust-root':
- set('build.rustc', value + '/bin/rustc')
- set('build.cargo', value + '/bin/cargo')
- elif option.name == 'llvm-root':
- set('target.{}.llvm-config'.format(build()), value + '/bin/llvm-config')
- elif option.name == 'llvm-config':
- set('target.{}.llvm-config'.format(build()), value)
- elif option.name == 'llvm-filecheck':
- set('target.{}.llvm-filecheck'.format(build()), value)
- elif option.name == 'tools':
- set('build.tools', value.split(','))
- elif option.name == 'codegen-backends':
- set('rust.codegen-backends', value.split(','))
- elif option.name == 'host':
- set('build.host', value.split(','))
- elif option.name == 'target':
- set('build.target', value.split(','))
- elif option.name == 'full-tools':
- set('rust.codegen-backends', ['llvm'])
- set('rust.lld', True)
- set('rust.llvm-tools', True)
- set('build.extended', True)
- elif option.name == 'option-checking':
- # this was handled above
- pass
- elif option.name == 'dist-compression-formats':
- set('dist.compression-formats', value.split(','))
- else:
- raise RuntimeError("unhandled option {}".format(option.name))
+def apply_args(known_args, option_checking, config):
+ for key in known_args:
+ # The `set` option is special and can be passed a bunch of times
+ if key == 'set':
+ for option, value in known_args[key]:
+ keyval = value.split('=', 1)
+ if len(keyval) == 1 or keyval[1] == "true":
+ value = True
+ elif keyval[1] == "false":
+ value = False
+ else:
+ value = keyval[1]
+ set(keyval[0], value, config)
+ continue
-set('build.configure-args', sys.argv[1:])
+ # Ensure each option is only passed once
+ arr = known_args[key]
+ if option_checking and len(arr) > 1:
+ err("Option '{}' provided more than once".format(key))
+ option, value = arr[-1]
-# "Parse" the `config.toml.example` file into the various sections, and we'll
+ # If we have a clear avenue to set our value in rustbuild, do so
+ if option.rustbuild is not None:
+ set(option.rustbuild, value, config)
+ continue
+
+ # Otherwise we're a "special" option and need some extra handling, so do
+ # that here.
+ build_triple = build(known_args)
+
+ if option.name == 'sccache':
+ set('llvm.ccache', 'sccache', config)
+ elif option.name == 'local-rust':
+ for path in os.environ['PATH'].split(os.pathsep):
+ if os.path.exists(path + '/rustc'):
+ set('build.rustc', path + '/rustc', config)
+ break
+ for path in os.environ['PATH'].split(os.pathsep):
+ if os.path.exists(path + '/cargo'):
+ set('build.cargo', path + '/cargo', config)
+ break
+ elif option.name == 'local-rust-root':
+ set('build.rustc', value + '/bin/rustc', config)
+ set('build.cargo', value + '/bin/cargo', config)
+ elif option.name == 'llvm-root':
+ set('target.{}.llvm-config'.format(build_triple), value + '/bin/llvm-config', config)
+ elif option.name == 'llvm-config':
+ set('target.{}.llvm-config'.format(build_triple), value, config)
+ elif option.name == 'llvm-filecheck':
+ set('target.{}.llvm-filecheck'.format(build_triple), value, config)
+ elif option.name == 'tools':
+ set('build.tools', value.split(','), config)
+ elif option.name == 'codegen-backends':
+ set('rust.codegen-backends', value.split(','), config)
+ elif option.name == 'host':
+ set('build.host', value.split(','), config)
+ elif option.name == 'target':
+ set('build.target', value.split(','), config)
+ elif option.name == 'full-tools':
+ set('rust.codegen-backends', ['llvm'], config)
+ set('rust.lld', True, config)
+ set('rust.llvm-tools', True, config)
+ set('build.extended', True, config)
+ elif option.name == 'option-checking':
+ # this was handled above
+ pass
+ elif option.name == 'dist-compression-formats':
+ set('dist.compression-formats', value.split(','), config)
+ else:
+ raise RuntimeError("unhandled option {}".format(option.name))
+
+# "Parse" the `config.example.toml` file into the various sections, and we'll
# use this as a template of a `config.toml` to write out which preserves
# all the various comments and whatnot.
#
# Note that the `target` section is handled separately as we'll duplicate it
# per configured target, so there's a bit of special handling for that here.
-sections = {}
-cur_section = None
-sections[None] = []
-section_order = [None]
-targets = {}
-top_level_keys = []
-
-for line in open(rust_dir + '/config.toml.example').read().split("\n"):
- if cur_section == None:
- if line.count('=') == 1:
- top_level_key = line.split('=')[0]
- top_level_key = top_level_key.strip(' #')
- top_level_keys.append(top_level_key)
- if line.startswith('['):
- cur_section = line[1:-1]
- if cur_section.startswith('target'):
- cur_section = 'target'
- elif '.' in cur_section:
- raise RuntimeError("don't know how to deal with section: {}".format(cur_section))
- sections[cur_section] = [line]
- section_order.append(cur_section)
- else:
- sections[cur_section].append(line)
-
-# Fill out the `targets` array by giving all configured targets a copy of the
-# `target` section we just loaded from the example config
-configured_targets = [build()]
-if 'build' in config:
- if 'host' in config['build']:
- configured_targets += config['build']['host']
- if 'target' in config['build']:
- configured_targets += config['build']['target']
-if 'target' in config:
- for target in config['target']:
- configured_targets.append(target)
-for target in configured_targets:
- targets[target] = sections['target'][:]
- # 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.
- # Avoid using quotes unless it's necessary.
- targets[target][0] = targets[target][0].replace("x86_64-unknown-linux-gnu", "'{}'".format(target) if "." in target else target)
+def parse_example_config(known_args, config):
+ sections = {}
+ cur_section = None
+ sections[None] = []
+ section_order = [None]
+ targets = {}
+ top_level_keys = []
+
+ for line in open(rust_dir + '/config.example.toml').read().split("\n"):
+ if cur_section == None:
+ if line.count('=') == 1:
+ top_level_key = line.split('=')[0]
+ top_level_key = top_level_key.strip(' #')
+ top_level_keys.append(top_level_key)
+ if line.startswith('['):
+ cur_section = line[1:-1]
+ if cur_section.startswith('target'):
+ cur_section = 'target'
+ elif '.' in cur_section:
+ raise RuntimeError("don't know how to deal with section: {}".format(cur_section))
+ sections[cur_section] = [line]
+ section_order.append(cur_section)
+ else:
+ sections[cur_section].append(line)
+
+ # Fill out the `targets` array by giving all configured targets a copy of the
+ # `target` section we just loaded from the example config
+ configured_targets = [build(known_args)]
+ if 'build' in config:
+ if 'host' in config['build']:
+ configured_targets += config['build']['host']
+ if 'target' in config['build']:
+ configured_targets += config['build']['target']
+ if 'target' in config:
+ for target in config['target']:
+ configured_targets.append(target)
+ for target in configured_targets:
+ targets[target] = sections['target'][:]
+ # 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.
+ # Avoid using quotes unless it's necessary.
+ targets[target][0] = targets[target][0].replace("x86_64-unknown-linux-gnu", "'{}'".format(target) if "." in target else target)
+
+ configure_file(sections, top_level_keys, targets, config)
+ return section_order, sections, targets
def is_number(value):
@@ -476,38 +481,67 @@ def configure_top_level_key(lines, top_level_key, value):
raise RuntimeError("failed to find config line for {}".format(top_level_key))
-for section_key, section_config in config.items():
- if section_key not in sections and section_key not in top_level_keys:
- raise RuntimeError("config key {} not in sections or top_level_keys".format(section_key))
- if section_key in top_level_keys:
- configure_top_level_key(sections[None], section_key, section_config)
+# Modify `sections` to reflect the parsed arguments and example configs.
+def configure_file(sections, top_level_keys, targets, config):
+ for section_key, section_config in config.items():
+ if section_key not in sections and section_key not in top_level_keys:
+ raise RuntimeError("config key {} not in sections or top_level_keys".format(section_key))
+ if section_key in top_level_keys:
+ configure_top_level_key(sections[None], section_key, section_config)
+
+ elif section_key == 'target':
+ for target in section_config:
+ configure_section(targets[target], section_config[target])
+ else:
+ configure_section(sections[section_key], section_config)
+
+
+def write_uncommented(target, f):
+ block = []
+ is_comment = True
+
+ for line in target:
+ block.append(line)
+ if len(line) == 0:
+ if not is_comment:
+ for l in block:
+ f.write(l + "\n")
+ block = []
+ is_comment = True
+ continue
+ is_comment = is_comment and line.startswith('#')
+ return f
- elif section_key == 'target':
- for target in section_config:
- configure_section(targets[target], section_config[target])
- else:
- configure_section(sections[section_key], section_config)
-# Now that we've built up our `config.toml`, write it all out in the same
-# order that we read it in.
-p("")
-p("writing `config.toml` in current directory")
-with bootstrap.output('config.toml') as f:
+def write_config_toml(writer, section_order, targets, sections):
for section in section_order:
if section == 'target':
for target in targets:
- for line in targets[target]:
- f.write(line + "\n")
+ writer = write_uncommented(targets[target], writer)
else:
- for line in sections[section]:
- f.write(line + "\n")
-
-with bootstrap.output('Makefile') as f:
- contents = os.path.join(rust_dir, 'src', 'bootstrap', 'mk', 'Makefile.in')
- contents = open(contents).read()
- contents = contents.replace("$(CFG_SRC_DIR)", rust_dir + '/')
- contents = contents.replace("$(CFG_PYTHON)", sys.executable)
- f.write(contents)
-
-p("")
-p("run `python {}/x.py --help`".format(rust_dir))
+ writer = write_uncommented(sections[section], writer)
+
+
+if __name__ == "__main__":
+ p("processing command line")
+ # Parse all known arguments into a configuration structure that reflects the
+ # TOML we're going to write out
+ p("")
+ section_order, sections, targets = parse_args(sys.argv[1:])
+
+ # Now that we've built up our `config.toml`, write it all out in the same
+ # order that we read it in.
+ p("")
+ p("writing `config.toml` in current directory")
+ with bootstrap.output('config.toml') as f:
+ write_config_toml(f, section_order, targets, sections)
+
+ with bootstrap.output('Makefile') as f:
+ contents = os.path.join(rust_dir, 'src', 'bootstrap', 'mk', 'Makefile.in')
+ contents = open(contents).read()
+ contents = contents.replace("$(CFG_SRC_DIR)", rust_dir + '/')
+ contents = contents.replace("$(CFG_PYTHON)", sys.executable)
+ f.write(contents)
+
+ p("")
+ p("run `python {}/x.py --help`".format(rust_dir))