Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug] vcxproj ProjectReference from csproj triggers a build of the vcxproj but does not copy the target when modified #9841

Closed
fforjan opened this issue Mar 7, 2024 · 20 comments
Assignees
Labels

Comments

@fforjan
Copy link

fforjan commented Mar 7, 2024

Issue Description

Whe csproj references a vcxproj updated to copy the native dll to the .net folder, the initial build will copy the dll but any subsequent build triggered from the C# project following a modification to of the C++ will not copy the output.

Note that the option that building the solution is not acceptable, we have this type of issue into a large solution when a unit tests refrecnes a native DLL and the developer usually build the unit test project only.

Steps to Reproduce

Notice that the NativeDll.dll is copied into the output folder, both for net472 and net80

  • Modify a cpp file into the NativeDLL project
  • Build again the ConsoleApp project.

Expected Behavior

As one the initial build, if any projectreference is updated, the dll must be copied over ?

Actual Behavior

Notice the the NativeDLL.dll is NOT updated into the output folder while the NativeDLL compilation was triggered.

Analysis

No response

Versions & Configurations

Reproduced with Microsoft Visual Studio Enterprise 2022 (64-bit) - Version 17.9.2

@fforjan fforjan added the bug label Mar 7, 2024
@fforjan
Copy link
Author

fforjan commented Mar 7, 2024

I can reproduce a different behavior with MSBuild in command line.
The NativeDll will never appear when using the command line, and if the NativeDLL was already present :

CSProjectAndVcxprojReferences\ConsoleApp>msbuild
MSBuild version 17.9.5+33de0b227 for .NET Framework
Build started 3/7/2024 2:30:23 PM.

Project "C:\git\CSProjectAndVcxprojReferences\ConsoleApp\ConsoleApp.csproj" on node 1 (default targets).
Project "C:\git\CSProjectAndVcxprojReferences\ConsoleApp\ConsoleApp.csproj" (1) is building "C:\git\CSProjectAndVcxproj
References\ConsoleApp\ConsoleApp.csproj" (1:2) on node 1 (Build target(s)).
Project "C:\git\CSProjectAndVcxprojReferences\ConsoleApp\ConsoleApp.csproj" (1:2) is building "C:\git\CSProjectAndVcxpr
ojReferences\NativeDll\NativeDll.vcxproj" (2) on node 1 (default targets).
PrepareForBuild:
  Structured output is enabled. The formatting of compiler diagnostics will reflect the error hierarchy. See https://ak
  a.ms/cpp/structured-output for more details.
InitializeBuildStatus:
  Creating "NativeDll\Debug\NativeDll.tlog\unsuccessfulbuild" because "AlwaysCreate" was specified.
  Touching "NativeDll\Debug\NativeDll.tlog\unsuccessfulbuild".
ClCompile:
  All outputs are up-to-date.
  All outputs are up-to-date.
Link:
  All outputs are up-to-date.
  NativeDll.vcxproj -> C:\git\CSProjectAndVcxprojReferences\NativeDll\Debug\NativeDll.dll
FinalizeBuildStatus:
  Deleting file "NativeDll\Debug\NativeDll.tlog\unsuccessfulbuild".
  Touching "NativeDll\Debug\NativeDll.tlog\NativeDll.lastbuildstate".
Done Building Project "C:\git\CSProjectAndVcxprojReferences\NativeDll\NativeDll.vcxproj" (default targets).

GenerateTargetFrameworkMonikerAttribute:
Skipping target "GenerateTargetFrameworkMonikerAttribute" because all output files are up-to-date with respect to the i
nput files.
CoreGenerateAssemblyInfo:
Skipping target "CoreGenerateAssemblyInfo" because all output files are up-to-date with respect to the input files.
_GenerateSourceLinkFile:
  Source Link file 'obj\Debug\net8.0\ConsoleApp.sourcelink.json' is up-to-date.
CoreCompile:
Skipping target "CoreCompile" because all output files are up-to-date with respect to the input files.
_CreateAppHost:
Skipping target "_CreateAppHost" because all output files are up-to-date with respect to the input files.
_CopyOutOfDateSourceItemsToOutputDirectory:
Skipping target "_CopyOutOfDateSourceItemsToOutputDirectory" because all output files are up-to-date with respect to th
e input files.
CopyFilesToOutputDirectory:
  ConsoleApp -> C:\git\CSProjectAndVcxprojReferences\ConsoleApp\bin\Debug\net8.0\ConsoleApp.dll
IncrementalClean:
  Deleting file "C:\git\CSProjectAndVcxprojReferences\ConsoleApp\bin\Debug\net8.0\NativeDll.dll".
Done Building Project "C:\git\CSProjectAndVcxprojReferences\ConsoleApp\ConsoleApp.csproj" (Build target(s)).

Project "C:\git\CSProjectAndVcxprojReferences\ConsoleApp\ConsoleApp.csproj" (1) is building "C:\git\CSProjectAndVcxproj
References\ConsoleApp\ConsoleApp.csproj" (1:3) on node 1 (Build target(s)).
_WriteAppConfigWithSupportedRuntime:
Skipping target "_WriteAppConfigWithSupportedRuntime" because all output files are up-to-date with respect to the input
 files.
GenerateTargetFrameworkMonikerAttribute:
Skipping target "GenerateTargetFrameworkMonikerAttribute" because all output files are up-to-date with respect to the i
nput files.
CoreGenerateAssemblyInfo:
Skipping target "CoreGenerateAssemblyInfo" because all output files are up-to-date with respect to the input files.
_GenerateSourceLinkFile:
  Source Link file 'obj\Debug\net472\ConsoleApp.sourcelink.json' is up-to-date.
CoreCompile:
Skipping target "CoreCompile" because all output files are up-to-date with respect to the input files.
_CopyAppConfigFile:
Skipping target "_CopyAppConfigFile" because all output files are up-to-date with respect to the input files.
CopyFilesToOutputDirectory:
  ConsoleApp -> C:\git\CSProjectAndVcxprojReferences\ConsoleApp\bin\Debug\net472\ConsoleApp.exe
IncrementalClean:
  Deleting file "C:\git\CSProjectAndVcxprojReferences\ConsoleApp\bin\Debug\net472\NativeDll.dll".
Done Building Project "C:\git\CSProjectAndVcxprojReferences\ConsoleApp\ConsoleApp.csproj" (Build target(s)).

Done Building Project "C:\git\CSProjectAndVcxprojReferences\ConsoleApp\ConsoleApp.csproj" (default targets).


Build succeeded.
    0 Warning(s)
    0 Error(s)

Notice there is an 'incrementral clean' but it doesnt copy the native dll after ?
IncrementalClean:
Deleting file "C:\git\CSProjectAndVcxprojReferences\ConsoleApp\bin\Debug\net472\NativeDll.dll".

@AR-May
Copy link
Member

AR-May commented Mar 12, 2024

@GangWang01 Could you repro this issue? We suspect it might be an up-to-date check problem.

@GangWang01
Copy link
Member

It's easy to reproduce with the provided solution https://github.com/fforjan/CSProjectAndVcxprojReferences. As the issue mentioned, I reproduced and attached binlogs binlogs.zip.

  1. Clone the repo and open the solution using VS 17.9.2.
  2. Build C# project ConsoleApp. Binlog is FirstBuildWithVS.binlog.
  3. Make code change to C++ file in C++ project project NativeDLL.
  4. Build C# project ConsoleApp. Binlog is IncrementalBuildWithVS.binlog. Note that only C++ project was built, but C# project wasn't built at all. NativeDLL.dll in bin directory of C# project wasn't the latest one.
  5. Repeat step 3.
  6. Use msbuild.exe from Developer Command Prompt to build. Binlog is IncrementalBuildWithMSbuild.binlog. Note that another issue appeared. NativeDll.dll in bin directory of C# project was deleted.

@yuehuang010
Copy link
Contributor

The only difference I saw between the two binlog is that NativeDLL is populated from "GetTargetPath" target during P2P. While
"Build" did not.

image

image

@yuehuang010
Copy link
Contributor

Is the NativeDLL a CLI project? If it is not, it should not be returning from GetTargetPath.

@fforjan
Copy link
Author

fforjan commented Mar 25, 2024

@yuehuang010 no it is a C++ library project - not sure what you mean by CLI ? - and follows https://stackoverflow.com/a/42507529 to allow copying its output to the C# project.

@yuehuang010
Copy link
Contributor

I am leaning toward NativeDll getting copied in VS as a bug. A C# project wouldn't know what to do with a C++ output.

I think the csproj has another mechanism of fetching it via the Traversal copy that has to be opt-in. It should fetching the BuildOutputGroup target.

@fforjan
Copy link
Author

fforjan commented Mar 26, 2024

The stack overflow link as an interesting description about why it should work.

But if you have a different settings I'm happy to try.

@GangWang01
Copy link
Member

@rainersigwald can you help to take a look? Note that there are different problems when building with VS and msbuild.exe.

@fforjan
Copy link
Author

fforjan commented Apr 11, 2024

@GangWang01 let me know if you have any update

@GangWang01 GangWang01 assigned surayya-MS and unassigned GangWang01 Apr 17, 2024
@fforjan
Copy link
Author

fforjan commented Apr 30, 2024

@surayya-MS any update on your side ?

@fforjan
Copy link
Author

fforjan commented May 13, 2024

@surayya-MS ping !

@surayya-MS
Copy link
Member

Thanks for filing this bug @fforjan!
Currently, our team is focusing on higher-priority items, we will get to this one later.

@JoshuaRoweMsft
Copy link

I believe the issue is that the .vcxproj "Build" target does not return the primary build output, but the "GetTargetPath" target does.

  <Target Name="GetTargetPath" DependsOnTargets="$(GetTargetPathDependsOn)" Returns="@(TargetPathWithTargetPlatformMoniker)" />
  <Target Name="Build" Condition=" '$(_InvalidConfigurationWarning)' != 'true' " DependsOnTargets="$(BuildDependsOn)" Returns="@(ManagedTargetPath);@(WinMDFullPath)">

@JoshuaRoweMsft
Copy link

I'm able to work around this with the following ProjectReference:

    <ProjectReference Include="Foo.vcxproj">
      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
      
      <OutputItemType>Content</OutputItemType>
      
      <!-- Native projects do not include the primary build output 
      as a Returns item for the "Build" target, so we request the GetTargetPath target
      to get the primary output. -->
      <Targets>Build;GetTargetPath</Targets>
      <Targets Condition="'$(BuildProjectReferences)' == 'false'">GetTargetPath</Targets>
      
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </ProjectReference>

@yuehuang010
Copy link
Contributor

In the past, vcxproj project don't return its native output because RAR has issues processing them. Perhaps that has changed, in which case, add it would be an option.

@JoshuaRowePhantom
Copy link

In the past, vcxproj project don't return its native output because RAR has issues processing them. Perhaps that has changed, in which case, add it would be an option.

It does seem to me that Build and GetTargetPath should at least be consistent with each other, if the .csproj can call either one depending on the value of BuildProjectReferences.

@fforjan
Copy link
Author

fforjan commented Jul 25, 2024

@JoshuaRoweMsft would you be able to try to update my sample to confirm it is working for you ? (i may only have time only on Friday this week)

@fforjan
Copy link
Author

fforjan commented Aug 1, 2024

@JoshuaRoweMsft I tried the workaround, although it builds the project, the DLL is NOT copied to the .net project bin folder.

@YuliiaKovalova
Copy link
Member

I close this ticket as a dupe for that one:
#10931

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

8 participants