MSBuild, OutputPath to a lib directory is not hono

2019-08-23 00:24发布

问题:

I spent hours now but I simply don't get it:

Why is a lib sub directory not honoured by the VS "fast up-to-date check"? If a lib output dir for libraries is set, the solution is always rebuild - if changes have been made or not does not matter. If \lib sub dir is removed it works. Why?

Here is what I tested so far:

Refer to the next code snippet. That one works perfectly. If several dependent project are asked to build multiple times they actually build only once if no changes have been made. The Visual Studio FastUpToDateCheck kicks in.

But if you change the line

<OutputPath>$(SolutionDir)bin\$(Configuration)\$(Platform)</OutputPath>

to

<OutputPath>$(SolutionDir)bin\$(Configuration)\$(Platform)\lib\</OutputPath>

it constantly rebuilds. Any ideas why?

ComponentBuild.props located next to .sln file

<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

  <PropertyGroup>
    <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
    <IntermediateOutputPath>$(SolutionDir)obj\$(Configuration)\$(MSBuildProjectName)\</IntermediateOutputPath>
    <UseCommonOutputDirectory>False</UseCommonOutputDirectory>
    <DisableFastUpToDateCheck>false</DisableFastUpToDateCheck>
  </PropertyGroup>

  <PropertyGroup Condition=" '$(OutputType)' == 'Library' ">
    <!-- To distinguish by \lib\ does not work, a rebuild is triggered since the up-to-date check fails -->
    <!-- <OutputPath>$(SolutionDir)bin\$(Configuration)\$(Platform)\lib\</OutputPath> -->
    <OutputPath>$(SolutionDir)bin\$(Configuration)\$(Platform)</OutputPath>   
    <OutDir>$(OutputPath)</OutDir>
  </PropertyGroup>

  <PropertyGroup Condition=" '$(OutputType)' == 'Exe' ">
    <OutputPath>$(SolutionDir)bin\$(Configuration)\$(Platform)\</OutputPath>
    <OutDir>$(OutputPath)</OutDir>
  </PropertyGroup>
</Project>

The file is included in csproj files just before Import Microsoft.CSharp.targets:

.csproj file:

    <!-- position of include is important, OutputType of project must be defined already -->
    <Import Project="$(SolutionDir)ComponentBuild.props" Condition="Exists('$(SolutionDir)ComponentBuild.props')" /> 
    <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
    <PropertyGroup>
      <PostBuildEvent>
      </PostBuildEvent>
    </PropertyGroup>

The behaviour becomes more weird, the more I test. I created two simple library projects A and B. B depends on A. I added above mentioned import and the FastUpToDateCheck works. After adding lib path to the library outputtype, it works when nothing else is changed. But when lib B project is cleaned, every subsequent builds do rebuild project B.

When adding lib path to the exe outputtype as well. The FastUpToDateCheck works again.

Then I removed the lib path again from output type exe, but the FastUpToDateCheck surprisingly still works - always. Even when cleaning the build, changing a class or deleting all obj and bin folders.

BUT as soon as I removed the lib path from the lib outputtype as well, i.e. I set back all to the original state, it FAILS. It rebuilds every time. The first line of the diagnostic output is

Project 'ClassLibrary1' is not up to date. Missing output file 'c:\Users\hg348\Documents\Visual Studio 2015\Projects\BuildTest\bin\Debug\AnyCPU\lib\ClassLibrary1.dll'

It still looks into lib path even though it isn't set any more. I think there is some nasty caching involved.

Can someone please verify this?

回答1:

Well, my tests as described above lead to the answer: It is caching in Visual Studio (VS) which triggers the builds after changing the output path. After making changes to the outputpath and probably outdir as well, Visual Studio still looks in the old directory for its FastUpToDateCheck.

Closing and reopening the Solution helps already to clear the VS cache. In some cases it is necessary to delete the hidden file .suo in hidden folder .vs This solves all problems stated in the sample file given in the question above.

My final import file looks like this:

<?xml version="1.0" encoding="utf-8"?>
  <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

      <!--  Note that VS caches settings, to be sure the FastUpToDateCheck works
                * reopen the solution after 
                    - changing properties
                    - after adding a platform config
                    - after adding references to projects
                * close VS and remove the hidden file 
                  <solution folder>\.vs\<solution name>\v14\.suo   after changing IntermediateOutputPath,
                  (You have to enable "how hidden files" in windows file explorer)
                * After updating App.config do a random change in any .cs source file too, 
                  otherwise FastUpToDateCheck fails
      -->

      <PropertyGroup>
        <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>

        <IntermediateOutputPath>$(SolutionDir)obj\$(Configuration)\$(Platform)\$(MSBuildProjectName)\</IntermediateOutputPath>

        <!-- if true, don't copy output files of referenced assemblies, since everything builds to the same folder. -->
        <UseCommonOutputDirectory>true</UseCommonOutputDirectory>
        <DisableFastUpToDateCheck>false</DisableFastUpToDateCheck>
      </PropertyGroup>

      <PropertyGroup Condition=" '$(OutputType)' == 'Library' ">

        <OutputPath>$(SolutionDir)bin\$(Configuration)\$(Platform)\lib\</OutputPath>
        <OutDir>$(OutputPath)</OutDir>
      </PropertyGroup>

      <PropertyGroup Condition=" '$(OutputType)' == 'Exe' ">
        <OutputPath>$(SolutionDir)bin\$(Configuration)\$(Platform)\</OutputPath>
        <OutDir>$(OutputPath)</OutDir>
      </PropertyGroup>


      <!-- sets "Copy Local" property of references to false on reopen of solution
           don't copy output files of referenced assemblies, since everything builds to the same folder -->
      <ItemDefinitionGroup>
        <Reference>
            <Private>False</Private>
        </Reference>
        <ProjectReference>
            <Private>False</Private>
        </ProjectReference>
      </ItemDefinitionGroup>

  </Project>


标签: msbuild