Profile guided optimization with MSBuild - visual-studio-2010

How do I build a solution in MSBuild (command line only) with PGI/PGO without adding new build configuration to projects?
I've tried to add command line parameter /property:WholeProgramOptimization=PGInstrument which looks OK, it creates PGD files but does not create PGC after I ran the application. Obviously I'm missing something in MSBuild command line.

I spent two days scratching my head on this problem and I finally found how to do it:
First you need to build the instrumented version of your program:
msbuild.exe
/t:Rebuild "Letter:\path\YourProject.vcxproj"
/p:Configuration=Release
/p:Platform=x64
/p:WholeProgramOptimization=PGInstrument
Note that On my machine, MSBuild can be found here:
C:\Program Files (x86)\MSBuild\12.0\Bin\msbuild.exe. The order of the parameters are really important. If your project were placed after the /p options, it could overwrite them.
A pgd file should have been created in your output directory. You will need its path later.
Then you need to instrument the program:
Letter:\path\OutPutDir\YourProject.exe
In this step obviously you need to add parameters to feed your program with the data it needs. If your program complains about not having access to pgort120.dll you can add a line like this one to your script: set PATH=%PATH%;C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\bin\amd64
Finally you can build the optimized version of your program:
msbuild.exe
/t:LibLinkOnly "Letter:\path\YourProject.vcxproj"
/p:Configuration=Release
/p:Platform=x64
/p:WholeProgramOptimization=PGOptimize
/p:LinkTimeCodeGeneration=PGOptimization
/p:ProfileGuidedDatabase="Letter:\path\OutPutDir\YourProject.pgd"
Here you need to use the address of the pgd file of the first step. Note that the target is LibLinkOnly because there is no need to recompile everything.
Hope this helps others.

Building on the Answer from Arnaud, without which I would never have figured this out, there are additional settings that can be useful. In my solution, I only wanted to build one project out of 20+ with PGO, which required additional flags to prevent all the referenced projects being built:
/p:BuildProjectReferences=false
Use this to stop the projects referenced by the target project being built by the Rebuild target. You need to add this to both the /t:Rebuild command and from VS 16.8.0 onwards to the /t:LibLinkOnly command.
In VS2019, you will find the pgort140.dll buried in the:
Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.21.27702\bin\HostxNN\xNN
folder, where xNN is x86 or x64 as appropriate.
In the case of a solution, you are likely to have a $(OutDir) output location that depends on solution settings, but that when you build a separate project ends up in the wrong place, so you will all likely need to tell the Project file where the output is with:
/p:OutDir="path to output"
In my case, with a solution file holding lots of projects and one that I need to run with PGO I ended up with a batch file (see below). In this case, at the top level I
have a solution file MyApp.sln that contains many sub-projects in sub-folders. The
one I want is called subproj and lives in the subprob folder with a project file
called subproj.vcxproj in that folder. Each sub-project generates a DLL and there
are dependencies from subproj on other sub-projects. The gist of the batch file is
as follows:
REM Get the folder we are running out of, assumed to hold the solution file
SET parent=%~dp0
REM Set PLATFORM=x64, TOOLS=HOSTx64\x64 for 64-bits
SET PLATFORM=Win32
SET TOOLS=Hostx86\x86
ECHO Build %PLATFORM% Release of MyApp with PGO of the subprog project
REM Expanding Program Files (x86) causes problems so use PROGRA~2
SET VSPATH=C:\PROGRA~2\Microsoft Visual Studio\2019\Professional
REM Value for VS 16.?.? = \14.21.27702
REM Value for VS 16.3.2 = \14.22.27905\bin
REM Value for VS 16.3.3 = \14.23.28105\bin
REM Value for VS 16.4.0 = \14.24.28314\bin
REM Value for VS 16.5.0 = \14.25.28610
REM Value for VS 16.6.0 = \14.26.28801
REM Value for VS 16.7.0 = \14.27.29110
REM Value for VS 16.8.0 = \14.28.29333
SET VSTOOLS=%VSPATH%\VC\Tools\MSVC\14.21.278.29333\bin
if not exist "%VSTOOLS%" (
ECHO %VSTOOLS% Was not found. This is probably due to a new release. Please
ECHO find the new location and correct this batch file:
ECHO %parent%%me%.bat
exit /b 1
)
REM Set tools path (needed to locate the pgoNnn.dll used for PGO)
set PATH=%PATH%;%VSTOOLS%\%TOOLS%
REM MSB is the path to the MSBuild.exe command
SET MSB="%VSPATH%\MSBuild\Current\Bin\MSBuild.exe"
REM OPT is the common options shared by everything
REM /v: n=normal, m=minimal, q=quiet
SET OPT=/v:m /p:Configuration=Release /p:Platform=%PLATFORM%
REM Set where our output must go. VS likes it to end with \ for $(OutDir)
SET OUTDIR=%parent%%PLATFORM%\Release\
REM It is easier to build everything and rebuild subproj that build all the
REM sub-projects separately.
echo Build the entire solution in the Release build for the desired platform.
%MSB% MyApp.sln %OPT%
echo Now instrument the subproj
%MSB% /t:Rebuild "subproj\subproj.vcxproj" %OPT% /p:OutDir=%OUTDIR% /p:WholeProgramOptimization=PGInstrument /p:BuildProjectReferences=false
echo Run MyApp to exercise the subproj DLL as needed to generate the PGO database
%parent%%PLATFORM%\Release\MyApp.exe arguments as required...
echo Now build PGO optimized version of subproj
%MSB% /t:LibLinkOnly "subproj\subproj.vcxproj" %OPT% /p:WholeProgramOptimization=PGOptimize /p:LinkTimeCodeGeneration=PGOptimization /p:OutDir=%OUTDIR% /p:ProfileGuidedDatabase="%OUTDIR%compiler.pgd" /p:BuildProjectReferences=false

Related

Jenkins to build only modified files when checkout happens from subversion when build is scheduled

I have configured subversion and Jenkins for Microsoft visual basic 6 project. Subversion contains more than 4000 files. Every time the build triggers, Jenkins compiles 4000 files, even if only few files have changed. I have written a batch script to compile visual basic 6 files which will search for *.vpb files in every folder. If *.vpb, present it will compile files present in that folder
#echo off
del "D:\buildfiles\log_file.txt"
for /r "D:\jenkins_setup\workspace\project" %%a in (*.vbp) do (
"C:\Program Files\microsoft visualstudio\vb98\vb6.exe" /make %%a /outdir
"D:\buildfiles" /out D:error_log.txt
echo %%a >> "D:\buildfiles\log_file.txt"
)
pasted this script in jenkins.
If files from few folders have changed, I want my script to compile only those files, not all 4000 files which are present in Jenkins workspace. To make this work, what else do I need to add to my script?
Jenkins itself doesn't compile. That process is handed to whatever build software you use. For example, if you have a C or C++ project, Jenkins would probably call make and pass to it a Makefile. If you have a Java project, Jenkins would call mvn, ant, or gradle with the correct POM or Build script. It would then be up to the individual build system to rebuild intelligently if so desired.
In your case, it's how Visual Basic itself is handling your Visual Basic Project files. I believe the build system compiles only those files whose last modification date and time is newer than their corresponding object file's modification date and time.
You should be able to get onto your Jenkins system, go to the workdirectory of that project and actually run the build from the command line and see what happens. Check the file dates. You might also want to set the Jenkins project to do an update only instead of a checkout.

How do I compile a single source file within an MSVC project from the command line?

I'm about to start doing some benchmarking/testing of our builds, and I'd like to drive the whole thing from a command line. I am aware of DevEnv but am not convinced it can do what I want.
If I could have a single file built within a single project, I'd be happy.
Can this be done?
The magical incantation is as follows. Note that this has only been tested with VS 2010 - I have heard this is the first version of Visual Studio with this capability:
The Incantation
<msbuild> <project> <settings> <file>
Where
msbuild is a path to MSBuild.exe. Usually this should be set up for you by the VS2010 bat file so the right one will end up in your PATH, but if not I found one at C:\Windows\Microsoft.NET\Framework64\v4.0.30319\msbuild.exe
project is the path to the vcxproj file within which your source file resides.
settings include the following:
/p:Configuration="Debug" // or whatever your Configuration is
/p:Platform=x64 // or x86
/t:ClCompile // to specify specifically you're looking to compile the file
file is actually another setting:
/p:SelectedFiles="path_to_file"
Notes
For <project> I had to specify a project (vcxproj) file instead of a solution (sln) file. The sln I would have used has multiple projects within it, so there would have been extra work to go that route anyhow (if it can even be done).
For the /p:Platform=x64 setting, there are several environment variables that pivot on what platform you are targeting (x64 v. x86) so make sure you set those up properly via Visual Studio's vcvarsall.bat.
Regarding path_to_file in the SelectedFiles parameter, this path must be the path as specified in the project file. If the path does not match the path used in the project file to reference the source, it doesn't seem to work.

Visual Studio variable bin directory

I have a few VS 2010 C# projects that are shared between several solutions. I would like these projects to build to the directory of the solutions they are open in. How do I do this?
I considered setting up different build configurations (Debug_Xsln, debug_Ysln, Release_Xsln...) but wasn't sure if there was a better way.
http://msdn.microsoft.com/en-us/library/42x5kfw4(v=VS.100).aspx
You can use a postbuild event with xcopy and the macro $(SolutionName) or $(SolutionDir) to copy the compiled files into the correct folder.
Go into properties for the project, build events tab, and in Post Build event command line enter something like this:
xcopy "$(ProjectDir)bin\$(ConfigurationName)\*.*" "$(SolutionDir)$(ProjectName)\bin\$(ConfigurationName)" /i /d /y
The benefit of this method is you can copy the build output of one project to multiple locations
OR
(as Ziplin discovered)
If you only have one location you want the build output to go, you can use the macros above to set the output path, like this:
$(SolutionDir)$(ProjectName)\bin\$(ConfigurationName)
just go to the project properties on the build tab and set your macroed location as the output path

Build one project inside a solution from the command line

I am working on a large C++ solution in Visual Studio 2005. I want to log all of the output from the build of one project within that solution. The output window in VS seems to be malfunctioning. I suspect there is too much output for it to handle. I can't copy the output and I can't even save it to disk.
My idea is to build the project on the command line and just redirect the output to a file. I'm not sure what command I have to execute in order to build a project in the context of a solution. I tried to just vcbuild the project, but I think it's missing data inherited from the solution.
Any ideas?
Use DevEnv from the command line:
DevEnv /Build Debug /Project ProjectName %SOLUTION_FILE%
where %SOLUTION_FILE% is an environment variable holding the full
path to the solution file and ProjectName is the name of the project.
The output will go to standard output.
The entire solution can be rebuild with:
DevEnv /Rebuild Debug %SOLUTION_FILE%
Example; for an (installer) project named MSQuantSetup:
set SOLUTION_FILE=D:\dproj\MSQall\MSQuant\MSQuant.sln
DevEnv /Build Debug /Project MSQuantSetup %SOLUTION_FILE%
Or directly without the environment variable:
DevEnv /Build Debug /Project MSQuantSetup D:\dproj\MSQall\MSQuant\MSQuant.sln
Take a look at this page, I think this is what you are looking for. Don't forget the /Project parameter if you want to build only one project.
C# version with MSBuild (put the below code in a .bat file)
set msBuildDir=%WINDIR%\Microsoft.NET\Framework\v4.0.30319
set msBuildDir=%WINDIR%\Microsoft.NET\Framework\v2.0.50727
call %msBuildDir%\msbuild ".\SomeFolder\MyCSharpProject.csproj" /p:Configuration=Release /l:FileLogger,Microsoft.Build.Engine;logfile=Manual_MSBuild_ReleaseVersion_One_Project_CSharp_LOG.log
set msBuildDir=
Or for C++:
set msBuildDir=%WINDIR%\Microsoft.NET\Framework\v2.0.50727
set msBuildDir=%WINDIR%\Microsoft.NET\Framework\v4.0.30319
call %msBuildDir%\msbuild ".\Project1\Project1\Project1.vcxproj" /p:Configuration=Release /l:FileLogger,Microsoft.Build.Engine;logfile=Manual_MSBuild_ReleaseVersion_One_Project_C_Plus_Plus_LOG.log
set msBuildDir=
You'll need to pick your framework (2.0 or 4.0 (or other??), where I have
set msBuildDir=%WINDIR%\Microsoft.NET\Framework\vA.BCDEF
Just comment out or remove the framework version you do not want.
I had a solution with five (sub) projects. I built the "bottom most" project. And it only built this (single) assembly.
Keep in mind if the project you pick has dependencies, it'll build those as well. AKA, if you pick the "top most" assembly, it will build everything it needs.

Visual Studio Post Build Event - Copy to Relative Directory Location

On a successful build, I wish to copy the contents of the output directory to a different location under the same "base" folder. This parent folder is a relative part and can vary based on Source Control settings.
I have listed a few of the Macro values available to me ...
$(SolutionDir) = D:\GlobalDir\Version\AppName\Solution1\build
$(ProjectDir) = D:\GlobalDir\Version\AppName\Solution1\Version\ProjectA\
I want to copy the Output Dir contents to the following folder :
D:\GlobalDir\Version\AppName\Solution2\Project\Dependency
The base location "D:\GlobalDir\Version\AppName" needs to be fetched from one of the above macros. However, none of the macro values list only the parent location.
How do I extract only the base location for the post build copy command ?
Here is what you want to put in the project's Post-build event command line:
copy /Y "$(TargetDir)$(ProjectName).dll" "$(SolutionDir)lib\$(ProjectName).dll"
EDIT: Or if your target name is different than the Project Name.
copy /Y "$(TargetDir)$(TargetName).dll" "$(SolutionDir)lib\$(TargetName).dll"
If none of the TargetDir or other macros point to the right place, use the ".." directory to go backwards up the folder hierarchy.
ie. Use $(SolutionDir)\..\.. to get your base directory.
For list of all macros, see here:
http://msdn.microsoft.com/en-us/library/c02as0cs.aspx
You could try:
$(SolutionDir)..\..\
I think this is related, but I had a problem when building directly using msbuild command line (from a batch file) vs building from within VS.
Using something like the following:
<PostBuildEvent>
MOVE /Y "$(TargetDir)something.file1" "$(ProjectDir)something.file1"
start XCOPY /Y /R "$(SolutionDir)SomeConsoleApp\bin\$(ConfigurationName)\*" "$(ProjectDir)App_Data\Consoles\SomeConsoleApp\"
</PostBuildEvent>
(note: start XCOPY rather than XCOPY used to get around a permissions issue which prevented copying)
The macro $(SolutionDir) evaluated to ..\ when executing msbuild from a batchfile, which resulted in the XCOPY command failing. It otherwise worked fine when built from within Visual Studio. Confirmed using /verbosity:diagnostic to see the evaluated output.
Using the macro $(ProjectDir)..\ instead, which amounts to the same thing, worked fine and retained the full path in both build scenarios.
Would it not make sense to use msbuild directly? If you are doing this with every build, then you can add a msbuild task at the end? If you would just like to see if you can’t find another macro value that is not showed on the Visual Studio IDE, you could switch on the msbuild options to diagnostic and that will show you all of the variables that you could use, as well as their current value.
To switch this on in visual studio, go to Tools/Options then scroll down the tree view to the section called Projects and Solutions, expand that and click on Build and Run, at the right their is a drop down that specify the build output verbosity, setting that to diagnostic, will show you what other macro values you could use.
Because I don’t quite know to what level you would like to go, and how complex you want your build to be, this might give you some idea. I have recently been doing build scripts, that even execute SQL code as part of the build. If you would like some more help or even some sample build scripts, let me know, but if it is just a small process you want to run at the end of the build, the perhaps going the full msbuild script is a bit of over kill.
Hope it helps
Rihan
I solved my problem by reinstall VS and then download .Net Core (3.x and 2.x) sdk packages
Here is my post build script
Creates the custom path for my own. Including library and version.
Copies the .dll (target file)
Copies the *.md files.
script:
md c:\_References\$(ProjectName)\$(AssemblyVersion)
xcopy $(ProjectDir)$(OutDir)$(TargetFileName) c:\_References\$(ProjectName)\$(AssemblyVersion) /y
xcopy $(ProjectDir)*.md c:\_References\$(ProjectName)\$(AssemblyVersion) /y

Resources