PREPROCESSOR DEFINE WITH CONTENT OF A BUILD VARIABLE (in MSBuild)

Sysprogs forums Forums VisualGDB PREPROCESSOR DEFINE WITH CONTENT OF A BUILD VARIABLE (in MSBuild)

Viewing 12 posts - 1 through 12 (of 12 total)
  • Author
    Posts
  • #22341
    SR
    Participant

    Hi,

    I have read the following post:

    PREPROCESSOR DEFINE WITH CONTENT OF A BUILD VARIABLE

    I want to set a preprocessor define with the hash of my current git revision. I managed to put the revision into a custom build variable (git rev-parse HEAD in a custom build step).

    and wondered how that can be accomplished when using VisualGDB with MSBuild.

    Regards,

    SR

    #22345
    support
    Keymaster

    Hi,

    If you are using MSBuild, you can script it by creating a custom MSBuild target (VisualGDB uses the same target system as regular MSBuild projects).

    You can find extensive documentation on creating MSBuild tasks here: https://docs.microsoft.com/en-us/visualstudio/msbuild/task-writing?view=vs-2017

    Also consider having a quick look through our version updating task used by our open-source plugins. You could create a similar C# task that would export an MSBuild variable and then reference this variable in the “Preprocessor Definitions” setting.

     

    #22365
    SR
    Participant

    To summarize for everyone wondering:

    1. Make new C# Library GitProperties.dll
    2. Add NuGet-Packages: Microsoft.Build.Framework & Microsoft.Build.Utilities
    3. Add Task Class
    public class GitPropertiesTask : Task
    {
     [Output]
     public string GitCommitHash {get; set; }
    
     public override bool Execute()
     {
     try
     {
     GitCommitHash = GetGitBuildHash();
     }
     catch (Exception e)
     {
     Log.LogErrorFromException(e);
     return false;
     }
    
     return true;
     }
    
     private static string GetGitBuildHash()
     {
     ProcessStartInfo startInfo = new ProcessStartInfo
     {
     UseShellExecute = false,
     WindowStyle = ProcessWindowStyle.Hidden,
     FileName = "cmd.exe",
     Arguments = "/C git rev-parse --short=9 HEAD",
     RedirectStandardOutput = true,
     };
     Process process = new Process { StartInfo = startInfo };
    
     process.Start();
     string buildHash = process.StandardOutput.ReadToEnd().Trim();
     process.WaitForExit();
    
     return buildHash;
     }
    }
    1. Add the following lines at the end of your Project file:
    <UsingTask TaskName="GitPropertiesTask" AssemblyFile="./[Path]/GitProperties.dll" />
     <Target Name="Build">
      <GitPropertiesTask>
       <Output TaskParameter="GitCommitHash" PropertyName="GitCommitHash"/>
      </GitPropertiesTask>
     </Target>
    1. Add to your Project Settings –> C/C++ –> Preprocessor –> Preprocessor Defines:
    GIT_BUILD_ID=$(GitCommitHash)
    #22366
    SR
    Participant

    @Support: I have seen that you used a .props file instead of the project file for better reusability.

    I have tried this myself, but it didn’t work.

    What do i have to configure for MSBuild to automatically load this file?

    #22367
    SR
    Participant

    @Support: Have to correct myself:

    using <Target Name=”Build”> overrides the default build process and nothing works, but <Target Name=”BeforeBuild” BeforeTargets=”Build”> works neither in a .vcxproj.</span>

    • This reply was modified 5 years, 12 months ago by SR.
    • This reply was modified 5 years, 12 months ago by SR.
    #22370
    SR
    Participant

    I have again read the AutoVersion.props as you suggested and added

     <PropertyGroup>
     <BuildDependsOn>$(BuildDependsOn);GitPropertiesTarget</BuildDependsOn>
     </PropertyGroup>

    But the GitPropertiesTarget isn’t invoked.

    Does the VisualGDB Embedded ToolChain override these dependencies?

    #22372
    support
    Keymaster

    Hi,

    Thanks for sharing this. Indeed the target name should not collide with any of the existing targets, as it would override the original target. Setting $(BuildDependsOn) to include your target name should be the right thing to do.

    If it doesn’t work, please try setting the MSBuild build log verbosity to “Diagnostic” via Tools->Options->Build and Run and then check that your target is being built, the task is being executed and returns the correct value and that it happens before the actual compilation phase.

    #22381
    SR
    Participant

    Hi,

    Using the MSBuild Diagnostic setting helped a lot to unterstand the procedure.

    I changes small things in the Task to make it more reliable, but it doesn’t seem to be the problem.

    My new Task:

    using System;
    using System.Diagnostics;
    using Microsoft.Build.Framework;
    using Microsoft.Build.Utilities;
    
    namespace GitBuildStep
    {
    	public class GitPropertiesTask : Task
    	{
    		[Required]
    		public string GitDir { get; set; }
    
    		[Output]
    		public int GitCommitDay { get; set; }
    		[Output]
    		public int GitCommitMonth { get; set; }
    		[Output]
    		public int GitCommitYear { get; set; }
    		[Output]
    		public string GitCommitHash { get; set; }
    
    		public override bool Execute()
    		{
    			try
    			{
    				GitCommitHash = GetGitBuildHash();
    
    				DateTime buildTime = GetGitBuildDate();
    
    				GitCommitYear = buildTime.Year;
    				GitCommitMonth = buildTime.Month;
    				GitCommitDay = buildTime.Day;
    			}
    			catch (Exception e)
    			{
    				Log.LogErrorFromException(e);
    				return false;
    			}
    
    			return true;
    		}
    
    		private string GetGitBuildHash()
    		{
    			string buildHash = RunCmd(@"git rev-parse --short=9 HEAD");
    
    			return buildHash;
    		}
    
    		private DateTime GetGitBuildDate()
    		{
    			var buildDate = RunCmd(@"git log -1 --format=%cd --date=short");
    
    			return DateTime.Parse(buildDate);
    		}
    
    		private string RunCmd(string cmd)
    		{
    			ProcessStartInfo startInfo = new ProcessStartInfo
    			{
    				UseShellExecute = false,
    				WindowStyle = ProcessWindowStyle.Hidden,
    				FileName = "cmd.exe",
    				Arguments = $@"/C ({cmd})",
    				RedirectStandardOutput = true,
    				RedirectStandardError = true,
    				WorkingDirectory = GitDir
    			};
    
    			string pathEnv = Environment.GetEnvironmentVariable("PATH", EnvironmentVariableTarget.Machine);
    			startInfo.EnvironmentVariables.Add("PATH", pathEnv);
    
    			Process process = new Process { StartInfo = startInfo };
    
    			process.Start();
    			process.WaitForExit();
    
    			string error = process.StandardError.ReadToEnd().Trim();
    			if (!String.IsNullOrWhiteSpace(error))
    				throw new Exception(error);
    
    			string buildDate = process.StandardOutput.ReadToEnd().Trim();
    			return buildDate;
    		}
    	}
    }

    And my changes to Project.vcxproj

     <UsingTask TaskName="GitPropertiesTask" AssemblyFile="Utils/GitBuildStep.dll" />
     <Target Name="GitPropertiesTarget">
       <Message Text="Reading Git Properties!" Importance="high" />
       <GitPropertiesTask GitDir="$(SolutionDir)">
         <Output TaskParameter="GitCommitDay" PropertyName="GitCommitDay" />
         <Output TaskParameter="GitCommitMonth" PropertyName="GitCommitMonth" />
         <Output TaskParameter="GitCommitYear" PropertyName="GitCommitYear" />
         <Output TaskParameter="GitCommitHash" PropertyName="GitCommitHash" />
       </GitPropertiesTask>
       <Message Text="Git Properties:%0aDate=$(GitCommitDay).$(GitCommitMonth).$(GitCommitYear)%0aHash=$(GitCommitHash)" Importance="high" />
     </Target>

    And PreProcessor-Settings:

    GIT_BUILD_ID=$(GitCommitHash);GIT_YEAR=$(GitCommitYear);GIT_MONTH=$(GitCommitMonth);GIT_DAY=$(GitCommitDay)

    Outputs this:

    1>Target "GitPropertiesTarget" in file "X:\Firmware\Firmware\Firmware.vcxproj":
    1>  Using "Message" task from assembly "Microsoft.Build.Tasks.Core, Version=15.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a".
    1>  Task "Message"
    1>    Task Parameter:Text=Reading Git Properties!
    1>    Task Parameter:Importance=high
    1>    Reading Git Properties!
    1>  Done executing task "Message".
    1>  Using "GitPropertiesTask" task from assembly "X:\Firmware\Firmware\Utils/GitBuildStep.dll".
    1>  Task "GitPropertiesTask"
    1>    Task Parameter:GitDir=X:\Firmware\
    1>    Git Properties:
    1>    Date=18.10.2018
    1>    Hash=530a981c4
    1>    Output Property: GitCommitDay=18
    1>    Output Property: GitCommitMonth=10
    1>    Output Property: GitCommitYear=2018
    1>    Output Property: GitCommitHash=530a981c4
    1>  Done executing task "GitPropertiesTask".
    1> Task "Message"
    1>   Task Parameter:Text=Git Properties:
    1>   Date=18.10.2018
    1>   Hash=530a981c4
    1>   Task Parameter:Importance=high
    1>   Git Properties:
    1>   Date=18.10.2018
    1>   Hash=530a981c4
    1> Done executing task "Message".
    1>Done building target "GitPropertiesTarget" in project "Firmware.vcxproj".
    ...
    1>Target "BuildCppObjectList" in file "C:\Program Files (x86)\Sysprogs\VisualGDB\MSBuild\Targets\gcc.targets":
    1>  Added Item(s): 
    1>      Obj=
    1>          VisualGDB\Debug\eeprom.o
    ...
    1>                  PreprocessorDefinitions=ARM_MATH_CM4;flash_layout;STM32F407VG;USE_USB_FS;STM32F407xx;FAST_SEMIHOSTING_BUFFER_SIZE=4096;FAST_SEMIHOSTING_BLOCKING_MODE=0;FAST_SEMIHOSTING_STDIO_DRIVER=1;FAST_SEMIHOSTING_PROFILER_DRIVER=1;PROFILER_STM32F4;SYSPROGS_PROFILER_DEBUGGER_CHECK_MODE=1;GIT_BUILD_ID=;GIT_YEAR=;GIT_MONTH=;GIT_DAY=;DEBUG=1;;DEBUG=1
    

    To me it seems like the PreprocessorDefinitions get resolved before GitPropertiesTarget is triggered, as the variables seems to get set correctly, but not the PreprocessorDefinitions.

    PS: I have attached you a shortened version of MSBuild.log (due to your upload-size limit)

    • This reply was modified 5 years, 12 months ago by SR.
    #22383
    SR
    Participant

    Edit: Retrying the upload:

    Attachments:
    You must be logged in to view attached files.
    #22399
    support
    Keymaster

    Hi,

    If the PreprocessorDefinitions macro gets resolved before the custom tool has a chance to run, please consider a slightly different approach. Remove the reference to your variable from the regular PreprocessorDefinitions and add the following code inside your <Target> element after the invocation of the custom tool (please update it to reference the actual variables):

    <ItemDefinitionGroup>
     <ClCompile>
     <PreprocessorDefinitions>%(ClCompile.PreprocessorDefinitions);$(...)</PreprocessorDefinitions>
     </ClCompile>
    </ItemDefinitionGroup>
    

    As long as the code above is inside the “target” element, it will get evaluated after the tool is invoked and hence the variables will be resolved properly.

    #22408
    SR
    Participant

    Hi,

    I actually tried just that yesterday, but it failed with error:

    <ItemDefinitionGroup> is not allowed inside a target.

    But with the help of some google I figured that this works as desired.

    <ItemGroup>
     <ClCompile>
      <PreprocessorDefinitions>%(ClCompile.PreprocessorDefinitions);GIT_BUILD_ID="$(GitCommitHash)";GIT_YEAR=$(GitCommitYear);GIT_MONTH=$(GitCommitMonth);GIT_DAY=$(GitCommitDay);</PreprocessorDefinitions>
     </ClCompile>
    </ItemGroup>

    Thank you very much for your help!

    #22411
    support
    Keymaster

    Hi,

    Sorry about that, it should indeed be ItemGroup. When placed inside a target, it will work the same as ItemDefinitionGroup works normally.

    Good to know it works and let us know if you encounter any further issues.

Viewing 12 posts - 1 through 12 (of 12 total)
  • You must be logged in to reply to this topic.