Created
September 10, 2025 02:43
-
-
Save ghost-x47/293f3329178032c9092f62f25d498d13 to your computer and use it in GitHub Desktop.
Sublime text 4 MSVC Environment setup plugin to properly load env variables on start, rather than running vcvarsall directly in built script, therefore reduce compilation times for smaller programs substantialy.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import sublime | |
| import sublime_plugin | |
| from threading import Thread | |
| from subprocess import Popen, PIPE | |
| from os import environ | |
| import os | |
| # Modified version of | |
| # https://raw.githubusercontent.com/STealthy-and-haSTy/SublimeScraps/refs/heads/master/plugins/set_vc_vars.py | |
| # Changes: | |
| # - Fix issue with running vcvarsall arguments | |
| # Related reading; | |
| # https://stackoverflow.com/questions/39881091/how-to-run-sublimetext-with-visual-studio-environment-enabled/ | |
| # For the unfamiliar, Visual Studio ships with a batch file which sets up the | |
| # environment variables you need to be able to run visual studio tools from a | |
| # command prompt. | |
| # | |
| # This pluguin was written in response to someone that wanted to know how you | |
| # could run Sublime and have it have the visual studio environment already set | |
| # up. | |
| # | |
| # This plugin will use a subprocess to execute the batch file in the background | |
| # and then issue the 'set' command to get the command interpreter to output the | |
| # state of the environment before it exits. | |
| # | |
| # This output is gathered and parsed to come up with a dictionary similar to | |
| # the environ table that python uses. From here we can easily detect what new | |
| # environment variables were added and the values of those that changed, and | |
| # set them as appropriate. | |
| # | |
| # As written Sublime needs to be restarted in order to execute the batch file | |
| # again. A more elegant solution would be to save the environment prior to | |
| # modifying it so that it could be restored and a new environment applied. | |
| # To use this, you need to specify a setting in your user preferences named | |
| # 'vc_vars_cmd' which should contain a complete path to the batch file you want | |
| # to execute. Optionally you can also specify 'vc_vars_arch', which will be | |
| # passed as a command line argument to the batch file executed. Remember that | |
| # the preferences are JSON, so you need to quote all path separators. | |
| SENTINEL="SUBL_VC_VARS" | |
| def merge_env_paths(path1: str, path2: str) -> str: | |
| """ | |
| Merge two PATH-like environment variable strings into a single string | |
| containing unique paths, preserving order. | |
| Works on both Windows (;) and POSIX (:). | |
| """ | |
| sep = os.pathsep # ; on Windows, : on Linux/macOS | |
| # Split and filter out empty parts | |
| paths1 = [p for p in path1.split(sep) if p] | |
| paths2 = [p for p in path2.split(sep) if p] | |
| # Merge while preserving order and uniqueness | |
| seen = set() | |
| merged = [] | |
| for p in paths1 + paths2: | |
| if p not in seen: | |
| seen.add(p) | |
| merged.append(p) | |
| return sep.join(merged) | |
| def _get_vc_env(): | |
| """ | |
| Run the batch file specified in the vc_vars_cmd setting (with an | |
| optional architecture type) and return back a dictionary of the | |
| environment that the batch file sets up. | |
| Returns None if the preference is missing or the batch file fails. | |
| """ | |
| settings = sublime.load_settings("Preferences.sublime-settings") | |
| vars_cmd = settings.get("vc_vars_cmd") | |
| vars_arch = settings.get("vc_vars_arch", "x64") | |
| if vars_cmd is None: | |
| print("set_vc_vars: Cannot set Visual Studio Environment") | |
| print("set_vc_vars: Add 'vc_vars_cmd' setting to settings and restart") | |
| return None | |
| try: | |
| # Run the batch, outputting a sentinel value so we can separate out | |
| # any error messages the batch might generate. | |
| shell_cmd = "\"{0}\" -startdir=none -arch={1} -host_arch={1} && echo {2} && set".format( | |
| vars_cmd, vars_arch, SENTINEL) | |
| output = Popen(shell_cmd, stdout=PIPE, shell=True).stdout.read() | |
| lines = [line.strip() for line in output.decode("utf-8").splitlines()] | |
| env_lines = lines[lines.index(SENTINEL) + 1:] | |
| for e in lines: | |
| print(e) | |
| except: | |
| print("Running batch in try failed") | |
| return None | |
| # Convert from var=value to dictionary key/value pairs. We upper case the | |
| # keys, since Python does that to the mapping it stores in environ. | |
| env = {} | |
| for env_var in env_lines: | |
| parts = env_var.split("=", maxsplit=1) | |
| env_key = parts[0].upper() | |
| env[env_key] = parts[1] | |
| return env | |
| def install_vc_env(): | |
| """ | |
| Try to collect the appropriate Visual Studio environment variables and | |
| set them into the current environment. | |
| """ | |
| vc_env = _get_vc_env() | |
| if vc_env is None: | |
| print("set_vc_vars: Unable to fetch the Visual Studio Environment") | |
| return sublime.status_message("Error fetching VS Environment") | |
| # Add newly set environment variables | |
| for key in vc_env.keys(): | |
| if key not in environ: | |
| environ[key] = vc_env[key] | |
| # Update existing variables whose values changed. | |
| for key in environ: | |
| if key in vc_env and environ[key] != vc_env[key]: | |
| environ[key] = vc_env[key] | |
| # Set a sentinel variable so we know not to try setting up the path again. | |
| environ[SENTINEL] = "BOOTSTRAPPED" | |
| sublime.status_message("VS Environment enabled") | |
| def plugin_loaded(): | |
| if sublime.platform() != "windows": | |
| return sublime.status_message("VS is not supported on this platform") | |
| # To reload the environment if it changes, restart Sublime. | |
| if SENTINEL in environ: | |
| return sublime.status_message("VS Environment already enabled") | |
| # Update in the background so we don't block the UI | |
| Thread(target=install_vc_env).start() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment