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.24k stars 1.35k forks source link

Incremental build does not work for C++ project when using Build Solution command #4664

Open jozefizso opened 5 years ago

jozefizso commented 5 years ago

We want to extend our C++ project with the support for proto files. We defined ProjectSchemaDefinitions for ProtoBuf and Visual Studio can recognize such files.

We extended the BeforeBuildGenerateSourcesTargets property to execute protoc compiler when C++ project is generating source code files (see Microsoft.BuildSteps.Targets from VC160 toolset).

Out target is correctly called when we run Rebuild or the vcxproj file is changed. We checked the Inputs and Outputs definitions for the GrpcCompileForCpp target and incremental build detects if proto file changed and GrpcCompileForCpp should be run.

When we use Build Solution only, Visual Studio will immediately return All outputs are up-to-date. and it does not even run the msbuild. This causes issues when we change proto files - they won't be compiled unless we run Rebuild.

Steps to reproduce

Project file

<Project>
  <ItemGroup>
    <ProtoBuf Include="Server.proto" />
  </ItemGroup>

  <PropertyGroup>
    <!-- Extend the C++ build system with generating gRPC files -->
    <BeforeBuildGenerateSourcesTargets>$(BeforeBuildGenerateSourcesTargets);GrpcCompileForCpp</BeforeBuildGenerateSourcesTargets>
    <ProtoOutputPath>$(MSBuildThisFileDirectory)</ProtoOutputPath>
  </PropertyGroup>

  <Target Name="GrpcCompileForCpp" Inputs="@(ProtoBuf)" Outputs="@(ProtoBuf->'%(RootDir)%(Directory)%(Filename).pb.cc')">
    <PropertyGroup>
      <ProtocCommand>"$(ProtocFullPath)" --cpp_out=$(ProtoOutputPath) --grpc_out=$(ProtoOutputPath) --plugin=protoc-gen-grpc=$(GrpcCppPluginFullPath) -I $(ProtoOutputPath) @(ProtoBuf->'%(FullPath)', ' ')</ProtocCommand>
    </PropertyGroup>
    <Message Importance="high" Text="$(ProtocCommand)" />
    <Exec Command="$(ProtocCommand)" />
  </Target>
</Project>

Directory contents:

/
- Server.proto
- ConsoleApplication4.vcxproj

Run BuildBuild Solution command from Visual Studio.

Expected behavior

Visual Studio will run msbuild and it will detect the proto file has changed and it will generate new source code.

Actual behavior

Visual Studio reports All outputs are up-to-date.

Environment data

Windows 10 1903 Visual Studio 2019 msbuild 16.2.37902.0

rainersigwald commented 5 years ago

This is happening because Visual Studio imposes a check at the project level to determine whether the project as a whole is up to date before even invoking MSBuild. This is the fast up-to-date check.

Because you're working in a C++ .vcxproj, some of the details in that document don't apply to you because they're C#/VB/F# specific. The vcxproj implementation of the fast up to date check is not open source, but it does still respect UpToDateCheckInput. Can you add something like

<ItemGroup>
  <UpToDateCheckInput Include="@(ProtoBuf)" />
</ItemGroup>

to your project/targets and let me know if that doesn't work?

japj commented 3 years ago

I had a similar issue in .vcxproj files (VS2019 Update7) and using UpToDateCheckInput indeed fixed the issue to trigger an (incremental) build

jserio1869 commented 3 years ago

I wanted to note that using UpToDateCheckInput worked for me as well. I am using a VS2019 .vcxproj that was recently translated from VS2010. We have a pre-build customization that was functional for noting changes to .c and .cpp files within the .vcxproj at the project compile level, but was not functional for Fortran .f files within this hybrid project. I applied a UpToDateCheckInput to the Fortran files in bulk within the .vcxproj and it worked like a charm.