summaryrefslogtreecommitdiffstats
path: root/source/compiler-core/windows
diff options
context:
space:
mode:
Diffstat (limited to 'source/compiler-core/windows')
-rw-r--r--source/compiler-core/windows/slang-win-visual-studio-util.cpp401
-rw-r--r--source/compiler-core/windows/slang-win-visual-studio-util.h37
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