diff --git a/CHANGELOG.md b/CHANGELOG.md index acdf77b..672b73a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,3 +5,4 @@ Once we have a solid base, we will bump to v1 without any breaking changes from * #13 Fixed export writing task confusing success and failure (Thanks, @filmor) * #10 Fixed a bug where loading a NXPorts enabled project in designtime build mode (e.g. Visual Studio) would be blocked by a failing AssemblyExportWriterTask * #14 NXPorts now removes the obsolete `NXPorts.Attributes.dll` from the build output +* Significantly increased logging output to support diagnosing issues when using NXPorts. diff --git a/src/NXPorts/AssemblyExportWriterTask.cs b/src/NXPorts/AssemblyExportWriterTask.cs index df36523..49224f7 100644 --- a/src/NXPorts/AssemblyExportWriterTask.cs +++ b/src/NXPorts/AssemblyExportWriterTask.cs @@ -24,11 +24,19 @@ public sealed class AssemblyExportWriterTask : Task public override bool Execute() { - using (var expAttributedAssembly = new ExportAttributedAssembly(InputAssembly)) + try { - Write(expAttributedAssembly, OutputPath); - return !Log.HasLoggedErrors; + using (var expAttributedAssembly = new ExportAttributedAssembly(InputAssembly)) + { + Log.LogMessage(MessageImportance.Normal, $"Found {expAttributedAssembly.ExportDefinitions.Count} annotated method(s) ready for reweaving."); + Write(expAttributedAssembly, OutputPath); + } + } + catch (Exception e) + { + Log.LogErrorFromException(e, true, true, null); } + return !Log.HasLoggedErrors; } public void Write(ExportAttributedAssembly sourceAssembly, string outputPath) @@ -40,6 +48,16 @@ public void Write(ExportAttributedAssembly sourceAssembly, string outputPath) { foreach (var exportDefinition in sourceAssembly.ExportDefinitions) { + var message = $"Reweaving method '{exportDefinition.MethodDefinition.FullName}' with alias '{exportDefinition.Alias}' and calling convention '{exportDefinition.CallingConvention}'"; + if (exportDefinition.TryApproximateMethodSourcePosition(out var sourcePosition)) { + Log.LogMessage( + subcategory: null, code: null, helpKeyword: null, + file: sourcePosition.FilePath, lineNumber: sourcePosition.Line ?? 0, columnNumber: sourcePosition.Column ?? 0, endLineNumber: 0, endColumnNumber: 0, + MessageImportance.Low, message + ); + } else { + Log.LogMessage(MessageImportance.Low, message); + } var returnType = exportDefinition.MethodDefinition.MethodSig.RetType; exportDefinition.MethodDefinition.ExportInfo = new MethodExportInfo(exportDefinition.Alias); exportDefinition.MethodDefinition.MethodSig.RetType = new CModOptSig( @@ -51,15 +69,17 @@ public void Write(ExportAttributedAssembly sourceAssembly, string outputPath) ); exportDefinition.MethodDefinition.CustomAttributes.RemoveAll(typeof(ExportAttribute).FullName); } + Log.LogMessage(MessageImportance.Low, "Clearing assembly of incompatible assembly flags."); RemoveToxicDebuggableAttribute(sourceAssembly.Module); - + Log.LogMessage(MessageImportance.Low, "Adjusting PE32 header to reflect the reweaving changes to the assembly file."); var moduleWriterOptions = new ModuleWriterOptions(sourceAssembly.Module); moduleWriterOptions.Cor20HeaderOptions.Flags = StrictenCor20HeaderFlags(moduleWriterOptions.Cor20HeaderOptions.Flags); moduleWriterOptions.Cor20HeaderOptions.Flags &= ~ComImageFlags.ILOnly; moduleWriterOptions.PEHeadersOptions.Characteristics |= Characteristics.Dll; - + Log.LogMessage(MessageImportance.Low, "Writing the new assembly file to disk..."); sourceAssembly.Module.Write(outputStream, moduleWriterOptions); } + Log.LogMessage(MessageImportance.Normal, $"Successfully rewritten assembly at '{outputPath}'."); } private static void RemoveToxicDebuggableAttribute(ModuleDefMD module) diff --git a/src/NXPorts/ExportDefinition.cs b/src/NXPorts/ExportDefinition.cs index be1bd95..8e728d3 100644 --- a/src/NXPorts/ExportDefinition.cs +++ b/src/NXPorts/ExportDefinition.cs @@ -69,19 +69,18 @@ public bool Equals(ExportDefinition other) public bool TryApproximateMethodSourcePosition(out SourcePosition sourcePosition) { - sourcePosition = new SourcePosition(String.Empty); + sourcePosition = null; var firstILInstruction = this.MethodDefinition.Body.Instructions.First(); var sequencePoint = firstILInstruction.SequencePoint; - if (sequencePoint != null) - return false; - else - { + if (sequencePoint != null) { sourcePosition = new SourcePosition( filePath: sequencePoint.Document.Url, line: sequencePoint.StartLine - 1, column: sequencePoint.StartColumn ); return true; + } else { + return false; } } } diff --git a/src/NXPorts/SourcePosition.cs b/src/NXPorts/SourcePosition.cs index e289820..cc5e145 100644 --- a/src/NXPorts/SourcePosition.cs +++ b/src/NXPorts/SourcePosition.cs @@ -1,3 +1,5 @@ +using System; + namespace NXPorts { public class SourcePosition { @@ -7,8 +9,8 @@ public class SourcePosition { public SourcePosition(string filePath) { - if (string.IsNullOrEmpty(filePath)) - throw new System.ArgumentException("message", nameof(filePath)); + if (filePath == null) + throw new ArgumentNullException(nameof(filePath)); this.FilePath = filePath; } diff --git a/tests/NXPorts.Tests/AssemblyExportWriter_Tests.cs b/tests/NXPorts.Tests/AssemblyExportWriter_Tests.cs index 4e95f4b..774ffde 100644 --- a/tests/NXPorts.Tests/AssemblyExportWriter_Tests.cs +++ b/tests/NXPorts.Tests/AssemblyExportWriter_Tests.cs @@ -1,4 +1,5 @@ using dnlib.DotNet; +using Microsoft.Build.Utilities.ProjectCreation; using Microsoft.VisualStudio.TestTools.UnitTesting; using NXPorts.Tests.Infrastructure; using PeNet; @@ -31,6 +32,7 @@ public static string DoSomething() using (var testExportAttributedAssembly = new ExportAttributedAssembly("./test.dll")) { var writer = new AssemblyExportWriterTask(); + writer.BuildEngine = BuildEngine.Create(); writer.Write(testExportAttributedAssembly, "./test.dll"); } @@ -62,6 +64,7 @@ public static void DoSomething() { } using (var testExportAttributedAssembly = new ExportAttributedAssembly("./test.dll")) { var writer = new AssemblyExportWriterTask(); + writer.BuildEngine = BuildEngine.Create(); writer.Write(testExportAttributedAssembly, "./test.dll"); } @@ -97,6 +100,7 @@ public static void DoSomething() using (var testExportAttributedAssembly = new ExportAttributedAssembly("./test.dll")) { var writer = new AssemblyExportWriterTask(); + writer.BuildEngine = BuildEngine.Create(); writer.Write(testExportAttributedAssembly, "./testOut.dll"); } diff --git a/tests/NXPorts.Tests/Infrastructure/TestEnvironment.cs b/tests/NXPorts.Tests/Infrastructure/TestEnvironment.cs index f9b580c..9aa8a39 100644 --- a/tests/NXPorts.Tests/Infrastructure/TestEnvironment.cs +++ b/tests/NXPorts.Tests/Infrastructure/TestEnvironment.cs @@ -3,6 +3,8 @@ using System.IO; using System.Linq; using System.Reflection; +using Buildalyzer; +using Buildalyzer.Environment; using Microsoft.Build.Utilities.ProjectCreation; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; @@ -83,6 +85,27 @@ public void CopyFileFromTestFiles(string relativeTestFilesPath) { CopyFileFromTestFiles(relativeTestFilesPath, relativeTestFilesPath); } + + public (AnalyzerResults AnalyzerResults, string log) Build(string projectFilePath, bool designTime = false) + { + using(var logWriter = new StringWriter()) + { + var analyzerResults = new AnalyzerManager( + new AnalyzerManagerOptions() + { + LogWriter = logWriter + } + ).GetProject(projectFilePath).Build( + new EnvironmentOptions() + { + DesignTime = designTime + } + ); + return (analyzerResults, logWriter.ToString()); + } + } + + private static string GetApplicationDirectory() { return new Uri(Path.GetDirectoryName(Assembly.GetAssembly(typeof(TestEnvironment)).CodeBase)).LocalPath; diff --git a/tests/NXPorts.Tests/SdkBasedCSProjTests.cs b/tests/NXPorts.Tests/SdkBasedCSProjTests.cs index b5e7121..0ee5ef8 100644 --- a/tests/NXPorts.Tests/SdkBasedCSProjTests.cs +++ b/tests/NXPorts.Tests/SdkBasedCSProjTests.cs @@ -18,14 +18,9 @@ public void Building_a_simple_SDK_based_project_with_exports_succeeds() testEnv.SetupNXPortsProject("./sdknet48.csproj").Save(); testEnv.CopyFileFromTestFiles("Simple.cs"); - var results = new AnalyzerManager().GetProject("./sdknet48.csproj").Build( - new EnvironmentOptions() - { - DesignTime = false - } - ); + var results = testEnv.Build("./sdknet48.csproj"); + Assert.IsTrue(results.AnalyzerResults.OverallSuccess, "The build failed."); - Assert.IsTrue(results.OverallSuccess); var buildOutputFile = new PeFile("./bin/debug/net48/sdknet48.dll"); Assert.AreEqual(1, buildOutputFile.ExportedFunctions.Length, "There is more or less than one export function listed in the resulting dll."); Assert.AreEqual("DoSomething", buildOutputFile.ExportedFunctions[0].Name); @@ -40,14 +35,9 @@ public void Designtime_builds_of_NXPorts_enabled_projects_do_not_error() testEnv.SetupNXPortsProject("./sdknet48.csproj").Save(); testEnv.CopyFileFromTestFiles("Simple.cs"); - var results = new AnalyzerManager().GetProject("./sdknet48.csproj").Build( - new EnvironmentOptions() - { - DesignTime = true - } - ); + var results = testEnv.Build("./sdknet48.csproj", true); - Assert.IsTrue(results.OverallSuccess); + Assert.IsTrue(results.AnalyzerResults.OverallSuccess, "The designtime build failed."); } } @@ -59,22 +49,20 @@ public void The_attributes_assembly_file_does_not_end_up_in_the_build_output() testEnv.SetupNXPortsProject("./sdknet48.csproj").Save(); testEnv.CopyFileFromTestFiles("Simple.cs"); - var results = new AnalyzerManager().GetProject("./sdknet48.csproj").Build( - new EnvironmentOptions() - { - DesignTime = false - } - ); - Assert.IsTrue(results.OverallSuccess); - if(results.TryGetTargetFramework("net48", out var net48results)) + var results = testEnv.Build("./sdknet48.csproj"); + Assert.IsTrue(results.AnalyzerResults.OverallSuccess, "The build failed."); + if (results.AnalyzerResults.TryGetTargetFramework("net48", out var net48results)) { Assert.IsFalse( - File.Exists(Path.Combine(Path.GetDirectoryName(net48results.ProjectFilePath),"bin/debug/net48/NXPorts.Attributes.dll")), + File.Exists(Path.Combine(Path.GetDirectoryName(net48results.ProjectFilePath), "bin/debug/net48/NXPorts.Attributes.dll")), "NXPorts wasn't removed the from the build output." ); - } else { + } + else + { Assert.Inconclusive("Failed to retrieve build results"); } + } } }