|
9 | 9 | import pathlib |
10 | 10 | import shutil |
11 | 11 | import tempfile |
12 | | -import locale |
| 12 | +import pickle |
13 | 13 |
|
14 | 14 | from .. import mlog |
15 | 15 | from .core import MesonException |
16 | | -from .universal import is_windows, windows_detect_native_arch |
| 16 | +from .universal import (is_windows, windows_detect_native_arch, windows_proof_rm, |
| 17 | + get_meson_command, join_args) |
17 | 18 |
|
18 | 19 |
|
19 | 20 | __all__ = [ |
20 | 21 | 'setup_vsenv', |
21 | 22 | ] |
22 | 23 |
|
23 | 24 |
|
24 | | -bat_template = '''@ECHO OFF |
25 | | -
|
26 | | -call "{}" |
27 | | -
|
28 | | -ECHO {} |
29 | | -SET |
30 | | -''' |
31 | | - |
32 | 25 | # If on Windows and VS is installed but not set up in the environment, |
33 | 26 | # set it to be runnable. In this way Meson can be directly invoked |
34 | 27 | # from any shell, VS Code etc. |
@@ -91,42 +84,24 @@ def _setup_vsenv(force: bool) -> bool: |
91 | 84 | raise MesonException(f'Could not find {bat_path}') |
92 | 85 |
|
93 | 86 | mlog.log('Activating VS', bat_info[0]['catalog']['productDisplayVersion']) |
94 | | - bat_separator = '---SPLIT---' |
95 | | - bat_contents = bat_template.format(bat_path, bat_separator) |
96 | | - bat_file = tempfile.NamedTemporaryFile('w', suffix='.bat', encoding='utf-8', delete=False) |
97 | | - bat_file.write(bat_contents) |
98 | | - bat_file.flush() |
99 | | - bat_file.close() |
100 | | - bat_output = subprocess.check_output(bat_file.name, universal_newlines=True, |
101 | | - encoding=locale.getpreferredencoding(False)) |
102 | | - os.unlink(bat_file.name) |
103 | | - bat_lines = bat_output.split('\n') |
104 | | - bat_separator_seen = False |
105 | | - for bat_line in bat_lines: |
106 | | - if bat_line == bat_separator: |
107 | | - bat_separator_seen = True |
108 | | - continue |
109 | | - if not bat_separator_seen: |
110 | | - continue |
111 | | - if not bat_line: |
112 | | - continue |
113 | | - try: |
114 | | - k, v = bat_line.split('=', 1) |
115 | | - except ValueError: |
116 | | - # there is no "=", ignore junk data |
117 | | - pass |
118 | | - else: |
119 | | - try: |
120 | | - os.environ[k] = v |
121 | | - except ValueError: |
122 | | - # FIXME: When a value contains a newline, the output of SET |
123 | | - # command is impossible to parse because it makes not escaping. |
124 | | - # `VAR="Hello\n=World"` gets split into two lines: |
125 | | - # `VAR=Hello` and `=World`. That 2nd line will cause ValueError |
126 | | - # exception here. Just ignore for now because variables we do |
127 | | - # care won't have multiline values. |
128 | | - pass |
129 | | - |
| 87 | + # Write a bat file that first activates VS environment, and then calls |
| 88 | + # a Meson script that pickles the environment into a temp file. |
| 89 | + with tempfile.NamedTemporaryFile(delete=False) as env_file: |
| 90 | + pass |
| 91 | + vcvars_cmd = ['call', str(bat_path)] |
| 92 | + pickle_cmd = get_meson_command() + ['--internal', 'pickle_env', env_file.name] |
| 93 | + with tempfile.NamedTemporaryFile('w', suffix='.bat', encoding='utf-8', delete=False) as bat_file: |
| 94 | + bat_file.write(join_args(vcvars_cmd) + '\n') |
| 95 | + bat_file.write(join_args(pickle_cmd)) |
| 96 | + try: |
| 97 | + subprocess.check_call([bat_file.name], stdout=subprocess.DEVNULL) |
| 98 | + with open(env_file.name, 'rb') as f: |
| 99 | + vsenv = pickle.load(f) |
| 100 | + for k, v in vsenv.items(): |
| 101 | + os.environ[k] = v |
| 102 | + finally: |
| 103 | + windows_proof_rm(env_file.name) |
| 104 | + windows_proof_rm(bat_file.name) |
130 | 105 | return True |
131 | 106 |
|
132 | 107 | def setup_vsenv(force: bool = False) -> bool: |
|
0 commit comments