@@ -357,47 +357,77 @@ private bool ExecuteInternal()
357
357
358
358
_cache = new FileCache ( CacheFilePath , Log ) ;
359
359
360
- //FIXME: check the nothing changed at all case
360
+ List < PrecompileArguments > argsList = new ( ) ;
361
+ foreach ( var assemblyItem in _assembliesToCompile )
362
+ argsList . Add ( GetPrecompileArgumentsFor ( assemblyItem , monoPaths ) ) ;
361
363
362
364
_totalNumAssemblies = _assembliesToCompile . Count ;
363
- int allowedParallelism = Math . Min ( _assembliesToCompile . Count , Environment . ProcessorCount ) ;
364
- if ( BuildEngine is IBuildEngine9 be9 )
365
- allowedParallelism = be9 . RequestCores ( allowedParallelism ) ;
366
-
367
- if ( DisableParallelAot || allowedParallelism == 1 )
365
+ if ( CheckAllUpToDate ( argsList ) )
368
366
{
369
- foreach ( var assemblyItem in _assembliesToCompile )
370
- {
371
- if ( ! PrecompileLibrarySerial ( assemblyItem , monoPaths ) )
372
- return ! Log . HasLoggedErrors ;
373
- }
367
+ Log . LogMessage ( MessageImportance . High , "Everything is up-to-date, nothing to precompile" ) ;
368
+
369
+ _fileWrites . AddRange ( argsList . SelectMany ( args => args . ProxyFiles ) . Select ( pf => pf . TargetFile ) ) ;
370
+ foreach ( var args in argsList )
371
+ compiledAssemblies . GetOrAdd ( args . AOTAssembly . ItemSpec , args . AOTAssembly ) ;
374
372
}
375
373
else
376
374
{
377
- ParallelLoopResult result = Parallel . ForEach (
378
- _assembliesToCompile ,
379
- new ParallelOptions { MaxDegreeOfParallelism = allowedParallelism } ,
380
- ( assemblyItem , state ) => PrecompileLibraryParallel ( assemblyItem , monoPaths , state ) ) ;
375
+ int allowedParallelism = Math . Min ( _assembliesToCompile . Count , Environment . ProcessorCount ) ;
376
+ if ( BuildEngine is IBuildEngine9 be9 )
377
+ allowedParallelism = be9 . RequestCores ( allowedParallelism ) ;
381
378
382
- if ( ! result . IsCompleted )
379
+ if ( DisableParallelAot || allowedParallelism == 1 )
383
380
{
384
- return false ;
381
+ foreach ( var args in argsList )
382
+ {
383
+ if ( ! PrecompileLibrarySerial ( args ) )
384
+ return ! Log . HasLoggedErrors ;
385
+ }
385
386
}
387
+ else
388
+ {
389
+ ParallelLoopResult result = Parallel . ForEach (
390
+ argsList ,
391
+ new ParallelOptions { MaxDegreeOfParallelism = allowedParallelism } ,
392
+ ( args , state ) => PrecompileLibraryParallel ( args , state ) ) ;
393
+
394
+ if ( ! result . IsCompleted )
395
+ {
396
+ return false ;
397
+ }
398
+ }
399
+
400
+ int numUnchanged = _totalNumAssemblies - _numCompiled ;
401
+ if ( numUnchanged > 0 && numUnchanged != _totalNumAssemblies )
402
+ Log . LogMessage ( MessageImportance . High , $ "[{ numUnchanged } /{ _totalNumAssemblies } ] skipped unchanged assemblies.") ;
386
403
}
387
404
388
- int numUnchanged = _totalNumAssemblies - _numCompiled ;
389
- if ( numUnchanged > 0 && numUnchanged != _totalNumAssemblies )
390
- Log . LogMessage ( MessageImportance . High , $ "[{ numUnchanged } /{ _totalNumAssemblies } ] skipped unchanged assemblies.") ;
405
+ CompiledAssemblies = ConvertAssembliesDictToOrderedList ( compiledAssemblies , _assembliesToCompile ) . ToArray ( ) ;
391
406
392
407
if ( _cache . Save ( CacheFilePath ! ) )
393
408
_fileWrites . Add ( CacheFilePath ! ) ;
394
-
395
- CompiledAssemblies = ConvertAssembliesDictToOrderedList ( compiledAssemblies , _assembliesToCompile ) . ToArray ( ) ;
396
409
FileWrites = _fileWrites . ToArray ( ) ;
397
410
398
411
return ! Log . HasLoggedErrors ;
399
412
}
400
413
414
+ private bool CheckAllUpToDate ( IList < PrecompileArguments > argsList )
415
+ {
416
+ foreach ( var args in argsList )
417
+ {
418
+ // compare original assembly vs it's outputs.. all it's outputs!
419
+ string assemblyPath = args . AOTAssembly . GetMetadata ( "FullPath" ) ;
420
+ if ( args . ProxyFiles . Any ( pf => IsNewerThanOutput ( assemblyPath , pf . TargetFile ) ) )
421
+ return false ;
422
+ }
423
+
424
+ return true ;
425
+
426
+ static bool IsNewerThanOutput ( string inFile , string outFile )
427
+ => ! File . Exists ( inFile ) || ! File . Exists ( outFile ) ||
428
+ ( File . GetLastWriteTimeUtc ( inFile ) > File . GetLastWriteTimeUtc ( outFile ) ) ;
429
+ }
430
+
401
431
private IList < ITaskItem > EnsureAndGetAssembliesInTheSameDir ( ITaskItem [ ] originalAssemblies )
402
432
{
403
433
List < ITaskItem > filteredAssemblies = new ( ) ;
@@ -454,7 +484,7 @@ static bool ShouldSkip(ITaskItem asmItem)
454
484
=> bool . TryParse ( asmItem . GetMetadata ( "AOT_InternalForceToInterpret" ) , out bool skip ) && skip ;
455
485
}
456
486
457
- private bool PrecompileLibrary ( ITaskItem assemblyItem , string ? monoPaths )
487
+ private PrecompileArguments GetPrecompileArgumentsFor ( ITaskItem assemblyItem , string ? monoPaths )
458
488
{
459
489
string assembly = assemblyItem . GetMetadata ( "FullPath" ) ;
460
490
string assemblyDir = Path . GetDirectoryName ( assembly ) ! ;
@@ -463,7 +493,6 @@ private bool PrecompileLibrary(ITaskItem assemblyItem, string? monoPaths)
463
493
var processArgs = new List < string > ( ) ;
464
494
bool isDedup = assembly == DedupAssembly ;
465
495
List < ProxyFile > proxyFiles = new ( capacity : 5 ) ;
466
- string msgPrefix = $ "[{ Path . GetFileName ( assembly ) } ] ";
467
496
468
497
var a = assemblyItem . GetMetadata ( "AotArguments" ) ;
469
498
if ( a != null )
@@ -674,16 +703,26 @@ private bool PrecompileLibrary(ITaskItem assemblyItem, string? monoPaths)
674
703
sw . WriteLine ( responseFileContent ) ;
675
704
}
676
705
677
- string workingDir = assemblyDir ;
706
+ return new PrecompileArguments ( ResponseFilePath : responseFilePath ,
707
+ EnvironmentVariables : envVariables ,
708
+ WorkingDir : assemblyDir ,
709
+ AOTAssembly : aotAssembly ,
710
+ ProxyFiles : proxyFiles ) ;
711
+ }
678
712
713
+ private bool PrecompileLibrary ( PrecompileArguments args )
714
+ {
715
+ string assembly = args . AOTAssembly . GetMetadata ( "FullPath" ) ;
679
716
try
680
717
{
718
+ string msgPrefix = $ "[{ Path . GetFileName ( assembly ) } ] ";
719
+
681
720
// run the AOT compiler
682
721
( int exitCode , string output ) = Utils . TryRunProcess ( Log ,
683
722
CompilerBinaryPath ,
684
- $ "--response=\" { responseFilePath } \" ",
685
- envVariables ,
686
- workingDir ,
723
+ $ "--response=\" { args . ResponseFilePath } \" ",
724
+ args . EnvironmentVariables ,
725
+ args . WorkingDir ,
687
726
silent : true ,
688
727
debugMessageImportance : MessageImportance . Low ,
689
728
label : Path . GetFileName ( assembly ) ) ;
@@ -692,9 +731,9 @@ private bool PrecompileLibrary(ITaskItem assemblyItem, string? monoPaths)
692
731
// Log the command in a compact format which can be copy pasted
693
732
{
694
733
StringBuilder envStr = new StringBuilder ( string . Empty ) ;
695
- foreach ( KeyValuePair < string , string > kvp in envVariables )
734
+ foreach ( KeyValuePair < string , string > kvp in args . EnvironmentVariables )
696
735
envStr . Append ( $ "{ kvp . Key } ={ kvp . Value } ") ;
697
- Log . LogMessage ( importance , $ "{ msgPrefix } Exec (with response file contents expanded) in { workingDir } : { envStr } { CompilerBinaryPath } { responseFileContent } ") ;
736
+ Log . LogMessage ( importance , $ "{ msgPrefix } Exec (with response file contents expanded) in { args . WorkingDir } : { envStr } { CompilerBinaryPath } { File . ReadAllText ( args . ResponseFilePath ) } ") ;
698
737
}
699
738
700
739
Log . LogMessage ( importance , output ) ;
@@ -713,66 +752,66 @@ private bool PrecompileLibrary(ITaskItem assemblyItem, string? monoPaths)
713
752
}
714
753
finally
715
754
{
716
- File . Delete ( responseFilePath ) ;
755
+ File . Delete ( args . ResponseFilePath ) ;
717
756
}
718
757
719
758
bool copied = false ;
720
- foreach ( var proxyFile in proxyFiles )
759
+ foreach ( var proxyFile in args . ProxyFiles )
721
760
{
722
761
copied |= proxyFile . CopyOutputFileIfChanged ( ) ;
723
762
_fileWrites . Add ( proxyFile . TargetFile ) ;
724
763
}
725
764
726
765
if ( copied )
727
766
{
728
- string copiedFiles = string . Join ( ", " , proxyFiles . Select ( tf => Path . GetFileName ( tf . TargetFile ) ) ) ;
767
+ string copiedFiles = string . Join ( ", " , args . ProxyFiles . Select ( tf => Path . GetFileName ( tf . TargetFile ) ) ) ;
729
768
int count = Interlocked . Increment ( ref _numCompiled ) ;
730
769
Log . LogMessage ( MessageImportance . High , $ "[{ count } /{ _totalNumAssemblies } ] { Path . GetFileName ( assembly ) } -> { copiedFiles } ") ;
731
770
}
732
771
733
- compiledAssemblies . GetOrAdd ( aotAssembly . ItemSpec , aotAssembly ) ;
772
+ compiledAssemblies . GetOrAdd ( args . AOTAssembly . ItemSpec , args . AOTAssembly ) ;
734
773
return true ;
735
774
}
736
775
737
- private bool PrecompileLibrarySerial ( ITaskItem assemblyItem , string ? monoPaths )
776
+ private bool PrecompileLibrarySerial ( PrecompileArguments args )
738
777
{
739
778
try
740
779
{
741
- if ( PrecompileLibrary ( assemblyItem , monoPaths ) )
780
+ if ( PrecompileLibrary ( args ) )
742
781
return true ;
743
782
}
744
783
catch ( LogAsErrorException laee )
745
784
{
746
- Log . LogError ( $ "Precompile failed for { assemblyItem } : { laee . Message } ") ;
785
+ Log . LogError ( $ "Precompile failed for { args . AOTAssembly } : { laee . Message } ") ;
747
786
}
748
787
catch ( Exception ex )
749
788
{
750
789
if ( Log . HasLoggedErrors )
751
- Log . LogMessage ( MessageImportance . Low , $ "Precompile failed for { assemblyItem } : { ex } ") ;
790
+ Log . LogMessage ( MessageImportance . Low , $ "Precompile failed for { args . AOTAssembly } : { ex } ") ;
752
791
else
753
- Log . LogError ( $ "Precompile failed for { assemblyItem } : { ex } ") ;
792
+ Log . LogError ( $ "Precompile failed for { args . AOTAssembly } : { ex } ") ;
754
793
}
755
794
756
795
return false ;
757
796
}
758
797
759
- private void PrecompileLibraryParallel ( ITaskItem assemblyItem , string ? monoPaths , ParallelLoopState state )
798
+ private void PrecompileLibraryParallel ( PrecompileArguments args , ParallelLoopState state )
760
799
{
761
800
try
762
801
{
763
- if ( PrecompileLibrary ( assemblyItem , monoPaths ) )
802
+ if ( PrecompileLibrary ( args ) )
764
803
return ;
765
804
}
766
805
catch ( LogAsErrorException laee )
767
806
{
768
- Log . LogError ( $ "Precompile failed for { assemblyItem } : { laee . Message } ") ;
807
+ Log . LogError ( $ "Precompile failed for { args . AOTAssembly } : { laee . Message } ") ;
769
808
}
770
809
catch ( Exception ex )
771
810
{
772
811
if ( Log . HasLoggedErrors )
773
- Log . LogMessage ( MessageImportance . Low , $ "Precompile failed for { assemblyItem } : { ex } ") ;
812
+ Log . LogMessage ( MessageImportance . Low , $ "Precompile failed for { args . AOTAssembly } : { ex } ") ;
774
813
else
775
- Log . LogError ( $ "Precompile failed for { assemblyItem } : { ex } ") ;
814
+ Log . LogError ( $ "Precompile failed for { args . AOTAssembly } : { ex } ") ;
776
815
}
777
816
778
817
state . Break ( ) ;
@@ -908,6 +947,24 @@ private static IList<ITaskItem> ConvertAssembliesDictToOrderedList(ConcurrentDic
908
947
}
909
948
return outItems ;
910
949
}
950
+
951
+ internal class PrecompileArguments
952
+ {
953
+ public PrecompileArguments ( string ResponseFilePath , IDictionary < string , string > EnvironmentVariables , string WorkingDir , ITaskItem AOTAssembly , IList < ProxyFile > ProxyFiles )
954
+ {
955
+ this . ResponseFilePath = ResponseFilePath ;
956
+ this . EnvironmentVariables = EnvironmentVariables ;
957
+ this . WorkingDir = WorkingDir ;
958
+ this . AOTAssembly = AOTAssembly ;
959
+ this . ProxyFiles = ProxyFiles ;
960
+ }
961
+
962
+ public string ResponseFilePath { get ; private set ; }
963
+ public IDictionary < string , string > EnvironmentVariables { get ; private set ; }
964
+ public string WorkingDir { get ; private set ; }
965
+ public ITaskItem AOTAssembly { get ; private set ; }
966
+ public IList < ProxyFile > ProxyFiles { get ; private set ; }
967
+ }
911
968
}
912
969
913
970
internal class FileCache
@@ -1017,6 +1074,7 @@ public bool CopyOutputFileIfChanged()
1017
1074
File . Delete ( TempFile ) ;
1018
1075
}
1019
1076
}
1077
+
1020
1078
}
1021
1079
1022
1080
public enum MonoAotMode
0 commit comments