Access MS Build Parameter within a project - c#

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>

Related

include file for each target framework in nuget

I have a project (SDK style) with several target frameworks:
<PropertyGroup>
<TargetFrameworks>net48;netcoreapp3.1;net5.0-windows;net6.0-windows</TargetFrameworks>
</PropertyGroup>
When I build it, a pdb file is generated for each target framework. I want to include these pdb files in the nuget next to their corresponding dll (so, in \lib\targetFramework\).
I am able to do it for one specific framework:
<ItemGroup>
<Content Include="bin\$(Configuration)\net48\*.pdb" Pack="true" PackagePath="lib\net48" />
</ItemGroup>
How can I specify this for all TargetFrameworks without hard-coding?
I can do it generically if I have the collection of all TargetFrameworks transformed in a certain way:
<ItemGroup>
<!-- hard-coded collection -->
<PDBFile Include="bin\$(Configuration)\net48\$(AssemblyName).pdb">
<NugetFramework>net48</NugetFramework>
</PDBFile>
<PDBFile Include="bin\$(Configuration)\netcoreapp3.1\$(AssemblyName).pdb">
<NugetFramework>netcoreapp3.1</NugetFramework>
</PDBFile>
<PDBFile Include="bin\$(Configuration)\net5.0-windows\$(AssemblyName).pdb">
<NugetFramework>net5.0-windows7.0</NugetFramework>
</PDBFile>
<PDBFile Include="bin\$(Configuration)\net6.0-windows\$(AssemblyName).pdb">
<NugetFramework>net6.0-windows7.0</NugetFramework>
</PDBFile>
<!-- generic usage of the collection -->
<Content Include="#(PDBFile)" Pack="true" PackagePath="lib\%(NugetFramework)"/>
</ItemGroup>
But I still don't know how to define the PDBFile collection in a less hard-coded way...

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>

Disabling a specific C# 9 source generator

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>

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