# Check, a C unit test framework that runs every test out of process

> Check is a unit testing framework for C, and the decision that shapes it is that each test runs in a separate address space, so a test that segfaults is a failed test rather than a dead test run. Everything else in the repository follows from a project that is small, stable and built with two build systems, and the readme is refreshingly direct about the parts that annoy users, including the variadic macros in its public header.

**libcheck/check** — A unit testing framework for C

- Repository: https://github.com/libcheck/check
- Stars: 1,171 · Forks: 224
- Language: C
- License: LGPL-2.1
- Published: 2026-10-19 · Updated: 2026-10-19 · Language: en
- Canonical page: https://hysenlabs.com/projects/libcheck-check

## Each test gets its own process, and that is the design

Check is a unit testing framework for C that features a simple interface for defining unit tests, putting little in the way of the developer. The sentence that matters comes next: tests are run in a separate address space, so Check can catch both assertion failures and code errors that cause segmentation faults or other signals.

That single design decision is what separates Check from the alternatives in C. A test framework that runs in the same process as the code under test has a problem when the code under test dereferences a null pointer. The process dies, the runner dies with it, the remaining tests never run, and the report is whatever the operating system printed on the way out. Check runs each test in a forked child, so a segfault is a signal the parent can catch, attribute to a particular test, and report as a failure. The same applies to other fatal signals, which is why the readme says signals and not just crashes.

The benefit is not only the report. A test that corrupts memory does not take the rest of the suite with it, and a test that leaks or aborts does not stop the run. For a codebase with a lot of C, where undefined behaviour is the norm rather than the exception, that isolation is the feature people adopt it for.

The readme also notes that the output from the unit tests can be used within source code editors and IDEs, which is a small but practical point. A test runner whose output is a machine-readable stream is something an editor can parse, and the readme's promise of little in the way suggests the format is simple enough for that to work.

The project site at libcheck.github.io/check carries the documentation and a tutorial, and the tutorial is also available as the info check manual page, which is the traditional way to ship a manual with a Unix tool.

## Two build systems, both maintained

The repository carries an autotools build and a CMake build, and the readme documents both, which is unusual and useful for a library of this age.

The autotools route is the classic sequence:

```bash
$ autoreconf --install
$ ./configure
$ make
$ make check
$ make install
$ sudo ldconfig
```

The readme adds two notes that matter in practice. autoreconf calls all the necessary tools for you, like autoconf, automake and autoheader, so you do not have to know the order in which to invoke them. And if you change something during development, you should run autoreconf again, this time without --install, so that it performs the minimum set of actions necessary rather than reinstalling the whole machinery.

The last two steps are worth understanding. Check is installed to /usr/local/lib by default, and ldconfig rebuilds the linker cache so that the newly installed library file is included in it. Without that step, a program that links against libcheck can fail to find the shared library even though it is installed, which produces a confusing runtime error rather than a build error.

The CMake route is the out-of-source build with the test runner integrated:

```bash
$ mkdir build
$ cd build
$ cmake ../
$ make
$ CTEST_OUTPUT_ON_FAILURE=1 make test
```

The environment variable is the detail worth copying. CTEST_OUTPUT_ON_FAILURE=1 makes the CTest runner print the output of a test only when it fails, which turns a failing build from a scroll of thousands of lines into something a person can read.

The root listing shows both build systems in full, with configure.ac, Makefile.am, check.m4 and the m4/ directory for the autotools side, and CMakeLists.txt with the cmake/ directory for the other, plus the CI workflows for Linux, macOS and Windows and an older appveyor configuration.

## A dependency list from another era, with an honest caveat

The dependency list is short and dated, and the readme pre-empts the obvious objection.

The requirements are automake 1.9.6, or 1.11.3 on macOS if you are using /usr/bin/ar, autoconf 2.59, libtool 1.5.22, pkg-config 0.20, texinfo 4.7 for the documentation, tetex-bin or any texinfo-compatible TeX installation also for the documentation, and a POSIX sed. The readme then adds a single sentence that saves a lot of confusion: the versions specified may be higher than those actually needed.

That caveat is doing real work. These are the versions the project was written and tested against, listed in the old style of a minimum version, and a modern system will have newer ones. The macOS exception is the kind of detail that is only in a readme written by someone who has hit it, since the Apple ar differs from the GNU one in a way that breaks an old automake.

The texinfo requirement is the one to notice, because it is a documentation dependency rather than a build dependency. Building the manual needs a TeX installation, and a machine that only wants the library does not have to install one. The repository carries a doc/ directory and a web/ directory, and the manual is what the tutorial page is generated from.

The pkg-config requirement is there because the project installs a check.pc file, generated from check.pc.in, which is how a consumer finds the library with pkg-config --cflags --libs check. That is the modern convention and it is the reason the dependency list includes pkg-config at all.

## The variadic macros in check.h, and the compiler flag to match

There is a short section on linking, and it is a section about a single annoyance.

Check uses variadic macros in check.h, and the strict C90 options for gcc will complain about this. In gcc 4.0 and above you can turn this off explicitly with -Wno-variadic-macros. And the readme adds, in a future API it would be nice to eliminate these macros.

Variadic macros are a C99 feature, and C90 was for a long time the default dialect that a strict compiler configuration would enforce, which is why a library that used them had to tell you how to silence the warning. The -Wno-variadic-macros flag is the workaround, and it is a targeted one: it disables the diagnostic rather than relaxing the language standard, so the rest of your strict settings stay in force.

The last sentence is the interesting one. The readme acknowledges that the macro use is a wart in the public API, and that the fix belongs in a future version of the interface rather than in a workaround every consumer has to apply. It is a rare admission in a project documentation file, and it is useful, because it tells you two things. The warning is expected rather than a sign of a broken build, and the public header is not going to change shape in a way that breaks your code, because the project considers that a future API question.

For a team with a strict compiler policy, the practical takeaway is that you will need that flag, and that a stricter C standard in your build is the one thing this library's header cannot accommodate.

## Packaging, the test generator and the documentation tree

The readme notes that Check is available packaged for a range of operating systems, and links a badge that shows the packaging status across the repositories that repology tracks. For a library that has been around for a long time, that is the practical answer to the question of how you install it, and the answer is usually your distribution's package rather than a build from source.

The repository also contains a few things that show what kind of project this is. The checkmk/ directory holds the machinery for generating test skeletons, the standard generator for a C test framework that writes the boilerplate for a test file so you do not have to. The xml/ directory suggests the project carries its test results in XML, which is what makes the output usable in an IDE, and the web/ directory holds the site material. The contrib/ directory is where contributed patches live.

The project files around them are conventional for a GNU-adjacent C library: an AUTHORS file, a ChangeLog, a HACKING file with the contribution rules, a NEWS file, a THANKS file, a TODO, a COPYING.LESSER file carrying the LGPL text, and a .editorconfig for formatting.

The LGPL-2.1 licence is worth a sentence for anyone linking it. It is a weak copyleft, so a proprietary program can link against libcheck and remain closed source, while modifications to the library itself must be published. For a testing framework, that is the licence a vendor would want, and it is a large part of why Check is found in commercial C codebases at all.

## Where Check is the wrong tool

The first limit is the release story, and it is a real one to plan around. The tagged releases are 0.15.0 in June 2020, 0.15.1 in July 2020 and 0.15.2 in August 2020, while the master branch received a push on 2026-07-13. The project is alive, the CI runs on three platforms, and there is no release newer than 2020. So a consumer choosing between the last tag and the tip of the branch is choosing between a six-year-old release and an unreleased one, and nothing in the readme tells you which to take.

The second is the size of the framework. Check does a small number of things well, which is a virtue in a testing library, and it does not attempt to be more. There is no mocking layer, no coverage integration, no test parameterisation beyond what the macros give you, no plugin system, and no fixture language. A team that expects the ergonomics of a modern framework, with generated mocks and a declarative test language, will find Check bare.

The third is the cost of the isolation. Forking a process per test is not free, and a suite with tens of thousands of small tests will run noticeably slower than an in-process runner. That is the right trade for a codebase with undefined behaviour in it, and the wrong one for a project with a large, well-behaved test suite where the run time is the complaint.

The fourth is the language. This is a C framework, and a C++ project that wants to use it will be writing C-interfaced test code, which is a friction the ecosystem solved years ago with a different approach. And the fifth is the toolchain, since building from source means the autotools and texinfo toolchain on a machine that may not have it, when a distribution package would be the sane route.

## Conclusion

The library fits a C project that wants a small test framework with no runtime dependencies and no opinions about how tests should be written, and the out-of-process model is the reason it can report a crash as a failure instead of taking the suite down with it. It does not fit a team that needs mocking, coverage integration or a plugin ecosystem, and it does not fit a project that needs a maintained release stream, because the last tag is 0.15.2 from 2020 while the master branch has continued to receive pushes. Before adopting it, check the version you are picking against the branch you need, and note that the public header uses variadic macros, which strict C90 compiler settings will reject until you pass -Wno-variadic-macros. The licence is LGPL-2.1 and the last push was on 2026-07-13.

## FAQ

### What is Check, the C unit testing framework?

It is a unit testing framework for C with a simple interface for defining tests and little in the way of the developer. Tests are run in a separate address space, so the framework can catch assertion failures as well as code errors that cause segmentation faults or other signals, and the output can be consumed by source code editors and IDEs.

### How do I build and install Check?

With autotools, run autoreconf --install, then ./configure, make, make check, make install and sudo ldconfig to refresh the linker cache. With CMake, configure in a build directory, build, and run the tests with CTEST_OUTPUT_ON_FAILURE=1 make test. The library is installed to /usr/local/lib by default.

### Why does gcc complain about check.h?

Check uses variadic macros in its public header, and the strict C90 options gcc enables will complain. On gcc 4.0 and above you can silence it explicitly with -Wno-variadic-macros, and the readme notes that eliminating the macros would be a job for a future API.

### What do I need installed to build Check from source?

Automake, autoconf, libtool, pkg-config, texinfo with a TeX installation for the documentation, and a POSIX sed. The readme notes that the versions it lists may be higher than those actually needed, and gives a specific automake version for macOS when using /usr/bin/ar.

### Is Check still being worked on?

The repository has continuous integration workflows for Linux, macOS and Windows, and the last push to the master branch was on 2026-07-13. The tagged releases stop at 0.15.2 from August 2020, so the branch moves without new tagged versions, and the project is also packaged by the major operating system distributions.

## Sources

- [Issues](https://github.com/libcheck/check/issues)
- [libcheck/check on GitHub](https://github.com/libcheck/check)
- [License: LGPL-2.1](https://github.com/libcheck/check/blob/master/LICENSE)
- [README](https://github.com/libcheck/check/blob/master/README.md)
- [Releases](https://github.com/libcheck/check/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/libcheck-check
