Getting Started
Merlin is designed to scaffold, build and test C projects. It utilizes a predefined directory structure and compiler flags to enforce safety constraints.
Project Initialization
You can create a new project from scratch using the new command, which creates a new directory, or you can scaffold an existing directory using init.
Using new
merlin new my_project
cd my_project
Using init
mkdir my_project
cd my_project
merlin init
Directory Structure
Merlin expects a strict directory layout. This is automatically generated when you scaffold a project.
my_project/
├── src/ # All implementation (.c) and header (.h) files
│ └── main.c # The entry point of the executable
├── tests/ # All unit and integration tests (.c)
│ └── test_main.c
├── bin/ # Generated executable binaries (ignored by Git)
├── obj/ # Generated object files (ignored by Git)
├── compile_flags.txt # Configuration for Language Servers (clangd)
└── .gitignore
src/: Place all of your application code here. Merlin recursively scans this directory.tests/: Place your tests here. These are compiled and linked againstsrc/when runningmerlin test.
Building and Running
Once your project is structured correctly, use the following commands to orchestrate your build.
Building
To compile your project:
merlin all
The resulting binary will be placed in the bin/ directory.
Running
To compile (if necessary) and immediately run your project:
merlin run
Testing
To run the automated sanitizer test suite:
merlin test
This requires a zero exit code from ASan (exit code 1), UBSan (exit code 1) and LSan (exit code 23).
NOTE
Example: Handling Test Failures
While your C test suite should return 0 on success, sanitizers operate at the compiler level. If they detect a violation, they will override your program’s return value and force a specific exit code.
For example, this C test will trigger a leak and cause the process to exit with 23, bypassing the return 0:
int main() {
void* leak = malloc(100);
return 0; // LSan intercepts this and exits with 23
}
You can catch these specific codes in your CI/CD pipelines to know exactly what failed:
#!/bin/bash
merlin test
EXIT_CODE=$?
if [ $EXIT_CODE -eq 23 ]; then
echo "Memory leak detected! Check your deallocations."
exit $EXIT_CODE
elif [ $EXIT_CODE -ne 0 ]; then
echo "Undefined behavior or memory corruption detected!"
exit $EXIT_CODE
fi
echo "All tests passed successfully."
Adding Dependencies
Merlin is designed for self-contained projects using the Camelot utility library. Currently, external dependencies must be added as source files directly into the src/ directory. Static library linking support (.a / .lib) is planned for future releases.