Correct way to use MSBuild Task that generates code with Intellisense
Asked Answered
U

1

6

Context

For some project, we've been attempting to do code generation directly from Visual Studio. The basic idea is that you can create a bunch of (.foo) files, and that each (.foo) file corresponds to a single generated (.foo.cs) file.

Basically the process works as follows:

  1. During build, all .foo files are collected.
  2. Some transformations take place. Note that some of the transformations require information from all the .foo files.
  3. For each .foo file, a .foo.cs file is emitted with a partial class.

Normally I'd create a single file generator (custom tool) for this - however, in this case I'd like to know that the filename is always .foo.cs, and there doesn't seem to be a way this can be controlled from a single file generator. Also, the fact that building requires information from multiple files made me opt for an alternative approach.

Therefore, I created an MS Build Task, and registered it in the csproj:

<UsingTask AssemblyFile="C:\Projects\FooTool\bin\Debug\FooBuildTool.dll"
           TaskName="FooBuildTool.FooTool" />
<Target Name="Foo" BeforeTargets="BeforeBuild" 
        Condition="'$(MSBuildProjectExtension)' == '.csproj'">
    <FooTool Language="C#" ProjectFolder="$(ProjectDir)" 
             ProjectName="$(ProjectName)" Sources="@(Foo)">
        <Output ItemName="FooCompile" TaskParameter="ComputedSources" />
    </FooTool>
    <ItemGroup>
        <Compile Include="@(FooCompile->'%(Outputs)')" />
    </ItemGroup>
</Target>

This works fine in the sense that code generation works and this generates all the required .cs files.

Note that if Intellisense doesn't work until I click 'build' - that's fine.

Situation

The problem now is that Intellisense is broken for the .foo.cs files, and I'm looking for a way to fix this.

I've attempted to fix this by changing the .csproj file even more:

<Compile Include="Test.foo.cs">
  <AutoGen>True</AutoGen>
  <DesignTime>True</DesignTime>
  <DependentUpon>Test.foo</DependentUpon>
</Compile>

...

<Foo Include="Test.foo" Generator="Foo" LastGenOutput="Test.foo.cs" />

This appears to work, in the sense that files now show up in the solution explorer of Visual Studio.

However, I don't know how to create this automatically, and couldn't find any documentation nor an example about it. I'm guessing it has to do with building a proper VSTemplate?

Question

What's the right way to fix this issue? E.g. how can I ensure that generated files show up in Visual Studio, so that Intellisense can pick them up?

Unify answered 1/11, 2018 at 14:6 Comment(4)
Can't really reproduce this: opening a project where a source file doesn't exist shows it with a yelow exclamation mark as expected. Then if I have an external tool or prebuild event which creates the file and then double click the file in solution explorer, the yellow icon disappears and VS opens the file and has Intellisense etc avilable. This might be a case where you need to provide a complete MCVE. And mention VS version. Also: in the first paragraph you have Compile Include the output of the tool, in the second you manually add Test.Foo.cs. Does this mean you're doing both?Beauvais
@Beauvais Hmm you get a yellow exclamation mark even though no custom tool/single file generator is registered (but just a msbuild task)? That's exactly what I want... In my case (which is btw the latest VS2017) this only works when I register a custom tool and/or hack the csproj file with the snippet I put in 'situation'.Unify
The yelow icon just means 'file not present' as far as I can tell, irregardless of how it gets generated or what metadata the item has. Can't try in VS2017 atm, using VS2013, but I don't recall it ever being different. Suppose you edit the project and add a non-existing Compile item, just that, and open the project, don't you get the yellow icon?Beauvais
@Beauvais If I don't hack the csproj file and just have the MSBuild item, I just get the .foo files, even after build. There's no cs file, there's no yellow exclamation mark, nothing. Generated CS files only appear after I set a custom tool (Single File Generator).Unify
B
2

I had similar problem: I have task that generates some .cs file based on a template. The project is targeting dotnet core 3.1

First I wrote

<Target Name="GenerateEnvFiles" BeforeTargets="BeforeBuild;BeforeClean">

The build worked, but intellisense did not.

I was checking different sources and found an article on msdn where they say:

Design-time IntelliSense To get IntelliSense support in Visual Studio before a build has generated an output assembly, the following conditions must be met:

There must be a target named Compile.

Although setting BeforeTargets=...;Compile didn't work, setting CoreCompile instead worked for me and now both build and intellisense work fine.

I assume the intellisense analyzer has its own workflow where other targets are used other than BeforeBuild. But I didn't find any details about which exactly targets it uses.(For example from the msdn article above I would think BeforeTargets="Compile" should work, while it doesn't)

Brittnybritton answered 22/6, 2020 at 14:13 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.