66using System . Collections . Generic ;
77using System . Diagnostics ;
88using System . IO ;
9+ using System . Linq ;
910using System . Reflection ;
1011using System . Runtime . InteropServices ;
1112using System . Text . RegularExpressions ;
@@ -22,6 +23,8 @@ namespace FwBuildTasks
2223 public static class BuildUtils
2324 {
2425 public static bool IsUnix => Environment . OSVersion . Platform == PlatformID . Unix ;
26+ private const string NetFxLegacyVersionFolder = "v4.0.30319" ;
27+ private static readonly string [ ] NetFxFrameworkFolders = { "Framework64" , "Framework" } ;
2528
2629 /// <summary>
2730 /// Return the executing assembly's location as a directory path.
@@ -204,5 +207,167 @@ public static bool ParseSymbolFile(string symbolFile, TaskLoggingHelper log, out
204207 }
205208 return true ;
206209 }
210+
211+ public static string ResolveDotNetFrameworkSdkTool ( string toolName )
212+ {
213+ if ( IsUnix )
214+ return Path . GetFileNameWithoutExtension ( toolName ) ;
215+
216+ var probeLog = new List < string > ( ) ;
217+ foreach ( var sdkPath in GetToolLocationHelperCandidates ( toolName , probeLog ) )
218+ {
219+ if ( File . Exists ( sdkPath ) )
220+ return sdkPath ;
221+ }
222+
223+ var programFilesX86 = Environment . GetFolderPath ( Environment . SpecialFolder . ProgramFilesX86 ) ;
224+ if ( ! string . IsNullOrEmpty ( programFilesX86 ) )
225+ {
226+ var sdkBase = Path . Combine ( programFilesX86 , "Microsoft SDKs" , "Windows" , "v10.0A" , "bin" ) ;
227+ if ( Directory . Exists ( sdkBase ) )
228+ {
229+ var netfxDirs = Directory . GetDirectories ( sdkBase , "NETFX*" )
230+ . OrderByDescending ( d => d )
231+ . ToList ( ) ;
232+ foreach ( var dir in netfxDirs )
233+ {
234+ var x64Path = Path . Combine ( dir , "x64" , toolName ) ;
235+ probeLog . Add ( x64Path ) ;
236+ if ( File . Exists ( x64Path ) )
237+ return x64Path ;
238+
239+ var anyPath = Path . Combine ( dir , toolName ) ;
240+ probeLog . Add ( anyPath ) ;
241+ if ( File . Exists ( anyPath ) )
242+ return anyPath ;
243+ }
244+ }
245+ }
246+
247+ if ( IsToolOnPath ( toolName ) )
248+ return toolName ;
249+
250+ throw new FileNotFoundException (
251+ $ "Unable to locate required SDK tool '{ toolName } '. " +
252+ "Install Visual Studio Build Tools with .NET Framework 4.8 SDK/targeting pack or run build.ps1/test.ps1 from this repo. " +
253+ $ "Probed: { string . Join ( "; " , probeLog . Distinct ( ) ) } ") ;
254+ }
255+
256+ public static string ResolveDotNetFrameworkAssemblyPath ( string assemblyFileName )
257+ {
258+ var probeLog = new List < string > ( ) ;
259+ foreach ( var candidate in GetFrameworkAssemblyCandidates ( assemblyFileName , probeLog ) )
260+ {
261+ if ( File . Exists ( candidate ) )
262+ return candidate ;
263+ }
264+
265+ throw new FileNotFoundException (
266+ $ "Unable to locate required .NET Framework assembly '{ assemblyFileName } ' for resgen. " +
267+ $ "Probed: { string . Join ( "; " , probeLog . Distinct ( ) ) } ") ;
268+ }
269+
270+ private static IEnumerable < string > GetToolLocationHelperCandidates ( string toolName , ICollection < string > probeLog )
271+ {
272+ var candidates = new List < string > ( ) ;
273+ try
274+ {
275+ candidates . Add ( ToolLocationHelper . GetPathToDotNetFrameworkSdkFile (
276+ toolName ,
277+ TargetDotNetFrameworkVersion . Version48 ,
278+ VisualStudioVersion . Version170 ,
279+ DotNetFrameworkArchitecture . Bitness64 ) ) ;
280+ }
281+ catch
282+ {
283+ }
284+
285+ try
286+ {
287+ candidates . Add ( ToolLocationHelper . GetPathToDotNetFrameworkSdkFile (
288+ toolName ,
289+ TargetDotNetFrameworkVersion . Version48 ,
290+ DotNetFrameworkArchitecture . Bitness64 ) ) ;
291+ }
292+ catch
293+ {
294+ }
295+
296+ try
297+ {
298+ candidates . Add ( ToolLocationHelper . GetPathToDotNetFrameworkSdkFile (
299+ toolName ,
300+ TargetDotNetFrameworkVersion . Version48 ) ) ;
301+ }
302+ catch
303+ {
304+ }
305+
306+ foreach ( var candidate in candidates . Where ( c => ! string . IsNullOrEmpty ( c ) ) )
307+ {
308+ probeLog . Add ( candidate ) ;
309+ yield return candidate ;
310+ }
311+ }
312+
313+ private static IEnumerable < string > GetFrameworkAssemblyCandidates ( string assemblyFileName , ICollection < string > probeLog )
314+ {
315+ var candidates = new List < string > ( ) ;
316+ try
317+ {
318+ var sdkPath = ToolLocationHelper . GetPathToDotNetFrameworkFile (
319+ assemblyFileName ,
320+ TargetDotNetFrameworkVersion . Version48 ) ;
321+ if ( ! string . IsNullOrEmpty ( sdkPath ) )
322+ candidates . Add ( sdkPath ) ;
323+ }
324+ catch
325+ {
326+ }
327+
328+ var runtimeDirectory = RuntimeEnvironment . GetRuntimeDirectory ( ) ;
329+ if ( ! string . IsNullOrEmpty ( runtimeDirectory ) )
330+ {
331+ var runtimeCandidate = Path . Combine ( runtimeDirectory , assemblyFileName ) ;
332+ candidates . Add ( runtimeCandidate ) ;
333+ }
334+
335+ var windowsFolder = Environment . GetFolderPath ( Environment . SpecialFolder . Windows ) ;
336+ if ( ! string . IsNullOrEmpty ( windowsFolder ) )
337+ {
338+ foreach ( var frameworkFolder in NetFxFrameworkFolders )
339+ {
340+ var candidate = Path . Combine (
341+ windowsFolder ,
342+ "Microsoft.NET" ,
343+ frameworkFolder ,
344+ NetFxLegacyVersionFolder ,
345+ assemblyFileName ) ;
346+ candidates . Add ( candidate ) ;
347+ }
348+ }
349+
350+ foreach ( var candidate in candidates )
351+ {
352+ probeLog . Add ( candidate ) ;
353+ yield return candidate ;
354+ }
355+ }
356+
357+ private static bool IsToolOnPath ( string toolName )
358+ {
359+ var path = Environment . GetEnvironmentVariable ( "PATH" ) ;
360+ if ( string . IsNullOrEmpty ( path ) )
361+ return false ;
362+
363+ foreach ( var entry in path . Split ( new [ ] { ';' } , StringSplitOptions . RemoveEmptyEntries ) )
364+ {
365+ var candidate = Path . Combine ( entry . Trim ( ) , toolName ) ;
366+ if ( File . Exists ( candidate ) )
367+ return true ;
368+ }
369+
370+ return false ;
371+ }
207372 }
208373}
0 commit comments