@@ -34,6 +34,16 @@ public enum Steps
3434 public const string MetadataXmlSubDir = "metadata" ;
3535 public const string CSharpSourcesSubDir = "csharp" ;
3636
37+ public static string [ ] StubPartialSources =>
38+ Directory . GetFiles ( Path . Combine ( ThisAssemblyDirectory , "SupportFiles" ) , "*.cs" )
39+ . Where ( cs => cs . IndexOf ( "Java_Lang_" , StringComparison . OrdinalIgnoreCase ) < 0 )
40+ . Where ( cs => ! string . Equals ( Path . GetFileName ( cs ) , "JavaObject.cs" , StringComparison . OrdinalIgnoreCase ) )
41+ . ToArray ( ) ;
42+ public static string [ ] StubAllSources =>
43+ Directory . GetFiles ( Path . Combine ( ThisAssemblyDirectory , "SupportFiles" ) , "*.cs" ) ;
44+
45+ static string ThisAssemblyDirectory => Path . GetDirectoryName ( new Uri ( typeof ( BindingBuilder ) . Assembly . CodeBase ) . LocalPath ) ;
46+
3747 public Steps ProcessSteps { get ; set ; } = Steps . All ;
3848
3949 // entire work (intermediate output) directory
@@ -42,7 +52,24 @@ public enum Steps
4252 // Used to resolve javac and rt.jar
4353 public string JdkPath { get ; set ; }
4454
45- public string GeneratorPath { get ; set ; } = Path . Combine ( Path . GetDirectoryName ( new Uri ( typeof ( BindingBuilder ) . Assembly . CodeBase ) . LocalPath ) , "generator.exe" ) ;
55+ public string GeneratorPath { get ; set ; } = Path . Combine ( ThisAssemblyDirectory , "generator.exe" ) ;
56+
57+ public bool UseSystemCsc { get ; set ; } // we don't have to default to csc-dim, but why "not" ?
58+
59+ public string CscPath { get ; set ; }
60+
61+ static string GetMscorlibPath ( ) => new Uri ( typeof ( object ) . Assembly . CodeBase ) . LocalPath ;
62+
63+ static string ProbeCscDimPath ( )
64+ {
65+ // For Windows, use nuget package. For Mac/Linux, use SYSMONO dim/csc.exe.
66+ if ( Environment . OSVersion . Platform == PlatformID . Win32NT )
67+ return Path . Combine ( ".." , ".." , ".." , "packages" , "xamarin.android.csc.dim.0.1.2" , "tools" , "csc.exe" ) ;
68+ // assume path relative to framework dll in the GAC.
69+ return Path . GetFullPath ( Path . Combine ( GetMscorlibPath ( ) , ".." , "dim" , "csc.exe" ) ) ;
70+ }
71+
72+ static string GetSystemRuntimeDll ( ) => Path . Combine ( Path . GetDirectoryName ( GetMscorlibPath ( ) ) , "Facades" , "System.Runtime.dll" ) ;
4673
4774 static string ProbeJavaHome ( )
4875 {
@@ -54,7 +81,10 @@ static string ProbeJavaHome ()
5481
5582 public static BindingBuilder CreateBestBetDefault ( BindingProject project )
5683 {
57- return new BindingBuilder ( project ) { JdkPath = ProbeJavaHome ( ) } ;
84+ return new BindingBuilder ( project ) {
85+ JdkPath = ProbeJavaHome ( ) ,
86+ CscPath = ProbeCscDimPath ( ) ,
87+ } ;
5888 }
5989
6090 public BindingBuilder ( BindingProject project )
@@ -125,8 +155,8 @@ void Javac ()
125155 project . JavacExecutionOutput = $ "Execute javac as: { psi . FileName } { psi . Arguments } \n ";
126156
127157 var proc = new Process ( ) { StartInfo = psi } ;
128- proc . OutputDataReceived += ( sender , e ) => project . JavacExecutionOutput += e . Data ;
129- proc . ErrorDataReceived += ( sender , e ) => project . JavacExecutionOutput += e . Data ;
158+ proc . OutputDataReceived += ( sender , e ) => project . JavacExecutionOutput += e . Data + ' \n ' ;
159+ proc . ErrorDataReceived += ( sender , e ) => project . JavacExecutionOutput += e . Data + ' \n ' ;
130160 proc . Start ( ) ;
131161 proc . BeginOutputReadLine ( ) ;
132162 proc . BeginErrorReadLine ( ) ;
@@ -160,8 +190,8 @@ void Jar ()
160190 project . JarExecutionOutput = $ "Execute jar as: { psi . FileName } { psi . Arguments } \n ";
161191
162192 var proc = new Process ( ) { StartInfo = psi } ;
163- proc . OutputDataReceived += ( sender , e ) => project . JarExecutionOutput += e . Data ;
164- proc . ErrorDataReceived += ( sender , e ) => project . JarExecutionOutput += e . Data ;
193+ proc . OutputDataReceived += ( sender , e ) => project . JarExecutionOutput += e . Data + ' \n ' ;
194+ proc . ErrorDataReceived += ( sender , e ) => project . JarExecutionOutput += e . Data + ' \n ' ;
165195 proc . Start ( ) ;
166196 proc . BeginOutputReadLine ( ) ;
167197 proc . BeginErrorReadLine ( ) ;
@@ -275,8 +305,8 @@ void GenerateBindingSources ()
275305 project . GeneratorExecutionOutput = $ "Execute generator as: { psi . FileName } { psi . Arguments } \n ";
276306
277307 var proc = new Process ( ) { StartInfo = psi } ;
278- proc . OutputDataReceived += ( sender , e ) => project . GeneratorExecutionOutput += e . Data ;
279- proc . ErrorDataReceived += ( sender , e ) => project . GeneratorExecutionOutput += e . Data ;
308+ proc . OutputDataReceived += ( sender , e ) => project . GeneratorExecutionOutput += e . Data + ' \n ' ;
309+ proc . ErrorDataReceived += ( sender , e ) => project . GeneratorExecutionOutput += e . Data + ' \n ' ;
280310 proc . Start ( ) ;
281311 proc . BeginOutputReadLine ( ) ;
282312 proc . BeginErrorReadLine ( ) ;
@@ -287,6 +317,63 @@ void GenerateBindingSources ()
287317
288318 void CompileBindings ( )
289319 {
320+ if ( ( ProcessSteps & Steps . Csc ) == 0 )
321+ return ;
322+
323+ if ( CscPath == null )
324+ throw new InvalidOperationException ( "CscPath is not set." ) ;
325+
326+ var objDir = IntermediateOutputPathAbsolute ;
327+ EnsureDirectory ( objDir ) ;
328+
329+ if ( project . GeneratedCSharpSourceFiles == null )
330+ project . GeneratedCSharpSourceDirectory = Path . Combine ( objDir , CSharpSourcesSubDir ) ;
331+ if ( ! Directory . GetFiles ( project . GeneratedCSharpSourceDirectory , "*.cs" ) . Any ( ) && ! project . CSharpSourceFiles . Any ( ) && ! project . CSharpSourceStrings . Any ( ) )
332+ throw new InvalidOperationException ( "No C# sources exist." ) ;
333+ if ( project . GeneratedDllFile == null )
334+ project . GeneratedDllFile = Path . Combine ( objDir , project . Id + ".dll" ) ;
335+
336+ foreach ( var item in project . CSharpSourceStrings )
337+ File . WriteAllText ( Path . Combine ( project . GeneratedCSharpSourceDirectory , item . FileName ) , item . Content ) ;
338+ var csFiles = project . CSharpSourceFiles . AsEnumerable ( ) ;
339+
340+ switch ( project . CSharpStubUsage ) {
341+ case CSharpStubUsage . Partial :
342+ csFiles = csFiles . Concat ( StubPartialSources ) ;
343+ break ;
344+ case CSharpStubUsage . Full :
345+ csFiles = csFiles . Concat ( StubAllSources ) ;
346+ break ;
347+ }
348+
349+ string localSystemRuntime = Path . Combine ( ThisAssemblyDirectory , "System.Runtime.dll" ) ;
350+ if ( ! File . Exists ( localSystemRuntime ) )
351+ File . Copy ( GetSystemRuntimeDll ( ) , localSystemRuntime ) ;
352+
353+ var psi = new ProcessStartInfo ( ) {
354+ UseShellExecute = false ,
355+ FileName = UseSystemCsc ? "csc" : CscPath ,
356+ Arguments = $ " -t:library -unsafe" +
357+ $ " -out:\" { project . GeneratedDllFile } \" { project . GeneratedCSharpSourceDirectory } { Path . DirectorySeparatorChar } *.cs " +
358+ $ " { string . Join ( " " , csFiles . Select ( s => '"' + s + '"' ) ) } " +
359+ $ " -r:{ ThisAssemblyDirectory } { Path . DirectorySeparatorChar } System.Runtime.dll" +
360+ $ " -r:{ ThisAssemblyDirectory } { Path . DirectorySeparatorChar } Java.Interop.dll" +
361+ $ " { string . Join ( " " , project . ReferenceDlls . Select ( s => " -r \" " + s + '"' ) ) } ",
362+ RedirectStandardOutput = true ,
363+ RedirectStandardError = true ,
364+ } ;
365+
366+ project . CscExecutionOutput = $ "Execute csc as: { psi . FileName } { psi . Arguments } \n ";
367+
368+ var proc = new Process ( ) { StartInfo = psi } ;
369+ proc . OutputDataReceived += ( sender , e ) => project . CscExecutionOutput += e . Data + '\n ' ;
370+ proc . ErrorDataReceived += ( sender , e ) => project . CscExecutionOutput += e . Data + '\n ' ;
371+ proc . Start ( ) ;
372+ proc . BeginOutputReadLine ( ) ;
373+ proc . BeginErrorReadLine ( ) ;
374+ proc . WaitForExit ( ) ;
375+ if ( proc . ExitCode != 0 )
376+ throw new Exception ( "csc failed: " + project . CscExecutionOutput ) ;
290377 }
291378 }
292379}
0 commit comments