Added documentation and explanatory comments to vccexe

This commit is contained in:
Fredrik Høisæther Rasch
2017-03-26 17:08:41 +02:00
parent 24f07d9b71
commit 3d21e2ab66
4 changed files with 117 additions and 36 deletions

View File

@@ -1,15 +1,33 @@
## VCC compiler backend discovery Utility
##
## Module to discover the path to the vcvarsall utility of a VCC compiler backend.
## The module supports discovery for either the latest recognizable version (default)
## or discovery of a specific VCC compiler backend version.
##
## This module can also produce a standalone command-line executable.
## It supports a `--help` command-line argument. Refer to its output for further
## documentation on the `vccdiscover` standalone command-line application.
import strutils, os, vccenv
type
VccVersion* = enum
vccUndefined = (0, ""),
vcc90 = vs90, # Visual Studio 2008
vcc100 = vs100, # Visual Studio 2010
vcc110 = vs110, # Visual Studio 2012
vcc120 = vs120, # Visual Studio 2013
vcc140 = vs140 # Visual Studio 2015
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

View File

@@ -1,18 +1,40 @@
## VCC compiler backend installation discovery using Visual Studio common tools
## environment variables.
import os
type
VccEnvVersion* = enum
vsUndefined = (0, ""),
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
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")
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.
proc vccEnvVcVarsAllPath*(version: VccEnvVersion = vsUndefined): string =
if version == vsUndefined:
for tryVersion in [vs140, vs120, vs110, vs100, vs90]:
let tryPath = vccEnvVcVarsAllPath(tryVersion)

View File

@@ -47,6 +47,8 @@ Options:
--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
@@ -65,6 +67,11 @@ when isMainModule:
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
@@ -87,6 +94,8 @@ when isMainModule:
echo HelpText
clArgs.add(wargv)
# Support for multiple specified versions. Attempt VCC discovery for each version
# specified, first successful discovery wins
for vccversionItem in vccversionArg:
var vccversionValue: VccVersion
try:
@@ -96,9 +105,11 @@ when isMainModule:
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:
vcvarsallArg = discoverVccVcVarsAllPath()
# 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:
@@ -108,8 +119,11 @@ when isMainModule:
if verboseArg:
vccOptions.incl poEchoCmd
# Default to the cl.exe command if no secondary command was specified
if commandArg.len < 1:
commandArg = "cl.exe"
# Run VCC command with the VCC process environment
let vccProcess = startProcess(
commandArg,
args = clArgs,

View File

@@ -1,33 +1,53 @@
## 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
comSpecEnvKey = "ComSpec" ## Environment Variable that specifies the command-line application path in Windows
## Usually set to cmd.exe
vcvarsallDefaultPath = "vcvarsall.bat"
type
VccArch* = enum
VccArch* = enum ## The VCC compile target architectures
vccarchUnspecified = "",
vccarchX86 = "x86",
vccarchAmd64 = "amd64",
vccarchX86Amd64 = "x86_amd64",
vccarchX86Arm = "x86_arm",
vccarchX86Arm64 = "x86_arm64",
vccarchAmd64X86 = "amd64_x86",
vccarchAmd64Arm = "amd64_arm",
vccarchAmd64Arm64 = "amd64_arm64",
vccarchX64 = "x64",
vccarchX64X86 = "x64_x86",
vccarchX64Arm = "x64_arm",
vccarchX64Arm64 = "x64_arm64"
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
vccplatEmpty = "",
vccplatStore = "store",
vccplatUWP = "uwp",
vccplatOneCore = "onecore"
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:
@@ -58,12 +78,19 @@ proc vccVarsAll*(path: string, arch: VccArch = vccarchUnspecified, platform_type
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: