22using System . Collections . Generic ;
33using System . Diagnostics ;
44using System . IO ;
5- using System . Threading ;
65
76using Microsoft . Build . Framework ;
8- using Microsoft . Build . Utilities ;
9-
10- using Xamarin . Android . Tools ;
117using Microsoft . Android . Build . Tasks ;
128
139namespace Xamarin . Android . Tasks
@@ -16,13 +12,6 @@ public class CompileNativeAssembly : AsyncTask
1612 {
1713 public override string TaskPrefix => "CNA" ;
1814
19- sealed class Config
20- {
21- public string AssemblerPath ;
22- public string AssemblerOptions ;
23- public string InputSource ;
24- }
25-
2615 [ Required ]
2716 public ITaskItem [ ] Sources { get ; set ; }
2817
@@ -37,124 +26,34 @@ sealed class Config
3726
3827 public override System . Threading . Tasks . Task RunTaskAsync ( )
3928 {
40- return this . WhenAll ( GetAssemblerConfigs ( ) , RunAssembler ) ;
29+ var context = new NativeAssemblerCompilation . AssemblerRunContext (
30+ Log ,
31+ Path . GetFullPath ( WorkingDirectory ) ,
32+ registerForCancellation : RegisterForCancellation ,
33+ cancel : Cancel
34+ ) ;
35+
36+ return this . WhenAll (
37+ GetAssemblerConfigs ( ) ,
38+ ( NativeAssemblerCompilation . AssemblerConfig config ) => NativeAssemblerCompilation . RunAssembler ( context , config )
39+ ) ;
4140 }
4241
43- void RunAssembler ( Config config )
42+ void RegisterForCancellation ( Process proc )
4443 {
45- var stdout_completed = new ManualResetEvent ( false ) ;
46- var stderr_completed = new ManualResetEvent ( false ) ;
47- var psi = new ProcessStartInfo ( ) {
48- FileName = config . AssemblerPath ,
49- Arguments = config . AssemblerOptions ,
50- UseShellExecute = false ,
51- RedirectStandardOutput = true ,
52- RedirectStandardError = true ,
53- CreateNoWindow = true ,
54- WindowStyle = ProcessWindowStyle . Hidden ,
55- WorkingDirectory = WorkingDirectory ,
56- } ;
57-
58- string assemblerName = Path . GetFileName ( config . AssemblerPath ) ;
59- LogDebugMessage ( $ "[LLVM llc] { psi . FileName } { psi . Arguments } ") ;
60-
61- var stdoutLines = new List < string > ( ) ;
62- var stderrLines = new List < string > ( ) ;
63-
64- using ( var proc = new Process ( ) ) {
65- proc . OutputDataReceived += ( s , e ) => {
66- if ( e . Data != null ) {
67- OnOutputData ( assemblerName , s , e ) ;
68- stdoutLines . Add ( e . Data ) ;
69- } else
70- stdout_completed . Set ( ) ;
71- } ;
72-
73- proc . ErrorDataReceived += ( s , e ) => {
74- if ( e . Data != null ) {
75- OnErrorData ( assemblerName , s , e ) ;
76- stderrLines . Add ( e . Data ) ;
77- } else
78- stderr_completed . Set ( ) ;
79- } ;
80-
81- proc . StartInfo = psi ;
82- proc . Start ( ) ;
83- proc . BeginOutputReadLine ( ) ;
84- proc . BeginErrorReadLine ( ) ;
85- CancellationToken . Register ( ( ) => { try { proc . Kill ( ) ; } catch ( Exception ) { } } ) ;
86- proc . WaitForExit ( ) ;
87-
88- if ( psi . RedirectStandardError )
89- stderr_completed . WaitOne ( TimeSpan . FromSeconds ( 30 ) ) ;
90-
91- if ( psi . RedirectStandardOutput )
92- stdout_completed . WaitOne ( TimeSpan . FromSeconds ( 30 ) ) ;
93-
94- if ( proc . ExitCode != 0 ) {
95- var sb = MonoAndroidHelper . MergeStdoutAndStderrMessages ( stdoutLines , stderrLines ) ;
96- LogCodedError ( "XA3006" , Properties . Resources . XA3006 , Path . GetFileName ( config . InputSource ) , sb . ToString ( ) ) ;
97- Cancel ( ) ;
44+ CancellationToken . Register ( ( ) => {
45+ try {
46+ proc . Kill ( ) ;
47+ } catch ( Exception ) {
9848 }
99- }
49+ } ) ;
10050 }
10151
102- static readonly List < string > llcArguments = new ( ) {
103- "-O2" ,
104- "--debugger-tune=lldb" , // NDK uses lldb now
105- "--debugify-level=location+variables" ,
106- "--fatal-warnings" ,
107- "--filetype=obj" ,
108- "--relocation-model=pic" ,
109- } ;
110-
111- static readonly List < string > llvmMcArguments = new ( ) {
112- "--assemble" ,
113- "--filetype=obj" ,
114- "-g" ,
115- } ;
116-
117- IEnumerable < Config > GetAssemblerConfigs ( )
52+ IEnumerable < NativeAssemblerCompilation . AssemblerConfig > GetAssemblerConfigs ( )
11853 {
119- const string llcOptions =
120- "-O2 " +
121- "--debugger-tune=lldb " + // NDK uses lldb now
122- "--debugify-level=location+variables " +
123- "--fatal-warnings " +
124- "--filetype=obj " +
125- "--relocation-model=pic" ;
126- string llcPath = Path . Combine ( AndroidBinUtilsDirectory , "llc" ) ;
127-
12854 foreach ( ITaskItem item in Sources ) {
129- // We don't need the directory since our WorkingDirectory is where all the sources are
130- string sourceFile = Path . GetFileName ( item . ItemSpec ) ;
131- string outputFile = QuoteFileName ( Path . ChangeExtension ( sourceFile , ".o" ) ) ;
132- string executableDir = Path . GetDirectoryName ( llcPath ) ;
133- string executableName = MonoAndroidHelper . GetExecutablePath ( executableDir , Path . GetFileName ( llcPath ) ) ;
134-
135- yield return new Config {
136- InputSource = item . ItemSpec ,
137- AssemblerPath = Path . Combine ( executableDir , executableName ) ,
138- AssemblerOptions = $ "{ llcOptions } -o={ outputFile } { QuoteFileName ( sourceFile ) } ",
139- } ;
55+ yield return NativeAssemblerCompilation . GetAssemblerConfig ( AndroidBinUtilsDirectory , item , stripFilePaths : true ) ;
14056 }
14157 }
142-
143- void OnOutputData ( string assemblerName , object sender , DataReceivedEventArgs e )
144- {
145- LogDebugMessage ( $ "[{ assemblerName } stdout] { e . Data } ") ;
146- }
147-
148- void OnErrorData ( string assemblerName , object sender , DataReceivedEventArgs e )
149- {
150- LogMessage ( $ "[{ assemblerName } stderr] { e . Data } ", MessageImportance . High ) ;
151- }
152-
153- static string QuoteFileName ( string fileName )
154- {
155- var builder = new CommandLineBuilder ( ) ;
156- builder . AppendFileNameIfNotNull ( fileName ) ;
157- return builder . ToString ( ) ;
158- }
15958 }
16059}
0 commit comments