STM32CubeIDE Headless Builds Need an Explicit Workspace and Artifact Contract

A firmware archive can look complete because it contains a recent ELF file, even though the unattended job never built the intended project. For an Eclipse-based STM32CubeIDE handover, make the workspace, build configuration, and expected output explicit. Then prove that the delivered binary came from that invocation rather than from yesterday’s output directory.

The procedure below is an engineering proposal based on STM32CubeIDE 2.2.0 documentation, not an executed CI run. It applies to managed-build projects using the IDE’s headless launcher, not automatically to every CMake workflow or the separate VS Code product.

Name the build independently of the developer’s desktop

Write a short build contract before writing the job. Identify the repository revision, project name as recorded in the project metadata, configuration name, compiler identity, and expected ELF path. A folder called controller does not prove the imported Eclipse project has that name. Likewise, a desktop that last built Debug does not establish the configuration needed for a release artifact.

Treat the workspace as job state rather than as a source dependency. A fresh workspace makes missing imports and hidden desktop assumptions visible. Keep it separate from the checkout, and do not share it with another running job. Give each concurrently executing build its own workspace and output ownership so that a second invocation cannot change the evidence underneath the first.

UM2609 Rev 18, section 2.3.3.3 documents the headless launcher, its help command, and the restriction against using a workspace already open in the IDE. Figure 131 lists project import and project/configuration selection options. Check the installed launcher’s help rather than copying an old installation path from the manual.

Import the intended project and select one configuration

The following Windows command-file example uses invented paths and a hypothetical project named PumpController. Replace every path and identifier. Confirm the exact spelling of the launcher and configuration on the pinned installation before integrating it into a job.

call "C:\ST\STM32CubeIDE_2.2.0\STM32CubeIDE\headless-build.bat" ^
  -data "C:\ci\workspaces\job-042" ^
  -import "C:\ci\src\controller" ^
  -cleanBuild "PumpController/Release" ^
  > "C:\ci\logs\job-042-build.txt" 2>&1
set "BUILD_RC=%ERRORLEVEL%"
exit /b %BUILD_RC%

Create the log directory before invoking this example. The import location must contain the intended project metadata; it is not necessarily the repository root. Avoid a broad import-all operation until you have decided which nested examples, bootloader projects, and test applications belong in this particular build.

Record the resolved project and configuration from the build output. If the selection is wrong or matches nothing, stop there. A subsequent file-copy command cannot repair a build that never ran. Do not turn a missing project into a successful job by making the artifact upload step optional.

Headless build contract showing pinned checkout, isolated workspace, exact Release configuration, and fresh ELF plus log checked together

Original workflow diagram. Proposed acceptance gates, not a completed build result.

Preserve failure through the wrapper

A job can lose the meaningful return code when a wrapper runs another command before examining it. Capture the build process result immediately, preserve its full log, and make the final job result reflect failure. If output is piped through another utility, verify the shell’s pipeline error behavior instead of assuming the displayed console text determines the job status.

This is worth testing deliberately. RN0114 Rev 39, the historical v1.5.0 fixed-issues table, records issue 93098 concerning headless-script subprocess exit codes. That historical fix does not establish that your additional wrapper propagates errors correctly.

In a disposable checkout, introduce a known syntax error, run the same automation, and check that it rejects the job and withholds the release artifact. Restore the source afterward. This is a proposed negative test, not a claim that the sample commands have passed it.

Reject an ELF left behind by a different run

Use a disposable output area or record the expected artifact’s pre-build state. After a successful process result, require the named output to exist in the agreed configuration directory. Retain the log that produced it and calculate its hash after the build has ended. Never select the newest ELF found anywhere below the repository: a different target or configuration may legitimately have a newer timestamp.

A timestamp check alone is weak evidence. File copies, clock differences, or retained outputs can confuse it. Prefer a clean checkout/output arrangement and a manifest associating source revision, configuration, tool versions, command, process result, and artifact hash. Do not promise bit-for-bit reproducibility until independent builds have actually been compared and any differences explained.

Finish the handover by having the receiver repeat the build without your workspace. Acceptance means the agreed invocation produces the expected artifact and the intentional failure case is rejected. Successful compilation remains separate from programming, functional testing, and release approval; the CI package should say which of those steps has and has not occurred.

Similar Posts