I have an Exe project that I would like to run in the PostBuildEvent block. I have tried adding a command to do this several ways but nothing seems to work.
dotnet run -- -i
dotnet run TestConsole.csproj -- -i
dotnet run ../../../TestConsole.csproj -- -i
../../../init.bat (which contains a cd to the project directory and "dotnet run...")
The first two fail being unable to find anything to run. The last two fail by hanging. Apparently, dotnet build recursively calling dotnet run doesn't work very well.
Is there a way of doing this?
The easiest way to do this is to re-use the built-in targets that already calculate the command. dotnet run also builds the project, so calling dotnet run could cause an infinite recursion - instead it should be dotnet path/to/the.dll. Also, PostBuildEvent is considered deprecated and has problems in SDK-based projects (an upcoming VS update will add targets instead when adding post build commands).
To execute the program on build, you can add the following to the csproj file:
<Project Sdk="Microsoft.NET.Sdk">
<!-- other project content -->
<Target Name="RunAfterBuild" AfterTargets="Build">
<Exec Command="$(RunCommand) $(RunArguments)" WorkingDirectory="$(RunWorkingDirectory)" />
</Target>
</Project>
The AfterTargets="Build" will cause to to run after ever build, even if it is invoked through VS. If it should not be run when working on the project in VS, you could add
Condition=" '$(BuildingInsideVisualStudio)' != 'true' "
as an attribute to the <Target> element.
The values for $(RunCommand), $(RunArguments) and $(RunWorkingDirectory) are defaulted by the SDK and contain the right paths to the host / exe file etc. involved. You can add any custom parameters to the Command="..." attribute and they will be passed to the application (no -- needed).
In order to add global arguments that would also be respected when the project was built/run through dotnet run, the StartArguments property in the project can be set. it will be added to RunArguments automatically:
<Project …>
<PropertyGroup>
<StartArguments>--sample-option</StartArguments>
</PropertyGroup>
<!-- other content -->
</Project>
Related
I have a TFS 2013 build xaml workflow, that eventually calls the Microsoft.TeamFoundation.Build.Workflow.Activities.MSBuild activity once for each solution that I want to build. When msbuild.exe is called, it's working directory is the working directory of the current solution being built. I can see this through the 'MSBuildStartupDirectory' property when running msbuild with a 'diagnostic' verbosity.
Unfortunately, I need the working of msbuild.exe to be somewhere else when msbuild.exe starts. This is because I use the MSBuild SonarQube runner that imposes constraints on the directory from which msbuild is called.
I have looked at the 'msbuild' activity and there is no way to control the working directory. Is there another way to control the working directory of this activity?
Its been a while since I edited a build process template but I believe you could use an activity that just executes a command in CMD and provide the full MSBuild command. I'm sure there are tons of variables you will need to setup for this to work.
Instead of editing the build process template have you considered using a PowerShell script in the Post-build script to execute SonarQube?
I still haven't found any way to control the working directory of msbuild. But since I know that the working directory will be the directory of the project being built by msbuild, I created a new proj file at the root of my workspace (where my working directory has to be) and only build this new proj file from my workflow. This new proj file then builds all my other solutions. That way, my working directory is the same for all the solutions being built.
Here is an example of my top level proj file:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Build">
<ItemGroup>
<Solutions Include="**\*.sln"/>
</ItemGroup>
<Target Name="Build">
<MSBuild Projects="#(Solutions)" Targets="Build"/>
</Target>
</Project>
But beware that doing this may affect the output directory (OutDir) given to each solution. So you may want to do something like this:
<MSBuild Projects="#(Solutions)" Targets="Build" Properties="OutDir=$(OutDir)..\%(Solutions.Filename)"/>
I need help in running stylecop task on all cs files included in solution.
Please let me know if its possible and how?
Right now I can run it on a file, but not on solution.
<CreateItem Include="$(RootPath)\**\*.cs">
<Output TaskParameter="Include" ItemName="StyleCopFiles"/>
</CreateItem>
<MSBuild.ExtensionPack.CodeQuality.StyleCop
TaskAction="Scan"
ShowOutput="true"
ForceFullAnalysis="true"
CacheResults="false"
SourceFiles="#(StyleCopFiles)"
logFile="$(OutDir)\StyleCopLog.txt"
SettingsFile="$(MSBuildStartupDirectory)\..\Settings.StyleCop"
ContinueOnError="false">
<Output TaskParameter="Succeeded" PropertyName="AllPassed"/>
<Output TaskParameter="ViolationCount" PropertyName="Violations"/>
<Output TaskParameter="FailedFiles" ItemName="Failures"/>
</MSBuild.ExtensionPack.CodeQuality.StyleCop>
Have you considered automatically running StyleCop rules as a part of your project build process? This won't run all rules at the solution level but at a project level. I prefer this approach because the rules will run whenever you build your project/solution and will display as Warnings in the Error List panel (double click to navigate to the offending line of code). Configuring this on a project by project basis may seem like a pain but we have a different set of StyleCop rules for our Unit Test projects, and this allows us to configure them individually.
Also, You won't have to explicitly add a MSBuild task to your build script because building the projects will automatically execute the StyleCop rules.
It's also worth noting that I'm using the NuGet Package: StyleCop.MSBuild (version 4.7.17.1) and using a relative path to reference the package from within my .csproj file like this:
<Project>
<Import Project="..\Packages\StyleCop.MSBuild.4.7.17.1\tools\StyleCop.targets" />
</Project>
http://stylecop.codeplex.com/wikipage?title=Running%20StyleCop%20in%20VS2005%20or%20VS%20Express&referringTitle=Documentation
You can also set conditions on when you want the rules to run. If the condition evaluates to false StyleCop will not run. We use the condition to suppress StyleCop when running Unit Tests
<Project>
<Import Project="..\Packages\StyleCop.MSBuild.4.7.17.1\tools\StyleCop.targets" Condition="'$(NCrunch)'!='1'" />
</Project>
In order to configure StyleCop rules, you will need to install StyleCop_v4.7.17.0.msi. We only define a single Settings.StyleCop file (Parent Settings File) for our entire codebase.
http://stylecop.codeplex.com/wikipage?title=Sharing%20StyleCop%20Settings%20Across%20Projects&referringTitle=Documentation
I have a project group in C++ Builder 2010. It contains several projects. One of these projects has, besides Debug and Releae, a Demo build configuration that is a child of the Release one.
The issue I run into is that if I run this from the build script we have, calling the project group file and telling it I want to build using the Demo configuration I get an error about unresolved WinMain. I get the same error by using a build configuration name that does not exist. So my initial thought was that this had to be due to the fact that the other projects in the project group didn't have a Demo configuration. But when I tried running msbuild against the project group file from cmd passing it Demo it built just fine.
C:\src\foo\AutoBuild> msbuild ..\foo.groupproj /t:build /p:Configuration=Demo
The same goes for building the specific project using msbuild from cmd. I have checked that the Config/*Configuration* property is carried over through each <msbuild /> task call and it is.
Hacking the project group (.groupproj) file and forcing it to run Demo for the project in question when running Release also worked.
...
<Target Name="Foo:Make">
<MSBuild Targets="Make" Projects="Foo.cbproj" Properties="Config=Demo"/>
</Target>
...
Any idea what could be causing this?
Update
Also, by running only the specific project in the main build script when Demo is selected it also works fine. Note that the Release build has been built by the build script prior to this.
<Target Name="Foo:Build">
...
<MSBuild Condition="$(Configuration)==''" Targets="Make" Projects="..\Server\Bar.groupproj" Properties="Config=Release" />
<MSBuild Condition="$(Configuration)==''" Targets="Foo" Projects="..\Server\Bar.groupproj" Properties="Config=Demo" />
...
</Target>
I am facing an issue with MSBuild I can't overcome it by myself. As a result I rely on community's wisdom.
The real situation I'm having troubles with
I have a soluiton file containing several projects with dependencies to other projects in same solution. I'd like to append a custom target to one of the project's csproj file and build it from the command line. It will allow me to make all the necessary output binaries for this project for further processing during the building of the custom target. But the main thing is that I can't figure out how to do it, googling doesn't help either.
Simplification
To make thing simplier I decided to make a new C# console project, add a simple custom target to the project's file and try to make it build. Still no success! Here what I've done so far:
Created a solution app with a default console project coreapp. This gaves me at least two files:
app.sln
coreapp\coreapp.csproj
Modified coreapp.csproj with addition of my custom target inside of the Project tag
<Target Name="SampleTarget">
<Message Text="This is a SampleTarget" />
</Target>
Run on the command line the following command
%windir%\Microsoft.NET\framework\v3.5\msbuild.exe app.sln /t:coreapp:SampleTarget
or even
%windir%\Microsoft.NET\framework\v3.5\msbuild.exe app.sln /t:coreapp.csproj:SampleTarget
Results
No luck, facing the error
MSB4057: The target "coreapp.csproj:SampleTarget" does not exist in the project.
I suspect that MSBuild thinks somehting fundamentally different from what I want it to think...
BEsides that, I also tried to set on the same command line the environment variable MSBuildEmitSolution=1 to force msbuild dump a temporary solution file it creates while processing the solution. In this file, indeed, no such target. However I guess it isn't the reason because I asked msbuild to build coreapp.proj where target SampleTarget really resides.
The question is how to build SampleTarget in this simplified scenario using solution file since potencially it can contain dependencies for the project containing this SampleTarget target?
I'd be greatful for any sort of help or firection for further investigation!
Instead of inserting a custom target in your project file, you could try creating a new standalone msbuild file, which would:
build the solution file (which builds projects)
defines your extra target
Call it app-custom-Debug.msbuild , for example.
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<WorkingFolder>$(MSBuildProjectDirectory)</WorkingFolder>
<Configuration>Debug</Configuration>
<SolutionFile>app.sln</SolutionFile>
</PropertyGroup>
<Target Name="Build" DependsOnTargets="Compile" />
<Target Name="Compile">
<Message Text="=== COMPILING $(Configuration) configuration ===" />
<MSBuild Projects="$(SolutionFile)"
Properties="Configuration=$(Configuration)" />
</Target>
<Target Name="SampleTarget">
<Message Text="This is a SampleTarget" />
</Target>
</Project>
Then you execute:
msbuild.exe app-custom-Debug.msbuild /t:SampleTarget
One option is to tie your SampleTarget to the standard Build targets via overriding the appropriate DependsOn property. In this case you could tell BeforeBuild that it DependsOn SampleTarget or you do the same thing with AfterBuild. This will ensure that MSBuild processes your target prior to the standard target indicated.
I need a set of tasks that need to be executed exactly once for the entire solution. This will run tasks that will modify each project to run a separate set of tasks for each project. We had done this earlier using a separate project to the solution which had the solution level tasks, but we want to move away from that. Has anyone done this or does anyone have any suggestions on how to implement this?
Since Solution files are not in MSBuild format they are not easily extended or customized. If you want more control over the build process you would have to create a "driver" msbuild file which would replace your solution file. Inside this driver file you would build all the projects that you needed and perform some additional tasks. You would do this using the MSBuild task. Here is a sample showing how to build more than 1 project.
<Project ...>
<ItemGroup>
<Projects Include="proj01.csproj"/>
<Projects Include="proj02.csproj"/>
<Projects Include="proj03.csproj"/>
</ItemGroup>
<Target Name="BuildAll">
<MSBuild Projects="#(Projects)" BuildInParallel="true" />
</Target>
</Project>
So in your case you would just execute the tasks before you build the projects. Also note that I specified the value true for the BuildInParallel indicating that MSBuild can try and build more than one project at once.
An alternative solution is to have a single target that dispatches to an MSBuild invoked target with as many Global properties removed as possible. My team have a target in the InitialTargets of a Directory.Build.props Import'ed props file - something like:
<Target Name="Prebuild">
<MSBuild Projects="$(MSBuildThisFileFullPath)"
Targets="PrebuildWorker"
RemoveProperties="Configuration;Platform;TargetFramework;BuildProjectReferences" />
</Target>
Since MSBuild appears to synchronize parallel builds on the {project file, global properties, target} set, then by removing all of the properties you can synchronize the build and run it once for all projects being built. The downside: you have to maintain the RemoveProperties attribute - MSBuild doesn't have a way to remove all global properties. If something in the build issues a new MSBuild task with a custom property specified, then you'll get a second instance of the Target invoked.
And - of course - your build will be synchronized on this target. You could try hooking the target up by setting, say, CompileDependsOn to depend on the Prebuild target, to allow independent progress in the build. But to have the target run early and ubiquitously using InitialTargets seems like the better option.