Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to generate files during build using msbuild

Tags:

msbuild

Does anyone know how to modify a csproj file in a way to generate code files during build without actually referencing the files?

A process like :

  • create file,
  • dynamically reference temporary file during build
  • compiled assembly has additional members, depending on the files created during build

The purpose of this is to create a way of generating code files using roslyn instead of using t4 templates, which are very awkward to use once you're trying to do something depending on attributes.

Hence i am planning on providing a way to use a special csharp file (for full syntax support) to generate files programatically based on the contents of that special file.

I've spent a couple of weeks looking into resources on the internet (with the topic msbuild), but until now it seems i didn't use the right keywords.

This one has been the most insightful one to me yet: https://www.simple-talk.com/dotnet/.net-tools/extending-msbuild/

My guess is, that the correct build target for my purpose should be "BeforeCompile" in order to somehow populate the build process with custom code files.

Does anyone have experience with my issue, or is aware of any particular resources which deal with the task?

Solution i got it working with:

<UsingTask TaskName="DynamicCodeGenerator.DynamicFileGeneratorTask" AssemblyFile="..\DynamicCodeGenerator\bin\Debug\DynamicCodeGenerator.dll" />
<Target Name="DynamicCodeGeneratorTarget" BeforeTargets="BeforeBuild;BeforeRebuild">
    <DynamicFileGeneratorTask>
        <Output ItemName="Generated" TaskParameter="GeneratedFilePaths" />
    </DynamicFileGeneratorTask>
    <ItemGroup>
        <Compile Include="@(Generated)" />
        <FileWrites Include="@(Generated)" />
        <!-- For clean to work properly -->
    </ItemGroup>
</Target>

Unfortunately i did not get it to work with a propertygroup override as suggested

Update: This link is interesting too: https://github.com/firstfloorsoftware/xcc/blob/master/FirstFloor.Xcc/Targets/Xcc.targets

like image 270
Dbl Avatar asked Sep 19 '15 15:09

Dbl


People also ask

How do I create a SLN file in MSBuild?

At the command line, type MSBuild.exe <SolutionName>. sln , where <SolutionName> corresponds to the file name of the solution that contains the target that you want to execute. Specify the target after the -target: switch in the format <ProjectName>:<TargetName>.

Will MSBuild compile a file without any target?

If MSBuild determines that any output files are out of date with respect to the corresponding input file or files, then MSBuild executes the target. Otherwise, MSBuild skips the target. After the target is executed or skipped, any other target that lists it in an AfterTargets attribute is run.

How is Csproj file created?

A CSPROJ file is a C# (C Sharp) programming project file created by Microsoft Visual Studio. It contains XML-formatted text that lists a project's included files and compilation options. Developers compile CSPROJ files using MSBuild (the Microsoft Build Engine).


2 Answers

Generating the code file can be achieved by msbuild task or msbuild inline task. It is up to you to generate the proper code. One thing that you must care of is creating output item parameter in order to append it to the @(Compile) item. You can use $(IntDir) location to locate your newly generated file, and add them to the @(FileWrites) item group in order for Clean target work properly.

When you finish writing your task, you must use it in your project like this:

<UsingTask TaskName="TaskTypeFullName" AssemblyFile="YourAssembly.dll"/>
<PropertyGroup>
<!-- Here you need to experiment with [Build/Compile/SomeOther]DependsOn property -->
    <BuildDependsOn>
        MyCodeGenerator;
        $(BuildDependsOn)
    </BuildDependsOn>
</PropertyGroup>

<Target Name="MyCodeGenerator">
    <YourTaskName>
        <Output ItemName="Generated" TaskParameter="GeneratedFiles" />
    </YourTaskName>
    <ItemGroup>
        <Compile Include="@(Generated)" /> 
        <FileWrites Include="@(Generated)" /> <!-- For clean to work properly -->
    </ItemGroup>
</Target>

like image 78
stukselbax Avatar answered Oct 07 '22 14:10

stukselbax


I wanted to use a bash script to generate code for a project using dotnet core on Linux. Here is what worked for me. And thanks @stukselbax, I built this off of your answer.

  <Target Name="GenerateProtocolBuffers" BeforeTargets="BeforeBuild;BeforeRebuild">
    <Exec Command="./generatecode.sh" Outputs="proto/*.cs">
      <Output ItemName="Generated" TaskParameter="Outputs" />
    </Exec>
    <ItemGroup>
      <Compile Include="@(Generated)" />
      <FileWrites Include="@(Generated)" />
    </ItemGroup>
  </Target>

Note that the script I'm using to generate the code is called generatecode.sh. Replace this with your own.

like image 23
Austin Harris Avatar answered Oct 07 '22 14:10

Austin Harris