[mtouch] Fix an unnecessary re-link when the linker copies assemblies without processing them. (#1534)

Event sequence:

* mtouch is executed with the linker disabled.
* The linker pipeline copies all input assemblies (since the linker is
  disabled the assemblies don't change) into the PreBuild directory. This will
  keep the original timestamps of the input assemblies.
* mtouch is executed again, when none of the input assemblies changed.
* The linker pipeline will re-execute, because it will see that at least one
  of the input assemblies (at least the .exe) is newer than at least one of
  the assemblies in the PreBuild directory (usually a framework assembly,
  because those have the original timestamp from their install location).

Fix:

Touch all the assemblies in the PreBuild directory after the linker pipeline
executes the first time. This way the second time mtouch is executed, it will
find that all assemblies in the PreBuild directory have timestamps later than
all the input assemblies, so it will load the cached linked assemblies,
instead of re-executing the linker pipeline.
This commit is contained in:
Rolf Bjarne Kvinge 2017-01-20 10:45:08 +01:00 коммит произвёл GitHub
Родитель 72080fb320
Коммит 786ae13f80
5 изменённых файлов: 62 добавлений и 2 удалений

Просмотреть файл

@ -117,6 +117,22 @@ namespace Xamarin
}
}
[Test]
public void RebuildTest_DontLink ()
{
using (var mtouch = new MTouchTool ()) {
mtouch.NoFastSim = true;
mtouch.Linker = MTouchLinker.DontLink;
mtouch.CreateTemporaryApp ();
mtouch.Verbosity = 4;
mtouch.CreateTemporaryCacheDirectory ();
mtouch.AssertExecute (MTouchAction.BuildSim, "build 1");
mtouch.AssertOutputPattern ("Linking .*/testApp.exe into .*/PreBuild using mode 'None'");
mtouch.AssertExecute (MTouchAction.BuildSim, "build 2");
mtouch.AssertOutputPattern ("Cached assemblies reloaded.");
}
}
[Test]
// Simulator
[TestCase (Target.Sim, Config.Release, PackageMdb.Default, MSym.Default, false, false, "")]

Просмотреть файл

@ -18,6 +18,7 @@ using PlatformException = Xamarin.Bundler.MonoMacException;
namespace Xamarin.Bundler {
public partial class Assembly
{
public List<string> Satellites;
public Application App { get { return Target.App; } }
string full_path;
@ -392,5 +393,28 @@ namespace Xamarin.Bundler {
{
return FileName;
}
// This returns the path to all related files:
// * The assembly itself
// * Any debug files (mdb/pdb)
// * Any config files
// * Any satellite assemblies
public IEnumerable<string> GetRelatedFiles ()
{
yield return FullPath;
var mdb = FullPath + ".mdb";
if (File.Exists (mdb))
yield return mdb;
var pdb = Path.ChangeExtension (FullPath, ".pdb");
if (File.Exists (pdb))
yield return pdb;
var config = FullPath + ".config";
if (File.Exists (config))
yield return config;
if (Satellites != null) {
foreach (var satellite in Satellites)
yield return satellite;
}
}
}
}

Просмотреть файл

@ -13,7 +13,6 @@ using Xamarin.Utils;
namespace Xamarin.Bundler {
public partial class Assembly
{
public List<string> Satellites;
List<string> dylibs;
public string Dylib;

Просмотреть файл

@ -545,8 +545,21 @@ namespace Xamarin.Bundler
assemblies = linked_assemblies;
// Make the assemblies point to the right path.
foreach (var a in Assemblies)
foreach (var a in Assemblies) {
a.FullPath = Path.Combine (PreBuildDirectory, a.FileName);
// The linker can copy files (and not update timestamps), and then we run into this sequence:
// * We run the linker, nothing changes, so the linker copies
// all files to the PreBuild directory, with timestamps intact.
// * This means that for instance SDK assemblies will have the original
// timestamp from their installed location, and the exe will have the
// timestamp of when it was built.
// * mtouch is executed again for some reason, and none of the input assemblies changed.
// We'll still re-execute the linker, because at least one of the input assemblies
// (the .exe) has a newer timestamp than some of the assemblies in the PreBuild directory.
// So here we manually touch all the assemblies we have, to make sure their timestamps
// change (this is us saying 'we know these files are up-to-date at this point in time').
Driver.Touch (a.GetRelatedFiles ());
}
File.WriteAllText (cache_path, string.Join ("\n", linked_assemblies));
}

Просмотреть файл

@ -751,6 +751,14 @@ namespace Xamarin.Bundler
return true;
}
public static void Touch (IEnumerable<string> filenames, DateTime? timestamp = null)
{
if (timestamp == null)
timestamp = DateTime.Now;
foreach (var filename in filenames)
new FileInfo (filename).LastWriteTime = timestamp.Value;
}
public static string Quote (string f)
{
if (f.IndexOf (' ') == -1 && f.IndexOf ('\'') == -1 && f.IndexOf (',') == -1 && f.IndexOf ('$') == -1)