diff --git a/src/IKVM.MSBuild.Tasks/IkvmCompiler.cs b/src/IKVM.MSBuild.Tasks/IkvmCompiler.cs index 5258b160b8..1c84a19ea7 100644 --- a/src/IKVM.MSBuild.Tasks/IkvmCompiler.cs +++ b/src/IKVM.MSBuild.Tasks/IkvmCompiler.cs @@ -35,30 +35,63 @@ public class IkvmCompiler : IkvmToolExecTask [Required] public string Output { get; set; } + /// + /// Name of the assembly to output. + /// public string Assembly { get; set; } + /// + /// Version of the assembly to output. + /// public string Version { get; set; } + /// + /// Target type of the assembly to output. + /// public string Target { get; set; } + /// + /// Platform of the assembly to output. + /// public string Platform { get; set; } + /// + /// Key file with which to strong name the generated assembly. + /// public string KeyFile { get; set; } + /// + /// Key with which to strong name the generated assembly. + /// public string Key { get; set; } public bool DelaySign { get; set; } + /// + /// References to use when compiling. + /// public ITaskItem[] References { get; set; } public ITaskItem[] Recurse { get; set; } + /// + /// Path to class exclusion file. + /// public string Exclude { get; set; } + /// + /// File version of assembly to output. + /// public string FileVersion { get; set; } + /// + /// Path to the Win32 icon file. + /// public string Win32Icon { get; set; } + /// + /// Path to the Win32 manifest file. + /// public string Win32Manifest { get; set; } public ITaskItem[] Resources { get; set; } @@ -123,19 +156,88 @@ public class IkvmCompiler : IkvmToolExecTask public bool Static { get; set; } + /// + /// Paths to the assembly attributes file. + /// public ITaskItem[] AssemblyAttributes { get; set; } + /// + /// Path to the IKVM.Runtime assembly to incorporate. + /// public string Runtime { get; set; } - public string JNI { get; set; } - public string WarningLevel { get; set; } public bool NoParameterReflection { get; set; } + /// + /// Path to the map.xml file to use. + /// public string Remap { get; set; } - string GetAbsolutePathIfNotNull(string path) => path != null ? Path.GetFullPath(path) : null; + public override bool Execute() + { + if (ResponseFile != null) + ResponseFile = Path.GetFullPath(ResponseFile); + + if (Output != null) + Output = Path.GetFullPath(Output); + + if (KeyFile != null) + KeyFile = Path.GetFullPath(KeyFile); + + if (References != null) + foreach (var reference in References) + if (reference.ItemSpec != null) + reference.ItemSpec = Path.GetFullPath(reference.ItemSpec); + + if (Lib != null) + foreach (var lib in Lib) + if (lib.ItemSpec != null) + lib.ItemSpec = Path.GetFullPath(lib.ItemSpec); + + if (Resources != null) + foreach (var i in Resources) + if (i.ItemSpec != null) + i.ItemSpec = Path.GetFullPath(i.ItemSpec); + + if (ExternalResources != null) + foreach (var i in ExternalResources) + if (i.ItemSpec != null) + i.ItemSpec = Path.GetFullPath(i.ItemSpec); + + if (AssemblyAttributes != null) + foreach (var i in AssemblyAttributes) + if (i.ItemSpec != null) + i.ItemSpec = Path.GetFullPath(i.ItemSpec); + + if (Runtime != null) + Runtime = Path.GetFullPath(Runtime); + + if (Remap != null) + Remap = Path.GetFullPath(Remap); + + if (Input != null) + foreach (var i in Input) + if (i.ItemSpec != null) + i.ItemSpec = Path.GetFullPath(i.ItemSpec); + + if (Recurse != null) + foreach (var i in Recurse) + if (i.ItemSpec != null) + i.ItemSpec = Path.GetFullPath(i.ItemSpec); + + if (Exclude != null) + Exclude = Path.GetFullPath(Exclude); + + if (Win32Icon != null) + Win32Icon = Path.GetFullPath(Win32Icon); + + if (Win32Manifest != null) + Win32Manifest = Path.GetFullPath(Win32Manifest); + + return base.Execute(); + } protected override async Task ExecuteAsync(IkvmToolTaskDiagnosticWriter writer, CancellationToken cancellationToken) { @@ -146,8 +248,8 @@ protected override async Task ExecuteAsync(IkvmToolTaskDiagnosticWriter wr } var options = new IkvmImporterOptions(); - options.ResponseFile = GetAbsolutePathIfNotNull(ResponseFile); - options.Output = GetAbsolutePathIfNotNull(Output); + options.ResponseFile = ResponseFile; + options.Output = Output; options.Assembly = Assembly; options.Version = Version; @@ -173,16 +275,16 @@ protected override async Task ExecuteAsync(IkvmToolTaskDiagnosticWriter wr _ => throw new NotImplementedException(), }; - options.KeyFile = GetAbsolutePathIfNotNull(KeyFile); + options.KeyFile = KeyFile; options.Key = Key; options.DelaySign = DelaySign; - if (References is not null) - foreach (var reference in References.Select(i => GetAbsolutePathIfNotNull(i.ItemSpec))) - if (options.References.Contains(reference) == false) - options.References.Add(reference); + if (References != null) + foreach (var reference in References) + if (options.References.Contains(reference.ItemSpec) == false) + options.References.Add(reference.ItemSpec); - if (Recurse is not null) + if (Recurse != null) foreach (var recurse in Recurse) options.Recurse.Add(recurse.ItemSpec); @@ -193,11 +295,11 @@ protected override async Task ExecuteAsync(IkvmToolTaskDiagnosticWriter wr if (Resources is not null) foreach (var resource in Resources) - options.Resources.Add(new IkvmImporterResourceItem(GetAbsolutePathIfNotNull(resource.ItemSpec), resource.GetMetadata("ResourcePath"))); + options.Resources.Add(new IkvmImporterResourceItem(resource.ItemSpec, resource.GetMetadata("ResourcePath"))); if (ExternalResources is not null) foreach (var resource in ExternalResources) - options.ExternalResources.Add(new IkvmImporterExternalResourceItem(GetAbsolutePathIfNotNull(resource.ItemSpec), resource.GetMetadata("ResourcePath"))); + options.ExternalResources.Add(new IkvmImporterExternalResourceItem(resource.ItemSpec, resource.GetMetadata("ResourcePath"))); options.CompressResources = CompressResources; options.Debug = Debug; @@ -208,13 +310,13 @@ protected override async Task ExecuteAsync(IkvmToolTaskDiagnosticWriter wr options.RemoveAssertions = RemoveAssertions; options.StrictFinalFieldSemantics = StrictFinalFieldSemantics; - if (NoWarn is not null) + if (NoWarn != null) foreach (var i in NoWarn.Split(';')) options.NoWarn.Add(i); options.WarnAsError = WarnAsError; - if (WarnAsErrorWarnings is not null) + if (WarnAsErrorWarnings != null) foreach (var i in WarnAsErrorWarnings.Split(';')) options.WarnAsErrorWarnings.Add(i); @@ -223,21 +325,21 @@ protected override async Task ExecuteAsync(IkvmToolTaskDiagnosticWriter wr options.SrcPath = SrcPath; options.Apartment = Apartment; - if (SetProperties is not null) + if (SetProperties != null) foreach (var p in SetProperties.Split(new[] { ';' }).Select(i => i.Split(new[] { '=' }, 2))) options.SetProperties[p[0]] = p.Length == 2 ? p[1] : ""; options.NoStackTraceInfo = NoStackTraceInfo; - if (XTrace is not null) + if (XTrace != null) foreach (var i in XTrace.Split(';')) options.XTrace.Add(i); - if (XMethodTrace is not null) + if (XMethodTrace != null) foreach (var i in XMethodTrace.Split(';')) options.XMethodTrace.Add(i); - if (PrivatePackages is not null) + if (PrivatePackages != null) foreach (var i in PrivatePackages.Split(';')) options.PrivatePackages.Add(i); @@ -248,29 +350,29 @@ protected override async Task ExecuteAsync(IkvmToolTaskDiagnosticWriter wr options.NoPeerCrossReference = NoPeerCrossReference; options.NoStdLib = NoStdLib; - if (Lib is not null) + if (Lib != null) foreach (var i in Lib) - options.Lib.Add(GetAbsolutePathIfNotNull(i.ItemSpec)); + options.Lib.Add(i.ItemSpec); options.HighEntropyVA = HighEntropyVA; options.Static = Static; - if (AssemblyAttributes is not null) + if (AssemblyAttributes != null) foreach (var i in AssemblyAttributes) options.AssemblyAttributes.Add(i.ItemSpec); - options.Runtime = GetAbsolutePathIfNotNull(Runtime); + options.Runtime = Runtime; - if (options.WarningLevel is not null) + if (options.WarningLevel != null) options.WarningLevel = int.Parse(WarningLevel); options.NoParameterReflection = NoParameterReflection; - options.Remap = GetAbsolutePathIfNotNull(Remap); + options.Remap = Remap; options.NoLogo = true; if (Input != null) foreach (var i in Input) - options.Input.Add(GetAbsolutePathIfNotNull(i.ItemSpec)); + options.Input.Add(i.ItemSpec); // kick off the launcher with the configured options return await new IkvmImporterLauncher(ToolPath, writer).ExecuteAsync(options, cancellationToken) == 0; diff --git a/src/IKVM.MSBuild.Tasks/IkvmExporter.cs b/src/IKVM.MSBuild.Tasks/IkvmExporter.cs index 33728f5753..bb9b87754b 100644 --- a/src/IKVM.MSBuild.Tasks/IkvmExporter.cs +++ b/src/IKVM.MSBuild.Tasks/IkvmExporter.cs @@ -1,4 +1,5 @@ -using System.Threading; +using System.IO; +using System.Threading; using System.Threading.Tasks; using IKVM.Tools.Runner.Exporter; @@ -59,6 +60,27 @@ public class IkvmExporter : IkvmToolExecTask public bool Bootstrap { get; set; } + public override bool Execute() + { + if (Input != null) + Input = Path.GetFullPath(Input); + + if (Output != null) + Output = Path.GetFullPath(Output); + + if (References != null) + foreach (var i in References) + if (i.ItemSpec != null) + i.ItemSpec = Path.GetFullPath(i.ItemSpec); + + if (Lib != null) + foreach (var i in Lib) + if (i.ItemSpec != null) + i.ItemSpec = Path.GetFullPath(i.ItemSpec); + + return base.Execute(); + } + protected override async Task ExecuteAsync(IkvmToolTaskDiagnosticWriter writer, CancellationToken cancellationToken) { var options = new IkvmExporterOptions(); diff --git a/src/IKVM.MSBuild.Tasks/IkvmJavaCompiler.cs b/src/IKVM.MSBuild.Tasks/IkvmJavaCompiler.cs index 094de33f70..26e17b25e0 100644 --- a/src/IKVM.MSBuild.Tasks/IkvmJavaCompiler.cs +++ b/src/IKVM.MSBuild.Tasks/IkvmJavaCompiler.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading; using com.sun.tools.javac.util; @@ -19,31 +20,182 @@ namespace IKVM.MSBuild.Tasks /// /// Executes the Java compiler. /// - public class IkvmJavaCompiler : Microsoft.Build.Utilities.Task + public class IkvmJavaCompiler : Task { + /// + /// Implements . + /// + class MSBuildDiagnosticListener : DiagnosticListener + { + + readonly TaskLoggingHelper log; + + /// + /// Initializes a new instance. + /// + /// + /// + public MSBuildDiagnosticListener(TaskLoggingHelper log) + { + this.log = log ?? throw new ArgumentNullException(nameof(log)); + } + + public void report(Diagnostic diagnostic) + { + var kind = diagnostic.getKind(); + var code = diagnostic.getCode(); + var source = diagnostic.getSource() is DiagnosticSource f ? f.getFile().toUri().getPath() : null; + var startPosition = (int)diagnostic.getStartPosition(); + var columnNumber = (int)diagnostic.getColumnNumber(); + var endPosition = (int)diagnostic.getEndPosition(); + var message = diagnostic.getMessage(Locale.getDefault()) ?? "unknown"; + + if (kind == Diagnostic.Kind.ERROR) + log.LogError(null, code, null, source, startPosition, columnNumber, endPosition, -1, message); + else if (kind == Diagnostic.Kind.WARNING || kind == Diagnostic.Kind.MANDATORY_WARNING) + log.LogWarning(null, code, null, source, startPosition, columnNumber, endPosition, -1, message); + else + log.LogMessage(null, code, null, source, startPosition, columnNumber, endPosition, -1, MessageImportance.Normal, message); + } + + } + + readonly CancellationTokenSource cts; + + /// + /// Initializes a new instance. + /// + public IkvmJavaCompiler() + { + cts = new CancellationTokenSource(); + } + + /// + /// Classpath for compiler. + /// [Required] public ITaskItem[] Classpath { get; set; } + /// + /// Source files to compile. + /// [Required] public ITaskItem[] Sources { get; set; } + /// + /// Path to place the generated class files. + /// [Required] public string Destination { get; set; } + /// + /// Path to place the generated JNI header files. + /// public string HeaderDestination { get; set; } + /// + /// Whether to enable debug output of the compiler. + /// public string Debug { get; set; } + /// + /// If true disables warning messages. + /// public bool NoWarn { get; set; } + /// + /// Whether to enable verbose output of the compiler. + /// public bool Verbose { get; set; } + /// + /// Source version. + /// public string Source { get; set; } + /// + /// Target version. + /// public string Target { get; set; } + /// + /// Executes the Java compiler. + /// + /// public override bool Execute() + { + if (Classpath != null) + foreach (var i in Classpath) + if (i.ItemSpec != null) + i.ItemSpec = System.IO.Path.GetFullPath(i.ItemSpec); + + if (Sources != null) + foreach (var i in Sources) + if (i.ItemSpec != null) + i.ItemSpec = System.IO.Path.GetFullPath(i.ItemSpec); + + if (Destination != null) + Destination = System.IO.Path.GetFullPath(Destination); + + if (HeaderDestination != null) + HeaderDestination = System.IO.Path.GetFullPath(HeaderDestination); + + if (cts.IsCancellationRequested) + return false; + + // wait for result, and ensure we reacquire in case of return value or exception + System.Threading.Tasks.Task run; + + try + { + // kick off the launcher with the configured options + run = ExecuteAsync(cts.Token); + if (run.IsCompleted) + return run.GetAwaiter().GetResult(); + } + catch (OperationCanceledException) + { + return false; + } + + // yield and wait for the task to complete + BuildEngine3.Yield(); + + var result = false; + try + { + result = run.GetAwaiter().GetResult(); + } + catch (OperationCanceledException) + { + return false; + } + finally + { + BuildEngine3.Reacquire(); + } + + // check that we exited successfully + return result; + } + + /// + /// Execute the Java compiler in a separate thread. + /// + /// + /// + public System.Threading.Tasks.Task ExecuteAsync(CancellationToken cancellationToken) + { + return System.Threading.Tasks.Task.Run(Compile); + } + + /// + /// Executes the compiler. + /// + /// + /// + bool Compile() { var diagnostics = new MSBuildDiagnosticListener(Log); var javacArgLog = new List(); @@ -60,7 +212,7 @@ public override bool Execute() throw new IkvmTaskException("Invalid destination."); // create destination directory - var destination = new File(System.IO.Path.GetFullPath(Destination)); + var destination = new File(Destination); destination.mkdirs(); // set output path @@ -71,7 +223,7 @@ public override bool Execute() if (string.IsNullOrWhiteSpace(HeaderDestination) == false) { // create destination directory - var headerDestination = new File(System.IO.Path.GetFullPath(HeaderDestination)); + var headerDestination = new File(HeaderDestination); headerDestination.mkdirs(); // set header output path @@ -81,7 +233,7 @@ public override bool Execute() } // get set of source items to compile - var compilationUnits = fileManager.getJavaFileObjectsFromFiles(Arrays.asList(Sources.Select(i => new File(System.IO.Path.GetFullPath(i.ItemSpec))).Cast().ToArray())); + var compilationUnits = fileManager.getJavaFileObjectsFromFiles(Arrays.asList(Sources.Select(i => new File(i.ItemSpec)).Cast().ToArray())); foreach (var i in Sources) javacArgLog.Add($"\"{System.IO.Path.GetFullPath(i.ItemSpec)}\""); @@ -142,7 +294,7 @@ public override bool Execute() { var cp = new ArrayList(); foreach (var i in Classpath) - cp.add(new File(System.IO.Path.GetFullPath(i.ItemSpec))); + cp.add(new File(i.ItemSpec)); fileManager.setLocation(StandardLocation.CLASS_PATH, cp); javacArgLog.Add("-cp"); @@ -152,53 +304,13 @@ public override bool Execute() // emit log about command Log.LogMessage(MessageImportance.Low, $"javac {string.Join(" ", javacArgLog)}"); - // yield and wait for the task to complete - BuildEngine3.Yield(); + // initiate compiler and wait for result var rsl = compiler.getTask(null, fileManager, diagnostics, options.size() > 0 ? options : null, null, compilationUnits).call(); - BuildEngine3.Reacquire(); // result indicates status return rsl?.booleanValue() ?? false; } - /// - /// Implements . - /// - class MSBuildDiagnosticListener : DiagnosticListener - { - - readonly TaskLoggingHelper log; - - /// - /// Initializes a new instance. - /// - /// - /// - public MSBuildDiagnosticListener(TaskLoggingHelper log) - { - this.log = log ?? throw new ArgumentNullException(nameof(log)); - } - - public void report(Diagnostic diagnostic) - { - var kind = diagnostic.getKind(); - var code = diagnostic.getCode(); - var source = diagnostic.getSource() is DiagnosticSource f ? f.getFile().toUri().getPath() : null; - var startPosition = (int)diagnostic.getStartPosition(); - var columnNumber = (int)diagnostic.getColumnNumber(); - var endPosition = (int)diagnostic.getEndPosition(); - var message = diagnostic.getMessage(Locale.getDefault()) ?? "unknown"; - - if (kind == Diagnostic.Kind.ERROR) - log.LogError(null, code, null, source, startPosition, columnNumber, endPosition, -1, message); - else if (kind == Diagnostic.Kind.WARNING || kind == Diagnostic.Kind.MANDATORY_WARNING) - log.LogWarning(null, code, null, source, startPosition, columnNumber, endPosition, -1, message); - else - log.LogMessage(null, code, null, source, startPosition, columnNumber, endPosition, -1, MessageImportance.Normal, message); - } - - } - } } diff --git a/src/IKVM.MSBuild.Tasks/IkvmReferenceExportItemPrepare.cs b/src/IKVM.MSBuild.Tasks/IkvmReferenceExportItemPrepare.cs index df28e4a6b4..05705e4f49 100644 --- a/src/IKVM.MSBuild.Tasks/IkvmReferenceExportItemPrepare.cs +++ b/src/IKVM.MSBuild.Tasks/IkvmReferenceExportItemPrepare.cs @@ -20,7 +20,6 @@ public class IkvmReferenceExportItemPrepare : Microsoft.Build.Utilities.Task, ICancelableTask { - const string XML_ROOT_ELEMENT_NAME = "IkvmReferenceExportItemPrepareState"; const string XML_ASSEMBLY_INFO_STATE_ELEMENT_NAME = "AssemblyInfoState"; const string XML_FILE_IDENTITY_STATE_ELEMENT_NAME = "FileIdentityState"; @@ -91,6 +90,9 @@ public IkvmReferenceExportItemPrepare() /// public override bool Execute() { + if (StateFile != null) + StateFile = Path.GetFullPath(StateFile); + if (cts.IsCancellationRequested) return false; diff --git a/src/IKVM.MSBuild.Tasks/IkvmReferenceItemPrepare.cs b/src/IKVM.MSBuild.Tasks/IkvmReferenceItemPrepare.cs index 6f2722da7a..a1b4d8801c 100644 --- a/src/IKVM.MSBuild.Tasks/IkvmReferenceItemPrepare.cs +++ b/src/IKVM.MSBuild.Tasks/IkvmReferenceItemPrepare.cs @@ -153,6 +153,9 @@ public IkvmReferenceItemPrepare() : /// public override bool Execute() { + if (StateFile != null) + StateFile = Path.GetFullPath(StateFile); + if (cts.IsCancellationRequested) return false; diff --git a/src/IKVM.MSBuild.Tasks/IkvmToolExecTask.cs b/src/IKVM.MSBuild.Tasks/IkvmToolExecTask.cs index 7082ca4a47..ac1d3f6f4d 100644 --- a/src/IKVM.MSBuild.Tasks/IkvmToolExecTask.cs +++ b/src/IKVM.MSBuild.Tasks/IkvmToolExecTask.cs @@ -76,6 +76,12 @@ public IkvmToolExecTask() /// public override bool Execute() { + // normalize paths due to yields potential of allowing continuation after CWD change + if (ToolPath != null) + ToolPath = Path.GetFullPath(ToolPath); + if (LogFile != null) + LogFile = Path.GetFullPath(LogFile); + if (cts.IsCancellationRequested) return false; diff --git a/src/IKVM.NET.Sdk/targets/IKVM.Java.Core.targets b/src/IKVM.NET.Sdk/targets/IKVM.Java.Core.targets index 5f394932cf..4bd9c3aae3 100644 --- a/src/IKVM.NET.Sdk/targets/IKVM.Java.Core.targets +++ b/src/IKVM.NET.Sdk/targets/IKVM.Java.Core.targets @@ -14,7 +14,6 @@ <_IkvmReferenceExportItemPrepareStateFile Condition=" '$(_IkvmReferenceExportItemPrepareStateFile)' == '' ">$(IntermediateOutputPath)$(MSBuildProjectFile).IkvmReferenceExportItemPrepare.state - <_IkvmReferenceExportItemPrepareStateFile>$([System.IO.Path]::GetFullPath('$(_IkvmReferenceExportItemPrepareStateFile)'))