Compare commits

..

20 Commits

Author SHA1 Message Date
portersky 8d6483eb80 docs: clarify license scope in README 2026-06-15 04:53:27 +02:00
portersky de64c90a6d docs: add build instructions to AGENTS.md 2026-06-15 04:51:45 +02:00
portersky 4269f65942 docs: remove duplicated commands from AGENTS.md
Commands, CMake module path, and commit message examples are
all in skills now. AGENTS.md references them with /skill: links.

Update Source Layout to match current files.
2026-06-15 04:40:45 +02:00
portersky 657d154560 style: fix include order in all source files
Move C stdlib headers before local/project headers with a
blank line separator, matching the AGENTS.md include order rule.

Replace em dash with colon in main.c comment.
2026-06-15 04:35:44 +02:00
portersky 3ce42cc8db chore: add gitattributes, rename guide, and template comments
Add .gitattributes enforcing LF line endings.

Add a rename guide to README.md for scaffolding new projects.

Comment main.c as a template placeholder to replace.
2026-06-15 04:33:55 +02:00
portersky 2d25ad3a10 style: apply AGENTS.md rules to .pi markdown files
Replace em dashes with colons in tdd skill. Split combined\nshell commands in git skill into separate fenced blocks with\nlabels.
2026-06-15 04:31:59 +02:00
portersky 2ba1d2f7b6 fix: use C syntax in tdd skill examples
auto trailing return types are C++ only. Split header and\nimplementation examples into C and C++ variants.
2026-06-15 04:31:04 +02:00
portersky 457b6651be chore: generalize tdd skill for template reuse
Replace ctdd-specific paths with <src>/ placeholders so the skill
works in any project scaffolded from this template.
2026-06-15 04:30:42 +02:00
portersky 95ec83a0fd chore: generalize cmake skill for template reuse
Replace ctdd-specific paths with <src>/ placeholders so the skill
works in any project scaffolded from this template.
2026-06-15 04:29:49 +02:00
portersky 79d3b92511 chore: add pi skills for tdd, cmake, and git
Create .pi/skills/ with three skills:
- tdd: Red-Green-Refactor workflow, Unity assertions, CMock patterns
- cmake: build commands, adding modules, dependency FetchContent pattern
- git: conventional commits, semver tagging, branching conventions

Update AGENTS.md and README.md to reference the skills and template
project description.
2026-06-15 04:27:39 +02:00
portersky 286c51b2e7 feat: add architecture detection to Platform.cmake 2026-06-15 00:57:36 +02:00
portersky 4b501676b7 feat: support cmock_config.yml in cmock_generate_mock 2026-06-15 00:53:50 +02:00
portersky 7fbc4a49c5 docs: remove em dashes from README 2026-06-15 00:50:46 +02:00
portersky e9bdd3bff5 chore: add TDD workflow, behavioral guidelines, and ASan support
Add deps/Sanitizers.cmake for AddressSanitizer support (ENABLE_ASAN).
Add TDD workflow and behavioral guidelines to AGENTS.md.
2026-06-14 19:36:04 +02:00
portersky 6227ddf5df fix: clear Unity INTERFACE_SYSTEM_INCLUDE_DIRECTORIES
CI / macOS (push) Has been cancelled
CI / Windows / Clang (push) Has been cancelled
Unity sets INTERFACE_SYSTEM_INCLUDE_DIRECTORIES to a path inside
the build tree, which CMake rejects on newer versions. Clear it
after FetchContent; the path remains in INTERFACE_INCLUDE_DIRECTORIES.
2026-05-10 01:38:49 +02:00
portersky 8df5eaa4e8 fix: use xcrun for llvm-cov on AppleClang
AppleClang ships llvm-cov inside Xcode and it is not on PATH,
so find_program fails. Use xcrun llvm-cov gcov via a wrapper
script instead.
2026-05-10 01:35:38 +02:00
portersky 0eb646e0b4 ci: add GitHub Actions workflow for macOS and Windows
CI / macOS (push) Has been cancelled
CI / Windows / Clang (push) Has been cancelled
Runs tests and coverage on macOS (AppleClang) and Windows with
Clang. Coverage HTML reports are uploaded as artifacts.
2026-05-10 01:30:56 +02:00
portersky 2ed2b60f43 docs: add macOS to platform support list 2026-05-10 01:21:39 +02:00
portersky 10c78343fe docs: fix AGENTS.md project info and no-em-dash rule
Remove stale cuber references and unrelated static library
section. Add no-em-dash rule and apply it throughout.
2026-05-10 01:03:32 +02:00
portersky a457b5351a Add LICENSE 2026-05-10 00:57:59 +02:00
23 changed files with 1001 additions and 114 deletions
+1
View File
@@ -0,0 +1 @@
* text=auto eol=lf
+60
View File
@@ -0,0 +1,60 @@
name: CI
on:
push:
branches: [trunk]
pull_request:
branches: [trunk]
jobs:
macos:
name: macOS
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- name: Install Ninja
run: brew install ninja
- name: Install gcovr
run: pip install gcovr
- name: Configure with coverage
run: cmake -S . -B build-cov -G Ninja -DENABLE_COVERAGE=ON
- name: Build and generate coverage
run: ninja -C build-cov coverage
- name: Upload coverage report
uses: actions/upload-artifact@v4
with:
name: coverage-macos
path: build-cov/coverage/
windows-clang:
name: Windows / Clang
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- uses: ilammy/msvc-dev-cmd@v1
- name: Install gcovr
run: pip install gcovr
- name: Configure with coverage
shell: bash
run: |
cmake -S . -B build-cov -G Ninja \
-DENABLE_COVERAGE=ON \
-DCMAKE_C_COMPILER="C:/Program Files/LLVM/bin/clang.exe" \
-DCMAKE_CXX_COMPILER="C:/Program Files/LLVM/bin/clang++.exe"
- name: Build and generate coverage
run: ninja -C build-cov coverage
- name: Upload coverage report
uses: actions/upload-artifact@v4
with:
name: coverage-windows-clang
path: build-cov/coverage/
+43
View File
@@ -0,0 +1,43 @@
# Pi Skills
Project-level skills loaded by Pi on-demand.
## Skills
| Skill | Description |
| ------------------------------ | ---------------------------------------------------- |
| [tdd](skills/tdd/SKILL.md) | TDD workflow with Unity and CMock |
| [cmake](skills/cmake/SKILL.md) | Build configuration, adding modules and dependencies |
| [git](skills/git/SKILL.md) | Commit messages, tagging, and branching workflow |
## Installation
Skills are auto-discovered by Pi from `.pi/skills/`. No extra setup
required.
To install this project's skills into another project:
```sh
pi install -l git:github.com/portersky/helloctdd
```
Or as a temporary package for the current session:
```sh
pi -e git:github.com/portersky/helloctdd
```
Pi auto-discovers `skills/` directories from installed packages.
## Adding a New Skill
Place a `SKILL.md` inside a directory under `.pi/skills/`:
```
.pi/skills/
my-skill/
SKILL.md
```
Pi validates the frontmatter and registers `/skill:my-skill` in the
TUI.
+148
View File
@@ -0,0 +1,148 @@
---
name: cmake
description: CMake build configuration for projects scaffolded from the ctdd
template. Use when adding modules, adding dependencies, configuring coverage
or sanitizers, or understanding the build system.
---
# CMake Skill
> Replace `<src>/` with the project source directory (e.g. `ctdd/`, `src/`).
> Replace `<module>` with the module name (e.g. `counter`, `timer`).
## Build Commands
| Action | Command |
| --------- | ------------------------------------------------------------------------------------------ |
| Configure | `cmake -S . -B build -G Ninja` |
| Build | `ninja -C build` |
| Run tests | `ninja -C build check` |
| Coverage | `cmake -S . -B build-cov -G Ninja -DENABLE_COVERAGE=ON` then `ninja -C build-cov coverage` |
| ASan | `cmake -S . -B build-asan -G Ninja -DENABLE_ASAN=ON` then `ninja -C build-asan` |
> ASan and coverage cannot be used together.
## Adding a Module
Modules live in `<src>/` as static libraries. Register them in
`<src>/CMakeLists.txt`:
```cmake
add_library(<src>_<module> <module>.c)
target_include_directories(<src>_<module> PUBLIC "${CMAKE_SOURCE_DIR}")
target_compile_features(<src>_<module> PRIVATE c_std_23)
```
Link into `main` in the root `CMakeLists.txt`:
```cmake
target_link_libraries(main PRIVATE ... <src>_<module>)
```
## Adding a Dependency
Dependencies are fetched via custom `Find<name>.cmake` scripts in `deps/`.
`deps/` is on `CMAKE_MODULE_PATH` so `find_package()` resolves to these
scripts first.
### 1. Create `deps/Find<name>.cmake`
Pattern (follow `deps/FindUnity.cmake` or `deps/FindCMock.cmake`):
```cmake
if (DEFINED _FIND<NAME>_INCLUDED)
return()
endif()
set(_FIND<NAME>_INCLUDED TRUE)
set(<NAME>_VERSION "x.y.z")
message(STATUS "Fetching <name> ${<NAME>_VERSION}")
include(FetchContent)
FetchContent_Declare(
<name>
URL https://github.com/org/<name>/archive/refs/tags/v${<NAME>_VERSION}.zip
DOWNLOAD_EXTRACT_TIMESTAMP TRUE
)
FetchContent_MakeAvailable(<name>)
if (NOT TARGET <Name>::<Name>)
add_library(<Name>::<Name> ALIAS <name>)
endif()
set(<Name>_FOUND TRUE)
```
For libraries without CMakeLists.txt (like CMock), use
`FetchContent_Populate` and compile manually. See `FindCMock.cmake`
for the pattern.
### 2. Add `find_package(<Name> REQUIRED)` to `CMakeLists.txt`
Place it after `include(Platform)` and `include(Flags)`.
### 3. Link with `<Name>::<Name>`
In `<src>/CMakeLists.txt` or `tests/CMakeLists.txt` as needed:
```cmake
target_link_libraries(<src>_<module> PRIVATE <Name>::<Name>)
```
## Platform Flags
`deps/Platform.cmake` sets these variables for conditional logic:
| Variable | Meaning |
| ----------------- | ------------------------------------------------ |
| `IS_CLANG_OR_GCC` | Clang or GCC compiler |
| `IS_MSVC` | MSVC compiler |
| `IS_WINDOWS` | Windows target |
| `IS_LINUX` | Linux target |
| `IS_MACOS` | macOS target |
| `IS_IOS` | iOS target |
| `IS_ANDROID` | Android target |
| `IS_EMSCRIPTEN` | Emscripten/WASM target |
| `ARCH` | Normalized arch (`amd64`, `arm64`, `wasm`, etc.) |
| `IS_AMD64` | x86_64 |
| `IS_ARM64` | arm64/aarch64 |
## Compiler Flags
`deps/Flags.cmake` defines `BASE_OPTIONS` (warning flags) and
`BASE_DEFINITIONS`. Apply per-target to avoid polluting fetched
dependencies:
```cmake
target_compile_options(<target> PRIVATE ${BASE_OPTIONS})
target_compile_definitions(<target> PRIVATE ${BASE_DEFINITIONS})
```
## CMock Mock Generation
`tests/CMakeLists.txt` provides a `cmock_generate_mock` helper function:
```cmake
cmock_generate_mock(<target> "<absolute-path-to-header>")
```
With optional config file:
```cmake
cmock_generate_mock(<target> "<header>" "cmock_config.yml")
```
Generated mocks go into `build/mocks/` as `Mock<name>.h/.c`.
## Coverage
Enabled via `-DENABLE_COVERAGE=ON`. Requires GCC or Clang + `gcovr`.
Report at `build-cov/coverage/index.html`. Only `<src>/` sources are
measured; Unity, CMock, and mocks are excluded.
## Sanitizers
`deps/Sanitizers.cmake` provides AddressSanitizer via `-DENABLE_ASAN=ON`.
Incompatible with coverage.
+188
View File
@@ -0,0 +1,188 @@
---
name: git
description: Git workflow for the ctdd template project. Use when committing
changes, creating tags for releases, or following the branching and commit
message conventions.
---
# Git Skill
## Commit Messages
Follow [Conventional Commits](https://www.conventionalcommits.org/) with the
50/72 rule.
### Format
```
<type>: <subject>
<body>
<footer>
```
- **Subject:** max 50 characters, imperative mood, no period
- **Body:** wrapped at 72 characters, optional
- **Blank line** between subject and body
- **No co-author trailers** (`Co-Authored-By:` is forbidden)
- **No em dashes** (`—`). Use a colon or rewrite the sentence
### Types
| Type | Use |
| ---------- | ---------------------------------- |
| `feat` | New feature or module |
| `fix` | Bug fix |
| `docs` | Documentation only |
| `chore` | Build, deps, config, housekeeping |
| `ci` | CI/CD changes |
| `refactor` | Code change without feature or fix |
| `test` | Adding or changing tests |
| `style` | Formatting, whitespace, semicolons |
### Examples
Good:
```
feat: add stopwatch timer
Replace Hello World with a live stopwatch that prints elapsed time
in HH:MM:SS.mmm format, updating every 10ms with color output.
```
```
fix: clear Unity INTERFACE_SYSTEM_INCLUDE_DIRECTORIES
CMake rejects the path inside the build tree on newer versions.
```
```
chore: bump CMock to v2.6.0
```
Bad:
```
added a new thing # no type, lowercase, vague
feat: add stopwatch # no body for a significant change
feat: add stopwatch timer. # trailing period
feat: add timer — it's fast # em dash not allowed
```
## Committing
Stage changes:
```sh
git add -A
```
Commit:
```sh
git commit -m "type: subject"
```
For multi-line messages:
```sh
git commit -m "type: subject
body line 1
body line 2"
```
## Tagging
This project uses semantic versioning for template releases.
### Creating a tag
Create the tag:
```sh
git tag -a v0.1.0 -m "Release v0.1.0"
```
Push the tag:
```sh
git push origin v0.1.0
```
Tag messages follow the same rules as commit messages: no em dashes,
wrapped at 72 characters.
### Tag naming
| Version | Meaning |
| -------- | ------------------------------------ |
| `v0.x.0` | Minor changes, breaking template API |
| `v0.x.y` | Patch changes, backward-compatible |
| `v1.x.0` | Major release |
### When to tag
- After merging a feature branch that changes the template structure
- Before sharing the template with others
- When CMakeLists.txt, deps/, or build system changes could affect
projects using this template
### Listing tags
```sh
git tag -l
```
### Deleting a tag
Delete the local tag:
```sh
git tag -d v0.1.0
```
Remove the remote tag:
```sh
git push origin --delete v0.1.0
```
## Branching
For local development:
```sh
git checkout -b feat/add-counter
```
Branch naming:
| Prefix | Use |
| -------- | ------------- |
| `feat/` | New feature |
| `fix/` | Bug fix |
| `chore/` | Housekeeping |
| `docs/` | Documentation |
## Common Commands
| Command | Use |
| ----------------------- | --------------------------------- |
| `git log --oneline -10` | Recent history |
| `git diff --staged` | Check staged changes |
| `git status` | Current state |
| `git reset HEAD~1` | Undo last commit (keep changes) |
| `git rebase -i HEAD~3` | Interactive rebase last 3 commits |
## Checklist Before Committing
- [ ] Tests pass: `ninja -C build check`
- [ ] Commit message follows 50/72 rule
- [ ] Conventional commit type used
- [ ] No co-author trailers
- [ ] No em dashes
- [ ] No large unchanged regions reformatted
- [ ] No speculative code or unused imports
+249
View File
@@ -0,0 +1,249 @@
---
name: tdd
description: Test-driven development with Unity and CMock. Use when adding new
modules, writing tests, mocking dependencies, or following Red-Green-Refactor
in projects scaffolded from the ctdd template.
---
# TDD Skill
> Replace `<src>/` with the project source directory (e.g. `ctdd/`, `src/`).
> Replace `<module>` with the module name (e.g. `counter`, `timer`).
## Quick Reference
| Action | Command |
| ----------------------- | ------------------------------------------------------- |
| Configure (default) | `cmake -S . -B build -G Ninja` |
| Configure (coverage) | `cmake -S . -B build-cov -G Ninja -DENABLE_COVERAGE=ON` |
| Build | `ninja -C build` |
| Run tests (full output) | `ninja -C build check` |
| Run tests (summary) | `ninja -C build test` |
| Run tests + coverage | `ninja -C build-cov coverage` |
## Red-Green-Refactor
Every change to `<src>/` follows this cycle:
1. **RED** : Write a failing test. Confirm it fails.
2. **GREEN** : Write the minimum code to pass. Confirm it passes.
3. **REFACTOR** : Clean up without changing behavior. Tests still pass.
Never skip the RED step. If the test passes immediately, you wrote the test
before the implementation was missing.
## Adding a New Module
### 1. Write the header
Create `<src>/<module>.h` with the public prototype(s).
C:
```c
#pragma once
#include <stddef.h>
int fn_name(int arg);
```
C++:
```cpp
#pragma once
#include <cstddef>
auto fn_name(int arg) -> int;
```
### 2. Write the test
Create `tests/test_<module>.c`. Two patterns exist:
**State-based** (pure functions, no mocks):
```c
#include "unity.h"
#include "<src>/<module>.h"
void setUp(void) {}
void tearDown(void) {}
void test_fn_name_returns_expected(void) {
TEST_ASSERT_EQUAL_INT(42, fn_name(1));
}
int main(void) {
UNITY_BEGIN();
RUN_TEST(test_fn_name_returns_expected);
return UNITY_END();
}
```
**Interaction-based** (mocking a dependency):
```c
#include "unity.h"
#include "<src>/<module>.h"
#include "Mock<dep>.h"
void setUp(void) { Mock<dep>_Init(); }
void tearDown(void) { Mock<dep>_Verify(); Mock<dep>_Destroy(); }
void test_fn_calls_dep(void) {
dep_fn_ExpectAndReturn(arg, expected);
TEST_ASSERT_TRUE(fn_name());
}
int main(void) {
UNITY_BEGIN();
RUN_TEST(test_fn_calls_dep);
return UNITY_END();
}
```
### 3. Register the test in `tests/CMakeLists.txt`
Add after existing test targets, before the `check` target:
**State-based (no mock):**
```cmake
add_executable(test_<module> test_<module>.c)
target_include_directories(test_<module> PRIVATE "${CMAKE_SOURCE_DIR}")
target_link_libraries(test_<module> PRIVATE <src>_<module> Unity::Unity)
target_compile_features(test_<module> PRIVATE c_std_23)
add_test(NAME test_<module> COMMAND test_<module>)
list(APPEND TEST_TARGETS test_<module>)
```
**Interaction-based (with mock):**
```cmake
add_executable(test_<module> test_<module>.c)
target_include_directories(test_<module> PRIVATE "${CMAKE_SOURCE_DIR}")
target_link_libraries(test_<module> PRIVATE <src>_<module> Unity::Unity CMock::CMock)
target_compile_features(test_<module> PRIVATE c_std_23)
cmock_generate_mock(test_<module> "${CMAKE_SOURCE_DIR}/<src>/<dep>.h")
add_test(NAME test_<module> COMMAND test_<module>)
list(APPEND TEST_TARGETS test_<module>)
```
### 4. Stub the implementation
Create `<src>/<module>.c` with a dummy return:
C:
```c
#include "<src>/<module>.h"
int fn_name(int arg) {
return 0;
}
```
C++:
```cpp
#include "<src>/<module>.h"
auto fn_name(int arg) -> int {
return 0;
}
```
Register the library in `<src>/CMakeLists.txt`:
```cmake
add_library(<src>_<module> <module>.c)
target_include_directories(<src>_<module> PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}")
target_compile_features(<src>_<module> PRIVATE c_std_23)
```
### 5. Confirm RED
```sh
ninja -C build check
```
The test must fail. If it does not, something is wrong.
### 6. Implement and confirm GREEN
Write the real implementation. Run tests again:
```sh
ninja -C build check
```
All tests must pass.
## CMock Patterns
### Expecting a call with arguments
```c
dep_fn_Expect(arg1, arg2);
```
### Expecting a call and returning a value
```c
dep_fn_ExpectAndReturn(arg, expected_value);
```
### Verifying a call was NOT made
Do not set any `_Expect`. If the function is called, CMock fails
automatically in `tearDown`.
### Multiple calls
```c
dep_fn_ExpectAndReturn(first_call_arg, first_return);
dep_fn_ExpectAndReturn(second_call_arg, second_return);
```
Calls are matched in order.
## Test Naming
- `test_<function>_<scenario>`
- Use present tense: `test_upper_converts_lowercase`
- Cover: happy path, edge cases, boundaries, and error conditions
## Unity Assertions
| Assertion | Use |
| -------------------------------- | ---------------- |
| `TEST_ASSERT_TRUE(x)` | Boolean true |
| `TEST_ASSERT_FALSE(x)` | Boolean false |
| `TEST_ASSERT_EQUAL_INT(a, b)` | Integer equality |
| `TEST_ASSERT_EQUAL_STRING(a, b)` | String equality |
| `TEST_ASSERT_NULL(p)` | Null pointer |
| `TEST_ASSERT_NOT_NULL(p)` | Non-null pointer |
## Coverage
To check coverage after tests:
```sh
ninja -C build-cov coverage
```
Open `build-cov/coverage/index.html` in a browser.
## Checklist
Before considering a task done:
- [ ] Header declares the public API
- [ ] Test covers at least one happy path, one edge case
- [ ] Test registered in `tests/CMakeLists.txt`
- [ ] Library registered in `<src>/CMakeLists.txt` (if new module)
- [ ] `ninja -C build check` passes with zero failures
- [ ] No semicolons after closing braces
- [ ] Trailing return type on all functions
- [ ] East const (`char const*`)
- [ ] `snake_case` naming
+113 -88
View File
@@ -2,7 +2,18 @@
## Project Overview ## Project Overview
`cuber` is an OpenGL 3D renderer with multiple scenes. `ctdd` is a C23 template project wired for test-driven development
using Unity and CMock. Use it as the core template when scaffolding
new projects.
For TDD workflows (adding modules, writing tests, mocking), load the
`tdd` skill with `/skill:tdd`.
For build configuration (dependencies, coverage, sanitizers), load the
`cmake` skill with `/skill:cmake`.
For committing, tagging, and branching, load the `git` skill with
`/skill:git`.
## Build System ## Build System
@@ -10,102 +21,97 @@
- **CMake minimum:** 3.21 - **CMake minimum:** 3.21
- **C standard:** C23 - **C standard:** C23
### Commands ### Dependencies
Dependencies are managed via custom `Find*.cmake` scripts in `deps/`.
See `/skill:cmake` for adding new dependencies.
## Build
Configure:
Configure (default):
```sh ```sh
cmake -S . -B build -G Ninja cmake -S . -B build -G Ninja
``` ```
Configure with coverage:
```sh
cmake -S . -B build-cov -G Ninja -DENABLE_COVERAGE=ON
```
Build: Build:
```sh ```sh
ninja -C build ninja -C build
``` ```
Run tests full Unity output, colored: Run tests (full Unity output):
```sh ```sh
ninja -C build check ninja -C build check
``` ```
Run tests CTest summary only: Run tests (CTest summary only):
```sh ```sh
ninja -C build test ninja -C build test
``` ```
Run tests and generate coverage HTML: Configure with coverage:
```sh
cmake -S . -B build-cov -G Ninja -DENABLE_COVERAGE=ON
```
Generate coverage report:
```sh ```sh
ninja -C build-cov coverage ninja -C build-cov coverage
``` ```
Run (Linux/macOS): Open `build-cov/coverage/index.html` in a browser to view results.
Run the application:
```sh ```sh
./build/main ./build/main
``` ```
Run (Windows): On Windows use `./build/main.exe`.
```sh
./build/main.exe
```
### Dependencies See `/skill:cmake` for coverage and sanitizer details.
Dependencies are managed via custom `Find*.cmake` scripts in `deps/`.
These scripts use `FetchContent` under the hood to download and build
libraries automatically.
To add a new dependency:
1. Add the corresponding `Find<name>.cmake` to `deps/`
2. Add `find_package(<name> REQUIRED)` to `CMakeLists.txt`
3. Link with `<name>::<name>` in `target_link_libraries()`
### Static Libraries
The project is split into static libraries:
- **`cbt_opengl`** — OpenGL abstraction and window management (window,
context, buffer, texture, vao, shader, descriptor)
- **`cbt_scene`** — Base scene class
- **`scenes_cube`** — Spinning cube scene implementation
- **`scenes_sphere`** — Cube-to-sphere mapped mesh with diffuse lighting
### CMake Module Path
`deps/` is added to `CMAKE_MODULE_PATH` so `find_package()` resolves
to the custom scripts instead of system-installed packages.
## Coding Conventions ## Coding Conventions
### C
- **Language:** C23 - **Language:** C23
- **Trailing return type** for function signatures (e.g. `auto fn() -> void`)
- **4-space indentation**
- **No semicolons after closing braces** for namespaces/classes
- `auto` for obvious types (e.g. `auto main(...) -> int`)
- **East const** (e.g. `char const*` not `const char*`) - **East const** (e.g. `char const*` not `const char*`)
- **4-space indentation**
- `<>` includes for system headers (C stdlib, OS, etc.)
- `""` includes for third-party and local headers
- **Naming:** `snake_case` for variables, functions, and structs
- **Naming:** `SCREAMING_SNAKE_CASE` only for macros and constants
### C++
- **Trailing return type** for function signatures
(e.g. `auto fn() -> void`)
- `auto` for obvious types (e.g. `auto main(...) -> int`)
- **No semicolons after closing braces** for namespaces/classes
- **Trailing return type** for all function definitions, including - **Trailing return type** for all function definitions, including
operators (e.g. `auto operator=(T&&) noexcept -> T&`) operators (e.g. `auto operator=(T&&) noexcept -> T&`)
- **Public members first** in class declarations, private members at the - **Public members first** in class declarations, private members at
bottom the bottom
- `<>` includes only for system headers (std, OS, etc.)
- `""` includes for third-party dependencies (e.g. `fmt`, ### Include Order
`nlohmann/json`)
- **Naming:** `snake_case` for variables, functions, and classes Both C and C++ follow the same include order:
- **Naming:** `SCREAMING_SNAKE_CASE` only for macros and constants
- Include order: 1. C++ standard library headers (`<chrono>`, `<vector>`, etc.)
1. C++ standard library headers (`<chrono>`, `<vector>`, etc.) 2. *(blank line)*
2. *(blank line)* 3. C standard library headers (`<stdlib.h>`, `<string.h>`, etc.)
3. C standard library headers (`<stdlib.h>`, `<string.h>`, etc.) 4. *(blank line)*
4. *(blank line)* 5. OS-specific headers (Windows API, POSIX, etc.)
5. OS-specific headers (Windows API, POSIX, etc.) 6. *(blank line)*
6. *(blank line)* 7. Third-party dependencies (`"fmt/core.h"`, etc.)
7. Third-party dependencies (`"fmt/core.h"`, etc.) 8. *(blank line)*
8. *(blank line)* 9. Local/project headers
9. Local/project headers
## Shell Scripts ## Shell Scripts
@@ -117,23 +123,7 @@ to the custom scripts instead of system-installed packages.
## Commit Messages ## Commit Messages
- Follow the 50/72 rule: See `/skill:git` for commit message conventions, types, and examples.
- Subject line: max 50 characters
- Body lines: wrapped at 72 characters
- Use conventional commit prefixes (`feat:`, `fix:`, `docs:`, `chore:`,
etc.)
- Separate subject from body with a blank line
- Do **not** add yourself as a co-author (`Co-Authored-By:` trailers are
forbidden)
Example:
```
feat: add stopwatch timer
Replace Hello World with a live stopwatch that prints elapsed time
in HH:MM:SS.mmm format, updating every 10ms with color output.
```
## Documentation (Markdown) ## Documentation (Markdown)
@@ -145,7 +135,8 @@ in HH:MM:SS.mmm format, updating every 10ms with color output.
`-` or numbered lists, fenced code blocks with language hints `-` or numbered lists, fenced code blocks with language hints
(```` ```cpp ````, ```` ```sh ````). (```` ```cpp ````, ```` ```sh ````).
- Keep examples concise, up-to-date, and self-documenting. - Keep examples concise, up-to-date, and self-documenting.
- Each shell command gets its own fenced code block — do **not** combine - Do not use em dashes (``). Use a colon or rewrite the sentence.
- Each shell command gets its own fenced code block; do **not** combine
multiple commands into one block. Precede each block with a short multiple commands into one block. Precede each block with a short
plain-text label describing what the command does: plain-text label describing what the command does:
@@ -158,21 +149,55 @@ in HH:MM:SS.mmm format, updating every 10ms with color output.
## Source Layout ## Source Layout
```text ```
ctdd/ ctdd/
str.h / str.c Pure string utilities (no dependencies) str.h / str.c Pure string utilities (no dependencies)
report.h / report.c Formats a value and calls log_message() report.h / report.c Formats a value and calls log_info()
logger.h / logger.c Real log_message — printf to stdout logger.h / logger.c Log levels, emits via log_write()
main.c Entry point log_write.h / log_write.c Real log_write via printf to stdout
main.c Entry point (template placeholder)
tests/ tests/
test_str.c Unity state-based tests for ctdd/str test_str.c Unity state-based tests for ctdd/str
test_report.c Interaction-based tests using CMock test_report.c Interaction-based tests using CMock
test_logger.c Interaction-based tests using CMock
deps/ deps/
FindUnity.cmake Fetches Unity v2.6.1 via ZIP FindUnity.cmake Fetches Unity v2.6.1 via ZIP
FindCMock.cmake Fetches CMock v2.6.0 via ZIP FindCMock.cmake Fetches CMock v2.6.0 via ZIP
``` ```
## Platform Support ## Behavioral Guidelines
The project supports Windows, Linux, Emscripten, and Android via Reduce common LLM coding mistakes. Bias toward caution over speed.
`Platform.cmake` and `Flags.cmake` in `deps/`. For trivial tasks, use judgment.
### Think Before Coding
- State assumptions explicitly. If uncertain, ask.
- If multiple interpretations exist, present them, don't pick silently.
- If something is unclear, stop. Name what's confusing. Ask.
### Simplicity First
Minimum code that solves the problem. Nothing speculative.
- No features beyond what was asked.
- No abstractions for single-use code.
- If you write 200 lines and it could be 50, rewrite it.
### Surgical Changes
Touch only what you must. Clean up only your own mess.
- Don't "improve" adjacent code, comments, or formatting.
- Don't refactor things that aren't broken.
- Match existing style, even if you'd do it differently.
- Remove imports/variables/functions that YOUR changes made unused.
- Don't remove pre-existing dead code unless asked.
### Goal-Driven Execution
Transform tasks into verifiable goals:
- "Add validation" means: write tests for invalid inputs, then pass.
- "Fix the bug" means: write a test that reproduces it, then pass.
- "Refactor X" means: ensure tests pass before and after.
+1
View File
@@ -0,0 +1 @@
@AGENTS.md
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2026 PorterSky
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+64 -7
View File
@@ -1,30 +1,43 @@
# ctdd # ctdd
A C23 project wired for test-driven development using A C23 template project wired for test-driven development using
[Unity](https://github.com/ThrowTheSwitch/Unity) and [Unity](https://github.com/ThrowTheSwitch/Unity) and
[CMock](https://github.com/ThrowTheSwitch/CMock). [CMock](https://github.com/ThrowTheSwitch/CMock). Use it as the core
template when scaffolding new projects.
All dependencies are fetched automatically via CMake `FetchContent` no All dependencies are fetched automatically via CMake `FetchContent` with no
manual installation required beyond the tools listed below. manual installation required beyond the tools listed below.
## License
This template is licensed under the MIT License. The license covers the
CMake build files, `deps/` scripts, and other template infrastructure.
Because this is a project template, your own source code is not bound by
this license. You are free to choose any license for your project that is
compatible with MIT. Simply replace the `LICENSE` file with your chosen
license.
## Requirements ## Requirements
| Tool | Purpose | | Tool | Purpose |
| ------------ | ----------------------------------------------------- | | ------------ | ---------------------------------------------------- |
| CMake ≥ 3.21 | Build system | | CMake ≥ 3.21 | Build system |
| Ninja | Build backend | | Ninja | Build backend |
| C23 compiler | GCC 14+, Clang 18+ | | C23 compiler | GCC 14+, Clang 18+ |
| Ruby ≥ 3.0 | CMock mock generation | | Ruby ≥ 3.0 | CMock mock generation |
| gcovr ≥ 6.0 | Coverage reports optional (`uv tool install gcovr`) | | gcovr ≥ 6.0 | Coverage reports, optional (`uv tool install gcovr`) |
## Build ## Build
Configure: Configure:
```sh ```sh
cmake -S . -B build -G Ninja cmake -S . -B build -G Ninja
``` ```
Build: Build:
```sh ```sh
ninja -C build ninja -C build
``` ```
@@ -32,11 +45,13 @@ ninja -C build
## Test ## Test
Full Unity output with colors: Full Unity output with colors:
```sh ```sh
ninja -C build check ninja -C build check
``` ```
CTest summary only: CTest summary only:
```sh ```sh
ninja -C build test ninja -C build test
``` ```
@@ -48,18 +63,20 @@ binaries by hand.
## Coverage ## Coverage
Configure with coverage instrumentation: Configure with coverage instrumentation:
```sh ```sh
cmake -S . -B build-cov -G Ninja -DENABLE_COVERAGE=ON cmake -S . -B build-cov -G Ninja -DENABLE_COVERAGE=ON
``` ```
Generate the HTML report: Generate the HTML report:
```sh ```sh
ninja -C build-cov coverage ninja -C build-cov coverage
``` ```
Open `build-cov/coverage/index.html` in a browser to view results. Open `build-cov/coverage/index.html` in a browser to view results.
Only `ctdd/` source files are measured Unity, CMock, and generated Only `ctdd/` source files are measured. Unity, CMock, and generated
mock files are excluded. Requires GCC or Clang with gcov support, and mock files are excluded. Requires GCC or Clang with gcov support, and
`gcovr` on `PATH`. `gcovr` on `PATH`.
@@ -70,16 +87,32 @@ mock files are excluded. Requires GCC or Clang with gcov support, and
## Run ## Run
Windows: Windows:
```sh ```sh
./build/main.exe ./build/main.exe
``` ```
Linux / macOS: Linux / macOS:
```sh ```sh
./build/main ./build/main
``` ```
## Adding a new module (TDD workflow) ## Renaming the Project
To use this template for a new project, rename `ctdd` to your project
name:
1. Rename the `ctdd/` directory to `<src>/`.
2. Replace `ctdd` with `<src>` in:
- `CMakeLists.txt` (project name, `target_link_libraries`)
- `ctdd/CMakeLists.txt` (library names)
- All source `#include` directives
- `tests/CMakeLists.txt` (library references)
3. Update the `project()` call in `CMakeLists.txt`.
4. Update `main.c` to include your new headers.
Example: `ctdd/` becomes `mylib/`, `ctdd_str` becomes `mylib_str`.
### 1. Write the header ### 1. Write the header
@@ -158,3 +191,27 @@ void test_something_logs(void) {
The `_Expect` call records the expected argument. CMock verifies the The `_Expect` call records the expected argument. CMock verifies the
actual argument matches at call time using string comparison, and actual argument matches at call time using string comparison, and
`Mocklogger_Verify` confirms the expected number of calls were made. `Mocklogger_Verify` confirms the expected number of calls were made.
## Configuring CMock
Pass a config file as the third argument to `cmock_generate_mock`:
```cmake
cmock_generate_mock(test_mymodule "${CMAKE_SOURCE_DIR}/ctdd/logger.h"
"cmock_config.yml")
```
The file is loaded by the CMock Ruby generator with `-o`. A typical
`tests/cmock_config.yml` enables plugins:
```yaml
:cmock:
:plugins:
- :ignore
- :ignore_arg
- :return_thru_ptr
```
Use `:ignore` to skip certain mocks, `:ignore_arg` to stop checking
particular parameters, or `:return_thru_ptr` to have CMock write
through pointer return values automatically.
+2 -1
View File
@@ -1,6 +1,7 @@
#include "ctdd/log_write.h"
#include <stdio.h> #include <stdio.h>
#include "ctdd/log_write.h"
void log_write(char const* msg) { void log_write(char const* msg) {
printf("%s\n", msg); printf("%s\n", msg);
} }
+2 -1
View File
@@ -1,6 +1,7 @@
#include <stdio.h>
#include "ctdd/logger.h" #include "ctdd/logger.h"
#include "ctdd/log_write.h" #include "ctdd/log_write.h"
#include <stdio.h>
static log_level s_level = LOG_DEBUG; static log_level s_level = LOG_DEBUG;
+2 -1
View File
@@ -1,6 +1,7 @@
#include <stdio.h>
#include "ctdd/report.h" #include "ctdd/report.h"
#include "ctdd/logger.h" #include "ctdd/logger.h"
#include <stdio.h>
void report_value(char const* label, int value) { void report_value(char const* label, int value) {
char buf[256]; char buf[256];
+3 -2
View File
@@ -1,6 +1,7 @@
#include "ctdd/str.h"
#include <string.h>
#include <ctype.h> #include <ctype.h>
#include <string.h>
#include "ctdd/str.h"
int str_starts_with(char const* s, char const* prefix) { int str_starts_with(char const* s, char const* prefix) {
return strncmp(s, prefix, strlen(prefix)) == 0; return strncmp(s, prefix, strlen(prefix)) == 0;
+12 -2
View File
@@ -21,13 +21,23 @@ if (ENABLE_COVERAGE)
find_program(GCOVR_EXE gcovr REQUIRED) find_program(GCOVR_EXE gcovr REQUIRED)
if (CMAKE_C_COMPILER_ID MATCHES "Clang") if (CMAKE_C_COMPILER_ID MATCHES "Clang")
find_program(LLVM_COV_EXE llvm-cov REQUIRED)
# gcovr needs a single-token gcov executable. Wrap llvm-cov gcov in a # gcovr needs a single-token gcov executable. Wrap llvm-cov gcov in a
# script placed in the build dir (guaranteed no spaces in path). # script placed in the build dir (guaranteed no spaces in path).
# AppleClang ships llvm-cov inside Xcode, reached only via xcrun.
if (WIN32) if (WIN32)
find_program(LLVM_COV_EXE llvm-cov REQUIRED)
set(GCOV_EXECUTABLE "${CMAKE_BINARY_DIR}/llvm-gcov.bat") set(GCOV_EXECUTABLE "${CMAKE_BINARY_DIR}/llvm-gcov.bat")
file(WRITE "${GCOV_EXECUTABLE}" "@echo off\r\n\"${LLVM_COV_EXE}\" gcov %*\r\n") file(WRITE "${GCOV_EXECUTABLE}" "@echo off\r\n\"${LLVM_COV_EXE}\" gcov %*\r\n")
elseif (CMAKE_C_COMPILER_ID STREQUAL "AppleClang")
find_program(XCRUN_EXE xcrun REQUIRED)
set(GCOV_EXECUTABLE "${CMAKE_BINARY_DIR}/llvm-gcov.sh")
file(WRITE "${GCOV_EXECUTABLE}" "#!/bin/sh\nexec xcrun llvm-cov gcov \"$@\"\n")
file(CHMOD "${GCOV_EXECUTABLE}"
PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE
GROUP_READ GROUP_EXECUTE
WORLD_READ WORLD_EXECUTE)
else() else()
find_program(LLVM_COV_EXE llvm-cov REQUIRED)
set(GCOV_EXECUTABLE "${CMAKE_BINARY_DIR}/llvm-gcov.sh") set(GCOV_EXECUTABLE "${CMAKE_BINARY_DIR}/llvm-gcov.sh")
file(WRITE "${GCOV_EXECUTABLE}" "#!/bin/sh\nexec \"${LLVM_COV_EXE}\" gcov \"$@\"\n") file(WRITE "${GCOV_EXECUTABLE}" "#!/bin/sh\nexec \"${LLVM_COV_EXE}\" gcov \"$@\"\n")
file(CHMOD "${GCOV_EXECUTABLE}" file(CHMOD "${GCOV_EXECUTABLE}"
@@ -35,7 +45,7 @@ if (ENABLE_COVERAGE)
GROUP_READ GROUP_EXECUTE GROUP_READ GROUP_EXECUTE
WORLD_READ WORLD_EXECUTE) WORLD_READ WORLD_EXECUTE)
endif() endif()
message(STATUS "Coverage: enabled (gcovr: ${GCOVR_EXE}, gcov: ${LLVM_COV_EXE} gcov)") message(STATUS "Coverage: enabled (gcovr: ${GCOVR_EXE}, gcov: llvm-cov gcov)")
else() else()
set(GCOV_EXECUTABLE "gcov") set(GCOV_EXECUTABLE "gcov")
message(STATUS "Coverage: enabled (gcovr: ${GCOVR_EXE})") message(STATUS "Coverage: enabled (gcovr: ${GCOVR_EXE})")
+7 -5
View File
@@ -36,6 +36,13 @@ FetchContent_Declare(
FetchContent_MakeAvailable(unity) FetchContent_MakeAvailable(unity)
# Unity sets INTERFACE_SYSTEM_INCLUDE_DIRECTORIES to a path inside the build
# tree, which CMake rejects on newer versions. The path stays in
# INTERFACE_INCLUDE_DIRECTORIES so headers are still found.
if (TARGET unity)
set_target_properties(unity PROPERTIES INTERFACE_SYSTEM_INCLUDE_DIRECTORIES "")
endif()
if (NOT TARGET Unity::Unity) if (NOT TARGET Unity::Unity)
if (TARGET unity) if (TARGET unity)
add_library(Unity::Unity ALIAS unity) add_library(Unity::Unity ALIAS unity)
@@ -49,11 +56,6 @@ set(Unity_LIBRARIES Unity::Unity)
set(Unity_VERSION "${UNITY_VERSION}") set(Unity_VERSION "${UNITY_VERSION}")
set(Unity_INCLUDE_DIR "${unity_SOURCE_DIR}/src") set(Unity_INCLUDE_DIR "${unity_SOURCE_DIR}/src")
if (Unity_INCLUDE_DIR AND TARGET unity)
set_target_properties(unity PROPERTIES
INTERFACE_SYSTEM_INCLUDE_DIRECTORIES "${Unity_INCLUDE_DIR}"
)
endif()
if (TARGET unity) if (TARGET unity)
target_compile_definitions(unity PUBLIC target_compile_definitions(unity PUBLIC
+37
View File
@@ -15,6 +15,11 @@
# IS_IOS - TRUE if building for iOS # IS_IOS - TRUE if building for iOS
# IS_ANDROID - TRUE if building for Android # IS_ANDROID - TRUE if building for Android
# IS_EMSCRIPTEN - TRUE if building for WebAssembly via Emscripten # IS_EMSCRIPTEN - TRUE if building for WebAssembly via Emscripten
#
# Architecture flags set:
# ARCH - Normalized architecture name (amd64, arm64, wasm, etc.)
# IS_AMD64 - TRUE if building for x86_64/amd64
# IS_ARM64 - TRUE if building for arm64/aarch64
# ============================================================================== # ==============================================================================
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
@@ -62,3 +67,35 @@ elseif(UNIX)
else() else()
message(FATAL_ERROR "Unknown platform!") message(FATAL_ERROR "Unknown platform!")
endif() endif()
# ------------------------------------------------------------------------------
# Architecture Detection
# ------------------------------------------------------------------------------
set(ARCH "")
set(IS_AMD64 FALSE)
set(IS_ARM64 FALSE)
if (IS_EMSCRIPTEN)
set(ARCH "wasm")
elseif(DEFINED CMAKE_OSX_ARCHITECTURES)
# Cross-compile on macOS (e.g. iOS simulator on Apple Silicon)
set(ARCH "${CMAKE_OSX_ARCHITECTURES}")
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^aarch64|^arm64|^ARM64")
set(ARCH "arm64")
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^x86_64|^AMD64|^x64")
set(ARCH "amd64")
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^armv[0-9]")
set(ARCH "arm")
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^i[3-6]86")
set(ARCH "x86")
else()
set(ARCH "${CMAKE_SYSTEM_PROCESSOR}")
endif()
if(ARCH STREQUAL "amd64")
set(IS_AMD64 TRUE)
elseif(ARCH STREQUAL "arm64")
set(IS_ARM64 TRUE)
endif()
message(STATUS "Architecture: ${ARCH}")
+28
View File
@@ -0,0 +1,28 @@
# ==============================================================================
# Sanitizers
# ==============================================================================
# AddressSanitizer (ASan) support.
# Works with GCC/Clang on Linux and macOS, Clang on Windows (requires
# compiler-rt with sanitizers), and MSVC on Windows (/fsanitize=address).
#
# Usage: cmake -DENABLE_ASAN=ON ...
# ==============================================================================
option(ENABLE_ASAN "Build with AddressSanitizer" OFF)
if (ENABLE_ASAN)
if (ENABLE_COVERAGE)
message(FATAL_ERROR "ENABLE_ASAN and ENABLE_COVERAGE cannot be used together")
endif()
if (MSVC)
add_compile_options(/fsanitize=address)
message(STATUS "ASan: enabled (MSVC)")
elseif (CMAKE_C_COMPILER_ID MATCHES "GNU|Clang")
add_compile_options(-fsanitize=address -fno-omit-frame-pointer)
add_link_options(-fsanitize=address)
message(STATUS "ASan: enabled (${CMAKE_C_COMPILER_ID})")
else()
message(FATAL_ERROR "ENABLE_ASAN: unsupported compiler ${CMAKE_C_COMPILER_ID}")
endif()
endif()
+3
View File
@@ -1,3 +1,6 @@
// Template placeholder: replace with your own entry point.
// Remove or rename this file when scaffolding a new project.
#include "ctdd/str.h" #include "ctdd/str.h"
#include "ctdd/report.h" #include "ctdd/report.h"
#include "ctdd/logger.h" #include "ctdd/logger.h"
+9 -2
View File
@@ -5,9 +5,11 @@ set(MOCK_GEN_DIR "${CMAKE_CURRENT_BINARY_DIR}/mocks")
file(MAKE_DIRECTORY "${MOCK_GEN_DIR}") file(MAKE_DIRECTORY "${MOCK_GEN_DIR}")
# Generate a CMock mock from a header and attach it to a target. # Generate a CMock mock from a header and attach it to a target.
# Usage: cmock_generate_mock(<target> <absolute-path-to-header>) # Usage: cmock_generate_mock(<target> <absolute-path-to-header> [config.yml])
# CMock names generated files Mock<Name>.h/.c (capital M, no separator) # CMock names generated files Mock<Name>.h/.c (capital M, no separator)
# If a config file is given it is passed to the Ruby generator with `-o`.
function(cmock_generate_mock target header) function(cmock_generate_mock target header)
cmake_parse_arguments(ARG "" "" "CONFIG" ${ARGN})
if (NOT RUBY_EXECUTABLE) if (NOT RUBY_EXECUTABLE)
message(FATAL_ERROR "Ruby is required for CMock generation") message(FATAL_ERROR "Ruby is required for CMock generation")
endif() endif()
@@ -15,12 +17,17 @@ function(cmock_generate_mock target header)
get_filename_component(header_dir "${header}" DIRECTORY) get_filename_component(header_dir "${header}" DIRECTORY)
set(mock_src "${MOCK_GEN_DIR}/Mock${name}.c") set(mock_src "${MOCK_GEN_DIR}/Mock${name}.c")
set(mock_hdr "${MOCK_GEN_DIR}/Mock${name}.h") set(mock_hdr "${MOCK_GEN_DIR}/Mock${name}.h")
if (ARG_CONFIG)
set(CMOCK_CONFIG_FLAG "-o${ARG_CONFIG}")
set(CMOCK_CONFIG_DEPENDS "${ARG_CONFIG}")
endif()
add_custom_command( add_custom_command(
OUTPUT "${mock_src}" "${mock_hdr}" OUTPUT "${mock_src}" "${mock_hdr}"
COMMAND "${RUBY_EXECUTABLE}" "${CMOCK_SCRIPT}" COMMAND "${RUBY_EXECUTABLE}" "${CMOCK_SCRIPT}"
${CMOCK_CONFIG_FLAG}
"--mock_path=${MOCK_GEN_DIR}" "--mock_path=${MOCK_GEN_DIR}"
"${header}" "${header}"
DEPENDS "${header}" DEPENDS "${header}" ${CMOCK_CONFIG_DEPENDS}
COMMENT "CMock: generating Mock${name}" COMMENT "CMock: generating Mock${name}"
VERBATIM VERBATIM
) )
+1
View File
@@ -1,4 +1,5 @@
#include "unity.h" #include "unity.h"
#include "ctdd/logger.h" #include "ctdd/logger.h"
#include "Mocklog_write.h" #include "Mocklog_write.h"
+1
View File
@@ -1,4 +1,5 @@
#include "unity.h" #include "unity.h"
#include "ctdd/report.h" #include "ctdd/report.h"
#include "Mocklogger.h" #include "Mocklogger.h"
+1
View File
@@ -1,4 +1,5 @@
#include "unity.h" #include "unity.h"
#include "ctdd/str.h" #include "ctdd/str.h"
void setUp(void) {} void setUp(void) {}