Disabling a specific C# 9 source generator - c#

Is there any way to disable a specific C# 9 source generator? Or alternatively disable them all?
the package in question is https://github.com/Husqvik/GraphQlClientGenerator#c-9-source-generator which is mean to be able to be used as both a lib and a source generator. but those are mutually exclusive, ie the majority of use cases it make no sense to gen code both by executing code and by code gen

seems this will disable all
<Target Name="DisableAnalyzers"
BeforeTargets="CoreCompile">
<ItemGroup>
<Analyzer Remove="#(Analyzer)" />
</ItemGroup>
</Target>
removing a named one uses the file path
<Target Name="DisableAnalyzers"
BeforeTargets="CoreCompile">
<ItemGroup>
<Analyzer Remove="D:\nugets\nugetx\0.9.2\analyzers\dotnet\cs\NugetXAnalizer.dll" />
</ItemGroup>
</Target>
ok and finally u can remove based on filename
<Target Name="DisableAnalyzers"
BeforeTargets="CoreCompile">
<ItemGroup>
<Analyzer Remove="#(Analyzer)"
Condition="'%(Filename)' == 'NugetXAnalizer'"/>
</ItemGroup>
</Target>

Related

Python as a post-build step to C#

I'm looking into ways to execute python as part of a C# build.
Specifically, I want to create a Python package based on a C# project through python.net. My general idea was to build the C# project first. And then, as some sort of post-build step, invoke python to build a package based on the newly generated NET assemblies.
I can't presume python will installed on the build host, so ideally I want to include a "portable" - even more ideally, nuget-based - python distribution.
I have found a promising nuget package, but am not entirely sure of its usage. It incldues no C# code, but has all python binaries included, and has build props as copy/pasted below for reference.
Given on that package's props - can I somehow reference its binaries from my own project as a post-build step?
Say, for example, I want to add a post-build step to my own project, that simply just invokes "python.exe" after the build. How could I do that?
My own project:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.1</TargetFramework>
<GenerateProgramFile>false</GenerateProgramFile>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="python" Version="3.10.0-a6" />
</ItemGroup>
<Target Name="MyCustomStep" AfterTargets="Build">
<!-- .. now what? I can't seem to access. e.g. #(PythonHome) or $(PythonHome) from here --/>
<Target>
</Project>
Props of the python package from nuget:
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition="$(Platform) == 'X64'">
<PythonHome Condition="$(PythonHome) == ''">$([System.IO.Path]::GetFullPath("$(MSBuildThisFileDirectory)\..\..\tools"))</PythonHome>
<PythonInclude>$(PythonHome)\include</PythonInclude>
<PythonLibs>$(PythonHome)\libs</PythonLibs>
<PythonTag>3.10</PythonTag>
<PythonVersion>3.10.0-a6</PythonVersion>
<IncludePythonExe Condition="$(IncludePythonExe) == ''">true</IncludePythonExe>
<IncludeDistutils Condition="$(IncludeDistutils) == ''">false</IncludeDistutils>
<IncludeLib2To3 Condition="$(IncludeLib2To3) == ''">false</IncludeLib2To3>
<IncludeVEnv Condition="$(IncludeVEnv) == ''">false</IncludeVEnv>
<GetPythonRuntimeFilesDependsOn>_GetPythonRuntimeFilesDependsOn310_None;$(GetPythonRuntimeFilesDependsOn)</GetPythonRuntimeFilesDependsOn>
</PropertyGroup>
<ItemDefinitionGroup Condition="$(Platform) == 'X64'">
<ClCompile>
<AdditionalIncludeDirectories>$(PythonInclude);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
</ClCompile>
<Link>
<AdditionalLibraryDirectories>$(PythonLibs);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<Target Name="GetPythonRuntimeFiles" Returns="#(PythonRuntime)" DependsOnTargets="$(GetPythonRuntimeFilesDependsOn)" />
<Target Name="_GetPythonRuntimeFilesDependsOn310_None" Returns="#(PythonRuntime)">
<ItemGroup>
<_PythonRuntimeExe Include="$(PythonHome)\python*.dll" />
<_PythonRuntimeExe Include="$(PythonHome)\python*.exe" Condition="$(IncludePythonExe) == 'true'" />
<_PythonRuntimeExe>
<Link>%(Filename)%(Extension)</Link>
</_PythonRuntimeExe>
<_PythonRuntimeDlls Include="$(PythonHome)\DLLs\*.pyd" />
<_PythonRuntimeDlls Include="$(PythonHome)\DLLs\*.dll" />
<_PythonRuntimeDlls>
<Link>DLLs\%(Filename)%(Extension)</Link>
</_PythonRuntimeDlls>
<_PythonRuntimeLib Include="$(PythonHome)\Lib\**\*" Exclude="$(PythonHome)\Lib\**\*.pyc;$(PythonHome)\Lib\site-packages\**\*" />
<_PythonRuntimeLib Remove="$(PythonHome)\Lib\distutils\**\*" Condition="$(IncludeDistutils) != 'true'" />
<_PythonRuntimeLib Remove="$(PythonHome)\Lib\lib2to3\**\*" Condition="$(IncludeLib2To3) != 'true'" />
<_PythonRuntimeLib Remove="$(PythonHome)\Lib\ensurepip\**\*" Condition="$(IncludeVEnv) != 'true'" />
<_PythonRuntimeLib Remove="$(PythonHome)\Lib\venv\**\*" Condition="$(IncludeVEnv) != 'true'" />
<_PythonRuntimeLib>
<Link>Lib\%(RecursiveDir)%(Filename)%(Extension)</Link>
</_PythonRuntimeLib>
<PythonRuntime Include="#(_PythonRuntimeExe);#(_PythonRuntimeDlls);#(_PythonRuntimeLib)" />
</ItemGroup>
<Message Importance="low" Text="Collected Python runtime from $(PythonHome):%0D%0A#(PythonRuntime->' %(Link)','%0D%0A')" />
</Target>
</Project>
That is for the use of internal nuget rather than your main project. You cannot get that property under main project.
You have to use my function:
1) edit csproj file and set this for your PackageReference python
<GeneratePathProperty>true</GeneratePathProperty>
Like this:
<ItemGroup>
<PackageReference Include="python" Version="3.10.0-a6">
<GeneratePathProperty>true</GeneratePathProperty>
</PackageReference>
</ItemGroup>
2) Then, you can use $(Pkgpython) to get that path.
<Target Name="MyCustomStep" AfterTargets="Build">
<Exec Command="$(Pkgpython)\tools\python.exe" />
</Target>

Assert number of items in Include with wildcard

I have a C# project where I need to include a file as a resource. I don't know the full name of the file in advance, as it will include a version number that I can't easily access at build time. So I'm using a wildcard like this:
<ItemGroup>
<EmbeddedResource Include="..\..\setup\bin\MyApp-setup-*.exe">
<Link>Setup\%(filename)%(extension)</Link>
<LogicalName>Setup\%(filename)%(extension)</LogicalName>
</EmbeddedResource>
</ItemGroup>
It works, but the problem is that it can include any number of files, and I want it to include exactly one. There should be only one matching file in the folder. If there are zero or several files that match the wildcard, I want it to be a build error. Is there a way to assert that only one file is included?
EDIT: Thanks to #stijn's answer, I was able to do it like this:
<Target Name="BeforeBuild">
<ItemGroup>
<EmbeddedResource Include="..\..\setup\bin\MyApp-setup-*.exe">
<Link>AppFiles\%(filename)%(extension)</Link>
<LogicalName>AppFiles\%(filename)%(extension)</LogicalName>
</EmbeddedResource>
</ItemGroup>
<PropertyGroup>
<SetupFileCount>#(EmbeddedResource->Count())</SetupFileCount>
</PropertyGroup>
<Error Text="Expected exactly one file matching 'MyApp-setup-*'; found $(SetupFileCount)." Condition="'$(SetupFileCount)' != '1'"/>
</Target>
Use the Item Function 'Count' to get the number of items and raise an error if it's not 1:
<Target Name="ErrorIfNotOneEmbeddedResourceFound" BeforeTargets="Build">
<ItemGroup>
<EmbeddedResource Include="..\..\setup\bin\MyApp-setup-*.exe">
<Link>Setup\%(filename)%(extension)</Link>
<LogicalName>Setup\%(filename)%(extension)</LogicalName>
</EmbeddedResource>
</ItemGroup>
<Error Text="Didn't find one match" Condition="'#(EmbeddedResource->Count())' != '1'"/>
</Target>

Access MS Build Parameter within a project

I have a project within a solution, and a MS Build that builds the solution. As a part of the build, I can add MS Build arguments. Is there anyway that I can reference that build argument within my code inside the project?
A sort of "quick and dirty" way I've achieved this before is by dynamically generating a source file in MSBuild and adding it to the Compile item group.
This is assuming you mean MSBuild Properties by "MS Build Parameter(s)", specified like /p:MyProperty=foo on the command-line.
<Target Name="WriteToFile" BeforeTargets="PrepareForBuild">
<ItemGroup>
<_Lines Include='// auto-generated!' />
<_Lines Include='public class MyProperties {' />
<_Lines Include=' public string Property1="$(Property1)"'; />
<_Lines Include='}'; />
</ItemGroup>
<WriteLinesToFile
File="autogen.cs"
Lines="#(_Lines)"
Overwrite="true" />
</Target>
<ItemGroup>
<Compile Include="autogen.cs">
</ItemGroup>
</Target>

How does the MSBuild:Compile generator work

I'm trying to use the MSBuild:Compile generator to trigger a compilation of my custom file type when the file is saved in Visual Studio (should work like a custom tool but with msbuild). The build process itself is working but it doesn't seem to be triggered if the file is saved.
Can someone explain what exactly the MSBuild:Compile entry is doing? As far I have just seen this used in the antlr msbuild scripts and for XAML.
Below I have an extract of the msbuild setup I use to compile a *.myext file to a *.g.ts file.
My targets file:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<UsingTask TaskName="SampleNamespace.CustomCompilerTask" AssemblyFile="MyTask.dll" />
<PropertyGroup>
<PrepareResourcesDependsOn>
CustomLayoutCompile;
$(PrepareResourcesDependsOn)
</PrepareResourcesDependsOn>
</PropertyGroup>
<ItemDefinitionGroup>
<CustomTypeCompile>
<Generator>MSBuild:Compile</Generator>
</CustomTypeCompile>
</ItemDefinitionGroup>
<Target Name="CustomLayoutCompile" Inputs="#(TypeScriptCompile);#(CustomTypeCompile)" Outputs="#(CustomTypeCompile->'%(RootDir)%(Directory)%(Filename).g.ts')">
<CustomCompilerTask TypeScriptFiles="#(TypeScriptCompile)" LayoutFiles="#(CustomTypeCompile)" />
</Target>
</Project>
Entries in the project file:
....
<ItemGroup>
<TypeScriptCompile Include="MyControl.ts">
<DependentUpon>MyControl.myext</DependentUpon>
</TypeScriptCompile>
<TypeScriptCompile Include="MyControl.g.ts">
<DependentUpon>MyControl.myext</DependentUpon>
</TypeScriptCompile>
</ItemGroup>
<ItemGroup>
<CustomTypeCompile Include="MyControl.myext">
<Generator>MSBuild:Compile</Generator>
</CustomTypeCompile>
</ItemGroup>
....
<Import Project="path/to/my/target/file/mytargets.targets" />
....
I am using VS 2019 and was suffering from the same exact issue. I finally figured out a workaround, which make the issue looks more like a VisualStudio/MSBuild bug to me. My workaround is that when you define your ItemDefinitionGroup, define a custom/extended file property page like below. It worked for me. Hope it also works for everyone else too.
<ItemGroup>
<PropertyPageSchema Include="$(MSBuildThisFileDirectory)CustomPerperties.CSharp.xml">
<Context>File;BrowseObject</Context>
</PropertyPageSchema>
<AvailableItemName Include="CustomTypeCompile" />
</ItemGroup>

How to integrate conditional logic in postbuild events

Hi I have a visual studio project which includes postbuildevents in the following form:
MyTool.exe $(ProjectDir)somesrcfile.txt $(TargetDir)sometargetfile.bin
Now I want to add some logic saying that these steps are taking place only if the files have changed. In peudocode:
if (somesrcfile.txt is newer than sometargetfile.bin)
{
MyTool.exe $(ProjectDir)somesrcfile.txt $(TargetDir)sometargetfile.bin
}
Can I do this with MsBuild?
EDIT:
I just tried it with a simple copy command but it seems not to work. Also the message is not displayed when I build the solution.
<ItemGroup>
<MyTextFile Include="*.txt" />
</ItemGroup>
<Target Name="Build" Inputs="#(MyTextFile)" Outputs="#(MyTextFile->'%(Filename).bin')">
<CustomBuild>
<Message>Encoding files...</Message>
<Command>
copy %(Identity) %(Filename).bin
</Command>
<Outputs>$(OutDir)%(Identity)</Outputs>
</CustomBuild>
</Target>
Yes, it is possible by using the Inputs and Outputs attributes on your target.
See: How to: Build incrementally
In your case, it would look something like this:
<Target Name="AfterBuild" DependsOnTargets="Test">
</Target>
<ItemGroup>
<MyTextFile Include="*.txt" />
</ItemGroup>
<Target Name="Test" Inputs="#(MyTextFile)" Outputs="#(MyTextFile->'%(FileName).bin')">
<Message Text="Copying #(MyTextFile)" Importance="high"/>
<Copy SourceFiles="#(MyTextFile)" DestinationFiles="#(MyTextFile->'%(FileName).bin')" />
</Target>
This target will only run if input files are newer than output files.

Categories