on 2025-08-07 8:43 AM
This article explains how to add post build commands in VS Code with CMake for STM32 projects.
When developing STM32 firmware using Visual Studio Code with the CMake extension, the build process often involves more than simply compiling source code into an executable .elf file. Post build steps are essential for preparing firmware for deployment, debugging, security, and production.
Some key post build tasks include:
Furthermore, many other post build tasks can be implemented to tailor your development process in a better way.
This article provides a comprehensive guide on adding and customizing post build commands in your CMakeLists.txt file within VS Code, including practical examples designed to streamline your STM32 development workflow.
Before you begin, ensure the following:
When you build an STM32 project with CMake, the default output is an .elf file (for example, project.elf). This file is a binary format that contains all the necessary information for debugging, linking, and execution. The .elf file can be used directly for programming and debugging, even without the project’s source code. However, it is not commonly used in production environments due to the presence of additional metadata that is unnecessary for flashing and may increase file size.
To prepare firmware for production, it is standard practice to convert the .elf file into simpler binary formats such as:
Common programming tools like STM32CubeProgrammer typically accept only these simpler binary formats (.bin and .hex), making conversion essential for deployment.
This conversion can be performed using the arm-none-eabi-objcopy tool, part of the Arm GCC toolchain. You can configure your CMakeLists.txt file to call this tool automatically after the build process, ensuring that .bin and .hex files are generated every time you build your project.
Pseudocode of a post build command in CMake:
add_custom_command(
TARGET <target_name>
POST_BUILD
COMMAND <command_to_run>
COMMENT "<comment_text>"
)
Import your project and locate the CMakeLists.txt file in the root of your STM32 project.
Insert the following code snippet at the end of your CMakeLists.txt file:
# Specify the output ELF file
set(TARGET_ELF "${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}.elf")
# Command to generate .bin file
add_custom_command(
TARGET ${CMAKE_PROJECT_NAME}
POST_BUILD
COMMAND ${CMAKE_OBJCOPY}
-O binary ${TARGET_ELF} ${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}.bin
COMMENT "Generating .bin file"
)
# Command to generate .hex file
add_custom_command(
TARGET ${CMAKE_PROJECT_NAME}
POST_BUILD
COMMAND ${CMAKE_OBJCOPY}
-O ihex ${TARGET_ELF} ${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}.hex
COMMENT "Generating .hex file"
)
Build the project by using the [Build] button at the lower left corner and after the build completes, navigate to the [build/] directory to verify that the *.elf, *.bin and *.hex files have been generated.
After generating the .bin or .hex files, you can flash them to your STM32 microcontroller using STM32CubeProgrammer to validate the code at runtime.
On STM32N6 MCUs, the first stage bootloader (FSBL) must be signed so the boot ROM can execute it in a secured-locked state, and same is true for the application. More information can be found on our wiki page: Getting started with STM32N6 security - stm32mcu. However, the steps necessary to execute this process can become repetitive and time-consuming, especially when working on applications that require more than one binary. This portion of the article aims to introduce a simple post build script that allows for the entire signing process to occur after the build is performed.
Since the signing tool will be called every time a new build is performed, it is mandatory to echo the "y" to replace the previous signed binary. A possible way to implement this is shown below, slightly editing the previous commands:
# Specify the output ELF file
set(TARGET_ELF "${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}.elf")
# Command to generate .bin file
add_custom_command(
TARGET ${CMAKE_PROJECT_NAME}
POST_BUILD
COMMAND ${CMAKE_OBJCOPY}
-O binary ${TARGET_ELF} ${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}.bin
COMMENT "Generating .bin file"
)
# Define the paths to the STM32 Signing Tool and the input/output files
set(SIGNING_TOOL "C:/Program Files/STMicroelectronics/STM32Cube/STM32CubeProgrammer/bin/STM32_SigningTool_CLI.exe")
# Define the input and output files for FSBL
set(FSBL_INPUT "${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}.bin")
set(FSBL_OUTPUT "${CMAKE_BINARY_DIR}/FSBL-trusted.bin")
# Add a post-build step to sign the FSBL binary
add_custom_command(
TARGET ${CMAKE_PROJECT_NAME}
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E echo y > input.txt
COMMAND "${SIGNING_TOOL}" -bin "${FSBL_INPUT}" -nk -of 0x80000000 -t fsbl -o "${FSBL_OUTPUT}" -hv 2.3 -dump "${FSBL_OUTPUT}" < input.txt
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
COMMENT "Signing FSBL binary: ${FSBL_INPUT} -> ${FSBL_OUTPUT}"
)
Similar to the FSBL signing process, the application firmware binaries can also be signed post-build to meet security requirements.
# Specify the output ELF file
set(TARGET_ELF "${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}.elf")
]# Command to generate .bin file
add_custom_command(
TARGET ${CMAKE_PROJECT_NAME}
POST_BUILD
COMMAND ${CMAKE_OBJCOPY} -O binary ${TARGET_ELF} ${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}.bin
COMMENT "Generating .bin file"
)
# Define the paths to the STM32 Signing Tool and the input/output files
set(SIGNING_TOOL "C:/Program Files/STMicroelectronics/STM32Cube/STM32CubeProgrammer/bin/STM32_SigningTool_CLI.exe")
# Define the input and output files for Appli
set(APPLI_INPUT "${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}.bin")
set(APPLI_OUTPUT "${CMAKE_BINARY_DIR}/Appli-trusted.bin")
# Add a post-build step to sign the Appli binary
add_custom_command(
TARGET ${CMAKE_PROJECT_NAME}
POST_BUILD
# Step 1: Create a file with 'y'
COMMAND ${CMAKE_COMMAND} -E echo y > "${CMAKE_BINARY_DIR}/input.txt"
# Step 2: Run the signing tool, redirecting input from the file
COMMAND "${SIGNING_TOOL}" -bin "${APPLI_INPUT}" -nk -of 0x80000000 -t fsbl -o "${APPLI_OUTPUT}" -hv 2.3 -dump "${APPLI_OUTPUT}" < "${CMAKE_BINARY_DIR}/input.txt"
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
COMMENT "Signing Appli binary: ${APPLI_INPUT} -> ${APPLI_OUTPUT}"
)
Post build commands are essential for automating repetitive tasks in STM32 development. By configuring them, you save time and simplify your workflow, ensuring your firmware is always ready for deployment with minimal effort.