Visual Studio build events - visual-studio-2017

I't trying to configure my solution in Visual Studio 2017 for cleanup after builds etc. I'm interested if there is a full list of commands/events for using in pre/post build events section. Is there any?

According to this page, there are PreBuild, PreLink, and PostBuild events. These can be declared inline (which VS does):
<ItemGroup>
<PostBuildEvent>rd /s /q obj</PostBuildEvent>
<ItemGroup>
The docs demonstrate it split up into separate Commands and Messages, but this didn't work for me in a C# project. I'm not sure if this is a C++ only feature.
<ItemGroup>
<PostBuildEvent>
<Command>rd /s /q obj<Command>
<Message>Cleanup intermediate output directory</Message>
</PostBuildEvent>
<ItemGroup>
Additionally, you can augment the build pipeline by adding new MSBuild targets. These can be configured to run before or after any specific target in the pipeline (there are many by default). Documentation for that is here, especially the section titled BeforeTargets and AfterTargets.

Related

Pass /MP option to the compiler using MSBuild

I have a VC project file that I'm building from command line using MSBuild. I want to specify the /MP flag without editing the project file. Is that possible?
I've tried set CL=/MP prior to calling MSBuild, but it has no effect.
This can be accomplished by accessing the CL_MPCount Visual Studio option:
MSBuild /m:2 /p:CL_MPCount=2 /p:Configuration=Release tf_tutorials_example_trainer.vcxproj
The above instructs the compiler to perform a maximum of 2 parallel compilation tasks. The /m:2 flag allows MSBuild to build two projects in parallel. The net result is that we have a maximum of 4 cl.exe processes running in parallel.
UPDATE: The CL_MPCount=2 flag gets passed on to cl.exe as /MP2. This allows parallel compilation of 2 .cpp files within the same project.
You need a property that you can override from the command line. Open the .vcxproj file in a text editor, Notepad will do. Locate the "Globals" property group and add a property named, say, "Turbo"
<PropertyGroup Label="Globals">
<Turbo>false</Turbo>
...etc...
</PropertyGroup>
And use the property to specify the compile option. Since it can only work in the Release build:
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<MultiProcessorCompilation>$(Turbo)</MultiProcessorCompilation>
...etc...
</ClCompile>
And run MSBuild:
msbuild /p:Configuration=Release /p:Turbo=true

Build process hangs when recursively building solution

While trying to answer this SO question I encountered an issue which I cannot explain and would appreciate your input on.
Setup:
Have solution consisting of several C++ projects (Test.sln),
Add a brand new project to your solution (BuildInstaller.vcxproj),
Open BuildInstaller.vcxproj in text editor and append following xml fragment right before closing </Project> tag:
<Target Name="Build">
<MSBuild Projects="..\Test.sln" Properties="Configuration=Release;Platform=Win32" />
<MSBuild Projects="..\Test.sln" Properties="Configuration=Release;Platform=x64" />
</Target>
Above code overrides default Build target of the BuildInstaller project and everytime the project is being built, it builds its parent solution with Release configuration for both Win32 and x64 platforms,
To prevent unbounded recursion, open Configuration Manager in Visual Studio and uncheck "Build" checkbox for BuildInstaller project for all combinations of Debug/Release and Win32/x64,
Then, still in Configuration Manager, create a new configuration, e.g. Installer for which you should uncheck all the other project's Build checkbox and leave it checked for BuildInstaller only,
Now build your solution for Installer configuration.
I would expect this build to finish successfully, but it simply hangs, even though BuildInstaller should not be built recursively as we are recursively building the Test.sln only for Release configuration.
I am not asking whether this is a good approach or how to work around it, I am just curious why the build hangs. Setting output window verbosity to Diagnostic was of no help to me.
I am using Visual Studio 2013 Ultimate.
MSBuild has an internal protection about recursion in the projects. Normally your build will fail with error MSB4006 in a case if any sort of circular dependency is discovered in the build graph. That said, if I were to guess what might have caused the hang, and if it is related to recursion, I would have inclined on the side of .sln files. The reason is that the way MSBuild treats .sln files is quite peculiar. Any time it encounters .sln file, it converts it to intermediate representation that actual MSBuild engine can understand. That intermediate representation does not have any identifier similar to the project file, thus the circular dependency detection logic might not work correctly if .sln is in the loop.
To solve your particular problem, there are couple of ways. The easiest one is to remove BuildInstaller.vcxproj from Test.sln. The second is to modify BuildInstaller.vcxproj as follows:
First, create an ItemGroup, populated with all projects from the solution:
<ItemGroup>
<AllMyProjects Include="..\Proj1\Proj1.vcxproj" />
<AllMyProjects Include="..\Proj2\Proj2.vcxproj" />
...
<!-- DO NOT ADD BuildInstaller project to prevent recursion!!! -->
</ItemGroup>
Then build the projects for every configuration:
<Target Name="Build">
<MSBuild Projects="#AllMyProjects" Properties="Configuration=Release;Platform=Win32" />
<MSBuild Projects="#AllMyProjects" Properties="Configuration=Release;Platform=x64" />
</Target>
The downside of the second approach is that you have to remember to maintain list of projects in sync between .sln and your installer project.

Building a multi-arch installer with msbuild

I'm building a multi-architecture installer for a C++ program with NSIS. I'm using Visual Studio 2010. All is well except I don't know how to make the installer depend on the build for all architectures.
I have created a project to run makensis as a build step, and configured it to depend on all other projects in the solution. I'm currently building for Win32 and X86_64 architectures. The NSIS project is only built as a part of X86_64 configuration. But it packs files built in both X86_64 and Win32 configurations. Here lies the problem. If I build Win32 and then immediately X86_64, all is well. If I start with X86_64, the build fails because it can't find Win32 files. Worse, if I change some source code and rebuild only X86_64, the installer project will happily pick up out-of-date Win32 files without any indication of a problem.
Can I force a Win32 build from an X86_64 build, or do anything else to make this work?
I'm a Unix type, Windows is an alien world to me.
Any
As for "foolproof" solutions, if I understand you correctly:
You have solution containing multiple projects (lets say Test.sln),
You want to build this solution for several platforms,
... and use the MakeNSIS tool (I have no idea what that is) to create an installer packaging binaries built for all the platforms.
Please correct me if I am wrong. So, to achieve this task:
I would completely drop the project you introduced (the one running MakeNSIS),
Then would create Test.msbuild file such as the one below,
Notice the <Exec> element, that is the place where you want to run you MakeNSIS,
Then simply run the msbuild as msbuild Test.msbuild,
Using this solution you would have all the projects from Test.sln first built for Win32, then for x64, and MakeNSIS would only be run afterwards.
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="Build" DependsOnTargets="Build_Win32;Build_x64">
<!-- Run whatever command you like, such as MakeNSIS .. ? -->
<Exec Command="notepad.exe" />
</Target>
<Target Name ="Build_Win32">
<MSBuild Projects="Test.sln" Properties="Configuration=Release;Platform=Win32" />
</Target>
<Target Name ="Build_x64">
<MSBuild Projects="Test.sln" Properties="Configuration=Release;Platform=x64" />
</Target>
</Project>
Please provide clarification to your actual question if the above isn't what you asked for.
EDIT:
After clarifying your request in the comment, I would propose following solution. I like the above solution with Test.msbuild more, but here you go:
Add new project BuildInstaller into your solution,
In Configuration Manager uncheck the checkbox "Build" for this new project for all combinations of Configuration/Platform,
Still in Configuration Manager, create new configuration, lets say Installers,
For this new configuration, uncheck the "Build" checkbox for all the projects from the solution, except for the BuildInstaller,
Now open the BuildInstaller.vcxproj in text editor and append the following snippet right before the closing </Project> tag:
<ItemGroup>
<ProjectsToBuild Include="..\**\*.vcxproj" Exclude="..\**\BuildInstaller.vcxproj"/>
</ItemGroup>
<Target Name="Build" DependsOnTargets="Build_Win32;Build_x64">
<!-- Run whatever command you like, such as MakeNSIS .. ? -->
<Exec Command="notepad.exe" />
</Target>
<Target Name="Build_Win32">
<MSBuild Projects="#(ProjectsToBuild)" Properties="Configuration=Release;Platform=Win32" />
</Target>
<Target Name="Build_x64">
<MSBuild Projects="#(ProjectsToBuild)" Properties="Configuration=Release;Platform=x64" />
</Target>
This way you effectively override the default build target,
So now:
Everytime you build for Release/Debug configuration, installer won't be built, that is preferred from many reasons,
Everytime you build for Installers configuration, your new BuildInstaller.vcxproj will take over, will build both win32 and x64 binaries and in the end will run the custom command line executable. Of course binaries will be built using Release configuration which should be desired.
Initially I thought I could drop the <ItemGroup> element and use Projects="..\Test.sln" instead of Projects="#(ProjectsToBuild)" as there should be no circular dependency (BuildInstaller.vcxproj is not built for Release) but the build took forever so there had to be some problem, weird...
Does this satisfy your needs?
I think you need to build Win32 configuration first and then 64bit configuration.
The makensis project should be built after both are finished (successfully!).
For example it is possible to call it from Post Build event (for 64bit configuration) or as separate project.
I am not sure whether your makensis project is based on Visual & Installer (http://www.visual-installer.com - sorry for little self promo :) or it is pure (text - batch) project included in VS Solution.
In both cases the Configuration manager in VS allows you to define the build order. The makensis project should be always the last so it can find all dependencies from previous configurations.
Also it is good to use relative path in makensis project - something like ${TARGET_PATH} which will be defined for each configuration with different value.

Specify ruleset for Visual Studio code analysis on command line or from CMake

I am trying to enable code analysis for my CMake driven project. I generate Visual Studio 2013 solutions, and would like to enable code analysis with a specific rule set. I know that I can enable the code analysis by specifying add_definitions("/analyze") in my CMake file, but how do I control which rule set is used?
As far as I can see, the only way to control the ruleset used is via the xml element CodeAnalysisRuleSet in the project file, but I cannot access this from CMake.
If you are trying to solve this for a command line build--either via cmake --build or direct invocation of msbuild--and not when using the generated solution with Visual Studio, you can set the relevant properties when you invoke the build.
With cmake driving the build:
PS c:\build-dir> cmake --build . -- '/p:RunCodeAnalysis=true' `
'/p:CodeAnalysisRuleSet=NativeRecommendedRules.ruleset'
With MSBuild driving the build:
PS c:\build-dir> msbuild ALL_BUILD.vcxproj '/p:RunCodeAnalysis=true' `
'/p:CodeAnalysisRuleSet=NativeRecommendedRules'
If you have a custom ruleset in a custom directory, you will also need to set the property CodeAnalysisRuleSetDirectories:
PS c:\build-dir> cmake --build . -- '/p:RunCodeAnalysis=true' `
'/p:CodeAnalysisRuleSet=custom.ruleset' `
'/p:CodeAnalysisRuleSetDirectories=c:\src\ruletsets'
(Tested with CMake 3.8.0, MSBuild 15.3.409.57025, and Visual C++ 2017 19.11.25506.)
I am not sure how far this works for VS2013 solutions. With Visual Studio 2015 I am using Project User Templates (*.vcxproj.user) with something along the following lines:
C:\MyProject\Template.USERNAME.user
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<CodeAnalysisRuleSet>#CMAKE_SOURCE_DIR#\SecurityRecommended.ruleset</CodeAnalysisRuleSet>
<RunCodeAnalysis>true</RunCodeAnalysis>
</PropertyGroup>
</Project>
You will probably have to change a few things like the ToolsVersion to 12.x.
The #CMAKE_SOURCE_DIR# will automatically get replaced by cmake when you use the CONFIGURE_FILE function to generate the actual PROJECT.vcxproj.user file. I have the following line in the CMakeLists.txt of my projects:
SET(USER_NAME $ENV{USERNAME} CACHE STRING UserName)
SET(USER_FILE ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.vcxproj.user)
CONFIGURE_FILE(${CMAKE_SOURCE_DIR}/Template.${USER_NAME}.user ${USER_FILE} #ONLY)
In the end, I would assume you could user-define anything that's in the PROJECT.vcxproj with those templates.
VS2017:In CMakeSettings.json section "configuration" add parameter "codeAnalysisRuleset": "NativeRecommendedRules.ruleset". Then in Solution Explorer right-click on need file .cpp select menu "Run Code Analysis on File". You can choose from a variety of analyzers in VS folder "c:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\Team Tools\Static Analysis Tools\Rule Sets\NativeRecommendedRules.ruleset"

How does Visual Studio 2010 hosts MSBuild for C++ projects?

I have a solution with several C++ projects. For some of the projects I need some custom file copy, e.g. to copy some configuration files to the output directory or to copy the output files of one project to a specific folder after build.
In some cases I don't want or cannot add these files to the projects directly through the Visual Studio IDE. I created simple .targets files which I can reuse and add to the projects which need the file copying.
Here is a simple example .targets file for copying configuration files:
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<BuildDependsOn>
$(BuildDependsOn);
CopyCustom
</BuildDependsOn>
</PropertyGroup>
<ItemGroup>
<CustomFiles Include="$(ProjectDir)Config\**\*.xml" />
</ItemGroup>
<PropertyGroup>
<DestCustFolder>$(OutDir)Config\</DestCustFolder>
</PropertyGroup>
<Target Name="CopyCustom"
Inputs="#(CustomFiles )"
Outputs="#(CustomFiles ->'$(DestCustFolder)%(RecursiveDir)%(FileName)%(Extension)')">
<Message Text="Copy custom files..." />
<Copy SourceFiles="#(CustomFiles )" DestinationFiles="#(CustomFiles->'$(DestCustFolder)%(RecursiveDir)%(FileName)%(Extension)')" SkipUnchangedFiles="true" />
</Target>
</Project>
Through the "Build Customization" dialog in Visual Studio I add it to the project so it will be included like this at the end of the project file:
<ImportGroup Label="ExtensionTargets">
<Import Project="..\Targets\CopyCustom.targets" />/
</ImportGroup>
This should enable incremental build of my custom target. If I just edit one of my custom files (and none of the C++ files) and build it form the console with
msbuild foo1.vcxproj
it will actually detect the changes and does an incremental build for my custom target. If no changes are made the target is skipped.
If I do however build inside Visual Studio it will not detect changes to the custom files and only and gives me the message that the project is up to data:
========== Build: 0 succeeded, 0 failed, 5 up-to-date, 0 skipped ==========
I would have to additionally change one of the C++ files to make it check all targets again and to the incremental build.
I was expecting that Visual Studio just executes MSBuild which will then do the up-to-date check on the projects, so it should be the same result as running MSBuild from the console. I was trying to get more information by setting the verbosity level to diagnostic but I just get the same line. It seems to me that MSBuild is not even executed for the project but Visual Studio itself determines that the project is up-to-date.
So I was wondering how Visual Studio actually determines when it should execute MSBuild for a project.
I asked basically the same question before on the MSDN forum but couldn't get a clear answer.
See this suggestion on Microsoft Connect.
Basically you need to set DisableFastUpToDateCheck property to true to disable the fast-up-to-date check.
Just add to your vcxproj or your targets file:
<PropertyGroup>
<DisableFastUpToDateCheck>true</DisableFastUpToDateCheck>
</PropertyGroup>
I found an answer by looking into the book "Inside the Microsoft Build Engine, Second Edition".
Note: I also updated the same in my question in the MSDN forum but I will mainly duplicate the text here again for completeness.
On page 280 they actually saying that the IDE does a "fast up-to-date check" on the project-level. It only spawns a project build and does a more fine-grained check on the individual tasks if this rough project-level check fails.
When running MSBuild from the command line however there is always a fine-grained up-to-date check on the individual tools.
So the IDE only seems to do this fast check on the files which are added to the projects directly and set as one of the "Input File" types.
In my opinion this is not a good design. I would prefer that the IDE is only used to edit the MSBuild project files and then just invokes MSBuild to do the up-to-date check. This would make it much clearer.
I can understand that in a solution with a lot of projects it can make the up-to-date check much faster but there should be at least an option to disable the fast up-to-date check. I was checking the IDE if there is a way to disable this behavior but could not find anything.
The solution suggested here actually works and I am using it at the moment. But I added several custom targets for different kinds of custom files. If I add a new custom file I should never forget to set it to "Custom Build Tool" otherwise the incremental build for this file will not work.
I guess a solution would be to make a full build customization for my custom files and use specific file extensions for them so Visual Studio will automatically detect them when I add them to the project and sets the right Item Type.