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 | |
| 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')
4 files changed, 347 insertions, 259 deletions
diff --git a/source/compiler-core/slang-downstream-compiler.cpp b/source/compiler-core/slang-downstream-compiler.cpp index 1dfaea0a4..5011b42a0 100644 --- a/source/compiler-core/slang-downstream-compiler.cpp +++ b/source/compiler-core/slang-downstream-compiler.cpp @@ -519,34 +519,32 @@ SlangResult CommandLineDownstreamCompiler::compile(const CompileOptions& inOptio /* !!!!!!!!!!!!!!!!!!!!!!!!! DownstreamCompiler::Desc !!!!!!!!!!!!!!!!!!!!!!*/ -static DownstreamCompiler::Desc _calcCompiledWithDesc() +static DownstreamCompilerMatchVersion _calcCompiledVersion() { - DownstreamCompiler::Desc desc; + DownstreamCompilerMatchVersion matchVersion; #if SLANG_VC - desc = WinVisualStudioUtil::getDesc(WinVisualStudioUtil::getCompiledVersion()); + matchVersion = WinVisualStudioUtil::getCompiledVersion(); #elif SLANG_CLANG - desc.type = SLANG_PASS_THROUGH_CLANG; - desc.majorVersion = Int(__clang_major__); - desc.minorVersion = Int(__clang_minor__); + matchVersion.type = SLANG_PASS_THROUGH_CLANG; + matchVersion.matchVersion.set(Index(__clang_major__), Index(__clang_minor__)); #elif SLANG_GCC - desc.type = SLANG_PASS_THROUGH_GCC; - desc.majorVersion = Int(__GNUC__); - desc.minorVersion = Int(__GNUC_MINOR__); + matchVersion.type = SLANG_PASS_THROUGH_GCC; + matchVersion.matchVersion.set(Index(__GNUC__), Index(__GNUC_MINOR__)); #else // TODO(JS): Hmmm None is not quite the same as unknown. It works for now, but we might want to have a distinct enum for unknown. - desc.type = SLANG_PASS_THROUGH_NONE; + matchVersion.type = SLANG_PASS_THROUGH_NONE; #endif - return desc; + return matchVersion; } /* !!!!!!!!!!!!!!!!!!!!!!!!! DownstreamCompilerUtil !!!!!!!!!!!!!!!!!!!!!!*/ -const DownstreamCompiler::Desc& DownstreamCompilerUtil::getCompiledWithDesc() +DownstreamCompilerMatchVersion DownstreamCompilerUtil::getCompiledVersion() { - static DownstreamCompiler::Desc s_desc = _calcCompiledWithDesc(); - return s_desc; + static DownstreamCompilerMatchVersion s_version = _calcCompiledVersion(); + return s_version; } /* static */DownstreamCompiler* DownstreamCompilerUtil::findCompiler(const DownstreamCompilerSet* set, MatchType matchType, const DownstreamCompiler::Desc& desc) @@ -626,22 +624,70 @@ const DownstreamCompiler::Desc& DownstreamCompilerUtil::getCompiledWithDesc() return (bestIndex >= 0) ? compilers[bestIndex] : nullptr; } -/* static */DownstreamCompiler* DownstreamCompilerUtil::findClosestCompiler(const List<DownstreamCompiler*>& compilers, const DownstreamCompiler::Desc& desc) +/* static */DownstreamCompiler* DownstreamCompilerUtil::findCompiler(const List<DownstreamCompiler*>& compilers, const DownstreamCompiler::Desc& desc) { - DownstreamCompiler* compiler; + for (auto compiler : compilers) + { + if (compiler->getDesc() == desc) + { + return compiler; + } + } + return nullptr; +} - compiler = findCompiler(compilers, MatchType::MinGreaterEqual, desc); - if (compiler) +/* static */DownstreamCompiler* DownstreamCompilerUtil::findCompiler(const List<DownstreamCompiler*>& compilers, SlangPassThrough type, const SemanticVersion& version) +{ + DownstreamCompiler::Desc desc; + desc.type = type; + desc.majorVersion = version.m_major; + desc.minorVersion = version.m_minor; + return findCompiler(compilers, desc); +} + +/* static */void DownstreamCompilerUtil::findVersions(const List<DownstreamCompiler*>& compilers, SlangPassThrough type, List<SemanticVersion>& outVersions) +{ + for (auto compiler : compilers) { - return compiler; + auto desc = compiler->getDesc(); + + if (desc.type == type) + { + outVersions.add(SemanticVersion(int(desc.majorVersion), int(desc.minorVersion), 0)); + } } - compiler = findCompiler(compilers, MatchType::MinAbsolute, desc); - if (compiler) +} + +/* static */DownstreamCompiler* DownstreamCompilerUtil::findClosestCompiler(const List<DownstreamCompiler*>& compilers, const DownstreamCompilerMatchVersion& matchVersion) +{ + List<SemanticVersion> versions; + + findVersions(compilers, matchVersion.type, versions); + + if (versions.getCount() > 0) { - return compiler; + if (versions.getCount() == 1) + { + // Must be that one + return findCompiler(compilers, matchVersion.type, versions[0]); + } + + // Okay lets find the best one + auto bestVersion = MatchSemanticVersion::findAnyBest(versions.getBuffer(), versions.getCount(), matchVersion.matchVersion); + + // If one is found use it + if (bestVersion.isSet()) + { + return findCompiler(compilers, matchVersion.type, bestVersion); + } } { + // TODO(JS): + // NOTE! This may not really be appropriate, because LLVM is *not* interchangable with + // a 'normal' C++ compiler as cannot access standard libraries/headers. + // So `slang-llvm` can't be used for 'host' code. + // These compilers should be usable interchangably. The order is important, as the first one that matches will // be used, so LLVM is used before CLANG or GCC if appropriate const SlangPassThrough compatiblePassThroughs[] = @@ -651,31 +697,20 @@ const DownstreamCompiler::Desc& DownstreamCompilerUtil::getCompiledWithDesc() SLANG_PASS_THROUGH_GCC, }; - bool isCompatible = false; - for (auto passThrough : compatiblePassThroughs) - { - if (desc.type == passThrough) - { - isCompatible = true; - break; - } - } - - if (isCompatible) + // Check the version is one of the compatible types + if (makeConstArrayView(compatiblePassThroughs).indexOf(matchVersion.type) >= 0) { + // Try each compatible type in turn for (auto passThrough : compatiblePassThroughs) { - if (passThrough != desc.type) + versions.clear(); + findVersions(compilers, passThrough, versions); + + if (versions.getCount() > 0) { - DownstreamCompiler::Desc compatible; - - compatible.type = passThrough; - // Find the latest version. - compiler = findCompiler(compilers, MatchType::Newest, compatible); - if (compiler) - { - return compiler; - } + // Get the latest version (as we have no way to really compare) + auto latestVersion = SemanticVersion::getLatest(versions.getBuffer(), versions.getCount()); + return findCompiler(compilers, matchVersion.type, latestVersion); } } } @@ -684,16 +719,11 @@ const DownstreamCompiler::Desc& DownstreamCompilerUtil::getCompiledWithDesc() return nullptr; } -/* static */DownstreamCompiler* DownstreamCompilerUtil::findClosestCompiler(const DownstreamCompilerSet* set, const DownstreamCompiler::Desc& desc) +/* static */DownstreamCompiler* DownstreamCompilerUtil::findClosestCompiler(const DownstreamCompilerSet* set, const DownstreamCompilerMatchVersion& matchVersion) { - DownstreamCompiler* compiler = set->getCompiler(desc); - if (compiler) - { - return compiler; - } List<DownstreamCompiler*> compilers; set->getCompilers(compilers); - return findClosestCompiler(compilers, desc); + return findClosestCompiler(compilers, matchVersion); } /* static */void DownstreamCompilerUtil::updateDefault(DownstreamCompilerSet* set, SlangSourceLanguage sourceLanguage) @@ -708,7 +738,7 @@ const DownstreamCompiler::Desc& DownstreamCompilerUtil::getCompiledWithDesc() // Find the compiler closest to the compiler this was compiled with if (!compiler) { - compiler = findClosestCompiler(set, getCompiledWithDesc()); + compiler = findClosestCompiler(set, getCompiledVersion()); } break; } diff --git a/source/compiler-core/slang-downstream-compiler.h b/source/compiler-core/slang-downstream-compiler.h index db89eeaf1..9d58f6678 100644 --- a/source/compiler-core/slang-downstream-compiler.h +++ b/source/compiler-core/slang-downstream-compiler.h @@ -154,6 +154,21 @@ protected: ComPtr<ISlangBlob> m_blob; }; +// Combination of a downstream compiler type (pass through) and +// a match version. +struct DownstreamCompilerMatchVersion +{ + DownstreamCompilerMatchVersion(SlangPassThrough inType, MatchSemanticVersion inMatchVersion): + type(inType), + matchVersion(inMatchVersion) + {} + + DownstreamCompilerMatchVersion():type(SLANG_PASS_THROUGH_NONE) {} + + SlangPassThrough type; ///< The type of the compiler + MatchSemanticVersion matchVersion; ///< The match version +}; + class DownstreamCompiler: public RefObject { public: @@ -190,6 +205,8 @@ public: Info infos[int(SLANG_PASS_THROUGH_COUNT_OF)]; }; + + // Compiler description struct Desc { typedef Desc ThisType; @@ -208,11 +225,17 @@ public: /// Ctor explicit Desc(SlangPassThrough inType = SLANG_PASS_THROUGH_NONE, Int inMajorVersion = 0, Int inMinorVersion = 0):type(inType), majorVersion(inMajorVersion), minorVersion(inMinorVersion) {} + explicit Desc(SlangPassThrough inType, const SemanticVersion& version):type(inType), majorVersion(version.m_major), minorVersion(version.m_minor) {} + SlangPassThrough type; ///< The type of the compiler + + /// TODO(JS): Would probably be better if changed to SemanticVersion, but not trivial to change + // because this type is part of the DownstreamCompiler interface, which is used with `slang-llvm`. Int majorVersion; ///< Major version (interpretation is type specific) Int minorVersion; ///< Minor version (interpretation is type specific) }; + enum class OptimizationLevel { None, ///< Don't optimize at all. @@ -526,12 +549,19 @@ struct DownstreamCompilerUtil: public DownstreamCompilerBaseUtil static DownstreamCompiler* findCompiler(const DownstreamCompilerSet* set, MatchType matchType, const DownstreamCompiler::Desc& desc); static DownstreamCompiler* findCompiler(const List<DownstreamCompiler*>& compilers, MatchType matchType, const DownstreamCompiler::Desc& desc); + static DownstreamCompiler* findCompiler(const List<DownstreamCompiler*>& compilers, SlangPassThrough type, const SemanticVersion& version); + static DownstreamCompiler* findCompiler(const List<DownstreamCompiler*>& compilers, const DownstreamCompiler::Desc& desc); + + /// Find all the compilers with the version + static void findVersions(const List<DownstreamCompiler*>& compilers, SlangPassThrough compiler, List<SemanticVersion>& versions); + + /// Find the compiler closest to the desc - static DownstreamCompiler* findClosestCompiler(const List<DownstreamCompiler*>& compilers, const DownstreamCompiler::Desc& desc); - static DownstreamCompiler* findClosestCompiler(const DownstreamCompilerSet* set, const DownstreamCompiler::Desc& desc); + static DownstreamCompiler* findClosestCompiler(const List<DownstreamCompiler*>& compilers, const DownstreamCompilerMatchVersion& version); + static DownstreamCompiler* findClosestCompiler(const DownstreamCompilerSet* set, const DownstreamCompilerMatchVersion& version); /// Get the information on the compiler used to compile this source - static const DownstreamCompiler::Desc& getCompiledWithDesc(); + static DownstreamCompilerMatchVersion getCompiledVersion(); static void updateDefault(DownstreamCompilerSet* set, SlangSourceLanguage sourceLanguage); static void updateDefaults(DownstreamCompilerSet* set); 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 |
