aboutsummaryrefslogtreecommitdiff
path: root/mesonbuild/mesonlib/vsenv.py
diff options
context:
space:
mode:
authorXavier Claessens <xavier.claessens@collabora.com>2021-09-30 11:54:43 -0400
committerJussi Pakkanen <jpakkane@gmail.com>2021-10-10 23:15:18 +0300
commit928078982c8643bffd95a8da06a1b4494fe87e2b (patch)
tree1e8e50892e5f329927d9196cea85e66801c1af03 /mesonbuild/mesonlib/vsenv.py
parent31bea202c9dc9d288d787f0073f0e221971669ba (diff)
downloadmeson-928078982c8643bffd95a8da06a1b4494fe87e2b.zip
meson-928078982c8643bffd95a8da06a1b4494fe87e2b.tar.gz
meson-928078982c8643bffd95a8da06a1b4494fe87e2b.tar.bz2
Add --vsenv command line option and active VS only when needed
Diffstat (limited to 'mesonbuild/mesonlib/vsenv.py')
-rw-r--r--mesonbuild/mesonlib/vsenv.py100
1 files changed, 100 insertions, 0 deletions
diff --git a/mesonbuild/mesonlib/vsenv.py b/mesonbuild/mesonlib/vsenv.py
new file mode 100644
index 0000000..1966634
--- /dev/null
+++ b/mesonbuild/mesonlib/vsenv.py
@@ -0,0 +1,100 @@
+import os
+import subprocess
+import json
+import pathlib
+import shutil
+import tempfile
+
+from .. import mlog
+from .universal import MesonException, is_windows
+
+
+bat_template = '''@ECHO OFF
+
+call "{}"
+
+ECHO {}
+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(force: bool) -> bool:
+ if not is_windows():
+ return False
+ if os.environ.get('OSTYPE') == 'cygwin':
+ return False
+ if 'Visual Studio' in os.environ['PATH']:
+ return False
+ # VSINSTALL is set when running setvars from a Visual Studio installation
+ # Tested with Visual Studio 2012 and 2017
+ if 'VSINSTALLDIR' in os.environ:
+ return False
+ # Check explicitly for cl when on Windows
+ if shutil.which('cl.exe'):
+ return False
+ if not force:
+ if shutil.which('cc'):
+ return False
+ if shutil.which('gcc'):
+ return False
+ if shutil.which('clang'):
+ return False
+ if shutil.which('clang-cl'):
+ return False
+
+ root = os.environ.get("ProgramFiles(x86)") or os.environ.get("ProgramFiles")
+ bat_locator_bin = pathlib.Path(root, 'Microsoft Visual Studio/Installer/vswhere.exe')
+ if not bat_locator_bin.exists():
+ raise MesonException(f'Could not find {bat_locator_bin}')
+ bat_json = subprocess.check_output(
+ [
+ str(bat_locator_bin),
+ '-latest',
+ '-prerelease',
+ '-requiresAny',
+ '-requires', 'Microsoft.VisualStudio.Component.VC.Tools.x86.x64',
+ '-products', '*',
+ '-utf8',
+ '-format',
+ 'json'
+ ]
+ )
+ bat_info = json.loads(bat_json)
+ if not bat_info:
+ # VS installer instelled but not VS itself maybe?
+ raise MesonException(f'Could not parse vswhere.exe output')
+ bat_root = pathlib.Path(bat_info[0]['installationPath'])
+ bat_path = bat_root / 'VC/Auxiliary/Build/vcvars64.bat'
+ if not bat_path.exists():
+ raise MesonException(f'Could not find {bat_path}')
+
+ mlog.log('Activating VS', bat_info[0]['catalog']['productDisplayVersion'])
+ bat_separator = '---SPLIT---'
+ bat_contents = bat_template.format(bat_path, bat_separator)
+ bat_file = tempfile.NamedTemporaryFile('w', suffix='.bat', encoding='utf-8')
+ bat_file.write(bat_contents)
+ bat_file.flush()
+ bat_output = subprocess.check_output(str(bat_file), universal_newlines=True)
+ bat_lines = bat_output.split('\n')
+ bat_separator_seen = False
+ 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
+ return True
+
+def setup_vsenv(force: bool = False):
+ try:
+ _setup_vsenv(force)
+ except MesonException:
+ if force:
+ raise
+ mlog.warning('Failed to activate VS environment:', str(e))