diff options
| author | jsmall-nvidia <jsmall@nvidia.com> | 2022-06-08 13:40:09 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-06-08 13:40:09 -0400 |
| commit | ff2ae7e0c1b48fa222f14dc84f15d0178ed056a1 (patch) | |
| tree | c4a3ab1e3441ec40267125086e511ef05342a547 /source/compiler-core/windows | |
| parent | 8e6e884eca5b33218a8cb2714266fb6ed4548d75 (diff) | |
Improvements around Visual Studio versions/matching versions (#2267)
* #include an absolute path didn't work - because paths were taken to always be relative.
* Use TerminatedUnownedStringSlice for literals in output C++.
* Remove Escape/Unescape functions used in slang-token-reader.cpp
Add target type of 'host-cpp' etc to map to the target types.
* Fix some corner cases around string encoding.
* Added unit test for string escaping.
Fixed some assorted escaping bugs.
* Updated test output.
* Added decode test.
* Stop using hex output, to get around 'greedy' aspect. Use octal instead.
* Added HostHostCallable
Small changes to use ArtifactDesc/Info instead of large switches.
* Fix C++ emit to handle arbitrary function export.
* Add options handling for callable without an output being specified.
* Can compile with COM interface. Added example using com interface.
* Use the IR Ptr type instead of hack in C++ emit for interfaces.
* Fix issue with outputting the COM call when ptr is used.
* Fix crash issue on compilation failure.
* Add support for __global.
* Added `ActualGlobalRate`
Added special handling around globals and COM interfaces.
Tested out in cpu-com-example.
* Fix typo in NodeBase.
* Support for accessing globals by name working.
* Check that actual global initialization is working.
* Refactor the com replacement such that it doesn't need a cache or do anything special with GlobalVar.
* Remove context.
Only create replacement if needed.
* Split out COM host-callable into a unit-test.
* host-callable com testing on C++and llvm.
* Comment around the COM ptr replacement.
* Disable com test on vs 32 bit.
Fix C++ prelude
* Disable 32 bit targets testing com host-callable.
* Use JSON parsing to locate VS version.
* Need platform detection in C++prelude.
* Fix com host callable test for LLVM.
* WIP improments finding downstream compiler version.
* Work around for not being able to include "targetConditionals.h"
* Matching semantic versioning support.
* DownstreamMatchVersion -> DownstreamCompilerMatchVersion
Small improvements.
Diffstat (limited to 'source/compiler-core/windows')
| -rw-r--r-- | source/compiler-core/windows/slang-win-visual-studio-util.cpp | 401 | ||||
| -rw-r--r-- | source/compiler-core/windows/slang-win-visual-studio-util.h | 37 |
2 files changed, 233 insertions, 205 deletions
diff --git a/source/compiler-core/windows/slang-win-visual-studio-util.cpp b/source/compiler-core/windows/slang-win-visual-studio-util.cpp index 9b175f308..b0b634d72 100644 --- a/source/compiler-core/windows/slang-win-visual-studio-util.cpp +++ b/source/compiler-core/windows/slang-win-visual-studio-util.cpp @@ -32,8 +32,6 @@ namespace Slang { namespace { // anonymous -typedef WinVisualStudioUtil::Version Version; - struct RegistryInfo { const char* regName; ///< The name of the entry in the registry @@ -42,7 +40,7 @@ struct RegistryInfo struct VersionInfo { - Version version; ///< The version + SemanticVersion version; ///< The version const char* name; ///< The name of the registry key }; @@ -75,13 +73,28 @@ static SlangResult _readRegistryKey(const char* path, const char* keyName, Strin } // Make easier to set up the array -static Version _makeVersion(int main, int dot = 0) { return WinVisualStudioUtil::makeVersion(main, dot); } + +static DownstreamCompilerMatchVersion _makeVersion(int main) +{ + DownstreamCompilerMatchVersion version; + version.type = SLANG_PASS_THROUGH_VISUAL_STUDIO; + version.matchVersion.set(main); + return version; +} + +static DownstreamCompilerMatchVersion _makeVersion(int main, int dot) +{ + DownstreamCompilerMatchVersion version; + version.type = SLANG_PASS_THROUGH_VISUAL_STUDIO; + version.matchVersion.set(main, dot); + return version; +} VersionInfo _makeVersionInfo(const char* name, int high, int dot = 0) { VersionInfo info; info.name = name; - info.version = WinVisualStudioUtil::makeVersion(high, dot); + info.version = SemanticVersion(high, dot); return info; } @@ -110,36 +123,41 @@ static const RegistryInfo s_regInfos[] = {"SOFTWARE\\Microsoft\\VisualStudio\\SxS\\VS7", "VC\\Auxiliary\\Build\\" }, }; -static bool _canUseVSWhere(Version version) +static bool _canUseVSWhere(SemanticVersion version) { // If greater than 15.0 we can use vswhere tool - return (int(version) >= int(_makeVersion(15))); + return version.m_major >= 15; } -static int _getRegistryKeyIndex(Version version) +static int _getRegistryKeyIndex(const SemanticVersion& version) { - if (int(version) >= int(_makeVersion(15))) + if (version.m_major >= 15) { return 1; } return 0; } -/* static */void WinVisualStudioUtil::getVersions(List<Version>& outVersions) +static SlangResult _parseVersion(UnownedStringSlice versionString, SemanticVersion& outVersion) { - const int count = SLANG_COUNT_OF(s_versionInfos); - outVersions.setCount(count); - - Version* dst = outVersions.begin(); - for (int i = 0; i < count; ++i) + // We only want the first 2 semantic numbers as 3rd looks like a build number, and too large + List<UnownedStringSlice> slices; + StringUtil::split(versionString, '.', slices); + if (slices.getCount() >= 2) { - dst[i] = s_versionInfos[i].version; + versionString = UnownedStringSlice(versionString.begin(), slices[1].end()); } + + // Extract the version + SemanticVersion semanticVersion; + return SemanticVersion::parse(versionString, outVersion); } -/* static */WinVisualStudioUtil::Version WinVisualStudioUtil::getCompiledVersion() + +/* static */DownstreamCompilerMatchVersion WinVisualStudioUtil::getCompiledVersion() { // Get the version of visual studio used to compile this source + // Not const, because otherwise we get an warning/error about constant expression... uint32_t version = _MSC_VER; switch (version) @@ -149,42 +167,65 @@ static int _getRegistryKeyIndex(Version version) case 1600: return _makeVersion(10); case 1700: return _makeVersion(11); case 1800: return _makeVersion(12); - case 1900: - { - return _makeVersion(14); - } - case 1911: - case 1912: - case 1913: - case 1914: - case 1915: - case 1916: - { - return _makeVersion(15); - } default: break; } // Seems like versions go in runs of 10 at this point // https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros?view=msvc-170 - - if (version >= 1920 && version < 1930) + // https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros?redirectedfrom=MSDN&view=msvc-170 + if (version >= 1900 && version < 1910) { - return _makeVersion(16); + return _makeVersion(14); + } + else if (version >= 1910 && version < 1920) + { + switch (version) + { + case 1910: return _makeVersion(15, 0); + case 1911: return _makeVersion(15, 3); + case 1912: return _makeVersion(15, 5); + case 1913: return _makeVersion(15, 6); + case 1914: return _makeVersion(15, 7); + case 1915: return _makeVersion(15, 8); + case 1916: return _makeVersion(15, 9); + default: return _makeVersion(15); + } + } + else if (version >= 1920 && version < 1930) + { + switch (version) + { + case 1920: return _makeVersion(16, 0); + case 1921: return _makeVersion(16, 1); + case 1922: return _makeVersion(16, 2); + case 1923: return _makeVersion(16, 3); + case 1924: return _makeVersion(16, 4); + case 1925: return _makeVersion(16, 5); + case 1926: return _makeVersion(16, 6); + case 1927: return _makeVersion(16, 7); + case 1928: return _makeVersion(16, 9); + case 1929: return _makeVersion(16, 11); + default: return _makeVersion(16); + } } else if (version >= 1930 && version < 1940) { - // We are going to assume it's a run of t0 - return _makeVersion(17); + switch (version) + { + case 1930: return _makeVersion(17, 0); + case 1931: return _makeVersion(17, 1); + case 1932: return _makeVersion(17, 2); + default: return _makeVersion(17); + } } else if (version >= 1940) { // Its an unknown newer version - return Version::Future; + return DownstreamCompilerMatchVersion(SLANG_PASS_THROUGH_VISUAL_STUDIO, MatchSemanticVersion::makeFuture()); } // Unknown version - return Version::Unknown; + return DownstreamCompilerMatchVersion(SLANG_PASS_THROUGH_VISUAL_STUDIO, MatchSemanticVersion()); } static SlangResult _parseJson(const String& contents, DiagnosticSink* sink, JSONContainer* container, JSONValue& outRoot) @@ -206,180 +247,217 @@ static SlangResult _parseJson(const String& contents, DiagnosticSink* sink, JSON return SLANG_OK; } -static SlangResult _find(int versionIndex, WinVisualStudioUtil::VersionPath& outPath) +static void _orderVersions(List<WinVisualStudioUtil::VersionPath>& ioVersions) { - const auto& versionInfo = s_versionInfos[versionIndex]; + typedef WinVisualStudioUtil::VersionPath VersionPath; + // Put into increasing version order, from oldest to newest + ioVersions.sort([&](const VersionPath& a, const VersionPath& b) -> bool { return a.version < b.version; }); +} - auto version = versionInfo.version; +static SlangResult _findVersionsWithVSWhere(const VersionInfo* versionInfo, List<WinVisualStudioUtil::VersionPath>& outVersions) +{ + typedef WinVisualStudioUtil::VersionPath VersionPath; - outPath.version = version; - outPath.vcvarsPath = String(); + CommandLine cmd; - if (_canUseVSWhere(version)) - { - CommandLine cmd; + // Lookup directly %ProgramFiles(x86)% path + // https://docs.microsoft.com/en-us/windows/desktop/api/shlobj_core/nf-shlobj_core-shgetfolderpatha + HWND hwnd = GetConsoleWindow(); - // Lookup directly %ProgramFiles(x86)% path - // https://docs.microsoft.com/en-us/windows/desktop/api/shlobj_core/nf-shlobj_core-shgetfolderpatha - HWND hwnd = GetConsoleWindow(); + char programFilesPath[_MAX_PATH]; + SHGetFolderPathA(hwnd, CSIDL_PROGRAM_FILESX86, NULL, 0, programFilesPath); - char programFilesPath[_MAX_PATH]; - SHGetFolderPathA(hwnd, CSIDL_PROGRAM_FILESX86, NULL, 0, programFilesPath); + String vswherePath = programFilesPath; + vswherePath.append("\\Microsoft Visual Studio\\Installer\\vswhere"); - String vswherePath = programFilesPath; - vswherePath.append("\\Microsoft Visual Studio\\Installer\\vswhere"); + cmd.setExecutableLocation(ExecutableLocation(vswherePath)); - cmd.setExecutableLocation(ExecutableLocation(vswherePath)); + // Using -? we can find out vswhere options. - const auto desc = WinVisualStudioUtil::getDesc(version); + // Previous args - works but returns multiple versions, without listing what version is associated with which path + // or the order. + //String args[] = { "-version", versionName, "-requires", "Microsoft.VisualStudio.Component.VC.Tools.x86.x64", ""-property", "installationPath" }; - StringBuilder versionName; - WinVisualStudioUtil::append(version, versionName); + // Use JSON parsing, we can verify the versions for a path, otherwise multiple versions are returned + // not just the version specified. The ordering isn't defined (and -sort doesn't appear to work) - // Using -? we can find out vswhere options. - - // Previous args - works but returns multiple versions, without listing what version is associated with which path - // or the order. - //String args[] = { "-version", versionName, "-requires", "Microsoft.VisualStudio.Component.VC.Tools.x86.x64", "-json", "-property", "installationPath", "-property", "installationVersion" }; + SemanticVersion requiredVersion; + if (versionInfo) + { + StringBuilder versionName; + versionInfo->version.append(versionName); - // Use JSON parsing, we can verify the versions for a path, otherwise multiple versions are returned - // not just the version specified. The ordering isn't defined (and -sort doesn't appear to work) - String args[] = { "-version", versionName, "-format", "json", "-requires", "Microsoft.VisualStudio.Component.VC.Tools.x86.x64"}; + cmd.addArg("-version"); + cmd.addArg(versionName); + } + // Add other args + { + // TODO(JS): + // For arm targets will probably need something different for tooling + String args[] = { "-format", "json", "-utf8", "-requires", "Microsoft.VisualStudio.Component.VC.Tools.x86.x64" }; cmd.addArgs(args, SLANG_COUNT_OF(args)); + } - SourceManager sourceManager; - sourceManager.initialize(nullptr, nullptr); - DiagnosticSink sink(&sourceManager, nullptr); - - RefPtr<JSONContainer> container = new JSONContainer(&sourceManager); - - ExecuteResult exeRes; - if (SLANG_SUCCEEDED(ProcessUtil::execute(cmd, exeRes))) - { - JSONValue jsonRoot; - SLANG_RETURN_ON_FAIL(_parseJson(exeRes.standardOutput, &sink, container, jsonRoot)); - - // Search through the array... - if (jsonRoot.getKind() != JSONValue::Kind::Array) - { - return SLANG_FAIL; - } - - auto arr = container->getArray(jsonRoot); - - const auto pathKey = container->getKey(UnownedStringSlice::fromLiteral("installationPath")); - const auto versionKey = container->getKey(UnownedStringSlice::fromLiteral("installationVersion")); + // We are going to use JSON parser to extract the info + SourceManager sourceManager; + sourceManager.initialize(nullptr, nullptr); + DiagnosticSink sink(&sourceManager, nullptr); - for (auto elem : arr) - { - // Get the path and the name - if (elem.getKind() != JSONValue::Kind::Object) - { - continue; - } + RefPtr<JSONContainer> container = new JSONContainer(&sourceManager); - auto pathJsonValue = container->findObjectValue(elem, pathKey); - auto versionJsonValue = container->findObjectValue(elem, versionKey); + ExecuteResult exeRes; + SLANG_RETURN_ON_FAIL(ProcessUtil::execute(cmd, exeRes)); - if (!pathJsonValue.isValid() || !versionJsonValue.isValid()) - { - continue; - } + JSONValue jsonRoot; + SLANG_RETURN_ON_FAIL(_parseJson(exeRes.standardOutput, &sink, container, jsonRoot)); - auto pathString = container->getString(pathJsonValue); - auto versionString = container->getString(versionJsonValue).trim(); + // Search through the array... + if (jsonRoot.getKind() != JSONValue::Kind::Array) + { + return SLANG_FAIL; + } - // If the versionString matches - List<UnownedStringSlice> versionSlices; - StringUtil::split(versionString, '.', versionSlices); + auto arr = container->getArray(jsonRoot); - if (versionSlices.getCount() <= 0) - { - continue; - } + const auto pathKey = container->getKey(UnownedStringSlice::fromLiteral("installationPath")); + const auto versionKey = container->getKey(UnownedStringSlice::fromLiteral("installationVersion")); - Int versionValue; - SLANG_RETURN_ON_FAIL(StringUtil::parseInt(versionSlices[0], versionValue)); + // Find all the versions, that match + for (auto elem : arr) + { + // Get the path and the name + if (elem.getKind() != JSONValue::Kind::Object) + { + continue; + } - if (versionValue != desc.majorVersion) - { - continue; - } + auto pathJsonValue = container->findObjectValue(elem, pathKey); + auto versionJsonValue = container->findObjectValue(elem, versionKey); - outPath.vcvarsPath = pathString; - outPath.vcvarsPath.append("\\VC\\Auxiliary\\Build\\"); - return SLANG_OK; - } + if (!pathJsonValue.isValid() || !versionJsonValue.isValid()) + { + continue; } - } - const Int keyIndex = _getRegistryKeyIndex(version); - if (keyIndex >= 0) - { - SLANG_ASSERT(keyIndex < SLANG_COUNT_OF(s_regInfos)); + auto pathString = container->getString(pathJsonValue); + auto versionString = container->getString(versionJsonValue).trim(); - // Try reading the key - const auto& keyInfo = s_regInfos[keyIndex]; + // Extract the version + SemanticVersion semanticVersion; + if (SLANG_SUCCEEDED(_parseVersion(versionString, semanticVersion))) + { + if (!requiredVersion.isSet() || requiredVersion.m_major == semanticVersion.m_major) + { + WinVisualStudioUtil::VersionPath versionPath; - StringBuilder keyName; - WinVisualStudioUtil::append(versionInfo.version, keyName); + versionPath.vcvarsPath = pathString; + versionPath.vcvarsPath.append("\\VC\\Auxiliary\\Build\\"); + versionPath.version = semanticVersion; - String value; - if (SLANG_SUCCEEDED(_readRegistryKey(keyInfo.regName, keyName.getBuffer(), value))) - { - outPath.vcvarsPath = value; - return SLANG_OK; + outVersions.add(versionPath); + } } } - return SLANG_FAIL; + return SLANG_OK; } -/* static */SlangResult WinVisualStudioUtil::find(List<VersionPath>& outVersionPaths) +static SlangResult _findVersionsWithRegistery(List<WinVisualStudioUtil::VersionPath>& outVersions) { - outVersionPaths.clear(); + typedef WinVisualStudioUtil::VersionPath VersionPath; const int versionCount = SLANG_COUNT_OF(s_versionInfos); for (int i = versionCount - 1; i >= 0; --i) { - VersionPath versionPath; - if (SLANG_SUCCEEDED(_find(i, versionPath))) + const auto versionInfo = s_versionInfos[i]; + + auto version = versionInfo.version; + + // Try locating via the registry + const Int keyIndex = _getRegistryKeyIndex(version); + if (keyIndex >= 0) { - outVersionPaths.add(versionPath); + SLANG_ASSERT(keyIndex < SLANG_COUNT_OF(s_regInfos)); + + // Try reading the key + const auto& keyInfo = s_regInfos[keyIndex]; + + StringBuilder keyName; + versionInfo.version.append(keyName); + + String value; + if (SLANG_SUCCEEDED(_readRegistryKey(keyInfo.regName, keyName.getBuffer(), value))) + { + VersionPath versionPath; + versionPath.version = versionInfo.version; + versionPath.vcvarsPath = value; + + // Append + if (keyInfo.pathFix && keyInfo.pathFix[0] != 0) + { + versionPath.vcvarsPath.append(keyInfo.pathFix); + } + + outVersions.add(versionPath); + } } } return SLANG_OK; } -/* static */SlangResult WinVisualStudioUtil::find(Version version, VersionPath& outPath) +/* static */SlangResult WinVisualStudioUtil::find(List<VersionPath>& outVersionPaths) { - const int versionCount = SLANG_COUNT_OF(s_versionInfos); + outVersionPaths.clear(); + + List<VersionPath> regVersions; - for (int i = 0; i < versionCount; ++i) + // Find all versions with vswhere + _findVersionsWithVSWhere(nullptr, outVersionPaths); + // Find all with the registry + _findVersionsWithRegistery(regVersions); + + // Merge + for (const auto& regVersion : regVersions) { - const auto& versionInfo = s_versionInfos[i]; - if (versionInfo.version == version) + Index foundIndex = -1; + if (_canUseVSWhere(regVersion.version)) + { + // If there is a major version already from vswhere, we don't need to merge + const auto majorVersion = regVersion.version.m_major; + foundIndex = outVersionPaths.findFirstIndex([&](const VersionPath& cur) -> bool { return cur.version.m_major == majorVersion; }); + } + else { - return _find(i, outPath); + // See if we can find the exact version + foundIndex = outVersionPaths.findFirstIndex([&](const VersionPath& cur) -> bool { return cur.version == regVersion.version; }); + } + + // If it wasn't found add it. + if (foundIndex < 0) + { + outVersionPaths.add(regVersion); } } - return SLANG_FAIL; + // Sort + _orderVersions(outVersionPaths); + return SLANG_OK; } /* static */SlangResult WinVisualStudioUtil::find(DownstreamCompilerSet* set) { - const int versionCount = SLANG_COUNT_OF(s_versionInfos); + List<VersionPath> versionPaths; + SLANG_RETURN_ON_FAIL(find(versionPaths)); - for (int i = versionCount - 1; i >= 0; --i) + for (const auto& versionPath : versionPaths) { - const auto& versionInfo = s_versionInfos[i]; - auto desc = getDesc(versionInfo.version); + // Turn into a desc + const DownstreamCompiler::Desc desc(SLANG_PASS_THROUGH_VISUAL_STUDIO, versionPath.version); - VersionPath versionPath; - if (!set->getCompiler(desc) && SLANG_SUCCEEDED(_find(i, versionPath))) + // If not in set add it + if (!set->getCompiler(desc)) { RefPtr<CommandLineDownstreamCompiler> compiler = new VisualStudioDownstreamCompiler(desc); calcExecuteCompilerArgs(versionPath, compiler->m_cmdLine); @@ -431,25 +509,4 @@ static SlangResult _find(int versionIndex, WinVisualStudioUtil::VersionPath& out return ProcessUtil::execute(cmdLine, outResult); } -/* static */void WinVisualStudioUtil::append(Version version, StringBuilder& outBuilder) -{ - switch (version) - { - case Version::Unknown: - { - outBuilder << "unknown"; - } - case Version::Future: - { - outBuilder << "future"; - break; - } - default: - { - outBuilder << (int(version) / 10) << "." << (int(version) % 10); - break; - } - } -} - } // namespace Slang diff --git a/source/compiler-core/windows/slang-win-visual-studio-util.h b/source/compiler-core/windows/slang-win-visual-studio-util.h index 05a3ea061..4dfac8f34 100644 --- a/source/compiler-core/windows/slang-win-visual-studio-util.h +++ b/source/compiler-core/windows/slang-win-visual-studio-util.h @@ -12,24 +12,15 @@ namespace Slang { struct WinVisualStudioUtil { - enum class Version: uint32_t - { - Unknown = 0, ///< This is an unknown (and not later) version - Future = 0xff * 10, ///< This is a version 'from the future' - that isn't specifically known. Will be treated as latest - }; - struct VersionPath { - Version version; ///< The visual studio version - String vcvarsPath; ///< The path to vcvars bat files, that need to be executed before executing the compiler + SemanticVersion version; ///< The visual studio version + String vcvarsPath; ///< The path to `vcvars.bat` files, that need to be executed before executing the compiler }; /// Find all the installations static SlangResult find(List<VersionPath>& outVersionPaths); - /// Given a version find it's path - static SlangResult find(Version version, VersionPath& outPath); - /// Find and add to the set (if not already there) static SlangResult find(DownstreamCompilerSet* set); @@ -39,28 +30,8 @@ struct WinVisualStudioUtil /// Run visual studio on specified path with the parameters specified on the command line. Output placed in outResult. static SlangResult executeCompiler(const VersionPath& versionPath, const CommandLine& commandLine, ExecuteResult& outResult); - /// Get all the known version numbers - static void getVersions(List<Version>& outVersions); - - /// Gets the msc compiler used to compile this version. Returning Version(0) means unknown - static Version getCompiledVersion(); - - /// Create a version from a high and low indices - static Version makeVersion(int high, int low = 0) { SLANG_ASSERT(low >= 0 && low <= 9); return Version(high * 10 + low); } - - /// Convert a version number into a string - static void append(Version version, StringBuilder& outBuilder); - - /// Get version as desc - static DownstreamCompiler::Desc getDesc(Version version) - { - DownstreamCompiler::Desc desc; - desc.type = SLANG_PASS_THROUGH_VISUAL_STUDIO; - desc.majorVersion = Int(version) / 10; - desc.minorVersion = Int(version) % 10; - return desc; - } - + /// Gets the msc compiler used to compile this version. + static DownstreamCompilerMatchVersion getCompiledVersion(); }; } // namespace Slang |
