IKVM11  11
Java SE 11 Virtual Machine for .NET
Loading...
Searching...
No Matches
IkvmExporterLauncher.cs
Go to the documentation of this file.
1using System;
2using System.Collections.Generic;
3using System.Diagnostics;
4using System.IO;
5using System.Linq;
6using System.Runtime.InteropServices;
7using System.Threading;
8using System.Threading.Tasks;
9
10using CliWrap;
11
14
16{
17
22 {
23
24 static readonly string TOOLNAME = "ikvmstub";
25 static readonly string TOOLPATH = typeof(IkvmExporterLauncher).Assembly.Location is string s ? Path.GetDirectoryName(s) ?? "" : "";
26
32 public IkvmExporterLauncher(string toolPath, IIkvmToolDiagnosticEventListener listener) :
33 base(TOOLNAME, toolPath, listener)
34 {
35
36 }
37
43 this(TOOLPATH, listener)
44 {
45
46 }
47
52 public IkvmExporterLauncher(string toolPath) :
53 this(toolPath, new IkvmToolNullDiagnosticListener())
54 {
55
56 }
57
65 public async Task<int> ExecuteAsync(IkvmExporterOptions options, CancellationToken cancellationToken = default)
66 {
67 if (options is null)
68 throw new ArgumentNullException(nameof(options));
69
70 var args = new List<string>();
71
72 if (options.Output is not null)
73 {
74 args.Add("--out");
75 args.Add(options.Output);
76 }
77
78 if (options.References is not null)
79 {
80 foreach (var reference in options.References)
81 {
82 args.Add("--reference");
83 args.Add(reference);
84 }
85 }
86
87 if (options.Namespaces is not null)
88 {
89 foreach (var ns in options.Namespaces)
90 {
91 args.Add("--ns");
92 args.Add(ns);
93 }
94 }
95
96 if (options.Shared)
97 args.Add("--shared");
98
99 if (options.NoStdLib)
100 args.Add("--nostdlib");
101
102 if (options.Forwarders)
103 args.Add("--forwarders");
104
105 if (options.IncludeNonPublicTypes)
106 args.Add("--non-public-types");
107
108 if (options.IncludeNonPublicInterfaces)
109 args.Add("--non-public-interfaces");
110
111 if (options.IncludeNonPublicMembers)
112 args.Add("--non-public-members");
113
114 if (options.IncludeParameterNames)
115 args.Add("--parameters");
116
117 if (options.Bootstrap)
118 args.Add("--bootstrap");
119
120 if (options.Lib is not null)
121 {
122 foreach (var i in options.Lib)
123 {
124 args.Add("--lib");
125 args.Add(i);
126 }
127 }
128
129 if (options.ContinueOnError)
130 args.Add("--skiperror");
131
132 args.Add("--log");
133 args.Add("json,file=stderr");
134
135 if (options.Input is not null)
136 args.Add(options.Input);
137
138 // path to the temporary response file
139 var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, new CancellationToken());
140
141 // combine manual cancellation with timeout
142 var ctk = cts.Token;
143 if (options.Timeout != Timeout.Infinite)
144 ctk = CancellationTokenSource.CreateLinkedTokenSource(ctk, new CancellationTokenSource(options.Timeout).Token).Token;
145
146 try
147 {
148 // locate EXE file
149 string? wrap = null;
150 var exe = GetToolExe();
151 if (exe is null || File.Exists(exe) == false)
152 throw new FileNotFoundException($"Could not locate tool at '{exe}'.");
153
154 // executing on Unix requires some considerations
155 if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) || RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
156 {
157 // tool executables on Unix need to be invoked through Mono
158 if (exe.EndsWith(".exe"))
159 {
160 wrap = "mono";
161 }
162 else
163 {
164 // else we need to ensure executable bit is set
165
166 try
167 {
168 var psx = Mono.Unix.UnixFileSystemInfo.GetFileSystemEntry(exe);
169 if (psx.FileAccessPermissions.HasFlag(Mono.Unix.FileAccessPermissions.UserExecute) == false)
170 psx.FileAccessPermissions |= Mono.Unix.FileAccessPermissions.UserExecute;
171 }
172 catch (Exception e)
173 {
174 throw new IkvmToolException($"Could not set user executable bit on '{exe}'.", e);
175 }
176 }
177 }
178
179 // configure CLI, with wrapper if required
180 Command cli;
181 if (wrap != null)
182 {
183 cli = Cli.Wrap(wrap);
184 args.Insert(0, exe);
185 }
186 else
187 cli = Cli.Wrap(exe);
188
189 // set configuration of CLI
190 cli = cli.WithWorkingDirectory(Environment.CurrentDirectory);
191 cli = cli.WithArguments(args);
192 cli = cli.WithValidation(CommandResultValidation.None);
193
194 // log the command we're about to run
195 await LogEventAsync(IkvmToolDiagnosticEventLevel.Trace, "Executing {0} {1}", [cli.TargetFilePath, cli.Arguments], ctk);
196
197 // send output to MSBuild (TODO, replace with binary reading)
198 cli = cli.WithStandardErrorPipe(PipeTarget.ToDelegate(l => ParseAndLogEventAsync(l, cancellationToken).AsTask()));
199
200 // execute command
201 var pid = cli.ExecuteAsync(ctk);
202
203 // windows provides special support for killing subprocesses on termination of parent
204 if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
205 try
206 {
207 if (pid.Task.IsCompleted == false)
208 WindowsChildProcessTracker.AddProcess(Process.GetProcessById(pid.ProcessId));
209 }
210 catch
211 {
212 await LogEventAsync(IkvmToolDiagnosticEventLevel.Error, "Failed to attach child process.", [], ctk);
213 }
214
215 // wait for the execution to finish
216 var ret = await pid;
217
218 // check that we exited successfully
219 return ret.ExitCode;
220 }
221 finally
222 {
223 // cancel the execution if it is still running
224 if (cts != null)
225 cts.Cancel();
226 }
227 }
228
229 }
230
231}
Diagnostic listener that invokes a delegate for each event.
Provides methods to launch the IKVM importer.
async Task< int > ExecuteAsync(IkvmExporterOptions options, CancellationToken cancellationToken=default)
Executes the compiler.
IkvmExporterLauncher(string toolPath, IIkvmToolDiagnosticEventListener listener)
Initializes a new instance.
IkvmExporterLauncher(IIkvmToolDiagnosticEventListener listener)
Initializes a new instance.
IkvmExporterLauncher(string toolPath)
Initializes a new instance.
Options available to the IKVM importer tool.
IList< string > References
Set of paths to assemblies to add as references.
bool IncludeNonPublicInterfaces
Whether to emit non-public interface implementations.
bool ContinueOnError
Continue when errors are encountered.
bool Shared
Process all assemblies in shared group.
bool IncludeNonPublicMembers
Whether to emit non-public members.
List< string > Namespaces
Only include types from specified namespaces.
IList< string > Lib
Additional directories to search for references.
bool IncludeNonPublicTypes
Whether to emit non-public types.
bool NoStdLib
Do not reference standard libraries.
bool IncludeParameterNames
Emit Java 8 classes with parameter names.
int Timeout
Number of milliseconds to wait for the command to execute.
string? GetToolExe()
Gets the path to executable for the given environment.
ValueTask ParseAndLogEventAsync(string line, CancellationToken cancellationToken)
Parses the line and logs it.
ValueTask LogEventAsync(in IkvmToolDiagnosticEvent @event, CancellationToken cancellationToken)
Logs an event if a listener is provided.
Allows processes to be automatically killed if this parent process unexpectedly quits....
static void AddProcess(Process process)
Add the process to be tracked. If our current process is killed, the child processes that we are trac...
IkvmToolDiagnosticEventLevel
Describes the level of diagnostic event a tool could emit.