using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Reflection; using Microsoft.Build.Framework; using Microsoft.Build.Utilities; using Microsoft.Win32; namespace YekNebTasks { public static class Utilities { private static string cmake = string.Empty; private static string git = string.Empty; private static string patch = string.Empty; private static string python = string.Empty; private static string VSWhere = string.Empty; public static string FindFileOnPath(string fileName) { if (string.IsNullOrEmpty(fileName)) { return string.Empty; } string FoundFile = string.Empty; fileName = Environment.ExpandEnvironmentVariables(fileName); if (File.Exists(fileName)) { FoundFile = Path.GetFullPath(fileName); } else if (string.IsNullOrEmpty(Path.GetDirectoryName(fileName))) { var path = Environment.GetEnvironmentVariable("PATH") ?? string.Empty; foreach (var dir in path.Split(Path.PathSeparator)) { var dirL = dir.Trim(); var fullPath = Path.GetFullPath(Path.Combine(dirL, fileName)); if (File.Exists(fullPath)) { FoundFile = fullPath; break; } } } return FoundFile; } public static string FindFileUsingCandidates( string[] candidates) { if (candidates == null || candidates.Length == 0) { return string.Empty; } string FoundFile = string.Empty; foreach (string candidate in candidates) { string candidateL = Environment.ExpandEnvironmentVariables( candidate); if (File.Exists(candidateL)) { FoundFile = candidateL; break; } } return FoundFile; } public static string FindCMake() { if (!string.IsNullOrEmpty(cmake)) { return cmake; } const string FileName = "cmake.exe"; string[] candidates = new string[]{ @"%ProgramFiles(x86)%\Microsoft Visual Studio\2019\Community\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin\cmake.exe", @"%ProgramFiles(x86)%\Microsoft Visual Studio\2019\BuildTools\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin\cmake.exe", @"%ProgramFiles(x86)%\Microsoft Visual Studio\2019\Professional\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin\cmake.exe", @"%ProgramFiles(x86)%\Microsoft Visual Studio\2017\Professional\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin\cmake.exe", @"%ProgramFiles%\CMake\bin\cmake.exe", @"%ProgramW6432%\CMake\bin\cmake.exe", @"%SystemDrive%\msys64\mingw64\bin\cmake.exe", @"%SystemDrive%\msys64\mingw32\bin\cmake.exe", @"%SystemDrive%\msys64\usr\bin\cmake.exe" }; cmake = FindFileUsingCandidates(candidates); if (!string.IsNullOrEmpty(cmake)) { return cmake; } cmake = FindFileOnPath(FileName); return cmake; } public static string FindGit() { if (!string.IsNullOrEmpty(git)) { return git; } const string FileName = "git.exe"; string[] candidates = new String[]{ @"%ProgramFiles%\Git\cmd\git.exe", @"%ProgramW6432%\Git\cmd\git.exe", @"%SystemDrive%\msys64\mingw64\bin\git.exe", @"%SystemDrive%\msys64\mingw32\bin\git.exe", @"%SystemDrive%\msys64\usr\bin\git.exe", @"%SystemDrive%\MinGW\msys\1.0\bin\git.exe" }; git = FindFileUsingCandidates(candidates); if (!string.IsNullOrEmpty(git)) { return git; } git = FindFileOnPath(FileName); return git; } public static string FindNMake() { string nmake = FindFileOnPath("nmake.exe"); if (!string.IsNullOrEmpty(nmake)) { return nmake; } string visualStudioDir = GetVisualStudioInstallDirectory("16.0"); if (string.IsNullOrEmpty(visualStudioDir) || !Directory.Exists(visualStudioDir)) { visualStudioDir = GetVisualStudioInstallDirectory("15.0"); } if (string.IsNullOrEmpty(visualStudioDir) || !Directory.Exists(visualStudioDir)) { visualStudioDir = GetVisualStudioInstallDirectory("14.0"); } if (string.IsNullOrEmpty(visualStudioDir) || !Directory.Exists(visualStudioDir)) { return string.Empty; } string vcDir = Path.Combine(visualStudioDir, "VC"); if (!Directory.Exists(vcDir)) { return string.Empty; } string[] foundFiles = Directory.GetFiles( vcDir, "nmake.exe", SearchOption.AllDirectories); if (foundFiles.Length == 0) { return string.Empty; } CultureInfo culture = CultureInfo.CurrentCulture; foreach (var candidate in foundFiles) { if (culture.CompareInfo.IndexOf(candidate, "x64", CompareOptions.IgnoreCase) >= 0) { nmake = candidate; } } return nmake; } public static string FindPatch() { if (!string.IsNullOrEmpty(patch)) { return patch; } const string FileName = "patch.exe"; string[] candidates = new string[]{ @"%SystemDrive%\msys64\mingw64\bin\patch.exe", @"%SystemDrive%\msys64\mingw32\bin\patch.exe", @"%SystemDrive%\msys64\usr\bin\patch.exe", @"%SystemDrive%\MinGW\msys\1.0\bin\patch.exe" }; patch = FindFileUsingCandidates(candidates); if (string.IsNullOrEmpty(patch)) { patch = FindFileOnPath(FileName); } return patch; } public static string FindPython() { if (!string.IsNullOrEmpty(python)) { return python; } const string FileName = "python.exe"; string[] candidates = new string[]{ @"%ProgramFiles%\Python39\python.exe", @"%ProgramW6432%\Python39\python.exe", @"%ProgramFiles%\Python38\python.exe", @"%ProgramW6432%\Python38\python.exe", @"%ProgramFiles(x86)%\Microsoft Visual Studio\Shared\Python37_64\python.exe", @"%ProgramFiles(x86)%\Microsoft Visual Studio\Shared\Python36_64\python.exe", @"%ProgramFiles%\Python36\python.exe", @"%ProgramW6432%\Python36\python.exe", @"%SystemDrive%\Python36\python3.6.exe", @"%SystemDrive%\Python36\python3.exe", @"%SystemDrive%\Python36\python.exe", @"%SystemDrive%\Python35\python3.5.exe", @"%SystemDrive%\Python35\python3.exe", @"%SystemDrive%\Python35\python.exe", @"%SystemDrive%\Python34\python3.4.exe", @"%SystemDrive%\Python34\python3.exe", @"%SystemDrive%\Python34\python.exe", @"%SystemDrive%\msys64\mingw64\bin\python3.8.exe", @"%SystemDrive%\msys64\mingw64\bin\python3.7.exe", @"%SystemDrive%\msys64\mingw64\bin\python3.6.exe", @"%SystemDrive%\msys64\mingw64\bin\python3.5.exe", @"%SystemDrive%\msys64\mingw64\bin\python3.exe", @"%SystemDrive%\msys64\mingw32\bin\python3.6.exe", @"%SystemDrive%\msys64\mingw32\bin\python3.5.exe", @"%SystemDrive%\msys64\mingw32\bin\python3.exe", @"%SystemDrive%\msys64\usr\bin\python3.6.exe", @"%SystemDrive%\msys64\usr\bin\python3.5.exe", @"%SystemDrive%\msys64\usr\bin\python3.exe" }; python = FindFileUsingCandidates(candidates); if (!string.IsNullOrEmpty(python)) { return python; } python = FindFileOnPath(FileName); return python; } private static string FindVSWhereUsingRegistry() { const string regKeyName = @"SOFTWARE\Microsoft\VisualStudio\Setup"; const string valueName = @"SharedInstallationPath"; string ret = string.Empty; using (RegistryKey regKey = Registry.LocalMachine.OpenSubKey(regKeyName)) { if (regKey == null) { return string.Empty; } ret = regKey.GetValue(valueName) as string; } if (string.IsNullOrEmpty(ret)) { return string.Empty; } DirectoryInfo info = Directory.GetParent(ret); if (info == null) { return string.Empty; } ret = Path.Combine(info.FullName, @"Installer\vswhere.exe"); if (!File.Exists(ret)) { return string.Empty; } return ret; } public static string FindVSWhere() { if (!string.IsNullOrEmpty(VSWhere)) { return VSWhere; } VSWhere = FindVSWhereUsingRegistry(); if (!string.IsNullOrEmpty(VSWhere)) { return VSWhere; } const string FileName = "vswhere.exe"; string[] candidates = new string[]{ @"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe", @"%ProgramFiles%\Microsoft Visual Studio\Installer\vswhere.exe" }; VSWhere = FindFileUsingCandidates(candidates); if (!string.IsNullOrEmpty(VSWhere)) { return VSWhere; } VSWhere = FindFileOnPath(FileName); return VSWhere; } private static string RunProcessAndGetStandardOutput(string fileName, string arguments) { string ret = string.Empty; Process p = null; try { p = new Process(); p.StartInfo.UseShellExecute = false; p.StartInfo.RedirectStandardOutput = true; p.StartInfo.FileName = fileName; p.StartInfo.Arguments = arguments; p.Start(); // Read the output stream first and then wait. ret = p.StandardOutput.ReadToEnd(); p.WaitForExit(); } finally { if (p != null) { p.Dispose(); } } return ret; } private static string GetVisualStudioInstallDirectoryUsingRegistry(string version) { const string VS7RegKeyName = @"SOFTWARE\Microsoft\VisualStudio\SxS\VS7"; const string VS7RegKeyX64Name = @"SOFTWARE\WOW6432Node\Microsoft\VisualStudio\SxS\VS7"; string regKeyName; if (Environment.Is64BitOperatingSystem) { regKeyName = VS7RegKeyX64Name; } else { regKeyName = VS7RegKeyName; } string installDirectory = string.Empty; using (RegistryKey regKey = Registry.LocalMachine.OpenSubKey(regKeyName)) { if (regKey != null) { installDirectory = regKey.GetValue(version) as string; } } return installDirectory; } private static string GetVisualStudioInstallDirectoryUsingVSWhere(string version) { string vsWhere = FindVSWhere(); if (string.IsNullOrEmpty(vsWhere)) { return string.Empty; } string output = RunProcessAndGetStandardOutput( vsWhere, $"-version {version} -property installationPath"); vsWhere = output.Trim(); return vsWhere; } public static string GetVisualStudioInstallDirectory(string version) { string ret = GetVisualStudioInstallDirectoryUsingVSWhere(version); if (string.IsNullOrEmpty(ret)) { ret = GetVisualStudioInstallDirectoryUsingRegistry(version); } return ret; } } }