Skip to content

Instantly share code, notes, and snippets.

@juntalis
Last active December 27, 2023 12:33
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save juntalis/10433731 to your computer and use it in GitHub Desktop.
Save juntalis/10433731 to your computer and use it in GitHub Desktop.
Utility batch script to locate Visual Studio installation
@echo off
rem Usage: find-msvc.cmd MinimumVersion MaximumVersion
rem
rem Given a range of versions to search for, this script attempts to locate a
rem valid Visual Studio installation based upon the current set of environment
rem variables. If a valid installation is found, this script sets the
rem environment variable "VCROOT" to Drive:\Path\To\VS\VC. On success, we
rem should be able to call %VCROOT%\vcvarsall.bat.
rem
rem Versions use the VSXX0COMNTOOLS environment variable:
rem
rem VS 2015 => 13
rem VS 2013 => 12
rem VS 2012 => 11
rem VS 2010 => 10
rem VS 2008 => 9
rem VS 2005 => 8
rem
rem Example
rem call find-msvc.cmd 8 13
rem if errorlevel 1 exit /B %ERRORLEVEL%
rem call "%VCROOT%\vcvarsall.bat" x86
rem
rem or
rem call find-msvc.cmd 13 8
rem if errorlevel 1 exit /B %ERRORLEVEL%
rem call "%VCROOT%\vcvarsall.bat" amd64
rem
rem TODO: Add the ability to specify a preferred version. (A version to search
rem for, even after the script discovered a working installation. if not
rem found, the script will fall back onthe valid installation it did find)
setlocal
:forkcheck
rem Since this batch file executes self executes, it's important that we make
rem sure there's no chance of it repeating its previous logic, which would
rem result in an infinite recursively executing script. (fork bomb for lack
rem of a better term) This could've easily been handled with a simple "if
rem defined" guard, but I felt like tracking the nesting level for shits and
rem giggles.
rem
rem Since each nested invocation of the script will copy the previous
rem environment before localizing it, (line 27: setlocal) the value of
rem CMD_FORK_LEVEL will steadily increment with each nesting level. When an
rem invocation has completd its execution of the script, it will return to
rem the previous nesting level, and revert back to the previous environment.
rem This will have the effect of CMD_FORK_LEVEL's value decrementing by one.
if not defined CMD_FORK_LEVEL (
set /A CMD_FORK_LEVEL=1
) else (
set /A CMD_FORK_LEVEL=%CMD_FORK_LEVEL% + 1
)
if %CMD_FORK_LEVEL% GTR 1 goto forked
:getopts
rem Figure out the minimum and maximum version numbers, as well as the
rem direction that we'll be searching in.
set _VC_STEP_VERSION_=1
if "%~1x"=="x" set _VC_MIN_VERSION_=8
if "%~2x"=="x" set _VC_MAX_VERSION_=13
if not defined _VC_MIN_VERSION_ set _VC_MIN_VERSION_=%~1
if not defined _VC_MAX_VERSION_ set _VC_MAX_VERSION_=%~2
if %_VC_MIN_VERSION_% GTR %_VC_MAX_VERSION_% set /A _VC_STEP_VERSION_=-1
goto main
:forked
if not "%VCVERS%x"=="x" goto forked_cleanup
call set "TESTVERS=%%VS%~10COMNTOOLS%%"
if "%TESTVERS%x"=="x" goto forked_cleanup
if not exist "%TESTVERS%" goto forked_cleanup
endlocal & set VCVERS=%~1
goto :EOF
:forked_cleanup
endlocal
goto :EOF
:dirname
rem Get the dirname of the second argument and set the variable who's
rem name was specified in the first argument.
call set %~1=%%~dp2
call set %~1=%%%~1:~0,-1%%
goto :EOF
:main
rem We'll start by finding the first existing install of msvc
set VCVERS=
set VCYEAR=
set VCROOT=
for /L %%V in (%_VC_MIN_VERSION_%,%_VC_STEP_VERSION_%,%_VC_MAX_VERSION_%) do @call "%~f0" %%~V
if "%VCVERS%x"=="x" goto notfound
endlocal & set VCVERS=%VCVERS%
:vcyear
rem Based on the version, we can figure out the year.
rem 13 => VS 2015
rem 12 => VS 2013
rem 11 => VS 2012
rem 10 => VS 2010
rem 9 => VS 2008
rem 8 => VS 2005
if "%VCVERS%"=="8" set VCYEAR=2005
if "%VCVERS%"=="9" set VCYEAR=2008
if "%VCVERS%"=="10" set VCYEAR=2010
if "%VCVERS%"=="11" set VCYEAR=2012
if "%VCVERS%"=="12" set VCYEAR=2013
if "%VCVERS%"=="13" set VCYEAR=2015
:vcroot
rem Finally, let's determine the root folder for this VC installation.
call set VCROOT=%%VS%VCVERS%0COMNTOOLS%%
if "%VCROOT:~-1%"=="\" set VCROOT=%VCROOT:~0,-1%
rem VCROOT=VSDir\Common7\Tools
call :dirname VCROOT "%VCROOT%"
rem VCROOT=VSDir\Common7
call :dirname VCROOT "%VCROOT%"
rem VCROOT=VSDir
set VCROOT=%VCROOT%\VC
goto :EOF
:notfound
echo Could not locate a valid MSVC version.
endlocal
exit /B 1
@IngwiePhoenix
Copy link

This looks super useful! I just have two questions:

  • Can you update it for the latest 2017 release of MSVC?
  • How do I check if there is an error?

I am a UNIX user... but I want to make my tool build on Windows too, so it'd be useful to see if they even have MSVC installed in the first place :) Plus... last time I did batch scripting on Windows is like ten years ago (thats...actually kinda scary, to think about it O.o).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment