Reputation: 3506
When compiling a project with Roslyn all works fine, but because the project references other assemblies I need to copy them to the output directory
I have this code:
var workspace = MSBuildWorkspace.Create();
var projects = workspace.OpenSolutionAsync(@"Solution.sln").Result;
var project = projects.Projects.First();
var compilation = project.GetCompilationAsync().Result;
var dllPath = Path.Combine(Directory.GetCurrentDirectory(), "Example.dll");
var pdbPath = Path.Combine(Directory.GetCurrentDirectory(), "Example.pdb");
using (FileStream dllStream = new FileStream(dllPath, FileMode.OpenOrCreate))
using (FileStream pdbStream = new FileStream(pdbPath, FileMode.OpenOrCreate))
{
var emit = compilation.Emit(dllStream, pdbStream);
}
var assembly = Assembly.LoadFile(dllPath);
Of course it only writes the Example.dll but I don't found the options to tell the compilation or emit to add also references with CopyLocal, etc (in a automatic way) without need to loop through references and do it myself
Upvotes: 1
Views: 773
Reputation: 522
Roslyn does not copy references. As @Kevin Pilch said it's not the compiler's responsibility.
I would argue that something called MSBuildWorkspace
should have that knowledge even if it doesn't act upon it.
Here's a quick fix for that project.FilePath
, parse the file.
private static IEnumerable<PortableExecutableReference> GetMetadataReferencesToCopy(string path, IEnumerable<MetadataReference> metadataReferences)
{
var references = metadataReferences
.OfType<PortableExecutableReference>()
.Select(x => new
{
Name = Path.GetFileNameWithoutExtension(x.FilePath),
Reference = x,
})
.ToDictionary(x => x.Name, x => x.Reference);
var xmldoc = new XmlDocument();
xmldoc.Load(path);
foreach (XmlNode item in xmldoc.GetElementsByTagName("Reference"))
{
var include = item.Attributes?
.OfType<XmlAttribute>()
.FirstOrDefault(x => x.Name == "Include")?
.Value;
if (include == null)
{
continue;
}
var name = new AssemblyName(include).Name;
bool copyLocal;
if (bool.TryParse(item.ChildNodes?
.OfType<XmlNode>()
.FirstOrDefault(x => x.Name == "Private")?
.InnerText, out copyLocal) &&
references.ContainsKey(name) &&
copyLocal)
{
yield return references[name];
}
}
}
You can call it like this:
var metadataReferences = GetMetadataReferencesToCopy(project.FilePath, project.MetadataReferences);
foreach (var item in metadataReferences)
{
Console.WriteLine(item.FilePath);
}
Upvotes: 0
Reputation: 11605
Roslyn will never copy the references. That isn't something the compiler does. In regular builds MSBuild decides whether or not to copy references locally.
If you want references to be copied that is something your code will need to handle.
Upvotes: 4