[mtouch/mmp] Fix tracking of whether the static registrar should run again or not. Fixes #641. (#3534) (#3536)
* [tests] Improve debug spew for the RebuildTest_WithExtensions test. * [mtouch/mmp] Store/load if the dynamic registrar is removed or not into the cached link results. Store/load if the dynamic registrar is removed or not into the cached link results, so that we generate the correct main.m even if cached linker results are used. * [mtouch/mmp] The static registrar must not execute if we're loading cached results from the linker. The static registrar must not execute if we're loading cached results from the linker, because the static registrar needs information from the linker that's not restored from the cache. * [mtouch/mmp] Share Touch code. * [mtouch/mmp] Make it possible to touch inexistent files (to create them). * [mtouch/mmp] Fix tracking of whether the static registrar should run again or not. The recent changes to support optimizing away the dynamic registrar caused the Xamarin.MTouch.RebuildTest_WithExtensions test to regress. The problem ----------- * The linker now collects and stores information the static registrar needs. * This information is not restored from disk when the linker realizes that it can reload previously linked assemblies instead of executing again. * The static registrar runs again (for another reason). * The information the static registrar needs isn't available, and incorrect output follows. So fix 1: show an error if the static registrar runs when the linker loaded cached results. The exact scenario the test ran into is this: * 1st build: everything is new and everything is built. * 2nd build: contents of .exe changes, the linker runs again, the static registrar runs again, but sees that the generated output didn't change, so it doesn't write the new content to disk (this is an optimization to avoid compiling the registrar.m file again unless needed). * 3rd build: only the .exe timestamp changes, the linker sees nothing changes in the contents of the .exe and loads the previously linked assemblies from disk, the static registrar sees that the .exe's timestamp is newer than registrar.m's timestamp and run again, but doesn't produce the right result because it doesn't have the information it needs. Considered solutions -------------------- 1. Only track timestamps, not file contents. This is not ideal, since it will result in more work done: in particular for the case above, it would add a registrar.m compilation in build #2, and linker rerun + static registrar rerun + registrar.m compilation + final native link in build #3. 2. Always write the output of the static registrar, even if it hasn't changed. This is not ideal either, since it will also result in more work done: for the case above, it would add a registrar.m compilation + final native link in build #3. 3. Always write the output of the static registrar, but track if it changed or not, and if it didn't, just touch registrar.o instead of recompiling it. This only means the final native link in build #3 is added (see #5 for why this is worse than it sounds). 4. Always write the output of the static registrar, but track it it changed or not, and if it didn't, just touch registrar.o instead of recompiling it, and track that too, so that the final native link in build #3 isn't needed anymore. Unfortunately this may result in incorrect behavior, because now the msbuild tasks will detect that the executable has changed, and may run dsymutil + strip again. The executable didn't actually change, which means it would be the previously stripped executable, and thus we'd end up with an empty .dSYM because we ran dsymtil on an already stripped executable. 5. Idea #4, but write the output of the final link into a temporary directory instead of the .app, so that we could track whether we should update the executable in the .app or not. This is not optimal either, because executables can be *big* (I've seen multi-GB tvOS bitcode executables), and extra copies of such files should not be taken lightly. 6. Idea #4, but tell the MSBuild tasks that dsymutil/strip doesn't need to be rerun even if the timestamp of the executable changed. This might actually work, but now the solution's become quite complex. Implemented solution -------------------- Use stamp files to detect whether a file is up-to-date or not. In particular: * When we don't write to a file because the new contents are identical to the old contents, we now touch a .stamp file. This stamp file means "the accompanying file was determined to be up-to-date when the stamp was touched." * When checking whether a file is up-to-date, also check for the presence of a .stamp file, and if it exists, use the highest timestamp between the stamp file and the actual file. Now the test scenario becomes: * 1st build: everything is new and everything is built. * 2nd build: contents of .exe changes, the linker runs again, the static registrar runs again, but sees that the generated output didn't change, so it doesn't write the new content to disk, but it creates a registrar.m.stamp file to indicate the point in time when registrar.m was considered up-to- date. * 3rd build: only the .exe timestamp changes, the linker sees nothing changes in the contents of the .exe and loads the previously linked assemblies from disk, the static registrar sees that the .exe's timestamp is *older* than registrar.m.stamp's timestamp and doesn't run again. We only use the stamp file for source code (registrar.[m|h], main.[m|h], pinvokes.[m|h]), since using it every time has too much potential for running into other problems (for instance we should never create .stamp files inside the .app). Fixes these test failures: 1) Failed : Xamarin.MTouch.RebuildTest_WithExtensions("single","",False,System.String[]) single Expected: <empty> But was: < "/Users/builder/data/lanes/5746/4123bf7e/source/xamarin-macios/tests/mtouch/bin/Debug/tmp-test-dir/Xamarin.Tests.BundlerTool.CreateTemporaryDirectory371/testApp.app/testApp is modified, timestamp: 2/15/2018 3:04:11 PM > 2/15/2018 3:04:09 PM" > 2) Failed : Xamarin.MTouch.RebuildTest_WithExtensions("dual","armv7,arm64",False,System.String[]) dual Expected: <empty> But was: < "/Users/builder/data/lanes/5746/4123bf7e/source/xamarin-macios/tests/mtouch/bin/Debug/tmp-test-dir/Xamarin.Tests.BundlerTool.CreateTemporaryDirectory375/testApp.app/testApp is modified, timestamp: 2/15/2018 3:06:03 PM > 2/15/2018 3:06:00 PM" > 3) Failed : Xamarin.MTouch.RebuildTest_WithExtensions("llvm","armv7+llvm",False,System.String[]) llvm Expected: <empty> But was: < "/Users/builder/data/lanes/5746/4123bf7e/source/xamarin-macios/tests/mtouch/bin/Debug/tmp-test-dir/Xamarin.Tests.BundlerTool.CreateTemporaryDirectory379/testApp.app/testApp is modified, timestamp: 2/15/2018 3:07:14 PM > 2/15/2018 3:07:12 PM" > 4) Failed : Xamarin.MTouch.RebuildTest_WithExtensions("debug","",True,System.String[]) debug Expected: <empty> But was: < "/Users/builder/data/lanes/5746/4123bf7e/source/xamarin-macios/tests/mtouch/bin/Debug/tmp-test-dir/Xamarin.Tests.BundlerTool.CreateTemporaryDirectory383/testApp.app/testApp is modified, timestamp: 2/15/2018 3:08:16 PM > 2/15/2018 3:08:13 PM" > 5) Failed : Xamarin.MTouch.RebuildTest_WithExtensions("single-framework","",False,System.String[]) single-framework Expected: <empty> But was: < "/Users/builder/data/lanes/5746/4123bf7e/source/xamarin-macios/tests/mtouch/bin/Debug/tmp-test-dir/Xamarin.Tests.BundlerTool.CreateTemporaryDirectory387/testApp.app/testApp is modified, timestamp: 2/15/2018 3:09:18 PM > 2/15/2018 3:09:16 PM" > Fixes https://github.com/xamarin/maccore/issues/641
This commit is contained in:
Родитель
a8e5fc5413
Коммит
2a29d0e0aa
|
@ -363,6 +363,21 @@ public class B : A {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DumpFileStats (MTouchTool mtouch)
|
||||||
|
{
|
||||||
|
if (mtouch.Verbosity < 1)
|
||||||
|
return;
|
||||||
|
var directory = mtouch.Cache;
|
||||||
|
var files = Directory.GetFileSystemEntries (directory, "*", SearchOption.AllDirectories).ToList ();
|
||||||
|
files.Sort ((string x, string y) => string.CompareOrdinal (x, y));
|
||||||
|
var max = files.Max ((v) => v.Length);
|
||||||
|
|
||||||
|
var format = " {0,-" + max + "} {1}";
|
||||||
|
foreach (var file in files) {
|
||||||
|
Console.WriteLine (format, file, File.GetLastWriteTimeUtc (file).ToString ("HH:mm:ss.fffffff"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
[TestCase ("single", "", false, new string [] { } )]
|
[TestCase ("single", "", false, new string [] { } )]
|
||||||
[TestCase ("dual", "armv7,arm64", false, new string [] { })]
|
[TestCase ("dual", "armv7,arm64", false, new string [] { })]
|
||||||
|
@ -397,17 +412,20 @@ public class B : A {}
|
||||||
mtouch.DSym = false; // faster test
|
mtouch.DSym = false; // faster test
|
||||||
mtouch.MSym = false; // faster test
|
mtouch.MSym = false; // faster test
|
||||||
mtouch.NoStrip = true; // faster test
|
mtouch.NoStrip = true; // faster test
|
||||||
|
//mtouch.Verbosity = 20; // Set the mtouch verbosity to something to print the mtouch output to the terminal. This will also enable additional debug output.
|
||||||
|
|
||||||
var timestamp = DateTime.MinValue;
|
var timestamp = DateTime.MinValue;
|
||||||
|
|
||||||
mtouch.AssertExecute (MTouchAction.BuildDev, "first build");
|
mtouch.AssertExecute (MTouchAction.BuildDev, "first build");
|
||||||
Console.WriteLine ($"{DateTime.Now} **** FIRST BUILD DONE ****");
|
Console.WriteLine ($"{DateTime.Now} **** FIRST BUILD DONE ****");
|
||||||
|
DumpFileStats (mtouch);
|
||||||
|
|
||||||
timestamp = DateTime.Now;
|
timestamp = DateTime.Now;
|
||||||
System.Threading.Thread.Sleep (1000); // make sure all new timestamps are at least a second older. HFS+ has a 1s timestamp resolution :(
|
System.Threading.Thread.Sleep (1000); // make sure all new timestamps are at least a second older. HFS+ has a 1s timestamp resolution :(
|
||||||
|
|
||||||
mtouch.AssertExecute (MTouchAction.BuildDev, "second build");
|
mtouch.AssertExecute (MTouchAction.BuildDev, "second build");
|
||||||
Console.WriteLine ($"{DateTime.Now} **** SECOND BUILD DONE ****");
|
Console.WriteLine ($"{DateTime.Now} **** SECOND BUILD DONE ****");
|
||||||
|
DumpFileStats (mtouch);
|
||||||
|
|
||||||
mtouch.AssertNoneModified (timestamp, name);
|
mtouch.AssertNoneModified (timestamp, name);
|
||||||
extension.AssertNoneModified (timestamp, name);
|
extension.AssertNoneModified (timestamp, name);
|
||||||
|
@ -416,6 +434,7 @@ public class B : A {}
|
||||||
new FileInfo (extension.RootAssembly).LastWriteTimeUtc = DateTime.UtcNow;
|
new FileInfo (extension.RootAssembly).LastWriteTimeUtc = DateTime.UtcNow;
|
||||||
mtouch.AssertExecute (MTouchAction.BuildDev, "touch extension executable");
|
mtouch.AssertExecute (MTouchAction.BuildDev, "touch extension executable");
|
||||||
Console.WriteLine ($"{DateTime.Now} **** TOUCH EXTENSION EXECUTABLE DONE ****");
|
Console.WriteLine ($"{DateTime.Now} **** TOUCH EXTENSION EXECUTABLE DONE ****");
|
||||||
|
DumpFileStats (mtouch);
|
||||||
mtouch.AssertNoneModified (timestamp, name);
|
mtouch.AssertNoneModified (timestamp, name);
|
||||||
extension.AssertNoneModified (timestamp, name);
|
extension.AssertNoneModified (timestamp, name);
|
||||||
|
|
||||||
|
@ -423,6 +442,7 @@ public class B : A {}
|
||||||
new FileInfo (mtouch.RootAssembly).LastWriteTimeUtc = DateTime.UtcNow;
|
new FileInfo (mtouch.RootAssembly).LastWriteTimeUtc = DateTime.UtcNow;
|
||||||
mtouch.AssertExecute (MTouchAction.BuildDev, "touch main app executable");
|
mtouch.AssertExecute (MTouchAction.BuildDev, "touch main app executable");
|
||||||
Console.WriteLine ($"{DateTime.Now} **** TOUCH MAIN APP EXECUTABLE DONE ****");
|
Console.WriteLine ($"{DateTime.Now} **** TOUCH MAIN APP EXECUTABLE DONE ****");
|
||||||
|
DumpFileStats (mtouch);
|
||||||
mtouch.AssertNoneModified (timestamp, name);
|
mtouch.AssertNoneModified (timestamp, name);
|
||||||
extension.AssertNoneModified (timestamp, name);
|
extension.AssertNoneModified (timestamp, name);
|
||||||
|
|
||||||
|
@ -440,6 +460,7 @@ public class B : A {}
|
||||||
extension.CreateTemporaryServiceExtension (extraCode: codeB);
|
extension.CreateTemporaryServiceExtension (extraCode: codeB);
|
||||||
mtouch.AssertExecute (MTouchAction.BuildDev, "change extension executable");
|
mtouch.AssertExecute (MTouchAction.BuildDev, "change extension executable");
|
||||||
Console.WriteLine ($"{DateTime.Now} **** CHANGE EXTENSION EXECUTABLE DONE ****");
|
Console.WriteLine ($"{DateTime.Now} **** CHANGE EXTENSION EXECUTABLE DONE ****");
|
||||||
|
DumpFileStats (mtouch);
|
||||||
mtouch.AssertNoneModified (timestamp, name);
|
mtouch.AssertNoneModified (timestamp, name);
|
||||||
extension.AssertNoneModified (timestamp, name, "testServiceExtension", "testServiceExtension.aotdata.armv7", "testServiceExtension.aotdata.arm64", "testServiceExtension.dll");
|
extension.AssertNoneModified (timestamp, name, "testServiceExtension", "testServiceExtension.aotdata.armv7", "testServiceExtension.aotdata.arm64", "testServiceExtension.dll");
|
||||||
|
|
||||||
|
@ -450,6 +471,7 @@ public class B : A {}
|
||||||
mtouch.CreateTemporaryApp (extraCode: codeB);
|
mtouch.CreateTemporaryApp (extraCode: codeB);
|
||||||
mtouch.AssertExecute (MTouchAction.BuildDev, "change app executable");
|
mtouch.AssertExecute (MTouchAction.BuildDev, "change app executable");
|
||||||
Console.WriteLine ($"{DateTime.Now} **** CHANGE APP EXECUTABLE DONE ****");
|
Console.WriteLine ($"{DateTime.Now} **** CHANGE APP EXECUTABLE DONE ****");
|
||||||
|
DumpFileStats (mtouch);
|
||||||
mtouch.AssertNoneModified (timestamp, name, "testApp", "testApp.aotdata.armv7", "testApp.aotdata.arm64", "testApp.exe");
|
mtouch.AssertNoneModified (timestamp, name, "testApp", "testApp.aotdata.armv7", "testApp.aotdata.arm64", "testApp.exe");
|
||||||
extension.AssertNoneModified (timestamp, name);
|
extension.AssertNoneModified (timestamp, name);
|
||||||
|
|
||||||
|
@ -460,6 +482,7 @@ public class B : A {}
|
||||||
File.WriteAllText (extension.RootAssembly + ".config", "<configuration></configuration>");
|
File.WriteAllText (extension.RootAssembly + ".config", "<configuration></configuration>");
|
||||||
mtouch.AssertExecute (MTouchAction.BuildDev, "add config to extension dll");
|
mtouch.AssertExecute (MTouchAction.BuildDev, "add config to extension dll");
|
||||||
Console.WriteLine ($"{DateTime.Now} **** ADD CONFIG TO EXTENSION DONE ****");
|
Console.WriteLine ($"{DateTime.Now} **** ADD CONFIG TO EXTENSION DONE ****");
|
||||||
|
DumpFileStats (mtouch);
|
||||||
mtouch.AssertNoneModified (timestamp, name);
|
mtouch.AssertNoneModified (timestamp, name);
|
||||||
extension.AssertNoneModified (timestamp, name, "testServiceExtension.dll.config", "testServiceExtension", "testServiceExtension.aotdata.armv7", "testServiceExtension.aotdata.arm64");
|
extension.AssertNoneModified (timestamp, name, "testServiceExtension.dll.config", "testServiceExtension", "testServiceExtension.aotdata.armv7", "testServiceExtension.aotdata.arm64");
|
||||||
CollectionAssert.Contains (Directory.EnumerateFiles (extension.AppPath, "*", SearchOption.AllDirectories).Select ((v) => Path.GetFileName (v)), "testServiceExtension.dll.config", "extension config added");
|
CollectionAssert.Contains (Directory.EnumerateFiles (extension.AppPath, "*", SearchOption.AllDirectories).Select ((v) => Path.GetFileName (v)), "testServiceExtension.dll.config", "extension config added");
|
||||||
|
@ -471,18 +494,19 @@ public class B : A {}
|
||||||
File.WriteAllText (mtouch.RootAssembly + ".config", "<configuration></configuration>");
|
File.WriteAllText (mtouch.RootAssembly + ".config", "<configuration></configuration>");
|
||||||
mtouch.AssertExecute (MTouchAction.BuildDev, "add config to container exe");
|
mtouch.AssertExecute (MTouchAction.BuildDev, "add config to container exe");
|
||||||
Console.WriteLine ($"{DateTime.Now} **** ADD CONFIG TO CONTAINER DONE ****");
|
Console.WriteLine ($"{DateTime.Now} **** ADD CONFIG TO CONTAINER DONE ****");
|
||||||
|
DumpFileStats (mtouch);
|
||||||
mtouch.AssertNoneModified (timestamp, name, "testApp.exe.config", "testApp", "testApp.aotdata.armv7", "testApp.aotdata.arm64");
|
mtouch.AssertNoneModified (timestamp, name, "testApp.exe.config", "testApp", "testApp.aotdata.armv7", "testApp.aotdata.arm64");
|
||||||
extension.AssertNoneModified (timestamp, name);
|
extension.AssertNoneModified (timestamp, name);
|
||||||
CollectionAssert.Contains (Directory.EnumerateFiles (mtouch.AppPath, "*", SearchOption.AllDirectories).Select ((v) => Path.GetFileName (v)), "testApp.exe.config", "container config added");
|
CollectionAssert.Contains (Directory.EnumerateFiles (mtouch.AppPath, "*", SearchOption.AllDirectories).Select ((v) => Path.GetFileName (v)), "testApp.exe.config", "container config added");
|
||||||
|
|
||||||
timestamp = DateTime.Now;
|
timestamp = DateTime.Now;
|
||||||
System.Threading.Thread.Sleep (1000); // make sure all new timestamps are at least a second older. HFS+ has a 1s timestamp resolution :(
|
System.Threading.Thread.Sleep (1000); // make sure all new timestamps are at least a second older. HFS+ has a 1s timestamp resolution :(
|
||||||
|
|
||||||
{
|
{
|
||||||
// Add a satellite to the extension.
|
// Add a satellite to the extension.
|
||||||
var satellite = extension.CreateTemporarySatelliteAssembly ();
|
var satellite = extension.CreateTemporarySatelliteAssembly ();
|
||||||
mtouch.AssertExecute (MTouchAction.BuildDev, "add satellite to extension");
|
mtouch.AssertExecute (MTouchAction.BuildDev, "add satellite to extension");
|
||||||
Console.WriteLine ($"{DateTime.Now} **** ADD SATELLITE TO EXTENSION DONE ****");
|
Console.WriteLine ($"{DateTime.Now} **** ADD SATELLITE TO EXTENSION DONE ****");
|
||||||
|
DumpFileStats (mtouch);
|
||||||
mtouch.AssertNoneModified (timestamp, name, Path.GetFileName (satellite));
|
mtouch.AssertNoneModified (timestamp, name, Path.GetFileName (satellite));
|
||||||
extension.AssertNoneModified (timestamp, name, Path.GetFileName (satellite));
|
extension.AssertNoneModified (timestamp, name, Path.GetFileName (satellite));
|
||||||
extension.AssertModified (timestamp, name, Path.GetFileName (satellite));
|
extension.AssertModified (timestamp, name, Path.GetFileName (satellite));
|
||||||
|
@ -497,6 +521,7 @@ public class B : A {}
|
||||||
var satellite = mtouch.CreateTemporarySatelliteAssembly ();
|
var satellite = mtouch.CreateTemporarySatelliteAssembly ();
|
||||||
mtouch.AssertExecute (MTouchAction.BuildDev, "add satellite to container");
|
mtouch.AssertExecute (MTouchAction.BuildDev, "add satellite to container");
|
||||||
Console.WriteLine ($"{DateTime.Now} **** ADD SATELLITE TO CONTAINER DONE ****");
|
Console.WriteLine ($"{DateTime.Now} **** ADD SATELLITE TO CONTAINER DONE ****");
|
||||||
|
DumpFileStats (mtouch);
|
||||||
mtouch.AssertNoneModified (timestamp, name, Path.GetFileName (satellite));
|
mtouch.AssertNoneModified (timestamp, name, Path.GetFileName (satellite));
|
||||||
extension.AssertNoneModified (timestamp, name, Path.GetFileName (satellite));
|
extension.AssertNoneModified (timestamp, name, Path.GetFileName (satellite));
|
||||||
mtouch.AssertModified (timestamp, name, Path.GetFileName (satellite));
|
mtouch.AssertModified (timestamp, name, Path.GetFileName (satellite));
|
||||||
|
|
|
@ -126,7 +126,13 @@ namespace Xamarin.Bundler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool IsUptodate (string source, string target, bool check_contents = false)
|
// Checks if the source file has a time stamp later than the target file.
|
||||||
|
//
|
||||||
|
// Optionally check if the contents of the files are different after checking the timestamp.
|
||||||
|
//
|
||||||
|
// If check_stamp is true, the function will use the timestamp of a "target".stamp file
|
||||||
|
// if it's later than the timestamp of the "target" file itself.
|
||||||
|
public static bool IsUptodate (string source, string target, bool check_contents = false, bool check_stamp = true)
|
||||||
{
|
{
|
||||||
if (Driver.Force)
|
if (Driver.Force)
|
||||||
return false;
|
return false;
|
||||||
|
@ -138,6 +144,14 @@ namespace Xamarin.Bundler {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (check_stamp) {
|
||||||
|
var tfi_stamp = new FileInfo (target + ".stamp");
|
||||||
|
if (tfi_stamp.Exists && tfi_stamp.LastWriteTimeUtc > tfi.LastWriteTimeUtc) {
|
||||||
|
Driver.Log (3, "Target '{0}' has a stamp file with newer timestamp ({1} > {2}), using the stamp file's timestamp", target, tfi_stamp.LastWriteTimeUtc, tfi.LastWriteTimeUtc);
|
||||||
|
tfi = tfi_stamp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var sfi = new FileInfo (source);
|
var sfi = new FileInfo (source);
|
||||||
|
|
||||||
if (sfi.LastWriteTimeUtc <= tfi.LastWriteTimeUtc) {
|
if (sfi.LastWriteTimeUtc <= tfi.LastWriteTimeUtc) {
|
||||||
|
@ -323,7 +337,10 @@ namespace Xamarin.Bundler {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks if any of the source files have a time stamp later than any of the target files.
|
// Checks if any of the source files have a time stamp later than any of the target files.
|
||||||
public static bool IsUptodate (IEnumerable<string> sources, IEnumerable<string> targets)
|
//
|
||||||
|
// If check_stamp is true, the function will use the timestamp of a "target".stamp file
|
||||||
|
// if it's later than the timestamp of the "target" file itself.
|
||||||
|
public static bool IsUptodate (IEnumerable<string> sources, IEnumerable<string> targets, bool check_stamp = true)
|
||||||
{
|
{
|
||||||
if (Driver.Force)
|
if (Driver.Force)
|
||||||
return false;
|
return false;
|
||||||
|
@ -356,6 +373,14 @@ namespace Xamarin.Bundler {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (check_stamp) {
|
||||||
|
var tfi_stamp = new FileInfo (t + ".stamp");
|
||||||
|
if (tfi_stamp.Exists && tfi_stamp.LastWriteTimeUtc > tfi.LastWriteTimeUtc) {
|
||||||
|
Driver.Log (3, "Target '{0}' has a stamp file with newer timestamp ({1} > {2}), using the stamp file's timestamp", t, tfi_stamp.LastWriteTimeUtc, tfi.LastWriteTimeUtc);
|
||||||
|
tfi = tfi_stamp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var lwt = tfi.LastWriteTimeUtc;
|
var lwt = tfi.LastWriteTimeUtc;
|
||||||
if (max_source > lwt) {
|
if (max_source > lwt) {
|
||||||
Driver.Log (3, "Prerequisite '{0}' is newer than target '{1}' ({2} vs {3}).", max_s, t, max_source, lwt);
|
Driver.Log (3, "Prerequisite '{0}' is newer than target '{1}' ({2} vs {3}).", max_s, t, max_source, lwt);
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
@ -304,7 +305,7 @@ namespace Xamarin.Bundler {
|
||||||
File.Move (source, target);
|
File.Move (source, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void MoveIfDifferent (string path, string tmp)
|
static void MoveIfDifferent (string path, string tmp, bool use_stamp = false)
|
||||||
{
|
{
|
||||||
// Don't read the entire file into memory, it can be quite big in certain cases.
|
// Don't read the entire file into memory, it can be quite big in certain cases.
|
||||||
|
|
||||||
|
@ -325,10 +326,12 @@ namespace Xamarin.Bundler {
|
||||||
FileMove (tmp, path);
|
FileMove (tmp, path);
|
||||||
} else {
|
} else {
|
||||||
Log (3, "Target {0} is up-to-date.", path);
|
Log (3, "Target {0} is up-to-date.", path);
|
||||||
|
if (use_stamp)
|
||||||
|
Driver.Touch (path + ".stamp");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void WriteIfDifferent (string path, string contents)
|
public static void WriteIfDifferent (string path, string contents, bool use_stamp = false)
|
||||||
{
|
{
|
||||||
var tmp = path + ".tmp";
|
var tmp = path + ".tmp";
|
||||||
|
|
||||||
|
@ -341,7 +344,7 @@ namespace Xamarin.Bundler {
|
||||||
}
|
}
|
||||||
|
|
||||||
File.WriteAllText (tmp, contents);
|
File.WriteAllText (tmp, contents);
|
||||||
MoveIfDifferent (path, tmp);
|
MoveIfDifferent (path, tmp, use_stamp);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
File.WriteAllText (path, contents);
|
File.WriteAllText (path, contents);
|
||||||
ErrorHelper.Warning (1014, e, "Failed to re-use cached version of '{0}': {1}.", path, e.Message);
|
ErrorHelper.Warning (1014, e, "Failed to re-use cached version of '{0}': {1}.", path, e.Message);
|
||||||
|
@ -350,7 +353,7 @@ namespace Xamarin.Bundler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void WriteIfDifferent (string path, byte[] contents)
|
public static void WriteIfDifferent (string path, byte[] contents, bool use_stamp = false)
|
||||||
{
|
{
|
||||||
var tmp = path + ".tmp";
|
var tmp = path + ".tmp";
|
||||||
|
|
||||||
|
@ -362,7 +365,7 @@ namespace Xamarin.Bundler {
|
||||||
}
|
}
|
||||||
|
|
||||||
File.WriteAllBytes (tmp, contents);
|
File.WriteAllBytes (tmp, contents);
|
||||||
MoveIfDifferent (path, tmp);
|
MoveIfDifferent (path, tmp, use_stamp);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
File.WriteAllBytes (path, contents);
|
File.WriteAllBytes (path, contents);
|
||||||
ErrorHelper.Warning (1014, e, "Failed to re-use cached version of '{0}': {1}.", path, e.Message);
|
ErrorHelper.Warning (1014, e, "Failed to re-use cached version of '{0}': {1}.", path, e.Message);
|
||||||
|
@ -438,5 +441,30 @@ namespace Xamarin.Bundler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void Touch (IEnumerable<string> filenames, DateTime? timestamp = null)
|
||||||
|
{
|
||||||
|
if (timestamp == null)
|
||||||
|
timestamp = DateTime.Now;
|
||||||
|
foreach (var filename in filenames) {
|
||||||
|
try {
|
||||||
|
var fi = new FileInfo (filename);
|
||||||
|
if (!fi.Exists) {
|
||||||
|
using (var fo = fi.OpenWrite ()) {
|
||||||
|
// Create an empty file.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fi.LastWriteTime = timestamp.Value;
|
||||||
|
} catch (Exception e) {
|
||||||
|
ErrorHelper.Warning (128, "Could not touch the file '{0}': {1}", filename, e.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Touch (params string [] filenames)
|
||||||
|
{
|
||||||
|
Touch ((IEnumerable<string>) filenames);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,8 +63,8 @@ namespace Xamarin.Bundler
|
||||||
|
|
||||||
Registrar.GeneratePInvokeWrappersEnd ();
|
Registrar.GeneratePInvokeWrappersEnd ();
|
||||||
|
|
||||||
Driver.WriteIfDifferent (HeaderPath, hdr.ToString () + "\n" + decls.ToString () + "\n" + ifaces.ToString () + "\n") ;
|
Driver.WriteIfDifferent (HeaderPath, hdr.ToString () + "\n" + decls.ToString () + "\n" + ifaces.ToString () + "\n", true);
|
||||||
Driver.WriteIfDifferent (SourcePath, mthds.ToString () + "\n" + sb.ToString () + "\n");
|
Driver.WriteIfDifferent (SourcePath, mthds.ToString () + "\n" + sb.ToString () + "\n", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ProcessMethod (MethodDefinition method)
|
public void ProcessMethod (MethodDefinition method)
|
||||||
|
|
|
@ -4508,6 +4508,9 @@ namespace Registrar {
|
||||||
|
|
||||||
public void Generate (IEnumerable<AssemblyDefinition> assemblies, string header_path, string source_path)
|
public void Generate (IEnumerable<AssemblyDefinition> assemblies, string header_path, string source_path)
|
||||||
{
|
{
|
||||||
|
if (Target?.CachedLink == true)
|
||||||
|
throw ErrorHelper.CreateError (99, "Internal error: the static registrar should not execute unless the linker also executed (or was disabled). A potential workaround is to pass '-f' as an additional " + Driver.NAME + " argument to force a full build. Please file a bug report with a test case (https://bugzilla.xamarin.com).");
|
||||||
|
|
||||||
this.input_assemblies = assemblies;
|
this.input_assemblies = assemblies;
|
||||||
|
|
||||||
foreach (var assembly in assemblies) {
|
foreach (var assembly in assemblies) {
|
||||||
|
@ -4561,12 +4564,12 @@ namespace Registrar {
|
||||||
|
|
||||||
FlushTrace ();
|
FlushTrace ();
|
||||||
|
|
||||||
Driver.WriteIfDifferent (source_path, methods.ToString ());
|
Driver.WriteIfDifferent (source_path, methods.ToString (), true);
|
||||||
|
|
||||||
header.AppendLine ();
|
header.AppendLine ();
|
||||||
header.AppendLine (declarations);
|
header.AppendLine (declarations);
|
||||||
header.AppendLine (interfaces);
|
header.AppendLine (interfaces);
|
||||||
Driver.WriteIfDifferent (header_path, header.ToString ());
|
Driver.WriteIfDifferent (header_path, header.ToString (), true);
|
||||||
|
|
||||||
header.Dispose ();
|
header.Dispose ();
|
||||||
header = null;
|
header = null;
|
||||||
|
|
|
@ -62,6 +62,12 @@ namespace Xamarin.Bundler {
|
||||||
this.StaticRegistrar = new StaticRegistrar (this);
|
this.StaticRegistrar = new StaticRegistrar (this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool CachedLink {
|
||||||
|
get {
|
||||||
|
return cached_link;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void ExtractNativeLinkInfo (List<Exception> exceptions)
|
public void ExtractNativeLinkInfo (List<Exception> exceptions)
|
||||||
{
|
{
|
||||||
foreach (var a in Assemblies) {
|
foreach (var a in Assemblies) {
|
||||||
|
@ -396,7 +402,7 @@ namespace Xamarin.Bundler {
|
||||||
sb.AppendLine ("}");
|
sb.AppendLine ("}");
|
||||||
sb.AppendLine ();
|
sb.AppendLine ();
|
||||||
|
|
||||||
Driver.WriteIfDifferent (reference_m, sb.ToString ());
|
Driver.WriteIfDifferent (reference_m, sb.ToString (), true);
|
||||||
|
|
||||||
#if MTOUCH
|
#if MTOUCH
|
||||||
foreach (var abi in GetArchitectures (AssemblyBuildTarget.StaticObject)) {
|
foreach (var abi in GetArchitectures (AssemblyBuildTarget.StaticObject)) {
|
||||||
|
|
|
@ -2,3 +2,5 @@ mmp
|
||||||
temp-dir-mmp
|
temp-dir-mmp
|
||||||
Xamarin.Mac.registrar.*
|
Xamarin.Mac.registrar.*
|
||||||
SdkVersions.cs
|
SdkVersions.cs
|
||||||
|
*.stamp
|
||||||
|
|
||||||
|
|
|
@ -68,6 +68,7 @@ namespace Xamarin.Bundler {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static partial class Driver {
|
public static partial class Driver {
|
||||||
|
internal const string NAME = "mmp";
|
||||||
internal static Application App = new Application (Environment.GetCommandLineArgs ());
|
internal static Application App = new Application (Environment.GetCommandLineArgs ());
|
||||||
static Target BuildTarget = new Target (App);
|
static Target BuildTarget = new Target (App);
|
||||||
static List<string> references = new List<string> ();
|
static List<string> references = new List<string> ();
|
||||||
|
|
|
@ -7,3 +7,5 @@ SdkVersions.cs
|
||||||
simlauncher-sgen
|
simlauncher-sgen
|
||||||
simlauncher32-sgen
|
simlauncher32-sgen
|
||||||
simlauncher64-sgen
|
simlauncher64-sgen
|
||||||
|
*.stamp
|
||||||
|
|
||||||
|
|
|
@ -537,17 +537,38 @@ namespace Xamarin.Bundler
|
||||||
if (!Driver.Force) {
|
if (!Driver.Force) {
|
||||||
if (File.Exists (cache_path)) {
|
if (File.Exists (cache_path)) {
|
||||||
using (var reader = new StreamReader (cache_path)) {
|
using (var reader = new StreamReader (cache_path)) {
|
||||||
string line;
|
string line = null;
|
||||||
|
|
||||||
while ((line = reader.ReadLine ()) != null) {
|
while ((line = reader.ReadLine ()) != null) {
|
||||||
var colon = line.IndexOf (':');
|
var colon = line.IndexOf (':');
|
||||||
if (colon == -1)
|
if (colon == -1)
|
||||||
continue;
|
continue;
|
||||||
var appex = line.Substring (0, colon);
|
var key = line.Substring (0, colon);
|
||||||
var asm = line.Substring (colon + 1);
|
var value = line.Substring (colon + 1);
|
||||||
List<string> asms;
|
switch (key) {
|
||||||
if (!cached_output.TryGetValue (appex, out asms))
|
case "RemoveDynamicRegistrar":
|
||||||
cached_output [appex] = asms = new List<string> ();
|
switch (value) {
|
||||||
asms.Add (asm);
|
case "true":
|
||||||
|
App.Optimizations.RemoveDynamicRegistrar = true;
|
||||||
|
break;
|
||||||
|
case "false":
|
||||||
|
App.Optimizations.RemoveDynamicRegistrar = false;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
App.Optimizations.RemoveDynamicRegistrar = null;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Driver.Log (1, $"Optimization dynamic registrar removal loaded from cached results: {(App.Optimizations.RemoveDynamicRegistrar.HasValue ? (App.Optimizations.RemoveUIThreadChecks.Value ? "enabled" : "disabled") : "not set")}");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// key: app(ex)
|
||||||
|
// value: assembly
|
||||||
|
List<string> asms;
|
||||||
|
if (!cached_output.TryGetValue (key, out asms))
|
||||||
|
cached_output [key] = asms = new List<string> ();
|
||||||
|
asms.Add (value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -683,6 +704,8 @@ namespace Xamarin.Bundler
|
||||||
|
|
||||||
// Write the input files to the cache
|
// Write the input files to the cache
|
||||||
using (var writer = new StreamWriter (cache_path, false)) {
|
using (var writer = new StreamWriter (cache_path, false)) {
|
||||||
|
var opt = App.Optimizations.RemoveDynamicRegistrar;
|
||||||
|
writer.WriteLine ($"RemoveDynamicRegistrar:{(opt.HasValue ? (opt.Value ? "true" : "false") : string.Empty)}");
|
||||||
foreach (var target in allTargets) {
|
foreach (var target in allTargets) {
|
||||||
foreach (var asm in target.Assemblies) {
|
foreach (var asm in target.Assemblies) {
|
||||||
writer.WriteLine ($"{target.App.AppDirectory}:{asm.FullPath}");
|
writer.WriteLine ($"{target.App.AppDirectory}:{asm.FullPath}");
|
||||||
|
|
|
@ -79,6 +79,8 @@ public enum OutputFormat {
|
||||||
namespace Xamarin.Bundler
|
namespace Xamarin.Bundler
|
||||||
{
|
{
|
||||||
partial class Driver {
|
partial class Driver {
|
||||||
|
internal const string NAME = "mtouch";
|
||||||
|
|
||||||
public static void ShowHelp (OptionSet os)
|
public static void ShowHelp (OptionSet os)
|
||||||
{
|
{
|
||||||
Console.WriteLine ("mtouch - Mono Compiler for iOS");
|
Console.WriteLine ("mtouch - Mono Compiler for iOS");
|
||||||
|
@ -698,7 +700,7 @@ namespace Xamarin.Bundler
|
||||||
sw.WriteLine ("}");
|
sw.WriteLine ("}");
|
||||||
|
|
||||||
}
|
}
|
||||||
WriteIfDifferent (main_source, sb.ToString ());
|
WriteIfDifferent (main_source, sb.ToString (), true);
|
||||||
} catch (MonoTouchException) {
|
} catch (MonoTouchException) {
|
||||||
throw;
|
throw;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
@ -799,24 +801,6 @@ namespace Xamarin.Bundler
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Touch (IEnumerable<string> filenames, DateTime? timestamp = null)
|
|
||||||
{
|
|
||||||
if (timestamp == null)
|
|
||||||
timestamp = DateTime.Now;
|
|
||||||
foreach (var filename in filenames) {
|
|
||||||
try {
|
|
||||||
new FileInfo (filename).LastWriteTime = timestamp.Value;
|
|
||||||
} catch (Exception e) {
|
|
||||||
ErrorHelper.Warning (128, "Could not touch the file '{0}': {1}", filename, e.Message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void Touch (params string [] filenames)
|
|
||||||
{
|
|
||||||
Touch ((IEnumerable<string>) filenames);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool CanWeSymlinkTheApplication (Application app)
|
public static bool CanWeSymlinkTheApplication (Application app)
|
||||||
{
|
{
|
||||||
if (app.Platform != ApplePlatform.iOS)
|
if (app.Platform != ApplePlatform.iOS)
|
||||||
|
|
Загрузка…
Ссылка в новой задаче