diff options
author | Araq <rumpf_a@web.de> | 2018-12-12 18:16:53 +0100 |
---|---|---|
committer | Araq <rumpf_a@web.de> | 2018-12-12 18:16:53 +0100 |
commit | 0ab1229c6988ed9ad2f9f1f87f41cddc17a849e0 (patch) | |
tree | 94b2b4ffb1631ac1b1bc51cb0b9cfa3de274c1e8 | |
parent | ac8274c60f860b334a08199c4c0a65620962ef2a (diff) | |
parent | caeb6110e6742e01a4daf07ed45752b5466f5d1c (diff) | |
download | Nim-0ab1229c6988ed9ad2f9f1f87f41cddc17a849e0.tar.gz |
resolve merge conflicts
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | compiler/extccomp.nim | 2 | ||||
-rw-r--r-- | config/nim.cfg | 49 | ||||
-rw-r--r-- | koch.nim | 2 | ||||
-rw-r--r-- | tools/vccenv/vccenv.nim | 59 | ||||
-rw-r--r-- | tools/vccenv/vccexe.nim | 66 | ||||
-rw-r--r-- | tools/vccexe/vccenv.nim | 47 | ||||
-rw-r--r-- | tools/vccexe/vccexe.nim | 188 | ||||
-rw-r--r-- | tools/vccexe/vcvarsall.nim | 99 |
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 |