Repository navigation
v1.2.0
🌟 Added
Delta builds
Delta builds have been restored after a temporary hiatus following a major refactoring for 1.0.0 (Restore delta test builds to Ceedling 1.0.0+).
A delta build is simply a build run that only performs regeneration, compilation, linking, or execution as needed because of changed files or configuration. Ceedling 1.0.0 introduced threaded parallel build steps but had to remove delta builds in the process. As of 1.2.0, both build speedups are now available. Delta builds are automatic with no configuration needed.
If a build requests a test to be built/run but no changes for it exist, its cached test results will be reported. The --force-test-rerun flag is available at the command line for any test-related tasks to force the delta build mechanism to rerun test executables and produce new test results.
Delta builds are fully integrated with test build plugins (e.g. GCov, Valgrind). Each runs its own build through the same test pipeline as an ordinary test build, under its own build context, so it benefits from the same staleness tracking within its own isolated dependency cache
#include relative paths & duplicate filename disambiguation
Added support for properly distinguishing all C files by filepath (addressing #1167 specifically but also the fundamental problem generally).
In Ceedling’s early history simplicity won out with the assumption that every C file would be uniquely named. But, for example, this meant dir1/foo.h and dir2/foo.h were indistiguishable and Ceedling “guessed” to disambiguate using the ordering of filepath collections. This worked, but there was no ability to use partial paths to explicitly select a specific file. Now Ceedling fully utilizes filepaths to distinguish all elements of a test build. Relative paths are supported in #include directives. test: build tasks at the command line can optionally include a filepath to distinguish test files of the same name. The previous convention still works where the ordering of paths is identical among compiler search paths and those used to find files for test builds, but now additional path information can be provided to target specific files in your source collection.
Partials filepaths & duplicate module name disambiguation
#1311 Added directory-qualified Partial directive macros so Partials share the filepath handling the rest of a test build gained in this release (see previous section).
Previously, Partial directive macros took only a bare module name with no means to provide path information to distinguish modules of the same name. Every Partials _MODULE and _CONFIG macro now has an _AT variant taking that module’s directory as a separate first argument (e.g. TEST_PARTIAL_PRIVATE_MODULE_AT(sensors/soil, Calibration)). As with #include directives elsewhere, the directory is matched against the trailing end of a real file’s path. Supply only as much of it as it takes to name the module you mean. A bare module name in the original macros continues to work unchanged.
A test file can now test two same-named modules together, and it can mock both of them too (see the next section).
Mocking same-named headers by directory
A test file can now mock two headers that share a filename, such as drivers/uart/config.h and drivers/spi/config.h, by including each mock through its folder (#include "drivers/uart/mock_config.h"). This works for traditional mocks, MOCK_PARTIAL_*_MODULE_AT() Partials, and the FFF plugin’s fakes. The new :cmock ↳ :mock_name_include_folder setting, enabled by default, names each mock’s internals by that folder so the two mocks no longer collide. It relies on matching features in CMock and Unity, which Ceedling’s vendored copies include.
Multiple file extensions per file type
Added support for multiple file extensions per type (e.g. :extension ↳ :source ⇒ ['.c', '.C']) such as requested in #947.
Dedicated mocks and test runner generation build tasks
Some users have asked for the ability to run the test build pipeline only up through generating mocks or test runners without running the rest of a build. This is now possible.
Tasks mirroring command line test: task invocation but with an early termination like test:build_only now exist:
Like with command line test: tasks, <test> can be all, a test file name, or a source file name that has a corresponding test file.
Test build fallback preprocessing improvements
If your toolchain’s preprocessor lacks certain features, Ceedling still attempts to extract information and code from C files through fallback text processing. In 1.1.0 this was exposed as a project configuration option mostly for Ceedling’s self-tests and also noted as a possible option should Ceedling’s probe for toolchain preprocessor features ever provide a false positive.
In 1.2.0, fallback preprocessing can now sometimes be used in projects with simple conditional compilation (e.g. #ifdef) as a faster alternative to full toolchain preprocessing. A test file’s #includes are now checked against a plain run of your toolchain’s preprocessor. A mock in an #if branch that is off no longer stops a build or replaces the real module it guards. Fallback preprocessing remains a best effort with no guarantees. Error messages will indicate if fallback preprocessing is insufficient for your project’s preprocessing needs.
Force fallback preprocessing with :test_build ↳ :preprocess_force_fallback but be sure to understand Ceedling’s test preprocessing before doing so.
Test case shuffling at runtime
Ceedling now integrates Unity’s features for randomizing test case execution within a test executable (PR #1041 via :unity ↳ :shuffle_tests ⇒ TRUE. If enabled, the behavior of delta builds automatically adjusts to always execute test executables even if no code changes have occurred. This ensures the randomization occurs when test executables would otherwise fail to run for lack of any code or configuration changes up the dependency tree.
Subtractive paths in TEST_SOURCE_FILE()
The TEST_SOURCE_FILE() build directive macro can now be used to remove source files from a test executable build using the same -: filepath decorator as available in :paths project configuration (ex. TEST_SOURCE_FILE("-:foo/bar/file.c")). This can be handy in overriding Ceedling’s conventions for associating source files with a test executable if your project structure does not match up with Ceedling’s conventions.
ceedling.yml as an alternate default project file
#1250 ceedling.yml is now recognized as an alternate default project filename alongside project.yml. Either name is loaded the same way; neither is preferred over the other. If both exist in the same directory, Ceedling raises an error. ceedling new continues to generate project.yml by default; pass --ceedling-yml to generate ceedling.yml instead. See Loading a Project Configuration.
ceedling dumpconfig gains a --stdout option
Running the dumpconfig application command to produce a fully resolved project configuration now supports an option to send the resulting YAML directly to $stdout instead of a filepath. This is one small step towards Ceedling support for working with other tooling (e.g. agentic coding tools) in future releases.
Gcov plugin
Gcovr raw custom arguments
#1159 Added :gcov ↳ :gcovr ↳ :custom_args:, a list of raw command line arguments passed straight through to gcovr. This is an escape hatch for any gcovr flag Ceedling has no named option for (e.g. limiting gcovr’s search root), mirroring the :report_generator ↳ :custom_args: option that already existed for the ReportGenerator side of the Gcov plugin. Unlike every other GCovr option, :custom_args: still applies even when :config_file is set.
Gcovr JaCoCo and LCOV reports
#963 Added JaCoCo to the Gcov plugin’s :reports, a JaCoCo XML coverage report generated by gcovr and importable by IDEs such as CLion. The existing lcov report, previously generated only by ReportGenerator, is now also generated by gcovr. Both require gcovr 7.0 or higher and come with options for pretty-printing, LCOV comments and test names, and artifact filenames.
ReportGenerator coverage-threshold parity
Added :gcov ↳ :report_generator ↳ :fail_under_line/:fail_under_branch/:fail_under_method/:fail_under_full_method, ReportGenerator’s own coverage-threshold options mirroring the Gcovr side’s existing :fail_under_* family. A configured threshold breaks the build in the same way as these options do with Gcovr.
Bullseye plugin
The Bullseye code coverage plugin using the commercial Bullseye tool is enabled again (disabled since 1.0.0). The makers of Bullseye generously provided a license in order to modernize the plugin.
The refreshed Bullseye plugin offers additional features over the original version including support for branch coverage detail, machine-readable coverage reports (XML flavors), and an optional coverage threshold that will break a test build.
Sanitize plugin
The new Sanitize plugin builds and runs tests with the compiler’s sanitizers. sanitize:all and its sibling tasks run AddressSanitizer, UndefinedBehaviorSanitizer, and LeakSanitizer in a build of their own, and :sanitize ↳ :test_builds instruments ordinary test: builds as well. The plugin’s flags never reach another plugin’s build, such as Gcov or Valgrind. A test a sanitizer stops fails with its finding named, such as AddressSanitizer heap-buffer-overflow at test/test_buffer.c:21, while a leak is reported as a finding without disturbing test results. Each test’s sanitizer reports are kept in a log of its own, :reports writes text, JSON, and SARIF reports, and :fail_build fails the build on any finding. The plugin runs on Linux and macOS; leak detection is Linux only.
Valgrind plugin
- Added
:valgrind↳:suppressions:, a list of Valgrind suppression files. Previously these had to be hand-injected into:arguments:. - Added
:valgrind↳:xml_report:to write a machine-readable report per test executable alongside the text log, for CI systems or other tooling to consume Valgrind output directly.
Cppcheck plugin
- Added
:cppcheck↳:fail_build:and:fail_build_severities:to break a build on findings. Cppcheck exits successfully even when it finds defects, socppcheck:allpreviously could not fail a build at all. Onlyerrorseverity fails by default, since whole project analysis always enables every check. cppcheck:allnow prints a per-severity tally of findings. Results previously landed only in report files, with nothing shown at the console.
Module Generator plugin
- #695 Added
module:test[...], which writes a test file holding an ignored test for each function a module’s header declares. Run again, it adds tests only for newly declared functions. - #665 Added
:test_guardto wrap generated tests in#ifrather than#ifdef. Generating tests now warns when the guarding test define is not defined for test builds, since those tests would compile to nothing. - #1025
module:createnow warns about each existing file elsewhere in the project that shares a name with a file it creates.
Dependencies plugin executables
#1110 A dependency can now list the programs it builds under :artifacts ↳ :executables for tools rather than libraries. A release build or dependencies:make builds them when missing, test builds do not wait on them, and they are never linked. dependencies:deploy copies them, along with dynamic libraries, to a new optional :paths ↳ :deploy folder, by default beside the release executable.
Build warnings plugin context, deduplication, and filtering
The Build Warnings Log plugin now logs each GCC or Clang warning with the lines that explain it — the function or include context before it along with the source line, caret, and any note after it. Each distinct warning is logged once per build context, so a header's warning appears once rather than once per file including it, and compiler summary lines are left out. New :patterns and :excludes settings optionally take regular expressions that replace the default match of any line mentioning “warning” and optionally drop warnings you have already accepted or prevent false positives.
Build warnings plugin SARIF and JSON reports
The Build Warnings Log plugin can now write its warnings as SARIF and JSON reports alongside, or instead of, its plain text log. SARIF, the standard format for static analysis results, lets GitHub code scanning, Azure DevOps, SonarQube, Jenkins, and IDE viewers show each warning on the line it concerns. The JSON report lists each warning’s file, line, column, severity, flag, message, and context for scripts. The new :reports setting selects any of :text, :sarif, and :json, and defaults to :text. The structured reports are written for every build context that ran a build step, even without warnings, so a CI step always finds its file.
JUnit report plugin test locations
#583 The Test Suite Report Log Factory plugin’s JUnit report now says where each test case lives. Each <testcase> carries classname, file, and line attributes, and a failure’s message starts with its file and line (e.g. test/TestUsartModel.c:44: ...). CI tools such as GitLab can then link a result to its code. classname keeps the test file’s path so same-named test files in different folders stay distinct. The new :junit ↳ :file_line_anchor option writes file as path#line for tools that follow that form.
GTest-like report plugin skipped tests
The GTest-like console report (report_tests_gtestlike_stdout) now reports a Unity test ignored with TEST_IGNORE() or TEST_IGNORE_MESSAGE() as a GoogleTest skipped test. A skipped test is listed with its location and message, counted in the run, and summarized between passed and failed tests, the way GoogleTest 1.10.0 and later reports GTEST_SKIP(). A test file whose every test is ignored now gets its own section. The new :report_tests_gtestlike_stdout ↳ :ignored_as_skipped: setting defaults to TRUE. Set it to FALSE to leave ignored tests out of the report for tools that do not understand skipped tests (see the related Changed entry below).
IDE report plugin formats
#633 The IDE console report (report_tests_ide_stdout) now lists failed and ignored tests in the shape of GCC diagnostics (e.g. test/TestModel.c:21:1: error: testInit: Expected 5 Was 4). Eclipse CDT, VS Code, CLion, and other tools that read GCC output show each failure as an error and each ignored test as a warning, linked to the test. The new :report_tests_ide_stdout ↳ :format setting defaults to :gcc. :legacy restores the earlier, simpler lines. :vscode, :eclipse, and :clion name the settings each IDE needs. The plugin documentation now covers set up for each of these IDEs (see the related Changed entry below).
Filepath limit checks
Platform filepath limits (especially on Windows) can lead to mysterious build failures, especially in CI where deep project subdirectories can occur. To help track down funny business, filepaths are intercepted and their lengths logged if they are nearing or exceed the platform limit.
Retry handling for child process generated file dependencies
In certain intervening circumstances, particularly on Windows, a child process may successfully generate a file that Ceedling expects to be present but OS-related issues (e.g. virus software, security checks, cloud storage syncing) delay from actually appearing in the file system. A new application-wide retry mechanism deals with the situations and fails properly if the delay exceeds the retry limit.
Windows test executable manifests
#146 #116 On Windows, Ceedling now writes a manifest beside each test executable to help ensure that any test filename can be run. The Installer Detection feature of User Account Control (UAC) otherwise demands administrator privileges for an executable whose name contains install, setup, update, or patch. A test filename containing one of these words is noted with a warning. Note that modern Windows compiler toolchains tend to
embed a manifest that prevents the privilege limitation; Ceedling’s external manifest is further insurance.
💪 Fixed
Note: 1.2.0 includes all bug fixes for 1.1.x.
- A CLI parameter string mutation issue that could corrupt certain build or plugin task invocations.
- Fixed a Unity
TEST_IGNORE_MESSAGE()test case being misreported as crash evidence during crash-diagnosis retries when it shares a test file with a genuine crash. - #104 Fixed a literal
[or]in a path being silently misread as a glob or regular expression syntax. This could drop files from a build with no error, cause issues with a:build_rootentry, or cause a passing test run to be reported as "no tests executed." - #1083 Fixed a test file’s
#includeof a mock being dropped with:use_test_preprocessorset to:testsor:allwhen an#ifdefor#ifaround it depended on a macro defined in a header. The mock was never generated, and the build stopped on a missing mock header. The macro now decides the#includeas it will at compile time, whether it reaches the test file through a header the test includes directly or through one it mocks. - #1267 Fixed a conditional
#includewhose target is a macro invocation (e.g.#include DEVICE_HEADER(x)) being silently dropped from includes extraction whenever its own guard condition depended on a symbol defined in another header. - #1292 Fixed an intermittent
Errno::ENOTDIR/EISDIRcrash when automatically vendoring Unity, CMock, and CException into a project’s build directory, caused by a transient file-system race (e.g. an antivirus/EDR lock, a cloud-sync filter driver, or a second concurrent Ceedling invocation). The copy step now retries transient races and self-heals a stale, wrong-typed leftover from a previous failed copy. - Fixed a rare, Ruby-version- and platform-dependent misordering of include lists and mixin environment variable resolution caused by relying on
sort/sort_by’s ordering among tied elements, which Ruby does not guarantee to be stable. - Fixed two source files of the same name in one test executable sharing a single preprocessed intermediate file, so whichever was preprocessed second overwrote the first. Preprocessed files now mirror their source’s own directory, matching the convention compiled objects already follow.
- Fixed a generated header’s fallback
#includeguard being built from a filename alone, so two same-named headers in one test shared one guard and whichever the compiler read second was emptied of its declarations. - Fixed a local release gem build packaging leftover build output from the machine that built it, including compiled object files and executables. Fixed the same packaging omitting the configuration file that the test suites bundled with the gem need in order to run at all. Since the release gem is produced in a clean CI environment the underlying issue never affected gems published through GitHub and RubyGems.org.
Backtrace / gdb handling
- Fixed
:use_backtrace⇒:gdbremaining active on a machine wheregdbcannot actually attach to a process (e.g. lost macOS codesigning trust after a system update or Homebrew upgrade). Previously, Ceedling validated thatgdbwas available but not its ability to probe a process. Ceedling now detects a degradedgdbat build startup and falls back to:simpleautomatically, with a prominent warning for the condition. - Fixed handling for a crashed test executable that
gdbcould not usefully explain looking identical to an ordinary crash report. Ceedling now better detects this and prominently warns when this happens.
Partials
- Fixed a bare, top-level macro invocation that expands to a full function definition (a common x-macro boilerplate idiom) silently corrupting or losing whatever construct followed it during Partials extraction.
- Fixed a Partial resolving its module’s header and its module’s source independently, which could pair one module’s header with a same-named other module’s source.
- Fixed a Partialized module’s own real header being reachable by its bare filename from inside the generated Partial, so a Partial could be compiled against a same-named other module’s header.
Mixins
- Fixed priority / precedence issues with command line mixin edge case (same mixin provided multiple times).
- Fixed mixin environment variable name matching issues such as a leading zero for
01numbering or improperly matching on an environment variable similar to the mixin convention. - Fixed an edge case for
tools:argument special handling merging involving a single string argument instead of list of arguments.
Reporting plugins
- Fixed a thread-safety issue in
report_build_warnings_logthat could crash a multi-threaded build or produce an incomplete warnings log. - Fixed the GTest-like console report (
report_tests_gtestlike_stdout) mislabeling ignored tests as passing and silently dropping their ignore message; its header and footer test counts could also disagree whenever a build had ignored tests. - Fixed the TeamCity console report (
report_tests_teamcity_stdout) not escaping a real line break in a failure message, corrupting the TeamCity service message it produced.
report_tests_log_factory
- Fixed
report_tests_log_factory’s JUnit, CppUnit, and HTML reports producing malformed or unsafe output when processing characters like<,>,&, or". - Fixed
report_tests_log_factoryreport content silently depending on the order reports were listed in:report_tests_log_factory↳:reports:(e.g. enablingjunitahead ofcppunit)
Module Generator plugin
- Fixed a path hint carrying over from one module to the next when a call names several, such as
module:create[lab:First,Second]. - Fixed several ordered hints such as
lab:secret:laircreating a file namedsecret:lairrather than matching nested folders. A Windows drive letter in a hint now stays part of its path. - Fixed a hint failing the whole command when it matched no path of one kind. Files of that kind now go to its first path, and only a hint matching nothing at all stops the command. Headers go with the source when no include paths are listed.
- Fixed any name beginning with
testbeing taken as a test file, turningtestimonyintoimony. Only a name carrying the configured:test_file_prefixasks for a test file alone. - Fixed
module:stubignoring the project’s:cmocksettings and a subdirectory named with a slash, printing its configuration, and triggering a CMock warning about:includes. - Fixed
:boilerplate_fileschanging the configured:boilerplates. A boilerplate file that does not exist now stops the command rather than being ignored.
Command Hooks plugin
- Fixed certain hooks handing their tools an empty
${1}. - The compile hooks now pass the source file as
${1}and the object file as${2}, and:pre_runner_generatepasses the test file, as documented. - Fixed a hook configured with a list of tools failing validation.
- Fixed the build hooks (
:pre_build,:post_build,:pre_test_build, and the like) handing their tools a date string rather than a timestamp in seconds on Windows.
Dependencies plugin
- Fixed enabling the plugin making its fetch tools (
unzip,tar,git,svn) and its:build_libcompiler and archiver requirements of every Ceedling command, including plaintest:all. Each is now checked just before a dependency fetches or builds with it. - #1076 Fixed a second
dependencies:fetch, or adependencies:makeafter a fetch, failing becausegit cloneran into the already-populated folder. A dependency whose fetch path holds files now counts as fetched, anddependencies:cleanallows a fresh fetch. Working paths are no longer created ahead of fetching, which made a clone into a fetch path containing the build path fail. - #1110 Fixed
dependencies:deploytrying to copy a file named for the dependency rather than its dynamic libraries. It now copies every dynamic library from the artifact path beside the release executable. - Fixed a
:tar_gzipfetch from an absolute Windows path failing with "Cannot connect to D: resolve failed" where GNU tar, as Git for Windows provides, came first on the path. GNU tar reads a path beginning with a drive letter as a remote host, sotarnow reads the archive on its standard input. - Fixed a dependency's
:environmentvariables lasting for the rest of the run, reaching every later dependency and Ceedling itself. They now apply only while that dependency's commands run. An entry not of the formNAME=value,NAME+=value, orNAME-=valuenow stops the build rather than being ignored. Text after+=and-=now keeps its leading space, so an appended flag can carry the delimiter it needs. - Fixed a dependency without
:artifactscrashing the build. Configuration problems now stop the build with a message naming the dependency: a missing name, a name without letters or digits, two names sharing a task name, an unknown fetch method, or a fetch method missing its:sourceor:executable. - Fixed an
:includesglob under:artifactsexpanding against the working directory rather than the artifact path, and joining every directory it found into one path. - Fixed
:build_libdepending on the process working directory, and miscomputing where to copy its library when the:artifactpath was absolute or climbed with... The:deps_compilertool now receives its search paths and defines as${5}and${6}, like Ceedling's own compilers.
Valgrind & Cppcheck plugins
- Fixed enabling either plugin making its analysis tool a hard dependency of every Ceedling command, including plain
test:all. Each tool is now required only by its own plugin’s tasks.ceedling files:cppcheckno longer needs Cppcheck installed either.
Valgrind plugin
- Fixed memory errors being undercounted for a test that forks. Valgrind reports a separate error summary for each process it traces, and only the first was counted.
- Fixed a test whose Valgrind report could not be read being treated as a clean result. Ceedling now warns that the memory error status is unknown.
- Fixed the "Wrote N Valgrind report(s)" notice repeating with a different partial count for each test that found errors. It is reported once and counts the reports actually written.
- Fixed settings other than
:argumentsconfigured under:tools↳:valgrindbeing silently discarded. - Fixed a
valgrind:build’s test results report coming up empty. The plugin looked for results where an ordinarytest:build writes them, not where its own build does. - Fixed
--test-caseand--exclude_test_casefilters in avalgrind:build being handed to Valgrind rather than to the test executable. - A
valgrind:task on a platform without Valgrind now explains that Valgrind runs on Linux and other Unix-like systems rather than only reporting a missing executable.
Cppcheck plugin
- Fixed
:cppcheck↳:xml_report_versiondefaulting to a version older Cppcheck releases reject outright, breaking the XML report on common installations. The default is now the version every release accepts. - Fixed requesting an
htmlreport makingcppcheck-htmlreportmandatory, contradicting that tool’s own optional status. - Fixed
cppcheck:allanalyzing nothing and saying nothing when no report is configured, which read like a successful run. The plugin now explains what to configure. - Fixed a configuration list containing a single non-string entry silently disabling
#{...}expansion for every other entry in that same list. - Fixed a misspelled path under
:paths↳:cppchecksilently collecting no suppression files, indistinguishable from a directory holding none.
⚠️ Changed
Build warnings plugin :filename is a base name
The Build Warnings Log plugin’s :filename now names the base of each report, and each report adds its own extension (.log, .sarif, .json). Its default is warnings, so the text log is still warnings.log. A project that sets :filename with any extension will have that extension overwritten by the default associated with each report type.
Module Generator :naming takes effect
#518 The Module Generator plugin’s :naming setting now applies. Previously it had no effect, and every name kept the case typed. :naming no longer defaults to :snake, so a project that does not set it still sees names kept as typed. :bumpy and :camel produce the case their documentation describes (BumpyFiles, camelFiles). A project that sets :naming will see generated file names change.
Performance improvements
Optimizations and fixes have yielded a 5–10% speed increase for most builds before the second-run speedup of the new delta build abilities.
#include relative paths & duplicate filename disambiguation in test builds
Because of the support added for handling paths and distinguishing duplicated filenames, the functional interface for testing has changed.
- The interface for test-build command line tasks has expanded. If you need to distinguish foo/test_thing.c from bar/test_thing.c, you must now add a trailing path to disambiguate the tests —
ceedling test:foo/thingandceedling test:bar/thing. The trailing path is optional and is only required to distinguish test files of the same name in different subdirectories. Of course, the test files must both be in the collection created by your:pathsand:extensionconfigurations. - Paths in
#includedirectives are optional but available to direct Ceedling to the proper header file for your test build needs. This is especially useful to distinguish header files of the same name in your project. Without a path in an#includedirective, Ceedling works identically to a compiler, selecting the first file among ordered search paths.
Use TEST_SOURCE_FILE() to override Ceedling’s .c / .h correspondence convention in tests
Historically, Ceedling automatically compiles and links into a test executable any C source file whose name matches an #included header file. Sometimes this convention can select the wrong file among same-named files or compile and link an entirely unwanted source file whose name happens to match a header file. Subtractive entries now allow this to be overridden (see more above).
Partials no longer silence CMock’s :treat_inlines project-wide
#1247 Enabling :use_partials previously turned off CMock’s :treat_inlines ⇒ :include option for every mock in every test in your project. This prevented unnecessary overhead and generation of files never used. However, this affected tests that used no Partials at all. Each mock now gets exactly the inline handling it needs on its own terms. A test using Partials gets Partials’ own handling for that mock, while every other mock keeps using whatever :treat_inlines setting you’ve configured.
A mock or Partial silently bypassed by its own real header
#1240 Added handling for edge cases where a mock or Partial could be silently bypassed by the real header these are meant to replace. Idiosyncrasies of C compilation search paths together with combinations of #include guards and #include ordering can lead to false negative test failures or outright crashes. Ceedling now discovers these scenarios on the other side of test compilation, rewires the test build to isolate the problematic header, and rebuilds with the fix in place. This intervention is only employed for shallow #include scenarios where this action is safe. More complex scenarios are prominently and proactively logged to provide hints on diagnosing failures that require more complex solutions than Ceedling should ever attempt to implement.
Guidance for a Partial colliding with its own module’s real header
#1247 Ceedling now recognizes when test compilation fails because a Partial’s generated content and its source module’s own real, un-Partialized header somehow both reached the compilation of the test fixture translation unit. Logging explains the likely cause and suggested solutions directly alongside the raw compiler error instead of leaving a confusing, bare redeclaration/conflicting types error.
Partials generation dependending on fallback preprocessing inadequaices
Partials generation now stops with an error if text-only fallback preprocessing cannot resolve a code element — an #include naming a macro or a type behind a conditional expression. The message names the file and line instead of the test build failing later with a confusing compiler or linker error.
report_build_warnings_log plugin warning lines
report_build_warnings_log’s log files now contain only the actual warning line(s) from a build step’s output, not that step’s entire lengthy console output whenever it happened to contain the word "warning."
Internal verbosity level mapping for Ceedling to CMock
Ceedling and CMock are interdependent but distinct tools. They each perform their own logging and have different verbosity level conventions. The internal mapping has been adjusted to configure CMock for verbosity levels that match the spirit of the selected top-level Ceedling logging verbosity level.
Smarter :flags and :defines matching for preprocessing overrides
Preprocessing flags and defines matchers now pass through to test compilation flags and defines for any matchers that are not defined. Previously, any preprocessing flags and defines matchers entirely overrode the test compilation flags and defines matchers. Now, you can selectively override them. Note that preprocessing flags and defines matchers are fairly specialized features used in rare cases.
Options that suppress preprocessor line markers are rejected
With test preprocessing enabled, Ceedling now stops at startup if -P or --no-line-commands appears in flags that reach preprocessing or in a preprocessing tool’s arguments. Test preprocessing reads the line markers these options remove to find #includes, mockable functions, and test cases. A preprocessor given either option still succeeds, so builds failed later with confusing errors or ran no tests at all. The error names each offending entry. Remember that :compile flags also apply to preprocessing wherever :preprocess flags do not.
Inline Ruby string expansion evaluates only #{…}
#289 Inline Ruby string expansion evaluates only the Ruby inside each #{…} and keeps all other text as written. Backslashes in Windows paths and quote marks around an expansion survive intact. Ruby escape sequences written outside #{…} (e.g. \" or \n in a single-quoted YAML string) are no longer interpreted.
Gcov console coverage summary names a module by path when needed
The Gcov plugin’s console summary labeled every file by filename alone, so a test covering two same-named modules produced two sets of figures with nothing to say which module either belonged to. Each label now carries as much trailing path as it takes to tell it apart from the other files in that same test’s summary. A filename that is already unique is labeled exactly as before.
More strict regex matching to exclude test artifacts from Gcov plugin coverage reports
Gcovr and ReportGenerator support within the GCov plugin now make use of more sophisticated and explicit regular expressions to filter out test files and test-build-generated files from coverage reporting. This helps prevent mistaken exclusions of source filenames with substrings (e.g. "_runner") that might otherwise match test filenames or generated files.
Test results report template filenames
The templates behind the $stdout test results reporting plugins have been renamed for what they produce. report_tests_pretty_stdout and report_tests_gtestlike_stdout now use assets/test_results.template, and the Bullseye plugin uses assets/coverage.template. The former assets/template.erb name is still honored, so a user-created custom plugin shipping that filename continues to work without changes.
Status line coloring for ceedling new, ceedling example, and ceedling upgrade
The create, exist, identical, and force status lines these commands print are now colored according to Ceedling’s own decoration settings rather than a separate scheme. Coloring also requires a terminal, so redirecting output to a file produces plain text. Set CEEDLING_DECORATORS to 0 to disable the coloring entirely.
Generated #include guard format
Ceedling writes #include guards into the headers it generates for test builds (e.g. Partials and reconstructed headers resulting from preprocessing). These guards now take the form GEN<hash>_<NAME>_H_CEEDLING (e.g. GEN2B4E27AE_DRIVERS_UART_CONFIG_H_CEEDLING), where the hash is derived from the header’s path. This format ensures uniqueness while conforming to the C standard’s reserved identifier and significant length rules (C99 §7.1.3, §5.2.4.1), MISRA C:2012 Rules 5.4 and 21.1, and CERT DCL37-C. Nothing in your project configuration or source code needs to change unless you referenced a generated guard by name.
GTest-like report plugin output matches GoogleTest
The GTest-like console report’s output now better matches GoogleTest’s own console format. Counts read in the singular for one (1 test, 1 FAILED TEST), test files are named test suites, and the run’s total time appears on its closing line. The failure list and its trailer appear only when a test fails. By default, ignored tests now appear in the report and its counts as skipped tests (see the related Added entry above). A tool that checks this report’s totals will see ignored tests counted unless :report_tests_gtestlike_stdout ↳ :ignored_as_skipped: is set to FALSE.
Valgrind builds stop on sanitizer flags
A test executable built with sanitizers cannot run under Valgrind. A valgrind: build uses :flags ↳ :test for any operation it has no flags of its own for, so sanitizer flags meant for test builds reached it. It now stops with a message naming the -fsanitize flags and how to keep them out. The Sanitize plugin instruments only its own builds.
Test case filters follow a custom test fixture tool’s arguments
--test-case, --exclude_test_case, and :simple backtrace filters now come after a :test_fixture tool’s own arguments rather than right after its executable. A wrapper tool runs the test executable as one of its arguments, so the filters now reach the test executable. The default test fixture tool has no arguments, so its command line is unchanged. A custom fixture tool with arguments after ${1} sees the filters move to the end of its command line.
IDE report plugin lines default to the GCC output format
The IDE console report’s failed and ignored tests now print as GCC diagnostics by default (see the related Added entry above). A multi-line message keeps its first line with the test’s location and indents the rest. The Gcov, Bullseye, and Valgrind plugins’ test results change the same way when this plugin is enabled. A script or tool that reads the earlier format needs :report_tests_ide_stdout ↳ :format: :legacy (see Breaking Changes).
👋 Removed
- The
erbgem dependency has been removed. Ceedling renders some of its plugin reports with a small template compiler of its own in place oferb. This reduces Ceedling’s external dependencies, simplifies installations where more recent versions oferbpull in further dependencies, and resolves security scanning findings againsterb(CVE-2026-41316). Ceedling never used the feature that security advisory concerns, but carrying the dependency at all was enough to be flagged. Custom plugin templates are unaffected unless they use ERB syntax Ceedling itself never used — see plugin development documentation for the supported template syntax. - The Module Generator plugin no longer adds and removes generated files in Subversion, and its
:update_svnsetting is ignored with a deprecation warning. Add new files to source control with your own tools.