Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions src/Xamarin.Android.Build.Tasks/Tasks/CompileNativeAssembly.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ sealed class Config
public string? AssemblerPath;
public string? AssemblerOptions;
public string? InputSource;
public string? OutputFile;
}

[Required]
Expand All @@ -43,6 +44,14 @@ public override System.Threading.Tasks.Task RunTaskAsync ()

void RunAssembler (Config config)
{
if (config.OutputFile is not null && config.InputSource is not null && File.Exists (config.OutputFile)) {
string sourceFile = Path.Combine (WorkingDirectory, Path.GetFileName (config.InputSource));
if (File.Exists (sourceFile) && File.GetLastWriteTimeUtc (config.OutputFile) >= File.GetLastWriteTimeUtc (sourceFile)) {
LogDebugMessage ($"[LLVM llc] Skipping '{Path.GetFileName (config.InputSource)}' because '{Path.GetFileName (config.OutputFile)}' is up to date");
return;
}
}

var stdout_completed = new ManualResetEvent (false);
var stderr_completed = new ManualResetEvent (false);
var psi = new ProcessStartInfo () {
Expand Down Expand Up @@ -118,10 +127,13 @@ IEnumerable<Config> GetAssemblerConfigs ()
string executableDir = Path.GetDirectoryName (llcPath);
string executableName = MonoAndroidHelper.GetExecutablePath (executableDir, Path.GetFileName (llcPath));

string outputFilePath = Path.Combine (WorkingDirectory, sourceFile.Replace (".ll", ".o"));

yield return new Config {
InputSource = item.ItemSpec,
AssemblerPath = Path.Combine (executableDir, executableName),
AssemblerOptions = $"{assemblerOptions} -o={outputFile} {QuoteFileName (sourceFile)}",
OutputFile = outputFilePath,
};
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1289,6 +1289,38 @@ public void GenerateJavaStubsAndAssembly ([Values] bool isRelease, [Values] Andr
}
}

[Test]
public void CompileNativeAssemblySourcesSkipsUnchangedFiles ([Values (AndroidRuntime.CoreCLR)] AndroidRuntime runtime)
{
if (IgnoreUnsupportedConfiguration (runtime, release: false)) {
return;
}

var proj = new XamarinAndroidApplicationProject ();
proj.SetRuntime (runtime);

string abi = "arm64-v8a";
proj.SetRuntimeIdentifier (abi);

using (var b = CreateApkBuilder ()) {
b.Verbosity = LoggerVerbosity.Detailed;
Assert.IsTrue (b.Build (proj), "first build should have succeeded.");

// Modify MainActivity to trigger recompilation of typemap sources
proj.MainActivity = proj.DefaultMainActivity + Environment.NewLine + "// test comment";
proj.Touch ("MainActivity.cs");
Assert.IsTrue (b.Build (proj), "second build should have succeeded.");

Assert.IsFalse (b.Output.IsTargetSkipped ("_CompileNativeAssemblySources"), "`_CompileNativeAssemblySources` should *not* be skipped!");

// At least one .ll file should have been skipped as up to date (e.g., environment.arm64-v8a.ll)
Assert.IsTrue (
StringAssertEx.ContainsRegex (@"\[LLVM llc\] Skipping.*up to date", b.LastBuildOutput),
"Expected at least one .ll file to be skipped as up to date"
);
}
}

readonly string [] ExpectedAssemblyFiles = new [] {
Path.Combine ("android", "environment.@ABI@.o"),
Path.Combine ("android", "environment.@ABI@.ll"),
Expand Down
Loading