Skip to content

Commit

Permalink
Look for dependencies next to task assemblies
Browse files Browse the repository at this point in the history
Fixes dotnet#658.

Assume we have an assembly called Task.dll that contains some number of tasks
a project may wish to use, and that Task.dll depends on Dependency.dll.
Currently .Net Core version of MSBuild can load Task.dll and run the tasks
within it, but will fail to find and load Dependency.dll unless it is located
immediately next to msbuild.exe.

The fix here is to update `CoreCLRAssemblyLoader` (our implementation of the
`AssemblyLoadContext` type) to remember the directories of loaded task
assemblies and to search those directories when trying to satisfy a dependency.
  • Loading branch information
analogrelay authored and tmeschter committed Aug 3, 2016
1 parent 0242a62 commit f59dcfb
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 13 deletions.
24 changes: 13 additions & 11 deletions src/MSBuild.sln
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.24720.0
VisualStudioVersion = 14.0.25420.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Build.Framework", "Framework\Microsoft.Build.Framework.csproj", "{571F09DB-A81A-4444-945C-6F7B530054CD}"
EndProject
Expand Down Expand Up @@ -628,11 +628,12 @@ Global
{2A0E81B1-9E7A-4F9F-81B2-AB180833F754}.Debug-NetCore|Any CPU.ActiveCfg = Debug-NetCore|Any CPU
{2A0E81B1-9E7A-4F9F-81B2-AB180833F754}.Debug-NetCore|x64.ActiveCfg = Debug-MONO|Any CPU
{2A0E81B1-9E7A-4F9F-81B2-AB180833F754}.Debug-NetCore|x86.ActiveCfg = Debug-MONO|Any CPU
{2A0E81B1-9E7A-4F9F-81B2-AB180833F754}.Debug-NetCore-Ubuntu|Any CPU.ActiveCfg = Debug-NetCore-Ubuntu|Any CPU
{2A0E81B1-9E7A-4F9F-81B2-AB180833F754}.Debug-NetCore-Ubuntu|x64.ActiveCfg = Debug-NetCore-Ubuntu|Any CPU
{2A0E81B1-9E7A-4F9F-81B2-AB180833F754}.Debug-NetCore-Ubuntu|x64.Build.0 = Debug-NetCore-Ubuntu|Any CPU
{2A0E81B1-9E7A-4F9F-81B2-AB180833F754}.Debug-NetCore-Ubuntu|x86.ActiveCfg = Debug-NetCore-Ubuntu|Any CPU
{2A0E81B1-9E7A-4F9F-81B2-AB180833F754}.Debug-NetCore-Ubuntu|x86.Build.0 = Debug-NetCore-Ubuntu|Any CPU
{2A0E81B1-9E7A-4F9F-81B2-AB180833F754}.Debug-NetCore-Ubuntu|Any CPU.ActiveCfg = Debug-NetCore|Any CPU
{2A0E81B1-9E7A-4F9F-81B2-AB180833F754}.Debug-NetCore-Ubuntu|Any CPU.Build.0 = Debug-NetCore|Any CPU
{2A0E81B1-9E7A-4F9F-81B2-AB180833F754}.Debug-NetCore-Ubuntu|x64.ActiveCfg = Debug-NetCore|x64
{2A0E81B1-9E7A-4F9F-81B2-AB180833F754}.Debug-NetCore-Ubuntu|x64.Build.0 = Debug-NetCore|x64
{2A0E81B1-9E7A-4F9F-81B2-AB180833F754}.Debug-NetCore-Ubuntu|x86.ActiveCfg = Debug-NetCore|x86
{2A0E81B1-9E7A-4F9F-81B2-AB180833F754}.Debug-NetCore-Ubuntu|x86.Build.0 = Debug-NetCore|x86
{2A0E81B1-9E7A-4F9F-81B2-AB180833F754}.Port-Progress|Any CPU.ActiveCfg = Port-Progress|Any CPU
{2A0E81B1-9E7A-4F9F-81B2-AB180833F754}.Port-Progress|Any CPU.Build.0 = Port-Progress|Any CPU
{2A0E81B1-9E7A-4F9F-81B2-AB180833F754}.Port-Progress|x64.ActiveCfg = Port-Progress|Any CPU
Expand All @@ -651,11 +652,12 @@ Global
{2A0E81B1-9E7A-4F9F-81B2-AB180833F754}.Release-NetCore|Any CPU.ActiveCfg = Release-NetCore|Any CPU
{2A0E81B1-9E7A-4F9F-81B2-AB180833F754}.Release-NetCore|x64.ActiveCfg = Release-MONO|Any CPU
{2A0E81B1-9E7A-4F9F-81B2-AB180833F754}.Release-NetCore|x86.ActiveCfg = Release-MONO|Any CPU
{2A0E81B1-9E7A-4F9F-81B2-AB180833F754}.Release-NetCore-Ubuntu|Any CPU.ActiveCfg = Release-NetCore-Ubuntu|Any CPU
{2A0E81B1-9E7A-4F9F-81B2-AB180833F754}.Release-NetCore-Ubuntu|x64.ActiveCfg = Release-NetCore-Ubuntu|Any CPU
{2A0E81B1-9E7A-4F9F-81B2-AB180833F754}.Release-NetCore-Ubuntu|x64.Build.0 = Release-NetCore-Ubuntu|Any CPU
{2A0E81B1-9E7A-4F9F-81B2-AB180833F754}.Release-NetCore-Ubuntu|x86.ActiveCfg = Release-NetCore-Ubuntu|Any CPU
{2A0E81B1-9E7A-4F9F-81B2-AB180833F754}.Release-NetCore-Ubuntu|x86.Build.0 = Release-NetCore-Ubuntu|Any CPU
{2A0E81B1-9E7A-4F9F-81B2-AB180833F754}.Release-NetCore-Ubuntu|Any CPU.ActiveCfg = Release-NetCore|Any CPU
{2A0E81B1-9E7A-4F9F-81B2-AB180833F754}.Release-NetCore-Ubuntu|Any CPU.Build.0 = Release-NetCore|Any CPU
{2A0E81B1-9E7A-4F9F-81B2-AB180833F754}.Release-NetCore-Ubuntu|x64.ActiveCfg = Release-NetCore|x64
{2A0E81B1-9E7A-4F9F-81B2-AB180833F754}.Release-NetCore-Ubuntu|x64.Build.0 = Release-NetCore|x64
{2A0E81B1-9E7A-4F9F-81B2-AB180833F754}.Release-NetCore-Ubuntu|x86.ActiveCfg = Release-NetCore|x86
{2A0E81B1-9E7A-4F9F-81B2-AB180833F754}.Release-NetCore-Ubuntu|x86.Build.0 = Release-NetCore|x86
{FC1C02BB-1585-4322-840F-B002E25AEAD6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FC1C02BB-1585-4322-840F-B002E25AEAD6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FC1C02BB-1585-4322-840F-B002E25AEAD6}.Debug|x64.ActiveCfg = Debug|Any CPU
Expand Down
41 changes: 40 additions & 1 deletion src/Shared/CoreCLRAssemblyLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@ internal sealed class CoreClrAssemblyLoader : AssemblyLoadContext
{
private readonly Dictionary<string, Assembly> _pathsToAssemblies = new Dictionary<string, Assembly>(StringComparer.OrdinalIgnoreCase);
private readonly Dictionary<string, Assembly> _namesToAssemblies = new Dictionary<string, Assembly>();
//private readonly List<string> _dependencyPaths = new List<string>();
private readonly List<string> _dependencyPaths = new List<string>();
private readonly object _guard = new object();
private static readonly string[] _extensions = new[] { "ni.dll", "ni.exe", "dll", "exe" };

/// <summary>
/// Creates a new instance of <see cref="CoreClrAssemblyLoader" />,
Expand All @@ -34,6 +35,19 @@ public static CoreClrAssemblyLoader CreateAndSetDefault()
return assemblyLoader;
}

public void AddDependencyLocation(string fullPath)
{
if (fullPath == null)
{
throw new ArgumentNullException(nameof(fullPath));
}

lock (_guard)
{
_dependencyPaths.Add(fullPath);
}
}

public Assembly LoadFromPath(string fullPath)
{
if (fullPath == null)
Expand Down Expand Up @@ -97,6 +111,21 @@ protected override Assembly Load(AssemblyName assemblyName)
return assembly;
}

foreach (var dependencyPath in _dependencyPaths)
{
foreach (var extension in _extensions)
{
var candidatePath = Path.Combine(dependencyPath, $"{assemblyName.Name}.{extension}");
if (IsAssemblyAlreadyLoaded(candidatePath) ||
!FileMatchesAssemblyName(candidatePath, assemblyName.Name))
{
continue;
}

return LoadAndCache(candidatePath);
}
}

return null;
}
}
Expand All @@ -114,5 +143,15 @@ private Assembly LoadAndCache(string fullPath)

return assembly;
}

private bool IsAssemblyAlreadyLoaded(string path)
{
return _pathsToAssemblies.ContainsKey(path);
}

private bool FileMatchesAssemblyName(string path, string assemblySimpleName)
{
return Path.GetFileNameWithoutExtension(path).Equals(assemblySimpleName, StringComparison.OrdinalIgnoreCase);
}
}
}
4 changes: 3 additions & 1 deletion src/Shared/TypeLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ private static Assembly LoadAssembly(AssemblyLoadInfo assemblyLoadInfo)
// If the Assembly is provided via a file path, the following rules are used to load the assembly:
// - if the simple name of the assembly exists in the same folder as msbuild.exe, then that assembly gets loaded, indifferent of the user specified path
// - otherwise, the assembly from the user specified path is loaded, if it exists.

var assemblyNameInExecutableDirectory = Path.Combine(FileUtilities.CurrentExecutableDirectory,
Path.GetFileName(assemblyLoadInfo.AssemblyFile));

Expand All @@ -198,6 +198,8 @@ private static Assembly LoadAssembly(AssemblyLoadInfo assemblyLoadInfo)
}
else
{
var baseDir = Path.GetDirectoryName(assemblyLoadInfo.AssemblyFile);
s_coreClrAssemblyLoader.AddDependencyLocation(baseDir);
loadedAssembly = s_coreClrAssemblyLoader.LoadFromPath(assemblyLoadInfo.AssemblyFile);
}
#endif
Expand Down
Empty file added testProject.proj
Empty file.

0 comments on commit f59dcfb

Please sign in to comment.