@@ -24,12 +24,26 @@ public override bool Execute()
2424 {
2525 try
2626 {
27+ Log . LogMessage ( MessageImportance . Normal , "Starting GenerateFwTargets task..." ) ;
2728 var gen = new CollectTargets ( Log , ToolsVersion ) ;
2829 gen . Generate ( ) ;
30+ Log . LogMessage ( MessageImportance . Normal , "GenerateFwTargets task completed successfully." ) ;
2931 return true ;
3032 }
31- catch ( CollectTargets . StopTaskException )
33+ catch ( CollectTargets . StopTaskException ex )
3234 {
35+ Log . LogError ( "GenerateFwTargets task failed." ) ;
36+ if ( ex . InnerException != null )
37+ {
38+ Log . LogError ( "Inner exception: {0}" , ex . InnerException . Message ) ;
39+ Log . LogError ( "Stack trace: {0}" , ex . InnerException . StackTrace ) ;
40+ }
41+ return false ;
42+ }
43+ catch ( Exception ex )
44+ {
45+ Log . LogError ( "GenerateFwTargets task failed with unexpected exception: {0}" , ex . Message ) ;
46+ Log . LogError ( "Stack trace: {0}" , ex . StackTrace ) ;
3347 return false ;
3448 }
3549 }
@@ -82,16 +96,22 @@ public CollectTargets(TaskLoggingHelper log, string toolsVersion)
8296 /// </summary>
8397 public void Generate ( )
8498 {
99+ Log . LogMessage ( MessageImportance . Normal , "Collecting project information from Src directory..." ) ;
85100 var infoSrc = new DirectoryInfo ( Path . Combine ( m_fwroot , "Src" ) ) ;
86101 CollectInfo ( infoSrc ) ;
102+
87103 // These projects from Lib had nant targets. They really should be under Src.
104+ Log . LogMessage ( MessageImportance . Normal , "Collecting project information from Lib directories..." ) ;
88105 var infoEth = new DirectoryInfo ( Path . Combine ( m_fwroot , "Lib/src/Ethnologue" ) ) ;
89106 CollectInfo ( infoEth ) ;
90107 var infoScr2 = new DirectoryInfo ( Path . Combine ( m_fwroot , "Lib/src/ScrChecks" ) ) ;
91108 CollectInfo ( infoScr2 ) ;
92109 var infoObj = new DirectoryInfo ( Path . Combine ( m_fwroot , "Lib/src/ObjectBrowser" ) ) ;
93110 CollectInfo ( infoObj ) ;
111+
112+ Log . LogMessage ( MessageImportance . Normal , "Found {0} projects. Writing target files..." , m_mapProjFile . Count ) ;
94113 WriteTargetFiles ( ) ;
114+ Log . LogMessage ( MessageImportance . Normal , "Target file generation completed." ) ;
95115 }
96116
97117 /// <summary>
@@ -100,11 +120,20 @@ public void Generate()
100120 private void CollectInfo ( DirectoryInfo dirInfo )
101121 {
102122 if ( dirInfo == null || ! dirInfo . Exists )
123+ {
124+ Log . LogMessage ( MessageImportance . Low , "Directory does not exist: {0}" , dirInfo ? . FullName ?? "null" ) ;
103125 return ;
126+ }
127+
128+ Log . LogMessage ( MessageImportance . Low , "Scanning directory: {0}" , dirInfo . FullName ) ;
129+
104130 foreach ( var fi in dirInfo . GetFiles ( ) )
105131 {
106132 if ( fi . Name . EndsWith ( ".csproj" ) && fi . Exists )
133+ {
134+ Log . LogMessage ( MessageImportance . Low , "Processing project file: {0}" , fi . FullName ) ;
107135 ProcessCsProjFile ( fi . FullName ) ;
136+ }
108137 }
109138 foreach ( var diSub in dirInfo . GetDirectories ( ) )
110139 CollectInfo ( diSub ) ;
@@ -165,7 +194,7 @@ private void ProcessCsProjFile(string filename)
165194 // here: we use the same .csproj file on both Windows and Linux
166195 // and so it contains backslashes in the name which is a valid
167196 // character on Linux.
168- var i0 = projectName . LastIndexOfAny ( new [ ] { '\\ ' , '/' } ) ;
197+ var i0 = projectName . LastIndexOfAny ( new [ ] { '\\ ' , '/' } ) ;
169198 if ( i0 >= 0 )
170199 projectName = projectName . Substring ( i0 + 1 ) ;
171200 projectName = projectName . Replace ( ".csproj" , "" ) ;
@@ -212,14 +241,62 @@ private string AssemblyName
212241 {
213242 get
214243 {
215- var name = m_csprojFile . SelectSingleNode ( "/c:Project/c:PropertyGroup/c:AssemblyName" ,
216- m_namespaceMgr ) ;
217- var type = m_csprojFile . SelectSingleNode ( "/c:Project/c:PropertyGroup/c:OutputType" ,
218- m_namespaceMgr ) ;
244+ // Try SDK-style project first (no namespace)
245+ var name = m_csprojFile . SelectSingleNode ( "/Project/PropertyGroup/AssemblyName" ) ;
246+ var type = m_csprojFile . SelectSingleNode ( "/Project/PropertyGroup/OutputType" ) ;
247+
248+ // If not found, try old-style project with namespace
249+ if ( name == null )
250+ {
251+ name = m_csprojFile . SelectSingleNode ( "/c:Project/c:PropertyGroup/c:AssemblyName" , m_namespaceMgr ) ;
252+ type = m_csprojFile . SelectSingleNode ( "/c:Project/c:PropertyGroup/c:OutputType" , m_namespaceMgr ) ;
253+ }
254+
255+ // Default extension is .dll (for Library output type or when OutputType is not specified)
219256 string extension = ".dll" ;
220- if ( type . InnerText == "WinExe" || type . InnerText == "Exe" )
257+ if ( type != null && ( type . InnerText == "WinExe" || type . InnerText == "Exe" ) )
221258 extension = ".exe" ;
222- return name . InnerText + extension ;
259+
260+ if ( name != null )
261+ return name . InnerText + extension ;
262+
263+ // If AssemblyName is not found, this shouldn't happen but return a safe default
264+ Log . LogWarning ( "AssemblyName not found in project file, using default" ) ;
265+ return "Unknown" + extension ;
266+ }
267+ }
268+
269+ /// <summary>
270+ /// Gets the assembly name for a specific project by name.
271+ /// </summary>
272+ /// <param name="projectName">The name of the project</param>
273+ /// <returns>The assembly name with extension</returns>
274+ private string GetAssemblyNameForProject ( string projectName )
275+ {
276+ if ( ! m_mapProjFile . ContainsKey ( projectName ) )
277+ {
278+ Log . LogWarning ( $ "Project { projectName } not found in project map") ;
279+ return projectName + ".dll" ;
280+ }
281+
282+ var projectPath = m_mapProjFile [ projectName ] ;
283+ var savedCsprojFile = m_csprojFile ;
284+
285+ try
286+ {
287+ // Load the specific project file
288+ LoadProjectFile ( projectPath ) ;
289+ return AssemblyName ;
290+ }
291+ catch ( Exception ex )
292+ {
293+ Log . LogWarning ( $ "Failed to load project file { projectPath } : { ex . Message } ") ;
294+ return projectName + ".dll" ;
295+ }
296+ finally
297+ {
298+ // Restore the original project file
299+ m_csprojFile = savedCsprojFile ;
223300 }
224301 }
225302
@@ -230,12 +307,33 @@ private XmlNodeList ConfigNodes
230307 {
231308 get
232309 {
310+ // Try SDK-style first (no namespace)
311+ var nodes = m_csprojFile . SelectNodes ( "//PropertyGroup[DefineConstants]" ) ;
312+ if ( nodes . Count > 0 )
313+ return nodes ;
314+
315+ // Fall back to legacy format with namespace
233316 return m_csprojFile . SelectNodes ( "/c:Project/c:PropertyGroup[c:DefineConstants]" ,
234317 m_namespaceMgr ) ;
235318 }
236319 }
237320
238- private string GetProjectSubDir ( string project )
321+ /// <summary>
322+ /// Get DefineConstants value from a PropertyGroup node
323+ /// </summary>
324+ private string GetDefineConstants ( XmlNode node )
325+ {
326+ // Try SDK-style first (no namespace)
327+ var defineConstantsElement = node . SelectSingleNode ( "DefineConstants" ) ;
328+ if ( defineConstantsElement != null )
329+ return defineConstantsElement . InnerText ;
330+
331+ // Fall back to legacy format with namespace
332+ var legacyElement = node . SelectSingleNode ( "c:DefineConstants" , m_namespaceMgr ) ;
333+ return legacyElement ? . InnerText ?? "" ;
334+ }
335+
336+ public string GetProjectSubDir ( string project )
239337 {
240338 var projectSubDir = Path . GetDirectoryName ( m_mapProjFile [ project ] ) ;
241339 projectSubDir = projectSubDir . Substring ( m_fwroot . Length ) ;
@@ -275,6 +373,7 @@ private static bool IsMono
275373 private void WriteTargetFiles ( )
276374 {
277375 var targetsFile = Path . Combine ( m_fwroot , "Build/FieldWorks.targets" ) ;
376+ string currentProject = null ;
278377 try
279378 {
280379 // Write all the C# targets and their dependencies.
@@ -289,6 +388,7 @@ private void WriteTargetFiles()
289388 writer . WriteLine ( ) ;
290389 foreach ( var project in m_mapProjFile . Keys )
291390 {
391+ currentProject = project ;
292392 LoadProjectFile ( m_mapProjFile [ project ] ) ;
293393
294394 var isTestProject = project . EndsWith ( "Tests" ) || project == "TestManager" ;
@@ -300,22 +400,26 @@ private void WriteTargetFiles()
300400 var configs = new Dictionary < string , string > ( ) ;
301401 foreach ( XmlNode node in ConfigNodes )
302402 {
303- var condition = node . Attributes [ "Condition" ] . InnerText ;
403+ var condition = node . Attributes [ "Condition" ] ? . InnerText ;
404+ if ( condition == null )
405+ {
406+ continue ;
407+ }
304408 var tmp = condition . Substring ( condition . IndexOf ( "==" ) + 2 ) . Trim ( ) . Trim ( '\' ' ) ;
305409 var configuration = tmp . Substring ( 0 , tmp . IndexOf ( "|" ) ) ;
306410
307411 // Add configuration only once even if same configuration is contained
308412 // for multiple platforms, e.g. for AnyCpu and x64.
309413 if ( configs . ContainsKey ( configuration ) )
310414 {
311- if ( configs [ configuration ] != node . SelectSingleNode ( "c:DefineConstants" , m_namespaceMgr ) . InnerText . Replace ( ";" , " " ) )
415+ if ( configs [ configuration ] != GetDefineConstants ( node ) . Replace ( ";" , " " ) )
312416 {
313417 Log . LogError ( "Configuration {0} for project {1} is defined several times " +
314418 "but contains differing values for DefineConstants." , configuration , project ) ;
315419 }
316420 continue ;
317421 }
318- configs . Add ( configuration , node . SelectSingleNode ( "c:DefineConstants" , m_namespaceMgr ) . InnerText . Replace ( ";" , " " ) ) ;
422+ configs . Add ( configuration , GetDefineConstants ( node ) . Replace ( ";" , " " ) ) ;
319423
320424 writer . WriteLine ( "\t \t <When Condition=\" '$(config-capital)' == '{0}' \" >" , configuration ) ;
321425 writer . WriteLine ( "\t \t \t <PropertyGroup>" ) ;
@@ -328,7 +432,7 @@ private void WriteTargetFiles()
328432 otherwiseBldr . AppendLine ( "\t \t <Otherwise>" ) ;
329433 otherwiseBldr . AppendLine ( "\t \t \t <PropertyGroup>" ) ;
330434 otherwiseBldr . AppendLine ( string . Format ( "\t \t \t \t <{0}Defines>{1} CODE_ANALYSIS</{0}Defines>" , project ,
331- node . SelectSingleNode ( "c:DefineConstants" , m_namespaceMgr ) . InnerText . Replace ( ";" , " " ) ) ) ;
435+ GetDefineConstants ( node ) . Replace ( ";" , " " ) ) ) ;
332436 otherwiseBldr . AppendLine ( "\t \t \t </PropertyGroup>" ) ;
333437 otherwiseBldr . AppendLine ( "\t \t </Otherwise>" ) ;
334438 otherwiseAdded = true ;
@@ -372,7 +476,7 @@ private void WriteTargetFiles()
372476 writer . WriteLine ( "\t \t \t Properties=\" $(msbuild-props);IntermediateOutputPath=$(dir-fwobj){0}{1}{0};DefineConstants=$({2}Defines);$(warningsAsErrors);WarningLevel=4;LcmArtifactsDir=$(LcmArtifactsDir)\" />" ,
373477 Path . DirectorySeparatorChar , GetProjectSubDir ( project ) , project ) ;
374478 // <Clouseau> verification task
375- writer . WriteLine ( $ "\t \t <Clouseau Condition=\" '$(Configuration)' == 'Debug'\" AssemblyPathname=\" $(dir-outputBase)/{ AssemblyName } \" />") ;
479+ writer . WriteLine ( $ "\t \t <Clouseau Condition=\" '$(Configuration)' == 'Debug'\" AssemblyPathname=\" $(dir-outputBase)/{ GetAssemblyNameForProject ( project ) } \" />") ;
376480
377481 if ( isTestProject )
378482 {
@@ -396,7 +500,7 @@ private void WriteTargetFiles()
396500 writer . WriteLine ( $ "\t \t <Message Text=\" Finished building { project } .\" Condition=\" '$(action)'!='test'\" />") ;
397501 writer . WriteLine ( $ "\t \t <Message Text=\" Finished building { project } and running tests.\" Condition=\" '$(action)'=='test'\" />") ;
398502 // Generate dotCover task
399- GenerateDotCoverTask ( writer , new [ ] { project } , $ "{ project } .coverage.xml") ;
503+ GenerateDotCoverTask ( writer , new [ ] { project } , $ "{ project } .coverage.xml") ;
400504 }
401505 else
402506 {
@@ -448,12 +552,56 @@ private void WriteTargetFiles()
448552 writer . Close ( ) ;
449553 }
450554 Console . WriteLine ( "Created {0}" , targetsFile ) ;
555+
556+ // Always output the generated file content for debugging
557+ if ( File . Exists ( targetsFile ) )
558+ {
559+ Log . LogMessage ( MessageImportance . High , "Generated targets file content:" ) ;
560+ try
561+ {
562+ var content = File . ReadAllText ( targetsFile ) ;
563+ Log . LogMessage ( MessageImportance . High , content ) ;
564+ }
565+ catch ( Exception readEx )
566+ {
567+ Log . LogError ( "Failed to read targets file for debugging: {0}" , readEx . Message ) ;
568+ }
569+ }
451570 }
452571 catch ( Exception e )
453572 {
573+ Log . LogError ( "Error occurred while writing target file {0}: {1}" , currentProject , e . Message ) ;
574+ Log . LogError ( "Stack trace: {0}" , e . StackTrace ) ;
575+
576+ // Output the generated file content for debugging
577+ if ( File . Exists ( targetsFile ) )
578+ {
579+ Log . LogError ( "Generated targets file content:" ) ;
580+ try
581+ {
582+ var content = File . ReadAllText ( targetsFile ) ;
583+ Log . LogError ( content ) ;
584+ }
585+ catch ( Exception readEx )
586+ {
587+ Log . LogError ( "Failed to read targets file for debugging: {0}" , readEx . Message ) ;
588+ }
589+ }
590+
454591 var badFile = targetsFile + ".bad" ;
455- File . Move ( targetsFile , badFile ) ;
456- Console . WriteLine ( "Failed to Create FieldWorks.targets bad result stored in {0}" , badFile ) ;
592+ try
593+ {
594+ if ( File . Exists ( badFile ) )
595+ File . Delete ( badFile ) ;
596+ File . Move ( targetsFile , badFile ) ;
597+ Log . LogMessage ( MessageImportance . High , "Failed to create FieldWorks.targets, bad result stored in {0}" , badFile ) ;
598+ Console . WriteLine ( "Failed to Create FieldWorks.targets bad result stored in {0}" , badFile ) ;
599+ }
600+ catch ( Exception moveEx )
601+ {
602+ Log . LogError ( "Failed to move bad targets file: {0}" , moveEx . Message ) ;
603+ }
604+
457605 throw new StopTaskException ( e ) ;
458606 }
459607 }
@@ -494,7 +642,7 @@ int TimeoutForProject(string project)
494642 }
495643 }
496644 }
497- return ( m_timeoutMap . ContainsKey ( project ) ? m_timeoutMap [ project ] : m_timeoutMap [ "default" ] ) * 1000 ;
645+ return ( m_timeoutMap . ContainsKey ( project ) ? m_timeoutMap [ project ] : m_timeoutMap [ "default" ] ) * 1000 ;
498646 }
499647 }
500648}
0 commit comments