Uses For Build Scripts within STM32CubeIDE


Introduction


In this tutorial, we will learn the many uses for build scripts within STM32CubeIDE. You actually build the scripts in an external editor or within the IDE, and then update STM32CubeIDE of there location and when to execute them.

We can create scripts to add lines of code, or remove lines of code before the compile even is started. This is extremely useful, when you are trying to insert include files, or remove dormant code, after the Configuration/IOC file updates have taken place while saving.

Scripts can be written in many languages, such as Perl, python, bash, and even powershell. If written in bash, you can also utilize standard Unix/Linux tools, such as sed, awk, etc.

For this tutorial, we won’t go into each language nor will we go into which one is better suited for the job, this will be up to the reader to determine. For this tutorial, we will use bash in our examples.
We will go into a few example uses that someone could utilize this scripting methodology as a tool to make some of the coding a repeatable process.

You can specify both PRE and POST Build Steps with scripts.



Project Layout

Uses For Build Scripts within STM32CubeIDE

Pre and Post Build Initial Setup

Uses For Build Scripts within STM32CubeIDE

First we need to add a line: Under Project->Properties->C/C++ Build->Settings, there should be a tab called: “Build Steps”. In that field add the following:

Bash
${ProjDirPath}/scripts/master_build_script.sh ${ProjDirPath}

The above example is the Linux path format, if using Windows, use the appropriate path symbols, instead of the Linux “/”.

What this does it tell the IDE that before we actually attempt to compile this project, we should look in the “ProjDirPath” for a folder called “scripts” and for a file called: “master_build_script.sh” then
pass in to this script a variable called: “ProjDirPath”, which is the location on the hard drive that contains the folder path to your project. This is helpful, because the scripts themselves need to know where the source code is to be able to modify the files.

Creating a master build script for each project and then adding pertinent scripts to perform work based on individual the project needs. Creating individual scripts that target a specific purpose is smart, as this leads to individual script re-use, which saves time.

So, you can have Project1’s master_build_script.sh include these example scripts:

Bash
!/bin/sh
cd $1  # This is the ProjDirPath parameter passed in, which sets the baseline as to where the script is executing the code.
./scripts/scriptA.sh
./scripts/scriptB.sh
./scripts/scriptC.sh

You can as an example have Project2’s master_build_script.sh include these example scripts:

Bash
!/bin/sh
cd $1  # This is the ProjDirPath parameter passed in, which sets the baseline as to where the script is executing the code.
./scripts/scriptY.sh
./scripts/scriptA.sh
./scripts/scriptZ.sh
./scripts/scriptC.sh

Pre Build Examples Scripts

In this example script, we are wanting to add some code that will redirect output from STDOUT, to a USART device that has been assigned huart2 via the IDE configuration tool and the IOC file.

This first part of the script determines if the new code has already been added by searching for a string of characters “define REDIRECT_PRINTF” if this string is found then we assume that the modifications have already taken place and nothing is needed, so we exit. Otherwise, we find “USER CODE BEGIN Private defines” and append the string ‘define REDIRECT_PRINTF’ main.h

The next step is to look in main.c and locate “ifdef REDIRECT_PRINTF”, if this string is NOT FOUND then, the script will locate “USER CODE BEGIN 0” and then execute the following code:

sed -i ‘/USER CODE BEGIN 0/r ../../scripts/printf_redirect_code.txt’ main.c, which will find the string “USER CODE BEGIN 0” and replace it will the contents of the file : ../../scripts/printf_redirect_code.txt

If the script finds “REDIRECT_PRINTF” is already present in main.h then only an informational message to the console is displayed, and nothing is modified!

Bash
#!/bin/sh

cd $1/Core/Inc

redirect=`cat main.h | grep "define REDIRECT_PRINTF" | grep -v grep`

if [ -n "$redirect" ]	# -n returns True if the string length is non-zero
then
	echo "#define REDIRECT_PRINTF already present in main.h"
else
	echo "Adding #define REDIRECT_PRINTF to main.h"

	sed -i '/USER CODE BEGIN Private defines/a #define REDIRECT_PRINTF' main.h
fi

cd $1/Core/Src

printf=`cat main.c | grep "ifdef REDIRECT_PRINTF" | grep -v grep`

if [ -n "$printf" ]		# -n returns True if the string length is non-zero	
then
	echo "REDIRECT_PRINTF code already implemented"
else
	echo "Adding REDIRECT_PRINTF code"
	
	sed -i '/USER CODE BEGIN 0/r ../../scripts/printf_redirect_code.txt' main.c
fi

Below is the text file for: ./scripts/printf_redirect_code.txt which contains the follow. This code is actually a text file template which will be used by the script. The below text will be insert into the source file main.h

#ifdef REDIRECT_PRINTF
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#endif

#ifdef REDIRECT_PRINTF
/**
  * @brief  Retargets the C library printf function to the USART.
  * @param  None
  * @retval None
  */
PUTCHAR_PROTOTYPE
{
  HAL_UART_Transmit(&huart2, (uint8_t *)&ch, 1, 0xFFFF);

  return ch;
}
#endif

Additional Uses

There are many uses that can be implemented where there is a need to keep code in place that would normally be wiped out after a configuration change, that regenerates code. You can also use this to set parameters or #defines for specific reasons based upon other changes in the code. This is a much better methodology than constantly re-adding code that gets wiped out, as this is a repeatable process. Doing manual code updates every time generated code is erased and regenerated, can cause human errors with code being wiped out or forgotten to be re-added.


Post Build Scripts

On the same “Build Steps” tab there is a section to have a script execute after the build is completed. This does not mean just when there is a successful build, but even if there are errors.
The post build script could test if the build was without errors, and if a successful build is achieved, you could perform some other task. An example task, might be to perform a “git commit”, or cause another build to occur.


STM32CubeIDE Additional Build Parameters

STm32CubeIDE is built off of Eclipse a Java based IDE capable of running on any platform that can run Java.
If you go to Project->Properties->C/C++ Build->Build Variables You will see a checkbox towards the bottom of the pop-up windows called “Show system variables” Select this and in the pop-up will now display every available Build Parameter/Variable that can be used with your scripts.

Uses For Build Scripts within STM32CubeIDE

STM32CubeIDE Build Log Location

The location of the build log is NOT located in the project folder itself, but the IDE stores this file in the following folder: ~/MyWorkSpaceLocation/.metadata/.plugins/org.eclipse.cdt.ui

If your build is successful without errors, the you should see a line at the end of the log that looks similar to this:

18:06:20 Build Finished. 0 errors, 0 warnings. (took 5s.355ms)

You can then use the “0 errors” text as a flag or indicator to perform a task.