List defined preprocessor symbols for C# - c#

When running dotnet, msbuild, or csc, I want to output a list of defined preprocessor symbols, similar to gcc -dM -E. How can I do this?

The defined preprocessor symbols are listed in a proprety called DefineConstants. To echo them, you could add a target to your project file like the following:
<Target Name="EchoDebugInfo" BeforeTargets="CoreCompile">
<Message Importance="high" Text="Just before building, current compile defines are $(DefineConstants)"></Message>
</Target>
In my test run (using dotnet build with no extra parameters), this printed:
Just before building, current compile defines are TRACE;DEBUG;NETCOREAPP;NETCOREAPP2_2
Note that if you omit Importance="high", the importance of the message defaults to "normal", which won't show in the default verbosity of dotnet build. Setting Importance="high" allowed me to get the output without changing the default verbosity of the dotnet build command.
BTW, if you try to define the BeforeBuild target as suggested in the Visual Studio docs, you'll discover that it doesn't work if you're using the new .Net Core-style projects (e.g., <Project Sdk="Microsoft.NET.Sdk">). This is because the SDK project is auto-imported after your project file, so you'll see something similar to this message in the build logs:
Overriding target "BeforeBuild" in project "/home/rmunn/path/to/project/Project.fsproj" with target "BeforeBuild" from project "/usr/share/dotnet/sdk/3.0.100/Microsoft.Common.CurrentVersion.targets".
And then your BeforeBuild target doesn't work. There's a note in the MSDN docs that explains this (emphasis in original):
SDK-style projects have an implicit import of targets after the last line of the project file. This means that you cannot override default targets unless you specify your imports manually as described in How to: Use MSBuild project SDKs.
If you need full control over when the SDK project is imported, then that's the way to go. But for this simple use case, I prefer to define my own target and use BeforeTargets="CoreCompile" to place it in the correct place in the build order.

Related

MSBuild looks for Main when building a project

I am working on a large project that consists of multiple executables. I'd like to automate deployment process by building all of them at once. That is why I resorted to msbuild command line utility.
When I build one of my projects in Visual Studio it build normally. When I try to do the same using msbuild cmd, it fails with an error
CSC : error CS5001: Program does not contain a static 'Main' method suitable for an entry point [pathToLibrary.csproj]
This is cmd code:
msbuild MainProject.csproj -property:Configuration=Release -property:Platform="AnyCPU" -property:OutputType="WinExe" -target:"Rebuild"
pathToLibrary.csproj indeed is a library so I don't know why msbuild is trying to find a main method. There is none. It is a library.
What am I missing here?
pathToLibrary.csproj indeed is a library so I don't know why msbuild
is trying to find a main method. There is none. It is a library.
When your main project references projects by Add Reference-->Projects, it will always build not only the main projects but also the referenced projects at the same time. So when you build that project by MSBuild command lines, -property:OutputType=winexe will also apply to these referenced projects. When you build the project in VS IDE and MSBuild, you will see these info in output log.
If there is no way to instruct msbuild to only overwrite OutputType
for main .csproj, editing every file separately will have to do
If you just want to find a way to specify -property:OutputType=winexe to the main project not the referenced projects by MSBuild command line, I think there is no such function.
Or you could try my suggestions:
1) please remove -property:OutputType=winexe in MSBuild command line and when you create the related project, you have already specified the output type of the project, so you don't need to specify it in MSBuild which is not the job of the MSBuild.
Note that you can modify the property in xxx.csproj directly like <OutputType>WinExe</OutputType>.
2) if you still want this feature when you build the project with MSBuild command line, I suggest you could create a script called Directory.Build.targets which can overwrite the OutputType property and then build the project separately with MSBuild.
~a) please create a file called Directory.Build.targets in every project folder which the xxxx.csproj file exists.
~b) write the related property about the project in it:(use Exe in a console project ,use WinExe in a windows project and use Library in a class library project.)
<Project>
<Target Name="inputproperty" BeforeTargets="AssignProjectConfiguration">
<PropertyGroup>
<OutputType>WinExe</OutputType>
</PropertyGroup>
</Target>
</Project>
write like this in your MainProject project and then create another Directory.Build.targets in your pathToLibrary project to use <OutputType>Library</OutputType> so that it will meet your expectations.

Disable code analysis when using MSBuild 14

I have a .NET solution containing several C# 6.0 projects. Every project references the StyleCop Analyzer via NuGet. Within Visual Studio, I have the possibility to distinguish between building and analyzing the code, but I don't see how to do this with MSBuild v14.0 on the command line (e. g. on a CI server). I'm calling msbuild mySolution.sln /t:Rebuild with the following options, none of them worked:
/p:RunCodeAnalysis=False
/p:RunCodeAnalysisOnThisProject=False
/p:RunCodeAnalysis=False,RunCodeAnalysisOnThisProject=False
Whatever I do, the warnings SAxxxx remain in the output. Does anyone know how to disable code analysis when using MSBuild?
Background: on our CI server, I want to distinguish between "basic MSBuild warnings" and warnings coming from static code analysis.
Regards
anyone know how to disable code analysis when using MSBuild?
The RunCodeAnalysis setting as defined in the build server TFSBuild.proj differs significantly from the local MSBuild project schema options.
Build server support the value of "Always, Default, Never" for RunCodeAnalysis. In contrast, locally MSBuild supports "True or False" for RunCodeAnalysis.
You can check the section of the Microsoft.TeamFoundation.Build.targets file:
<Target Name="CoreCompileSolution">
 
  <PropertyGroup>
    <CodeAnalysisOption Condition=" '$(RunCodeAnalysis)'=='Always'">RunCodeAnalysis=true</CodeAnalysisOption>
    <CodeAnalysisOption Condition=" '$(RunCodeAnalysis)'=='Never'">RunCodeAnalysis=false</CodeAnalysisOption>
    <!-- ... -->
  </PropertyGroup>
  <!-- ... -->
</Target>
From this we can infer that "Default" setting does not provide a value to the runtime, while "Always" and "Never" map to True/False respectively.
On the build server:
Always tells MSBuild to compile all projects with RunCodeAnalysis=True
Never tells MSBuild to suppress code analysis (RunCodeAnalysis=False) on all projects.
So the values for RunCodeAnalysis are either Default,Always,Never or True,False, depending on how you build.
You can refer to the How to: Edit a Build Type and CodeAnalysis, FxCop and Team Build to more detailed info.
Update:
According to the mu88 replied, I have create a test demo on the Jenkins with RunCodeAnalysis=False, the code analysis is disabled as expected. Below is my configuration on the Jenkins:
Besides, You can also check the build log whether has the section from "Running Code Analysis..." to "Code Analysis Complete "
And for the warnings SAxxxx remain in the output, this is not Code Analysis result. You can test it on the Visual Studio without code analysis. After install the package StyleCop.Analyzers, then build the project, you will get those warnings.
So please double check whether the build log on the Jenkins contains the section "Running Code Analysis..." and "Code Analysis Complete " after build the project with parameter:/p:RunCodeAnalysis=False.
Update2:
If you want to suppress StyleCop Warning, you can trick StyleCop into not processing a file at all by adding this header at the top of .cs file:
//------------------------------------------------------------------------------
// <auto-generated>
// Well, not really. This is just a trick to get StyleCop off my back.
// </auto-generated>
//------------------------------------------------------------------------------
It's not really supported, but there is a workaround:
Create a Directory.Build.targets (msbuild >= v15.0), After.{SolutionName}.sln.targets (msbuild < 15.0) file in your solution root folder and add:
<Project>
<Target Name="DisableAnalyzers"
BeforeTargets="CoreCompile"
Condition="'$(UseRoslynAnalyzers)' == 'false'">
<!--
Disable analyzers via an MSBuild property settable on the command line.
-->
<ItemGroup>
<Analyzer Remove="#(Analyzer)" />
</ItemGroup>
</Target>
</Project>
You can pass in /p:UseRoslynAnalyzers=false now to remove all analyzers configured in the project.
See also:
https://github.com/dotnet/roslyn/issues/23591#issuecomment-507802134
https://learn.microsoft.com/en-us/visualstudio/msbuild/customize-your-build?view=vs-2019#directorybuildprops-and-directorybuildtargets
You can edit the condition to also trigger on RunCodeAnalysis=False or Never.
<Target Name="DisableAnalyzers"
BeforeTargets="CoreCompile"
Condition="
'$(UseRoslynAnalyzers)' == 'false'
or '$(RunCodeAnalysis)' == 'false'
or '$(RunCodeAnalysis)' == 'never'" >
In .Net 5 supported project you can simply edit the .csproj and add:
<RunAnalyzersDuringBuild>false</RunAnalyzersDuringBuild> Disable code analysis on build
<RunAnalyzersDuringLiveAnalysis>false</RunAnalyzersDuringLiveAnalysis> Disable code analysis on live analysis
<RunAnalyzers>false</RunAnalyzers> prevent analyzers from running on this project
I use it in my Unit Testing Projects by adding it in the PropertyGroup that holds the TargetFramework like so:
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<IsPackable>false</IsPackable>
<!--disable code analysis on this XUNIT Project-->
<RunAnalyzersDuringBuild>false</RunAnalyzersDuringBuild>
<RunAnalyzersDuringLiveAnalysis>false</RunAnalyzersDuringLiveAnalysis>
<RunAnalyzers>false</RunAnalyzers>
</PropertyGroup>
for further details refer to MS Documentation
If you have a lot of csproj files in solution, it slow to set each project.
Download extension for visual studio 2022: SwitchRunCodeAnalysis

Adding and running custom target by msbuild

I am struggling with seemingly very basic task at the moment, that is addding a new custom target to csproj file and run it from the command line using msbuild.
I did an extensive research on the net but I found no solution that is actually working.
Let's say that I add the following target to my csproj file:
<Target Name="TeamCity">
<Message Text="I am Running!"/>
</Target>
or even something that depends on Build:
<Target Name="TeamCity" DependsOnTargets="Build">
<Message Text="I am Running!"/>
</Target>
This is what msbuild documentation suggests.
But running the target seems to be a mission impossible.
While I am able to run predefined target on csproj:
msbuild MySolution.sln /t:MyProject:Rebuild /p:Configuration="Release" /p:Platform="Any CPU"
I am not able to run the target I just added - that is TeamCity target:
msbuild MySolution.sln /t:MyProject:TeamCity /p:Configuration="Release" /p:Platform="Any CPU"
I always get error MSB4057: The target "TeamCity" does not exist in the project.
What is the deeply kept secret to make this running?
PS. Please note that I need the task to be working on a project level not on a solution. And I need to run msbuild MySolution.sln ... not as many incorrectly suggest msbuild MyProject.csproj ...
The secret is pretty simple - you can't make this running.
Because, msbuild generates intermediate project file (YourSolution.sln.metproj) but that will not have the imports from YourProject.csproj, including the .targets files. That's why YourCustomTarget is not recognized.
What you can try is using Before/After Targets to inject your targets in predefined build flow.
Hope it will help.

Get WIX to include references within a project

I'm completely new to WiX and setting up custom installers in general, so I apologise for the topic of the question!
I have a internal business application (a diary), which builds and works well, so I followed tutorials/official documentation as to adding the WiX project and referencing the Diary's csproj to it.
After then building and running this most basic version of a WiX installer, the output directory has a lone exe file, which crashes moments after loading with a File Not Found Exception.
My guess is that it has not built in either Crystal Report or NLog, both of which are referenced in my CSProj.
My question is this, how do I get WIX to include and build those project references to the output???
Any help is greatly appreciated!
/Antony
Unfortunately you will have to do some manual labor in order to get your projects right. I would take either of the two following approaches which require you to edit the .wixproj file:
Use HeatProject task. You will have to do this for all referenced projects and it will give you separate .wxs files for all of them. After this reference the component groups in those files in a feature of your WIX based setup.
<Target Name="BeforeBuild">
<HeatProject ToolPath="$(WixToolPath)" AutogenerateGuids="true" OutputFile="OutputFile.wxs" SuppressFragments="true" Project="ReferencedProject.csproj" ProjectOutputGroups="Binaries" />
</Target>
Use HeatDirectory task. Following will pick up everything in the bin folder of your project, including any binaries for the referenced projects, and give you a single .wxs containing UniqueComponentGroupName which can be included in any feature.
<Target Name="BeforeBuild">
<PropertyGroup>
<DefineConstants>BINFOLDER=PATH\TO\YourProject\bin\$(Configuration)</DefineConstants>
</PropertyGroup>
<HeatDirectory OutputFile="OutputFile.wxs" Directory="PATH\TO\YourProject\bin\$(Configuration)" KeepEmptyDirectories="true" DirectoryRefId="INSTALLFOLDER" ComponentGroupName="UniqueComponentGroupName" SuppressCom="true" SuppressFragments="true" SuppressRegistry="true" SuppressRootDirectory="true" GenerateGuidsNow="true" ToolPath="$(WixToolPath)" PreprocessorVariable="var.BINFOLDER" />
</Target>
Unlike the (now defunct) Setup Project project in older versions of Visual Studio, WiX does not do automatic reference detection. You'll have to add each referenced project to the WiX project manually, just as you did for the main project.

How can you access the Visual Studio solution level platform from a C# project's build event?

We have a large VS 2010 solution that is mostly C# code but there are a few native DLLs that various C# projects depend upon (including our unit testing DLL). We're in the processing of trying to support both 32-bit and 64-bit versions of our libraries. So we're now build the native DLLs as 32-bit and 64-bit. The problem is that a lot of our C# project's have post-build events that copy the required native DLLs into the project's TargetDir. Now that we have two different versions of the native DLLs (32 and 64 bit), I need to be able to specify the correct dir to copy the native DLL from. I originally thought I could simply use $(Platform) in the path like so:
copy $(SolutionDir)\NativeDll\$(Platform)\$(Configuration) $(TargetDir)
But that doesn't work because $(Platform) is the project's platform and not the solution level platform. In this case $(Platform) is "Any CPU". From what I can see looking at the post-build event macros in C# project, there doesn't appear to be a way to access the solution level platform that is being built. Is there a better way to accomplish my goal?
I believe the solution's platform, unlike that of the projects is simply text.
What I have down in the past is:
Delete Win32 and "mixed platform" from solution (and keep doing so after adding projects).
Set all C# DLLs to build as AnyCPU in solution platforms AnyCPU, x86, x64.
(Do not delete AnyCPU if you want to be able to open in Blend or if you have any pure managed applications in the solution.)
Set C# EXEs and unit tests to build in x86 in x86 solution platform and x64 in x64 solution platform and not to build at all in AnyCPU solution platform.
Set all natives to build in Win32 when solution is x86 and output to $(ProjectDir)\bin\x86\$(Configuration) and intermediate to same with obj in path instead of bin. x64 the same with x64 instead of x86 and Win32.
Set pre build events of C# EXEs and unit tests to copy native DLLs they are depended on from relative path with project's configuration name: $(Config)
Set unit tests' class initialize to copy entire contents of tests bin dir (correct platform and configuration, of course) to tests' out dir. Use if #DEBUG and unsafe sizeof(IntPtr) to tell where to look for tests' bin dir.
Manually (using Notepad) add relative reference path to .csproj files outside solution that use x86/x64 assemblies from solution's deployment location, so path will include $(Platform) and $(Configuration) and will not be per user.
Microsoft: Better 32/64 bit support in Visual Studio would be really in place.
When I had to do this, I simply made all of my assemblies buildable as x86 or x64 rather than AnyCPU, and had two separate output packages. There's really no point in AnyCPU if you KNOW your process must be 32-bit or 64-bit a prori.
I've not used it myself, but Build -> Batch Build is probably what you want. With it you can build multiple platforms.
http://msdn.microsoft.com/en-us/library/169az28z.aspx
Of course, this doesn't actually enable you to access the 'platform' for the solution, but you don't need to since you'll build each platform separately.
Update:
If you want to automate the build, create a batch file with the following contents
"c:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\devenv" ../solution.sln /rebuild "platform"
where 'platform' is "Release|Any CPU", "Release|x86" etc. and repeat the line for each configuration you need to build. Use the Configuration Manager to set up each project for a a build for x86 and x64 and you should have what you want.
I don't think the 'Active Solution Configuration' has an equivalent macro property.
What I suggest is to manually add a custom property in all .csproj files, like this (see the new MyVar custom property added for each configuration/platform combination):
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
...
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
...
<MyVar>MyDebugAnyCpu</MyVar>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
...
<MyVar>MyReleaseAnyCpu</MyVar>
</PropertyGroup>
You can use the 'Unload project' and 'Edit MyProject.csproj' menus to edit the .csprojet whil in Visual Studio. What's important to know is Visual Studio will not destroy these 'unknown' values even if you save it using the normal GUI editor.
Then in the post build event, you can use these values, for example:
copy $(SolutionDir)\$(MyVar)\$(Platform)\$(Configuration) $(TargetDir)
Francesco Pretto has an extension that helps with this. It seems to have some quirks and deficiencies, but it's a start.
http://visualstudiogallery.msdn.microsoft.com/619d92a2-4ead-410d-a105-135f7b4b4df9
With source on github:
https://github.com/ceztko/SolutionConfigurationName

Categories

Resources