Can upgrade build directory from an old version.
diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py
index 354d25a..e9012e5 100644
--- a/mesonbuild/backend/backends.py
+++ b/mesonbuild/backend/backends.py
@@ -24,6 +24,7 @@
 from ..mesonlib import classify_unity_sources
 from ..mesonlib import File
 from ..compilers import CompilerArgs
+from ..mupgrade import create_dump_dict
 from collections import OrderedDict
 import shlex
 
@@ -120,6 +121,7 @@
 # This class contains the basic functionality that is needed by all backends.
 # Feel free to move stuff in and out of it as you see fit.
 class Backend:
+
     def __init__(self, build):
         self.build = build
         self.environment = build.environment
@@ -922,3 +924,11 @@
         for s in self.build.postconf_scripts:
             cmd = s['exe'] + s['args']
             subprocess.check_call(cmd, env=child_env)
+
+    def dump_state_file(self):
+        import json
+        build_dir = self.environment.get_build_dir()
+        dumpfile = os.path.join(build_dir, 'meson-private', 'upgrade-state.json')
+        s = create_dump_dict(self.environment, self.build)
+        with open(dumpfile, 'w') as f:
+            json.dump(s, f)
diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py
index 09c4904..cde2151 100644
--- a/mesonbuild/backend/ninjabackend.py
+++ b/mesonbuild/backend/ninjabackend.py
@@ -238,6 +238,7 @@
         # fully created.
         os.replace(tempfilename, outfilename)
         self.generate_compdb()
+        self.dump_state_file()
 
     # http://clang.llvm.org/docs/JSONCompilationDatabase.html
     def generate_compdb(self):
diff --git a/mesonbuild/backend/vs2010backend.py b/mesonbuild/backend/vs2010backend.py
index d42e91d..aee3754 100644
--- a/mesonbuild/backend/vs2010backend.py
+++ b/mesonbuild/backend/vs2010backend.py
@@ -1,4 +1,4 @@
-# Copyright 2014-2016 The Meson development team
+# Copyright 2014-2018 The Meson development team
 
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -167,6 +167,7 @@
         self.generate_solution(sln_filename, projlist)
         self.generate_regen_info()
         Vs2010Backend.touch_regen_timestamp(self.environment.get_build_dir())
+        self.dump_state_file()
 
     @staticmethod
     def get_regen_stampfile(build_dir):
diff --git a/mesonbuild/backend/xcodebackend.py b/mesonbuild/backend/xcodebackend.py
index 9a9f88b..276e365 100644
--- a/mesonbuild/backend/xcodebackend.py
+++ b/mesonbuild/backend/xcodebackend.py
@@ -1,4 +1,4 @@
-# Copyright 2014-2016 The Meson development team
+# Copyright 2014-2018 The Meson development team
 
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -103,6 +103,7 @@
             self.generate_xc_build_configuration()
             self.generate_xc_configurationList()
             self.generate_suffix()
+            self.dump_state_file()
 
     def get_xcodetype(self, fname):
         return self.xcodetypemap[fname.split('.')[-1]]
diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py
index 25835a3..cefc741 100644
--- a/mesonbuild/compilers/compilers.py
+++ b/mesonbuild/compilers/compilers.py
@@ -1,4 +1,4 @@
-# Copyright 2012-2017 The Meson development team
+# Copyright 2012-2018 The Meson development team
 
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -72,6 +72,18 @@
                   'vala': 'VALAFLAGS',
                   'rust': 'RUSTFLAGS'}
 
+compiler_envvars = {'c': 'CC',
+                    'cpp': 'CXX',
+                    'java': 'JAVAC',
+                    'd': 'DC',
+                    'objc': 'OBJC',
+                    'objcpp': 'OBJCXX',
+                    'fortran': 'FC',
+                    'rust': 'RUSTC',
+                    'vala': 'VALAC',
+                    'cs': 'CSC',
+                    }
+
 # All these are only for C-linkable languages; see `clink_langs` above.
 
 def sort_clink(lang):
diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py
index b26516c..0d6676e 100644
--- a/mesonbuild/coredata.py
+++ b/mesonbuild/coredata.py
@@ -410,9 +410,16 @@
             sub = 'In subproject {}: '.format(subproject) if subproject else ''
             mlog.warning('{}Unknown options: "{}"'.format(sub, unknown_options))
 
+    def get_all_option_classes(self):
+        return (self.backend_options,
+                self.user_options,
+                self.compiler_options,
+                self.base_options)
+
 def load(build_dir):
     filename = os.path.join(build_dir, 'meson-private', 'coredata.dat')
     load_fail_msg = 'Coredata file {!r} is corrupted. Try with a fresh build tree.'.format(filename)
+    state_file_exists = os.path.isfile(os.path.join(build_dir, 'meson-private', 'upgrade_state.json'))
     try:
         with open(filename, 'rb') as f:
             obj = pickle.load(f)
@@ -421,8 +428,12 @@
     if not isinstance(obj, CoreData):
         raise MesonException(load_fail_msg)
     if obj.version != version:
-        raise MesonException('Build directory has been generated with Meson version %s, which is incompatible with current version %s.\nPlease delete this build directory AND create a new one.' %
-                             (obj.version, version))
+        msg = 'Build directory has been generated with Meson version %s, which is incompatible with current version %s.\n'
+        if state_file_exists:
+            msg += 'Upgrade the build directory by invoking the "upgrade-builddir" target.'
+        else:
+            msg += 'Please delete this build directory AND create a new one.'
+        raise MesonException(msg % (obj.version, version))
     return obj
 
 def save(obj, build_dir):
diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py
index 0aa0b32..ee206e3 100644
--- a/mesonbuild/environment.py
+++ b/mesonbuild/environment.py
@@ -1,4 +1,4 @@
-# Copyright 2012-2016 The Meson development team
+# Copyright 2012-2018 The Meson development team
 
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
diff --git a/mesonbuild/mesonmain.py b/mesonbuild/mesonmain.py
index 011ac14..fdf4d23 100644
--- a/mesonbuild/mesonmain.py
+++ b/mesonbuild/mesonmain.py
@@ -307,6 +307,10 @@
             sys.argv[1:] = remaining_args[1:]
             runpy.run_path(script_file, run_name='__main__')
             sys.exit(0)
+        elif cmd_name == 'upgrade-builddir':
+            from . import mupgrade
+            mupgrade.do_upgrade(args[1:] + ['.'])
+            sys.exit(0)
 
     # No special command? Do the basic setup/reconf.
     if len(args) >= 2 and args[0] == '--internal':
diff --git a/mesonbuild/mupgrade.py b/mesonbuild/mupgrade.py
new file mode 100644
index 0000000..7a97497
--- /dev/null
+++ b/mesonbuild/mupgrade.py
@@ -0,0 +1,93 @@
+# Copyright 2018 The Meson development team
+
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+
+#     http://www.apache.org/licenses/LICENSE-2.0
+
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys, os
+import json
+import subprocess
+import shlex
+from .mesonlib import meson_command
+from .compilers.compilers import compiler_envvars
+
+dump_format_version = 1
+
+def upgrade(state_file):
+    d = json.load(open(state_file, 'r'))
+    version = d.get('dump_format_version', 'missing')
+    if version != dump_format_version:
+        sys.exit('Can not upgrade because state dump file format is not compatible: %d != %d.' % (version, dump_format_version))
+    state = d['state']
+    env = os.environ.copy()
+    for c in state['compilers']:
+        ename = compiler_envvars[c[0]]
+        eval = ' '.join([shlex.quote(x) for x in c[1]])
+        env[ename] = eval
+    cmd_args = [state['source_root'],
+                state['build_root']]
+    if 'cross_file' in state:
+        cmd_args += ['--cross-file', state['cross_file']]
+    for o in state['options']:
+        cmd_args.append('-D%s=%s' % (o[0], o[1]))
+    pc = subprocess.run(meson_command + cmd_args)
+    if pc.returncode != 0:
+        sys.exit(1) # The output from above should be enough to debug any issues.
+
+def do_upgrade(potential_builddirs):
+    for bd in potential_builddirs:
+        state_file = os.path.join(bd, 'meson-private', 'upgrade-state.json')
+        corefile = os.path.join(bd, 'meson-private', 'coredata.dat')
+        corefile_bak = corefile + '~'
+        if os.path.exists(state_file):
+            was_success = False
+            try:
+                os.replace(corefile, corefile_bak)
+                upgrade(state_file)
+                was_success = True
+            finally:
+                if not was_success:
+                    try:
+                        os.replace(corefile_bak, corefile)
+                    except Exception as e:
+                        print('Could not restore original state: %s\nYou probably need to wipe the builddir' % str(e))
+            return
+    sys.exit('Could not find upgrade state file. Can not upgrade')
+
+def build_opt_array(environment):
+    options = []
+    for optclass in environment.coredata.get_all_option_classes():
+        for k, v in optclass.items():
+            options.append((k, str(v.value)))
+    return options
+
+def build_compiler_array(build):
+    result = []
+    # Only native ones, cross compilers come from the cross file.
+    for k, v in build.compilers.items():
+        result.append((k, v.exelist))
+    return result
+
+def build_state_dict(environment, build):
+    result = {}
+    result['source_root'] = environment.get_source_dir()
+    result['build_root'] = environment.get_build_dir()
+    if environment.coredata.cross_file:
+        result['cross_file'] = environment.coredata.cross_file
+    result['options'] = build_opt_array(environment)
+    result['compilers'] = build_compiler_array(build)
+    return result
+
+def create_dump_dict(environment, build):
+    s = {}
+    s['dump_format_version'] = dump_format_version
+    s['state'] = build_state_dict(environment, build)
+    return s