简体   繁体   中英

How to make Roslyn Compilation to copy references

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

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.

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);
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM