Skip to content

Commit 0b2a730

Browse files
committed
Set up VS environment automatically when run.
1 parent 204abd0 commit 0b2a730

File tree

5 files changed

+85
-6
lines changed

5 files changed

+85
-6
lines changed

docs/markdown/snippets/vsenv.md

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
## Automatically set up Visual Studio environment
2+
3+
When Meson is run on Windows it will automatically set up the
4+
environment to use Visual Studio if no other compiler toolchain
5+
can be detected. This means that you can run Meson commands from
6+
any command prompt or directly from any IDE. This sets up the
7+
64 bit native environment. If you need any other, then you
8+
need to set it up manually as before.

mesonbuild/mesonmain.py

+69-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2012-2016 The Meson development team
1+
# Copyright 2012-2021 The Meson development team
22

33
# Licensed under the Apache License, Version 2.0 (the "License");
44
# you may not use this file except in compliance with the License.
@@ -27,6 +27,73 @@
2727
from .environment import detect_msys2_arch
2828
from .wrap import wraptool
2929

30+
bat_template = '''@ECHO OFF
31+
32+
call "{}"
33+
34+
ECHO {}
35+
SET
36+
'''
37+
38+
# If on Windows and VS is installed but not set up in the environment,
39+
# set it to be runnable. In this way Meson can be directly invoked
40+
# from any shell, VS Code etc.
41+
def setup_vsenv():
42+
import subprocess, json, pathlib
43+
if not mesonlib.is_windows():
44+
return
45+
bat_placeholder = 'nananananananananananananananana'
46+
# If an existing build tool chain exists in PATH -> do nothing.
47+
if shutil.which('cc'):
48+
return
49+
if shutil.which('clang'):
50+
return
51+
if shutil.which('clang-cl'):
52+
return
53+
if os.environ.get('OSTYPE', bat_placeholder) == 'cygwin':
54+
return
55+
if 'Visual Studio' in os.environ['PATH']:
56+
return
57+
bat_locator_bin = r'c:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe'
58+
if not os.path.exists(bat_locator_bin):
59+
return
60+
bat_json = subprocess.check_output([bat_locator_bin, '-latest', '-format', 'json'])
61+
bat_info = json.loads(bat_json)
62+
if not bat_info:
63+
bat_json = subprocess.check_output([bat_locator_bin, '-prerelease', '-format', 'json'])
64+
bat_info = json.loads(bat_json)
65+
if not bat_info:
66+
# VS installer instelled but not VS itself maybe?
67+
return
68+
print('Activating VS', bat_info[0]['catalog']['productDisplayVersion'])
69+
bat_root = bat_info[0]['installationPath']
70+
bat_path = bat_root + r'\VC\Auxiliary\Build\vcvars64.bat'
71+
if not os.path.exists(bat_path):
72+
return
73+
74+
bat_file = pathlib.Path.home() / 'vsdetect.bat'
75+
76+
bat_separator = '---SPLIT---'
77+
bat_contents = bat_template.format(bat_path, bat_separator)
78+
bat_file.write_text(bat_contents)
79+
try:
80+
bat_output = subprocess.check_output(str(bat_file), universal_newlines=True)
81+
finally:
82+
bat_file.unlink()
83+
bat_lines = bat_output.split('\n')
84+
bat_separator_seen = False
85+
for bat_line in bat_lines:
86+
if bat_line == bat_separator:
87+
bat_separator_seen = True
88+
continue
89+
if not bat_separator_seen:
90+
continue
91+
if not bat_line:
92+
continue
93+
k, v = bat_line.split('=', 1)
94+
os.environ[k] = v
95+
96+
3097

3198
# Note: when adding arguments, please also add them to the completion
3299
# scripts in $MESONSRC/data/shell-completions/
@@ -222,6 +289,7 @@ def run(original_args, mainfile):
222289
return CommandLineParser().run(args)
223290

224291
def main():
292+
setup_vsenv()
225293
# Always resolve the command path so Ninja can find it for regen, tests, etc.
226294
if 'meson.exe' in sys.executable:
227295
assert(os.path.isabs(sys.executable))

run_project_tests.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#!/usr/bin/env python3
22

3-
# Copyright 2012-2019 The Meson development team
3+
# Copyright 2012-2021 The Meson development team
44

55
# Licensed under the Apache License, Version 2.0 (the "License");
66
# you may not use this file except in compliance with the License.
@@ -46,7 +46,7 @@
4646
from mesonbuild.mesonlib import MachineChoice, Popen_safe, TemporaryDirectoryWinProof
4747
from mesonbuild.mlog import bold, green, red, yellow
4848
from mesonbuild.coredata import backendlist, version as meson_version
49-
49+
from mesonbuild.mesonmain import setup_vsenv
5050
from run_tests import get_fake_options, run_configure, get_meson_script
5151
from run_tests import get_backend_commands, get_backend_args_for_dir, Backend
5252
from run_tests import ensure_backend_detects_changes
@@ -1356,6 +1356,7 @@ def clear_transitive_files():
13561356
mesonlib.windows_proof_rm(str(d))
13571357

13581358
if __name__ == '__main__':
1359+
setup_vsenv()
13591360
parser = argparse.ArgumentParser(description="Run the test suite of Meson.")
13601361
parser.add_argument('extra_args', nargs='*',
13611362
help='arguments that are passed directly to Meson (remember to have -- before these).')

run_tests.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#!/usr/bin/env python3
22

3-
# Copyright 2012-2017 The Meson development team
3+
# Copyright 2012-2021 The Meson development team
44

55
# Licensed under the Apache License, Version 2.0 (the "License");
66
# you may not use this file except in compliance with the License.
@@ -395,5 +395,6 @@ def main():
395395
return returncode
396396

397397
if __name__ == '__main__':
398+
mesonmain.setup_vsenv()
398399
print('Meson build system', meson_version, 'Project and Unit Tests')
399400
raise SystemExit(main())

run_unittests.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#!/usr/bin/env python3
2-
# Copyright 2016-2017 The Meson development team
2+
# Copyright 2016-2021 The Meson development team
33

44
# Licensed under the Apache License, Version 2.0 (the "License");
55
# you may not use this file except in compliance with the License.
@@ -69,7 +69,7 @@
6969
from mesonbuild.scripts import destdir_join
7070

7171
from mesonbuild.mtest import TAPParser, TestResult
72-
72+
from mesonbuild.mesonmain import setup_vsenv
7373
from mesonbuild.wrap.wrap import PackageDefinition, WrapException
7474

7575
from run_tests import (
@@ -10066,6 +10066,7 @@ def main():
1006610066
return unittest.main(defaultTest=cases, buffer=True)
1006710067

1006810068
if __name__ == '__main__':
10069+
setup_vsenv()
1006910070
print('Meson build system', mesonbuild.coredata.version, 'Unit Tests')
1007010071
start = time.monotonic()
1007110072
try:

0 commit comments

Comments
 (0)