dotnet / msbuild

The Microsoft Build Engine (MSBuild) is the build platform for .NET and Visual Studio.
https://docs.microsoft.com/visualstudio/msbuild/msbuild
MIT License
5.23k stars 1.35k forks source link

Unable to publish C# project with C++ dependencies #5968

Open joeltankam opened 3 years ago

joeltankam commented 3 years ago

Issue Description

We have a C# project, say ProjectA, using SDK project file format and targeting .NET Framework 4.7.1. This project depends on a VC10 C++/CLI project (ProjectB) which depends on VC10 C++ project (ProjectC): ProjectA [net471] <- ProjectB [VC10 C++/CLI] <- ProjectC [VC10 C++] (where A <- B means that A depends on B). We are trying to publish the C# entry project, ProjectA, using Publish target from MSBuild (msbuild /t:Publish)

Steps to Reproduce

Please reproduce the dependency graph mentioned above.

Expected Behavior

The publish directory should contain all the dependencies of ProjectA, recursively.

Actual Behavior

The resulting directory contains ProjectA.dll, ProjectB.dll but not ProjectC.dll. In general, the Publish target is not able to resolve C++ dependencies recursively.

Is this behavior expected? Is there anything we can do about this please? Could upgrading C++ to v142 help? Could migrating ProjectC to C++/CLI help?

Forgind commented 3 years ago

Team triage: Can you create a zipped project that reproduces this that you can share?

joeltankam commented 3 years ago

@Forgind sorry for the delayed reply. Here's a repository that reproduces the issue: https://github.com/joeltankam/cpp-publish-sample

benvillalobos commented 3 years ago

Note to self: Find the switch to modify how the transitive references work.

joeltankam commented 3 years ago

Thanks @BenVillalobos Any update on this please ?

joeltankam commented 3 years ago

Any update on this please ?

joeltankam commented 3 years ago

Any update on this please ?

benvillalobos commented 3 years ago

Hello! Thanks for the repro project.

Unfortunately this behavior is expected, but I do have a workaround available for an issue like this.

Add ProjectC.vcxproj as a projectreference to projectA, and set ReferenceOutputAssembly to false for that reference.

Then add ProjectC's dll as a content item and set it to copy to your output directory.

  <ItemGroup>
    <ProjectReference Include="..\ProjectB\ProjectB.vcxproj" />
    <ProjectReference Include="..\ProjectC\ProjectC.vcxproj" >
      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
    </ProjectReference>
  </ItemGroup>

  <ItemGroup>
    <Content Include="..\ProjectC\$(Configuration)\ProjectC.dll">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Content>
  </ItemGroup>
davidhunter22 commented 3 years ago

Hi, just wanted add our work around. Make ProjectC a static library. Then ProjectB will stick it internally inside it's assembly so then you have no ProjectC to distribute. Obviously this only works if you're OK with ProjectC being a static library.

joeltankam commented 3 years ago

Thanks for your replies.

Unfortunately this behavior is expected

Is there any particular reason to enforce this behavior?

@BenVillalobos Unfortunately, both yours and the workaround suggested by @davidhunter22 do not apply at scale in our case. The repository involved has around 980+ projects, 120+ being C++ projects. Given the size of the repository and the dependency graph, we cannot afford to apply any of these two hacks.

benvillalobos commented 2 years ago

Unassigning myself. This issue is tangetially related, there's been some talk about merging the way that nuget/msbuild handle project reference dependencies, which may eventually fix this.

bouchraRekhadda commented 4 months ago

Hello,

Is there any hope this might be looked at someday ?