Set up VS environment automatically when run.
diff --git a/docs/markdown/snippets/vsenv.md b/docs/markdown/snippets/vsenv.md
new file mode 100644
index 0000000..c46d25a
--- /dev/null
+++ b/docs/markdown/snippets/vsenv.md
@@ -0,0 +1,9 @@
+## Automatically set up Visual Studio environment
+
+When Meson is run on Windows it will automatically set up the
+environment to use Visual Studio if it has not been set up
+already. This means that you can run Meson commands from any command
+prompt or directly from any IDE. Meson automatically sets up the
+newest 64 bit VS install. If you need something else, you need to run
+the build from the corresponding dev tool command prompt just like
+with earlier Meson versions.
diff --git a/mesonbuild/mesonmain.py b/mesonbuild/mesonmain.py
index 208cfe4..2d0ecbd 100644
--- a/mesonbuild/mesonmain.py
+++ b/mesonbuild/mesonmain.py
@@ -1,4 +1,4 @@
-# Copyright 2012-2016 The Meson development team
+# Copyright 2012-2021 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.
@@ -27,6 +27,63 @@
 from .environment import detect_msys2_arch
 from .wrap import wraptool
 
+bat_template = '''@ECHO OFF
+
+call "{}"
+
+ECHO ---SPLIT---
+SET
+'''
+
+# If on Windows and VS is installed but not set up in the environment,
+# set it to be runnable. In this way Meson can be directly invoked
+# from any shell, VS Code etc.
+def setup_vsenv():
+    import subprocess, json, pathlib
+    if not mesonlib.is_windows():
+        return
+    if 'Visual Studio' in os.environ['PATH']:
+        return
+    vswhere_bin = r'c:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe'
+    if not os.path.exists(vswhere_bin):
+        return
+    vsjson = subprocess.check_output([vswhere_bin, '-latest', '-format', 'json'])
+    vsinfo = json.loads(vsjson)
+    if not vsinfo:
+        vsjson = subprocess.check_output([vswhere_bin, '-prerelease', '-format', 'json'])
+        vsinfo = json.loads(vsjson)
+    if not vsinfo:
+        # VS installer instelled but not VS itself maybe?
+        return
+    vs_root = vsinfo[0]['installationPath']
+    bat_path = vs_root + r'\VC\Auxiliary\Build\vcvars64.bat'
+    if not os.path.exists(bat_path):
+        #sys.exit(f'Could not find {bat_path}.')
+        return
+
+    bat_file = pathlib.Path.home() / 'vsdetect.bat'
+
+    bat_contents = bat_template.format(bat_path)
+    try:
+        bat_file.write_text(bat_contents)
+        bat_output = subprocess.check_output(bat_file, universal_newlines=True)
+    finally:
+        bat_file.unlink()
+    bat_lines = bat_output.split('\n')
+    bat_separator_seen = False
+    bat_separator = '---SPLIT---'
+    for bat_line in bat_lines:
+        if bat_line == bat_separator:
+            bat_separator_seen = True
+            continue
+        if not bat_separator_seen:
+            continue
+        if not bat_line:
+            continue
+        k, v = bat_line.split('=', 1)
+        os.environ[k] = v
+
+
 
 # Note: when adding arguments, please also add them to the completion
 # scripts in $MESONSRC/data/shell-completions/
@@ -222,6 +279,7 @@
     return CommandLineParser().run(args)
 
 def main():
+    setup_vsenv()
     # Always resolve the command path so Ninja can find it for regen, tests, etc.
     if 'meson.exe' in sys.executable:
         assert(os.path.isabs(sys.executable))
diff --git a/run_project_tests.py b/run_project_tests.py
index fcb8716..f477e6c 100755
--- a/run_project_tests.py
+++ b/run_project_tests.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python3
 
-# Copyright 2012-2019 The Meson development team
+# Copyright 2012-2021 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.
@@ -46,7 +46,7 @@
 from mesonbuild.mesonlib import MachineChoice, Popen_safe, TemporaryDirectoryWinProof
 from mesonbuild.mlog import bold, green, red, yellow
 from mesonbuild.coredata import backendlist, version as meson_version
-
+from mesonbuild.mesonmain import setup_vsenv
 from run_tests import get_fake_options, run_configure, get_meson_script
 from run_tests import get_backend_commands, get_backend_args_for_dir, Backend
 from run_tests import ensure_backend_detects_changes
@@ -1356,6 +1356,7 @@
             mesonlib.windows_proof_rm(str(d))
 
 if __name__ == '__main__':
+    setup_vsenv()
     parser = argparse.ArgumentParser(description="Run the test suite of Meson.")
     parser.add_argument('extra_args', nargs='*',
                         help='arguments that are passed directly to Meson (remember to have -- before these).')
diff --git a/run_tests.py b/run_tests.py
index b2a25f0..91fc8ba 100755
--- a/run_tests.py
+++ b/run_tests.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python3
 
-# Copyright 2012-2017 The Meson development team
+# Copyright 2012-2021 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.
@@ -396,5 +396,6 @@
     return returncode
 
 if __name__ == '__main__':
+    mesonmain.setup_vsenv()
     print('Meson build system', meson_version, 'Project and Unit Tests')
     raise SystemExit(main())
diff --git a/run_unittests.py b/run_unittests.py
index 1556b10..992cdc0 100755
--- a/run_unittests.py
+++ b/run_unittests.py
@@ -1,5 +1,5 @@
 #!/usr/bin/env python3
-# Copyright 2016-2017 The Meson development team
+# Copyright 2016-2021 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.
@@ -69,7 +69,7 @@
 from mesonbuild.scripts import destdir_join
 
 from mesonbuild.mtest import TAPParser, TestResult
-
+from mesonbuild.mesonmain import setup_vsenv
 from mesonbuild.wrap.wrap import PackageDefinition, WrapException
 
 from run_tests import (
@@ -10037,6 +10037,7 @@
     return unittest.main(defaultTest=cases, buffer=True)
 
 if __name__ == '__main__':
+    setup_vsenv()
     print('Meson build system', mesonbuild.coredata.version, 'Unit Tests')
     start = time.monotonic()
     try: