summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2018-12-12 18:16:53 +0100
committerAraq <rumpf_a@web.de>2018-12-12 18:16:53 +0100
commit0ab1229c6988ed9ad2f9f1f87f41cddc17a849e0 (patch)
tree94b2b4ffb1631ac1b1bc51cb0b9cfa3de274c1e8
parentac8274c60f860b334a08199c4c0a65620962ef2a (diff)
parentcaeb6110e6742e01a4daf07ed45752b5466f5d1c (diff)
downloadNim-0ab1229c6988ed9ad2f9f1f87f41cddc17a849e0.tar.gz
resolve merge conflicts
-rw-r--r--.gitignore2
-rw-r--r--compiler/extccomp.nim2
-rw-r--r--config/nim.cfg49
-rw-r--r--koch.nim2
-rw-r--r--tools/vccenv/vccenv.nim59
-rw-r--r--tools/vccenv/vccexe.nim66
-rw-r--r--tools/vccexe/vccenv.nim47
-rw-r--r--tools/vccexe/vccexe.nim188
-rw-r--r--tools/vccexe/vcvarsall.nim99
9 files changed, 367 insertions, 147 deletions
diff --git a/.gitignore b/.gitignore
index d736cdf8d..cbfb98a1b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -19,6 +19,8 @@ dnimcache/
 *.zip
 *.iss
 *.log
+*.ilk
+*.pdb
 
 mapping.txt
 tags
diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim
index 2fe151a1c..4b9e1c6fe 100644
--- a/compiler/extccomp.nim
+++ b/compiler/extccomp.nim
@@ -134,7 +134,7 @@ compiler vcc:
   result = (
     name: "vcc",
     objExt: "obj",
-    optSpeed: " /Ogityb2 /G7 /arch:SSE2 ",
+    optSpeed: " /Ogityb2 /G7 ",
     optSize: " /O1 /G7 ",
     compilerExe: "cl",
     cppCompiler: "cl",
diff --git a/config/nim.cfg b/config/nim.cfg
index 932e80331..38683b304 100644
--- a/config/nim.cfg
+++ b/config/nim.cfg
@@ -23,7 +23,7 @@ hint[LineTooLong]=off
 arm.linux.gcc.exe = "arm-linux-gnueabihf-gcc"
 arm.linux.gcc.linkerexe = "arm-linux-gnueabihf-gcc"
 
-# For OpenWRT, you will also need to adjust PATH to point to your toolchain. 
+# For OpenWRT, you will also need to adjust PATH to point to your toolchain.
 mips.linux.gcc.exe = "mips-openwrt-linux-gcc"
 mips.linux.gcc.linkerexe = "mips-openwrt-linux-gcc"
 
@@ -225,9 +225,13 @@ clang.options.speed = "-O3"
 clang.options.size = "-Os"
 
 # Configuration for the Visual C/C++ compiler:
-vcc.exe =     "vccexe.exe"
+# VCCEXE is a tool that invokes the Visual Studio Developer Command Prompt
+# before calling the compiler.
+# Please make sure either Visual Studio or C++ Build SKU is installed when using the vcc compiler backend.
+
+vcc.exe = "vccexe.exe"
 vcc.cpp.exe = "vccexe.exe"
-vcc.linkerexe =     "vccexe.exe"
+vcc.linkerexe = "vccexe.exe"
 vcc.cpp.linkerexe = "vccexe.exe"
 
 # set the options for specific platforms:
@@ -238,30 +242,35 @@ vcc.options.always =      "/nologo"
   vcc.options.always %= "${vcc.options.always} /Z7" # Get VCC to output full debug symbols in the obj file
 @end
 vcc.cpp.options.always %=  "${vcc.options.always} /EHsc"
-vcc.options.linker =      "/nologo /DEBUG /Zi /F33554432" # set the stack size to 32 MiB
+vcc.options.linker = "/nologo /DEBUG /Zi /F33554432" # set the stack size to 32 MiB
 vcc.cpp.options.linker %=  "${vcc.options.linker}"
 @if i386:
-vcc.options.always %=      "--platform:x86 ${vcc.options.always}"
-vcc.cpp.options.always %=  "--platform:x86 ${vcc.cpp.options.always}"
-vcc.options.linker %=      "--platform:x86 ${vcc.options.linker}"
-vcc.cpp.options.linker %=  "--platform:x86 ${vcc.cpp.options.linker}"
+  vcc.options.always = "--platform:x86 /nologo"
+  vcc.cpp.options.always = "--platform:x86 /nologo /EHsc"
+  vcc.options.linker = "--platform:x86 /nologo /DEBUG /Zi /F33554432" # set the stack size to 32 MiB
+  vcc.cpp.options.linker = "--platform:x86 /nologo /DEBUG /Zi /F33554432" # set the stack size to 32 MiB
 @elif amd64:
-vcc.options.always %=      "--platform:amd64 ${vcc.options.always}"
-vcc.cpp.options.always %=  "--platform:amd64 ${vcc.cpp.options.always}"
-vcc.options.linker %=      "--platform:amd64 ${vcc.options.linker}"
-vcc.cpp.options.linker %=  "--platform:amd64 ${vcc.cpp.options.linker}"
+  vcc.options.always = "--platform:amd64 /nologo"
+  vcc.cpp.options.always = "--platform:amd64 /nologo /EHsc"
+  vcc.options.linker = "--platform:amd64 /nologo /DEBUG /Zi /F33554432" # set the stack size to 32 MiB
+  vcc.cpp.options.linker = "--platform:amd64 /nologo /DEBUG /Zi /F33554432" # set the stack size to 32 MiB
 @elif arm:
-vcc.options.always %=      "--platform:arm ${vcc.options.always}"
-vcc.cpp.options.always %=  "--platform:arm ${vcc.cpp.options.always}"
-vcc.options.linker %=      "--platform:arm ${vcc.options.linker}"
-vcc.cpp.options.linker %=  "--platform:arm ${vcc.cpp.options.linker}"
+  vcc.options.always = "--platform:arm /nologo"
+  vcc.cpp.options.always = "--platform:arm /nologo /EHsc"
+  vcc.options.linker = "--platform:arm /nologo /DEBUG /Zi /F33554432" # set the stack size to 32 MiB
+  vcc.cpp.options.linker = "--platform:arm /nologo /DEBUG /Zi /F33554432" # set the stack size to 32 MiB
+@else:
+  vcc.options.always = "/nologo"
+  vcc.cpp.options.always = "/nologo /EHsc"
+  vcc.options.linker = "/nologo /DEBUG /Zi /F33554432" # set the stack size to 32 MiB
+  vcc.cpp.options.linker = "/nologo /DEBUG /Zi /F33554432" # set the stack size to 32 MiB
 @end
 
-vcc.options.debug =     "/Od"
-vcc.cpp.options.debug = "/Od"
-vcc.options.speed =     "/O2"
+vcc.options.debug = "/Zi /FS /Od"
+vcc.cpp.options.debug = "/Zi /FS /Od"
+vcc.options.speed = "/O2"
 vcc.cpp.options.speed = "/O2"
-vcc.options.size =     "/O1"
+vcc.options.size = "/O1"
 vcc.cpp.options.size = "/O1"
 
 # Configuration for the Tiny C Compiler:
diff --git a/koch.nim b/koch.nim
index 3f528a1b2..9596ce21f 100644
--- a/koch.nim
+++ b/koch.nim
@@ -154,7 +154,7 @@ proc bundleNimsuggest() =
   nimCompile("nimsuggest/nimsuggest.nim", options = "-d:release")
 
 proc buildVccTool() =
-  nimCompile("tools/vccenv/vccexe.nim")
+  nimCompile("tools/vccexe/vccexe.nim")
 
 proc bundleWinTools() =
   # TODO: consider building under `bin` instead of `.`
diff --git a/tools/vccenv/vccenv.nim b/tools/vccenv/vccenv.nim
deleted file mode 100644
index 1f172c7c0..000000000
--- a/tools/vccenv/vccenv.nim
+++ /dev/null
@@ -1,59 +0,0 @@
-import strtabs, os, osproc, streams, strutils
-
-const
-  comSpecEnvKey = "ComSpec"
-  vsComnToolsEnvKeys = [
-    "VS150COMNTOOLS",
-    "VS140COMNTOOLS",
-    "VS130COMNTOOLS",
-    "VS120COMNTOOLS",
-    "VS110COMNTOOLS",
-    "VS100COMNTOOLS",
-    "VS90COMNTOOLS"
-  ]
-  vcvarsallRelativePath = joinPath("..", "..", "VC", "vcvarsall")
-
-proc getVsComnToolsPath*(): TaintedString =
-  for vsComnToolsEnvKey in vsComnToolsEnvKeys:
-    let vsComnToolsEnvVal = getEnv vsComnToolsEnvKey
-    if vsComnToolsEnvVal.len > 0:
-      return vsComnToolsEnvVal
-
-proc getVccEnv*(platform: string, windowsStoreSdk: bool = false,
-                sdkVersion: string = ""): StringTableRef =
-  var comSpecCommandString = getEnv comSpecEnvKey
-  if comSpecCommandString.len == 0:
-    comSpecCommandString = "cmd"
-
-  let vsComnToolsPath = getVsComnToolsPath()
-  if vsComnToolsPath.len < 1:
-    return nil
-  let vcvarsallPath = expandFilename joinPath(vsComnToolsPath, vcvarsallRelativePath)
-
-  var vcvarsallArgs: seq[string] = @[]
-  if platform.len > 0:
-    vcvarsallArgs.add(platform)
-  if windowsStoreSdk:
-    vcvarsallArgs.add("store")
-  if sdkVersion.len > 0:
-    vcvarsallArgs.add(sdkVersion)
-  let vcvarsallArgString = vcvarsallArgs.join(" ")
-
-  var vcvarsallCommandString: string
-  if vcvarsallArgString.len > 0:
-    vcvarsallCommandString = "\"$1\" $2" % [vcvarsallPath, vcvarsallArgString]
-  else:
-    vcvarsallCommandString = vcvarsallPath
-
-  let vcvarsallExecCommand = "\"$1\" /C \"$2 && SET\"" %
-                             [comSpecCommandString, vcvarsallCommandString]
-  when defined(release):
-    let vccvarsallOptions = {poEvalCommand, poDemon}
-  else:
-    let vccvarsallOptions = {poEchoCmd, poEvalCommand, poDemon}
-  let vcvarsallStdOut = execProcess(vcvarsallExecCommand, options = vccvarsallOptions)
-  result = newStringTable(modeCaseInsensitive)
-  for line in vcvarsallStdOut.splitLines:
-    let idx = line.find('=')
-    if idx > 0:
-      result[line[0..(idx - 1)]] = line[(idx + 1)..(line.len - 1)]
diff --git a/tools/vccenv/vccexe.nim b/tools/vccenv/vccexe.nim
deleted file mode 100644
index e86e14c0f..000000000
--- a/tools/vccenv/vccexe.nim
+++ /dev/null
@@ -1,66 +0,0 @@
-import strutils, strtabs, os, osproc, vccenv
-
-when defined(release):
-  let vccOptions = {poParentStreams}
-else:
-  let vccOptions = {poEchoCmd, poParentStreams}
-
-const
-  platformPrefix = "--platform"
-  winstorePrefix = "--winstore"
-  sdkversionPrefix = "--sdkversion"
-
-  platformSepIdx = platformPrefix.len
-  sdkversionSepIdx = sdkversionPrefix.len
-
-  HelpText = """
-+-----------------------------------------------------------------+
-|         Microsoft C/C++ compiler wrapper for Nim                |
-|             (c) 2016 Fredrik Høisæther Rasch                    |
-+-----------------------------------------------------------------+
-
-Usage:
-  vccexe [options] [compileroptions]
-Options:
-  --platform:<arch>   Specify the Compiler Platform Tools architecture
-                      <arch>: x86 | amd64 | arm | x86_amd64 | x86_arm | amd64_x86 | amd64_arm
-  --winstore          Use Windows Store (rather than desktop) development tools
-  --sdkversion:<v>    Use a specific Windows SDK version:
-                      <v> is either the full Windows 10 SDK version number or
-                      "8.1" to use the windows 8.1 SDK
-
-Other command line arguments are passed on to the
-Microsoft C/C++ compiler for the specified SDK toolset
-"""
-
-when isMainModule:
-  var platformArg: string = ""
-  var sdkVersionArg: string = ""
-  var storeArg: bool = false
-
-  var clArgs: seq[TaintedString] = @[]
-
-  var wrapperArgs = commandLineParams()
-  for wargv in wrapperArgs:
-    # Check whether the current argument contains -- prefix
-    if wargv.startsWith(platformPrefix): # Check for platform
-      platformArg = wargv.substr(platformSepIdx + 1)
-    elif wargv == winstorePrefix: # Check for winstore
-      storeArg = true
-    elif wargv.startsWith(sdkversionPrefix): # Check for sdkversion
-      sdkVersionArg = wargv.substr(sdkversionSepIdx + 1)
-    else: # Regular cl.exe argument -> store for final cl.exe invocation
-      if (wargv.len == 2) and (wargv[1] == '?'):
-        echo HelpText
-      clArgs.add(wargv)
-
-  var vccEnvStrTab = getVccEnv(platformArg, storeArg, sdkVersionArg)
-  if vccEnvStrTab != nil:
-    for vccEnvKey, vccEnvVal in vccEnvStrTab:
-      putEnv(vccEnvKey, vccEnvVal)
-  let vccProcess = startProcess(
-      "cl.exe",
-      args = clArgs,
-      options = vccOptions
-    )
-  quit vccProcess.waitForExit()
diff --git a/tools/vccexe/vccenv.nim b/tools/vccexe/vccenv.nim
new file mode 100644
index 000000000..6ddf2e29a
--- /dev/null
+++ b/tools/vccexe/vccenv.nim
@@ -0,0 +1,47 @@
+## VCC compiler backend installation discovery using Visual Studio common tools
+## environment variables.
+
+import os
+
+type
+  VccEnvVersion* = enum ## The version of the Visual Studio C/C++ Developer Environment to load
+                        ## Valid versions are Versions of Visual Studio that permanently set a COMNTOOLS
+                        ## environment variable. That includes Visual Studio version up to and including
+                        ## Visual Studio 2015
+    vsUndefined = (0, ""), ## Version not specified, use latest recogized version on the system
+    vs90  = (90,   "VS90COMNTOOLS"), ## Visual Studio 2008
+    vs100 = (100, "VS100COMNTOOLS"), ## Visual Studio 2010
+    vs110 = (110, "VS110COMNTOOLS"), ## Visual Studio 2012
+    vs120 = (120, "VS120COMNTOOLS"), ## Visual Studio 2013
+    vs140 = (140, "VS140COMNTOOLS")  ## Visual Studio 2015
+
+const
+  vcvarsallRelativePath = joinPath("..", "..", "VC", "vcvarsall") ## Relative path from the COMNTOOLS path to the vcvarsall file.
+
+proc vccEnvVcVarsAllPath*(version: VccEnvVersion = vsUndefined): string = 
+  ## Returns the path to the VCC Developer Command Prompt executable for the specified VCC version.
+  ##
+  ## Returns `nil` if the specified VCC compiler backend installation was not found.
+  ## 
+  ## If the `version` parameter is omitted or set to `vsUndefined`, `vccEnvVcVarsAllPath` searches 
+  ## for the latest recognizable version of the VCC tools it can find.
+  ## 
+  ## `vccEnvVcVarsAllPath` uses the COMNTOOLS environment variables to find the Developer Command Prompt
+  ## executable path. The COMNTOOLS environment variable are permanently set when Visual Studio is installed.
+  ## Each version of Visual Studio has its own COMNTOOLS environment variable. E.g.: Visual Studio 2015 sets
+  ## The VS140COMNTOOLS environment variable.
+  ##
+  ## Note: Beginning with Visual Studio 2017, the installers no longer set environment variables to allow for
+  ## multiple side-by-side installations of Visual Studio. Therefore, `vccEnvVcVarsAllPath` cannot be used
+  ## to detect the VCC Developer Command Prompt executable path for Visual Studio 2017 and later.
+
+  if version == vsUndefined:
+    for tryVersion in [vs140, vs120, vs110, vs100, vs90]:
+      let tryPath = vccEnvVcVarsAllPath(tryVersion)
+      if tryPath.len > 0:
+        result = tryPath
+  else: # Specific version requested
+    let key = $version
+    let val = getEnv key
+    if val.len > 0:
+      result = expandFilename(val & vcvarsallRelativePath)
diff --git a/tools/vccexe/vccexe.nim b/tools/vccexe/vccexe.nim
new file mode 100644
index 000000000..2dcff8ce4
--- /dev/null
+++ b/tools/vccexe/vccexe.nim
@@ -0,0 +1,188 @@
+import strutils, strtabs, os, osproc, vcvarsall, vccenv
+
+type
+  VccVersion* = enum ## VCC compiler backend versions
+    vccUndefined = (0, ""), ## VCC version undefined, resolves to the latest recognizable VCC version
+    vcc90  =  vs90, ## Visual Studio 2008 (Version 9.0)
+    vcc100 = vs100, ## Visual Studio 2010 (Version 10.0)
+    vcc110 = vs110, ## Visual Studio 2012 (Version 11.0)
+    vcc120 = vs120, ## Visual Studio 2013 (Version 12.0)
+    vcc140 = vs140  ## Visual Studio 2015 (Version 14.0)
+
+proc discoverVccVcVarsAllPath*(version: VccVersion = vccUndefined): string =
+  ## Returns the path to the vcvarsall utility of the specified VCC compiler backend.
+  ##
+  ## version
+  ##   The specific version of the VCC compiler backend to discover.
+  ##   Defaults to the latest recognized VCC compiler backend that is found on the system.
+  ##
+  ## Returns `nil` if the VCC compiler backend discovery failed.
+
+  # TODO: Attempt discovery using vswhere utility.
+
+  # Attempt discovery through VccEnv
+  # (Trying Visual Studio Common Tools Environment Variables)
+  result = vccEnvVcVarsAllPath(cast[VccEnvVersion](version))
+  if result.len > 0:
+    return
+
+  # All attempts to dicover vcc failed
+
+const 
+  vccversionPrefix = "--vccversion"
+  printPathPrefix = "--printPath"
+  vcvarsallPrefix = "--vcvarsall"
+  commandPrefix = "--command"
+  noCommandPrefix = "--noCommand"
+  platformPrefix = "--platform"
+  sdktypePrefix = "--sdktype"
+  sdkversionPrefix = "--sdkversion"
+  verbosePrefix = "--verbose"
+
+  vccversionSepIdx = vccversionPrefix.len
+  vcvarsallSepIdx = vcvarsallPrefix.len
+  commandSepIdx = commandPrefix.len
+  platformSepIdx = platformPrefix.len
+  sdktypeSepIdx = sdktypePrefix.len
+  sdkversionSepIdx = sdkversionPrefix.len
+  
+  helpText = """
++-----------------------------------------------------------------+
+|         Microsoft C/C++ compiler wrapper for Nim                |
+|                                &                                |
+|        Microsoft C/C++ Compiler Discovery Utility               |
+|            (c) 2017 Fredrik Hoeisaether Rasch                   |
++-----------------------------------------------------------------+
+
+Usage:
+  vccexe [options] [compileroptions]
+Options:
+  --vccversion:<v>    Optionally specify the VCC version to discover
+                      <v>: 0, 90, 100, 110, 120, 140
+                      If <v> is omitted, attempts to discover the latest
+                      installed version. <v>: 0, 90, 100, 110, 120, 140
+                      A value of 0 will discover the latest installed SDK
+                      Multiple values can be specified, separated by ,
+  --printPath         Print the discovered path of the vcvarsall utility
+                      of the VCC version specified with the --vccversion argument.
+                      For each specified version the utility prints a line with the
+                      following format: <version>: <path>
+  --noCommand         Flag to supress VCC secondary command execution
+                      Useful in conjuction with --vccversion and --printPath to
+                      only perfom VCC discovery, but without executing VCC tools
+  --vcvarsall:<path>  Path to the Developer Command Prompt utility vcvarsall.bat that selects
+                      the appropiate devlopment settings.
+                      Usual path for Visual Studio 2015 and below:
+                        %VSInstallDir%\VC\vcvarsall
+                      Usual path for Visual Studio 2017 and above:
+                        %VSInstallDir%\VC\Auxiliary\Build\vcvarsall
+  --command:<exec>    Specify the command to run once the development environment is loaded.
+                      <exec> can be any command-line argument. Any arguments not recognized by vccexe
+                      are passed on as arguments to this command.
+                      cl.exe is invoked by default if this argument is omitted.
+  --platform:<arch>   Specify the Compiler Platform Tools architecture
+                      <arch>: x86 | amd64 | arm | x86_amd64 | x86_arm | amd64_x86 | amd64_arm
+                      Values with two architectures (like x86_amd64) specify the architecture
+                      of the cross-platform compiler (e.g. x86) and the target it compiles to (e.g. amd64).
+  --sdktype:<type>    Specify the SDK flavor to use. Defaults to the Desktop SDK.
+                      <type>: {empty} | store | uwp | onecore
+  --sdkversion:<v>    Use a specific Windows SDK version:
+                      <v> is either the full Windows 10 SDK version number or 
+                      "8.1" to use the windows 8.1 SDK
+  --verbose           Echoes the command line for loading the Developer Command Prompt
+                      and the command line passed on to the secondary command.
+
+Other command line arguments are passed on to the
+secondary command specified by --command or to the
+Microsoft (R) C/C++ Optimizing Compiler if no secondary
+command was specified
+"""
+
+when isMainModule:
+  var vccversionArg: seq[string] = @[]
+  var printPathArg: bool = false
+  var vcvarsallArg: string = nil
+  var commandArg: string = nil
+  var noCommandArg: bool = false
+  var platformArg: VccArch
+  var sdkTypeArg: VccPlatformType
+  var sdkVersionArg: string = nil
+  var verboseArg: bool = false
+
+  var clArgs: seq[TaintedString] = @[]
+
+  # Cannot use usual command-line argument parser here
+  # Since vccexe command-line arguments are intermingled
+  # with the secondary command-line arguments which have
+  # a syntax that is not supported by the default nim
+  # argument parser.
+  var wrapperArgs = commandLineParams()
+  for wargv in wrapperArgs:
+    # Check whether the current argument contains -- prefix
+    if wargv.startsWith(vccversionPrefix): # Check for vccversion
+      vccversionArg.add(wargv.substr(vccversionSepIdx + 1))
+    elif wargv.cmpIgnoreCase(printPathPrefix) == 0: # Check for printPath
+      printPathArg = true
+    elif wargv.startsWith(vcvarsallPrefix): # Check for vcvarsall
+      vcvarsallArg = wargv.substr(vcvarsallSepIdx + 1)
+    elif wargv.startsWith(commandPrefix): # Check for command
+      commandArg = wargv.substr(commandSepIdx + 1)
+    elif wargv.cmpIgnoreCase(noCommandPrefix) == 0: # Check for noCommand
+      noCommandArg = true
+    elif wargv.startsWith(platformPrefix): # Check for platform
+      platformArg = parseEnum[VccArch](wargv.substr(platformSepIdx + 1))
+    elif wargv.startsWith(sdktypePrefix): # Check for sdktype
+      sdkTypeArg = parseEnum[VccPlatformType](wargv.substr(sdktypeSepIdx + 1))
+    elif wargv.startsWith(sdkversionPrefix): # Check for sdkversion
+      sdkVersionArg = wargv.substr(sdkversionSepIdx + 1)
+    elif wargv.startsWith(verbosePrefix):
+      verboseArg = true
+    else: # Regular cl.exe argument -> store for final cl.exe invocation
+      if (wargv.len == 2) and (wargv[1] == '?'):
+        echo helpText
+      clArgs.add(wargv)
+
+  # Support for multiple specified versions. Attempt VCC discovery for each version
+  # specified, first successful discovery wins
+  var vccversionValue: VccVersion = vccUndefined
+  for vccversionItem in vccversionArg:
+    try:
+      vccversionValue = cast[VccVersion](parseInt(vccversionItem))
+    except ValueError:
+      continue
+    vcvarsallArg = discoverVccVcVarsAllPath(vccversionValue)
+    if vcvarsallArg.len > 0:
+      break
+  # VCC version not specified, discover latest (call discover without args)
+  if vcvarsallArg.len < 1 and vccversionArg.len < 1:
+    vccversionValue = vccUndefined
+    vcvarsallArg = discoverVccVcVarsAllPath()
+
+  if printPathArg:
+    var head = $vccversionValue
+    if head.len < 1:
+      head = "latest"
+    echo "$1: $2" % [head, vcvarsallArg]
+
+  # Call vcvarsall to get the appropiate VCC process environment
+  var vcvars = vccVarsAll(vcvarsallArg, platformArg, sdkTypeArg, sdkVersionArg, verboseArg)
+  if vcvars != nil:
+    for vccEnvKey, vccEnvVal in vcvars:
+      putEnv(vccEnvKey, vccEnvVal)
+
+  var vccOptions = {poParentStreams}
+  if verboseArg:
+    vccOptions.incl poEchoCmd
+
+  # Default to the cl.exe command if no secondary command was specified
+  if commandArg.len < 1:
+    commandArg = "cl.exe"
+
+  if not noCommandArg:
+    # Run VCC command with the VCC process environment
+    let vccProcess = startProcess(
+        commandArg,
+        args = clArgs,
+        options = vccOptions
+      )
+    quit vccProcess.waitForExit()
diff --git a/tools/vccexe/vcvarsall.nim b/tools/vccexe/vcvarsall.nim
new file mode 100644
index 000000000..e7a55069c
--- /dev/null
+++ b/tools/vccexe/vcvarsall.nim
@@ -0,0 +1,99 @@
+## VCC Developer Command Prompt Loader
+## 
+## In order for the VCC compiler backend to work properly, it requires numerous
+## environment variables to be set properly for the desired architecture and compile target.
+## For that purpose the VCC compiler ships with the vcvarsall utility which is an executable
+## batch script that can be used to properly set up an Command Prompt environment.
+
+import strtabs, strutils, os, osproc
+
+const
+  comSpecEnvKey = "ComSpec" ## Environment Variable that specifies the command-line application path in Windows
+                            ## Usually set to cmd.exe
+  vcvarsallDefaultPath = "vcvarsall.bat"
+
+type
+  VccArch* = enum ## The VCC compile target architectures
+    vccarchUnspecified = "",
+    vccarchX86 = "x86", ## VCC for compilation against the x86 architecture.
+    vccarchAmd64 = "amd64", ## VCC for compilation against the amd64 architecture.
+    vccarchX86Amd64 = "x86_amd64", ## VCC cross-compilation tools using x86 VCC for compilation against the amd64 architecture.
+    vccarchX86Arm = "x86_arm", ## VCC cross-compilation tools using x86 VCC for compilation against the ARM architecture.
+    vccarchX86Arm64 = "x86_arm64", ## VCC cross-compilation tools using x86 VCC for compilation against the ARM (64-bit) architecture.
+    vccarchAmd64X86 = "amd64_x86", ## VCC cross-compilation tools using amd64 VCC for compilation against the x86 architecture.
+    vccarchAmd64Arm = "amd64_arm", ## VCC cross-compilation tools using amd64 VCC for compilation against the ARM architecture.
+    vccarchAmd64Arm64 = "amd64_arm64", ## VCC cross-compilation tools using amd64 VCC for compilation against the ARM (64-bit) architecture.
+    vccarchX64 = "x64", ## VCC for compilation against the x64 architecture.
+    vccarchX64X86 = "x64_x86", ## VCC cross-compilation tools using x64 VCC for compilation against the x86 architecture.
+    vccarchX64Arm = "x64_arm", ## VCC cross-compilation tools using x64 VCC for compilation against the ARM architecture.
+    vccarchX64Arm64 = "x64_arm64" ## VCC cross-compilation tools using x64 VCC for compilation against the ARM (64-bit) architecture.
+
+  VccPlatformType* = enum ## The VCC platform type of the compile target
+    vccplatEmpty = "", ## Default (i.e. Desktop) Platfor Type
+    vccplatStore = "store", ## Windows Store Application
+    vccplatUWP = "uwp", ## Universal Windows Platform (UWP) Application
+    vccplatOneCore = "onecore" # Undocumented platform type in the Windows SDK, probably XBox One SDK platform type.
+
+proc vccVarsAll*(path: string, arch: VccArch = vccarchUnspecified, platform_type: VccPlatformType = vccplatEmpty, sdk_version: string = nil, verbose: bool = false): StringTableRef =
+  ## Returns a string table containing the proper process environment to successfully execute VCC compile commands for the specified SDK version, CPU architecture and platform type.
+  ##
+  ## path
+  ##   The path to the vcvarsall utility for VCC compiler backend.
+  ## arch
+  ##   The compile target CPU architecture. Starting with Visual Studio 2017, this value must be specified and must not be set to `vccarchUnspecified`.
+  ## platform_type
+  ##   The compile target Platform Type. Defaults to the Windows Desktop platform, i.e. a regular Windows executable binary.
+  ## sdk_version
+  ##   The Windows SDK version to use.
+  ## verbose
+  ##   Echo the command-line passed on to the system to load the VCC environment. Defaults to `false`.
+
+  var vccvarsallpath = path
+  # Assume that default executable is in current directory or in PATH
+  if path == nil or path.len < 1:
+    vccvarsallpath = vcvarsallDefaultPath
+  
+  var args: seq[string] = @[]
+  
+  let archStr: string = $arch
+  if archStr.len > 0:
+    args.add(archStr)
+  
+  let platStr: string = $platform_type
+  if platStr.len > 0:
+    args.add(platStr)
+
+  if sdk_version.len > 0:
+    args.add(sdk_version)
+
+  let argStr = args.join " "
+  
+  var vcvarsExec: string
+  if argStr.len > 0:
+    vcvarsExec = "\"$1\" $2" % [vccvarsallpath, argStr]
+  else:
+    vcvarsExec = "\"$1\"" % vccvarsallpath
+
+  var comSpecCmd = getenv comSpecEnvKey
+  if comSpecCmd.len < 1:
+    comSpecCmd = "cmd"
+  
+  # Run the Windows Command Prompt with the /C argument
+  # Execute vcvarsall with its command-line arguments
+  # and then execute the SET command to list all environment variables
+  let comSpecExec = "\"$1\" /C \"$2 && SET\"" % [comSpecCmd, vcvarsExec]
+  var comSpecOpts = {poEvalCommand, poDemon, poStdErrToStdOut}
+  if verbose:
+    comSpecOpts.incl poEchoCmd
+  let comSpecOut = execProcess(comSpecExec, options = comSpecOpts)
+
+  result = newStringTable(modeCaseInsensitive)
+
+  # Parse the output of the final SET command to construct a String Table
+  # with the appropiate environment variables
+  for line in comSpecOut.splitLines:
+    let idx = line.find('=')
+    if idx > 0:
+      result[line[0..(idx - 1)]] = line[(idx + 1)..(line.len - 1)]
+    elif verbose:
+      echo line