• J
    Force Microsoft.Build.Tasks.CodeAnalysis into the VSIX · f3662578
    Jason Malinowski 提交于
    When we build VisualStudioSetup.csproj, we include a bunch of assemblies from
    other projects into the VSIX. This is done through ProjectReferences to the
    other projects that produce each binary. It turns out this worked via some more
    magic than we expected: when we had a ProjectReference, we typically had the
    following metadata:
    
        <ProjectReference Include="..\..\Compilers\Core\Portable\CodeAnalysis.csproj">
          <Project>{1EE8CAD3-55F9-4D91-96B2-084641DA9A6C}</Project>
          <Name>CodeAnalysis</Name>
          <IncludeOutputGroupsInVSIX>BuiltProjectOutputGroup</IncludeOutputGroupsInVSIX>
        </ProjectReference>
    
    When the VSIX targets run, they would collect all the files that need to be put
    into the VSIX. When it would encounter this ProjectReference, it would actually
    try to include the output twice. One copy (call it Copy A) would come from the
    Binaries folder simply by virtue that the binary was a reference from the
    VisualStudioSetup project and must be copied local. The other copy (Copy B) was
    coming from the obj directory, because the VSIX targets see us specifying the
    BuiltProject- OutputGroup and that output group's items point to obj. (There is
    metadata that points to the Binaries folder but that is getting ignored by the
    VSIX targets.) The VSIX packaging task would realize we were adding two copies
    of a file, it'd arbitrarily pick the first one, which happened to be the one in
    the Binaries folder.
    
    This magic blows up in one very special case. If the project's binary happens to
    be also found in the GAC, the default behavior of MSBuild is to no longer count
    that binary as CopyLocal. Thus, when the VSIX tried to include a binary that was
    in the GAC (in this case, Microsoft.Build.Tasks.CodeAnalysis.dll), it'd decide
    it didn't need to copy it local at all. Thus Copy A in the earlier description
    didn't exist, and so the VSIX packager would fall back to using Copy B, the copy
    of the assembly from the obj folder. When we're doing a signed build, Copy A and
    Copy B are actually different -- one is signed, one isn't, and so a lack of Copy
    A being given to the VSIX packager meant that we'd end up including unsigned
    assemblies in our (supposedly) fully signed VSIX.
    
    The "fun" part is during non-signed builds Copy A is included, since the
    locally-built binary (with version 42.42.42.42) isn't in the GAC. Thus if you
    try to reproduce the strange MSBuild behavior on a regular build you don't see
    it and you don't understand why.
    
    There are two quick fixes:
    
    1. Un-GAC Microsoft.Build.Tasks.CodeAnalysis on any machines that need to do a
       proper signed build.
    2. Force the DLL to be copied local. We take this approach since it's best to
       not be subject to the whims of the GAC if we can be.
    
    Long term, we probably should fix the VSIX targets to never look in the obj
    folder. They found the obj folder by looking at the items from the
    BuiltProjectOutputGroup, but didn't look at the appropriate metadata that would
    have let it realize it should really copy from Binaries. This Copy A vs. Copy B
    fight happens with any VSIX project, and it'd be best to avoid that.
    f3662578
VisualStudioSetup.csproj 12.0 KB