msetup: Update options when builddir is already configured

`meson setup -Dfoo=bar builddir` command was returning success ignoring
new option values.

This now also update options. It is useful because it means
`meson setup -Dfoo=bar builddir && ninja -C builddir` works regardless
whether builddir already exists or not, and when done in a script,
changing options in the script will automatically trigger a reconfigure
if needed. This was already possible by always passing --reconfigure
argument, but that triggers a reconfigure even when options did not
change.
pull/12155/head
Xavier Claessens 2 years ago committed by Xavier Claessens
parent 1bb29b1b32
commit e3a71a7b58
  1. 11
      docs/markdown/Commands.md
  2. 13
      docs/markdown/snippets/msetup.md
  3. 9
      mesonbuild/mconf.py
  4. 34
      mesonbuild/msetup.py
  5. 7
      unittests/baseplatformtests.py
  6. 7
      unittests/platformagnostictests.py

@ -244,6 +244,17 @@ Configures a build directory for the Meson project.
was no COMMAND supplied). However, supplying the command is necessary to avoid was no COMMAND supplied). However, supplying the command is necessary to avoid
clashes with future added commands, so "setup" should be used explicitly. clashes with future added commands, so "setup" should be used explicitly.
*Since 1.1.0* `--reconfigure` is allowed even if the build directory does not
already exist, that argument is ignored in that case.
*Since 1.3.0* If the build directory already exists, options are updated with
their new value given on the command line (`-Dopt=value`). Unless `--reconfigure`
is also specified, this won't reconfigure immediately. This has the same behaviour
as `meson configure <builddir> -Dopt=value`.
*Since 1.3.0* It is possible to clear the cache and reconfigure in a single command
with `meson setup --clearcache --reconfigure <builddir>`.
{{ setup_arguments.inc }} {{ setup_arguments.inc }}
See [Meson introduction See [Meson introduction

@ -0,0 +1,13 @@
## Update options with `meson setup <builddir> -Dopt=value`
If the build directory already exists, options are updated with their new value
given on the command line (`-Dopt=value`). Unless `--reconfigure` is also specified,
this won't reconfigure immediately. This has the same behaviour as
`meson configure <builddir> -Dopt=value`.
Previous Meson versions were simply a no-op.
## Clear persistent cache with `meson setup --clearcache`
Just like `meson configure --clearcache`, it is now possible to clear the cache
and reconfigure in a single command with `meson setup --clearcache --reconfigure <builddir>`.

@ -301,9 +301,7 @@ class Conf:
for m in mismatching: for m in mismatching:
mlog.log(f'{m[0]:21}{m[1]:10}{m[2]:10}') mlog.log(f'{m[0]:21}{m[1]:10}{m[2]:10}')
def run(options: argparse.Namespace) -> int: def run_impl(options: argparse.Namespace, builddir: str) -> int:
coredata.parse_cmd_line_options(options)
builddir = os.path.abspath(os.path.realpath(options.builddir))
print_only = not options.cmd_line_options and not options.clearcache print_only = not options.cmd_line_options and not options.clearcache
c = None c = None
try: try:
@ -334,3 +332,8 @@ def run(options: argparse.Namespace) -> int:
# Pager quit before we wrote everything. # Pager quit before we wrote everything.
pass pass
return 0 return 0
def run(options: argparse.Namespace) -> int:
coredata.parse_cmd_line_options(options)
builddir = os.path.abspath(os.path.realpath(options.builddir))
return run_impl(options, builddir)

@ -55,15 +55,15 @@ def add_arguments(parser: argparse.ArgumentParser) -> None:
help='Wipe build directory and reconfigure using previous command line options. ' + help='Wipe build directory and reconfigure using previous command line options. ' +
'Useful when build directory got corrupted, or when rebuilding with a ' + 'Useful when build directory got corrupted, or when rebuilding with a ' +
'newer version of meson.') 'newer version of meson.')
parser.add_argument('--clearcache', action='store_true', default=False,
help='Clear cached state (e.g. found dependencies). Since 1.3.0.')
parser.add_argument('builddir', nargs='?', default=None) parser.add_argument('builddir', nargs='?', default=None)
parser.add_argument('sourcedir', nargs='?', default=None) parser.add_argument('sourcedir', nargs='?', default=None)
class MesonApp: class MesonApp:
def __init__(self, options: argparse.Namespace) -> None: def __init__(self, options: argparse.Namespace) -> None:
(self.source_dir, self.build_dir) = self.validate_dirs(options.builddir, self.options = options
options.sourcedir, (self.source_dir, self.build_dir) = self.validate_dirs()
options.reconfigure,
options.wipe)
if options.wipe: if options.wipe:
# Make a copy of the cmd line file to make sure we can always # Make a copy of the cmd line file to make sure we can always
# restore that file if anything bad happens. For example if # restore that file if anything bad happens. For example if
@ -96,8 +96,6 @@ class MesonApp:
os.makedirs(os.path.dirname(f), exist_ok=True) os.makedirs(os.path.dirname(f), exist_ok=True)
shutil.move(b, f) shutil.move(b, f)
self.options = options
def has_build_file(self, dirname: str) -> bool: def has_build_file(self, dirname: str) -> bool:
fname = os.path.join(dirname, environment.build_filename) fname = os.path.join(dirname, environment.build_filename)
return os.path.exists(fname) return os.path.exists(fname)
@ -144,8 +142,8 @@ class MesonApp:
with open(os.path.join(build_dir, '.hgignore'), 'w', encoding='utf-8') as ofile: with open(os.path.join(build_dir, '.hgignore'), 'w', encoding='utf-8') as ofile:
ofile.write(hg_ignore_file) ofile.write(hg_ignore_file)
def validate_dirs(self, dir1: T.Optional[str], dir2: T.Optional[str], reconfigure: bool, wipe: bool) -> T.Tuple[str, str]: def validate_dirs(self) -> T.Tuple[str, str]:
(src_dir, build_dir) = self.validate_core_dirs(dir1, dir2) (src_dir, build_dir) = self.validate_core_dirs(self.options.builddir, self.options.sourcedir)
if Path(build_dir) in Path(src_dir).parents: if Path(build_dir) in Path(src_dir).parents:
raise MesonException(f'Build directory {build_dir} cannot be a parent of source directory {src_dir}') raise MesonException(f'Build directory {build_dir} cannot be a parent of source directory {src_dir}')
if not os.listdir(build_dir): if not os.listdir(build_dir):
@ -155,21 +153,17 @@ class MesonApp:
has_valid_build = os.path.exists(os.path.join(priv_dir, 'coredata.dat')) has_valid_build = os.path.exists(os.path.join(priv_dir, 'coredata.dat'))
has_partial_build = os.path.isdir(priv_dir) has_partial_build = os.path.isdir(priv_dir)
if has_valid_build: if has_valid_build:
if not reconfigure and not wipe: if not self.options.reconfigure and not self.options.wipe:
print('Directory already configured.\n\n' print('Directory already configured.\n\n'
'Just run your build command (e.g. ninja) and Meson will regenerate as necessary.\n' 'Just run your build command (e.g. ninja) and Meson will regenerate as necessary.\n'
'If ninja fails, run "ninja reconfigure" or "meson setup --reconfigure"\n' 'Run "meson setup --reconfigure to force Meson to regenerate.\n\n'
'to force Meson to regenerate.\n\n'
'If build failures persist, run "meson setup --wipe" to rebuild from scratch\n' 'If build failures persist, run "meson setup --wipe" to rebuild from scratch\n'
'using the same options as passed when configuring the build.\n' 'using the same options as passed when configuring the build.')
'To change option values, run "meson configure" instead.') if self.options.cmd_line_options:
# FIXME: This returns success and ignores new option values from CLI. from . import mconf
# We should either make this a hard error, or update options and raise SystemExit(mconf.run_impl(self.options, build_dir))
# return success.
# Note that making this an error would not be backward compatible (and also isn't
# universally agreed on): https://github.com/mesonbuild/meson/pull/4249.
raise SystemExit(0) raise SystemExit(0)
elif not has_partial_build and wipe: elif not has_partial_build and self.options.wipe:
raise MesonException(f'Directory is not empty and does not contain a previous build:\n{build_dir}') raise MesonException(f'Directory is not empty and does not contain a previous build:\n{build_dir}')
return src_dir, build_dir return src_dir, build_dir
@ -179,6 +173,8 @@ class MesonApp:
mlog.initialize(env.get_log_dir(), self.options.fatal_warnings) mlog.initialize(env.get_log_dir(), self.options.fatal_warnings)
if self.options.profile: if self.options.profile:
mlog.set_timestamp_start(time.monotonic()) mlog.set_timestamp_start(time.monotonic())
if self.options.clearcache:
env.coredata.clear_cache()
with mesonlib.BuildDirLock(self.build_dir): with mesonlib.BuildDirLock(self.build_dir):
return self._generate(env, capture, vslite_ctx) return self._generate(env, capture, vslite_ctx)

@ -303,6 +303,13 @@ class BasePlatformTests(TestCase):
ensure_backend_detects_changes(self.backend) ensure_backend_detects_changes(self.backend)
self._run(self.mconf_command + arg + [self.builddir]) self._run(self.mconf_command + arg + [self.builddir])
def getconf(self, optname: str):
opts = self.introspect('--buildoptions')
for x in opts:
if x.get('name') == optname:
return x.get('value')
self.fail(f'Option {optname} not found')
def wipe(self): def wipe(self):
windows_proof_rmtree(self.builddir) windows_proof_rmtree(self.builddir)

@ -183,6 +183,13 @@ class PlatformAgnosticTests(BasePlatformTests):
Path(self.builddir, 'dummy').touch() Path(self.builddir, 'dummy').touch()
self.init(testdir, extra_args=['--reconfigure']) self.init(testdir, extra_args=['--reconfigure'])
# Setup a valid builddir should update options but not reconfigure
self.assertEqual(self.getconf('buildtype'), 'debug')
o = self.init(testdir, extra_args=['-Dbuildtype=release'])
self.assertIn('Directory already configured', o)
self.assertNotIn('The Meson build system', o)
self.assertEqual(self.getconf('buildtype'), 'release')
# Wipe of empty builddir should work # Wipe of empty builddir should work
self.new_builddir() self.new_builddir()
self.init(testdir, extra_args=['--wipe']) self.init(testdir, extra_args=['--wipe'])

Loading…
Cancel
Save