Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
run: sudo apt-get update && sudo apt-get install -y lcov

- name: Configure CMake with coverage
run: cmake -S . -B build -DENABLE_COVERAGE=ON
run: cmake -S . -B build -DENABLE_TEST=ON -DENABLE_COVERAGE=ON

- name: Build
run: cmake --build build --config Debug
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ jobs:
uses: jwlawson/actions-setup-cmake@v1

- name: Configure CMake
run: cmake -S . -B build
run: cmake -DENABLE_TEST=ON -DENABLE_SINGLE_HEADER=ON -DSTATIC_LIB=ON -S . -B build

- name: Build
run: cmake --build build --config Release
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,6 @@ cmake_install.cmake
Makefile
build/

# Single Include
single_include/

147 changes: 119 additions & 28 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,48 +4,139 @@ project(CXXStateTree VERSION 0.4.0 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

add_library(CXXStateTree INTERFACE)
target_include_directories(CXXStateTree INTERFACE include)
file (GLOB_RECURSE SRC_FILES "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp")

add_executable(basic examples/basic.cpp)
target_link_libraries(basic PRIVATE CXXStateTree)
option(STATIC_LIB "Enable Static Library instead of Dynamic" OFF)

if(STATIC_LIB)
add_library(CXXStateTree STATIC ${SRC_FILES})
target_include_directories(CXXStateTree INTERFACE include ${CMAKE_CURRENT_SOURCE_DIR}/include )
else()
add_library(CXXStateTree SHARED ${SRC_FILES})
target_include_directories(CXXStateTree INTERFACE include ${CMAKE_CURRENT_SOURCE_DIR}/include )
endif()

add_executable(nested examples/nested.cpp)
target_link_libraries(nested PRIVATE CXXStateTree)

add_executable(export_dot_example examples/export_dot.cpp)
target_include_directories(export_dot_example PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include)
add_executable(export_dot_nested_example examples/export_dot_nested.cpp)
target_include_directories(export_dot_nested_example PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include)
add_executable(export_dot_context_example examples/export_dot_context.cpp)
target_include_directories(export_dot_context_example PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include)

add_executable(context_example examples/context_example.cpp)
target_include_directories(context_example PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include)

# GoogleTest setup
include(FetchContent)
FetchContent_Declare(
googletest
URL https://github.com/google/googletest/archive/refs/heads/main.zip
set_target_properties(CXXStateTree PROPERTIES
RUNTIME_OUTPUT_DIRECTORY_RELEASE "${CMAKE_BINARY_DIR}/Release"
ARCHIVE_OUTPUT_DIRECTORY_RELEASE "${CMAKE_BINARY_DIR}/Release"
LIBRARY_OUTPUT_DIRECTORY_RELEASE "${CMAKE_BINARY_DIR}/Release"
)
# For Windows: Prevent overriding the parent project's compiler/linker settings
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(googletest)

option(ENABLE_TEST "Enable Test" OFF)

if(ENABLE_TEST)
# GoogleTest setup
include(FetchContent)
FetchContent_Declare(
googletest
URL https://github.com/google/googletest/archive/refs/heads/main.zip
DOWNLOAD_EXTRACT_TIMESTAMP true
)
# For Windows: Prevent overriding the parent project's compiler/linker settings
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(googletest)


enable_testing()
add_executable(state_tree_test tests/state_tree_test.cpp)
target_link_libraries(state_tree_test PRIVATE CXXStateTree gtest_main)

include(GoogleTest)
gtest_discover_tests(state_tree_test)

endif()

enable_testing()
add_executable(state_tree_test tests/state_tree_test.cpp)
target_link_libraries(state_tree_test PRIVATE CXXStateTree gtest_main)

include(GoogleTest)
gtest_discover_tests(state_tree_test)
option(ENABLE_EXAMPLE "Enable Example" OFF)

if(ENABLE_EXAMPLE)
add_executable(basic examples/basic.cpp)
target_include_directories(basic PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
target_link_libraries(basic PRIVATE CXXStateTree)

add_executable(nested examples/nested.cpp)
target_include_directories(basic PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
target_link_libraries(nested PRIVATE CXXStateTree)

add_executable(export_dot_example examples/export_dot.cpp)
target_include_directories(export_dot_example PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
target_link_libraries(export_dot_example PRIVATE CXXStateTree)
add_executable(export_dot_nested_example examples/export_dot_nested.cpp)
target_include_directories(export_dot_nested_example PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
target_link_libraries(export_dot_nested_example PRIVATE CXXStateTree)
add_executable(export_dot_context_example examples/export_dot_context.cpp)
target_include_directories(export_dot_context_example PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
target_link_libraries(export_dot_context_example PRIVATE CXXStateTree)

add_executable(context_example examples/context_example.cpp)
target_include_directories(context_example PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
target_link_libraries(context_example PRIVATE CXXStateTree)

endif()

option(ENABLE_COVERAGE "Enable coverage reporting" OFF)

if(ENABLE_COVERAGE)
message(STATUS "Building with coverage flags")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0 --coverage")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --coverage")
endif()

option(ENABLE_SINGLE_HEADER "Enable Single Header Generation" OFF)

if(ENABLE_SINGLE_HEADER)
find_package(Python3 REQUIRED COMPONENTS Interpreter)
include(FetchContent)

# ----- Download the script (configure‑time, once, cached in build dir) -----
FetchContent_Declare(
edlund_amalgamate
GIT_REPOSITORY https://github.com/edlund/amalgamate.git
GIT_TAG master # ↔ pin a commit / tag for reproducible builds
)
FetchContent_MakeAvailable(edlund_amalgamate) # populates edlund_amalgamate_SOURCE_DIR

set(AMALGAMATE_PY "${edlund_amalgamate_SOURCE_DIR}/amalgamate.py") # :contentReference[oaicite:0]{index=0}

set(AMALGAMATE_CFG "${CMAKE_CURRENT_SOURCE_DIR}/config_CXXStateTree.json")
set(AMALGAMATE_PRO "${CMAKE_CURRENT_SOURCE_DIR}/config_CXXStateTree.prologue")
set(AMALGAMATE_OUT "${CMAKE_CURRENT_SOURCE_DIR}/single_include/CXXStateTree.hpp")

add_custom_command(
OUTPUT ${AMALGAMATE_OUT}
COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_SOURCE_DIR}/single_include # ensure /dist
COMMAND python3 ${AMALGAMATE_PY} -c ${AMALGAMATE_CFG} -s ${CMAKE_CURRENT_SOURCE_DIR} -p ${AMALGAMATE_PRO} --verbose yes
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
DEPENDS ${AMALGAMATE_PY} ${AMALGAMATE_CFG}
COMMENT "Generating single‑header CXXStateTree.hpp with edlund/amalgamate"
VERBATIM
)

add_custom_target(amalgamate ALL DEPENDS ${AMALGAMATE_OUT})

if(ENABLE_TEST)
# GoogleTest setup
include(FetchContent)
FetchContent_Declare(
googletest
URL https://github.com/google/googletest/archive/refs/heads/main.zip
DOWNLOAD_EXTRACT_TIMESTAMP true
)
# For Windows: Prevent overriding the parent project's compiler/linker settings
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(googletest)


enable_testing()
add_executable(state_tree_singleheader_test tests/state_tree_singleheader_test.cpp)
target_include_directories(state_tree_singleheader_test PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/single_include)
target_link_libraries(state_tree_singleheader_test PRIVATE CXXStateTree gtest_main)

include(GoogleTest)
gtest_discover_tests(state_tree_singleheader_test)

endif()

endif()
31 changes: 29 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
* 🧪 Google Test integration
* 📈 Code coverage with Codecov
* 🌳 Designed for extensibility: nested states, DOT export coming soon
* 🔧 Deployed as Shared Library and as Single Header-Only library

---

Expand All @@ -26,7 +27,7 @@
using namespace CXXStateTree;

int main() {
auto machine = Builder()
auto machine = StateTree::Builder()
.initial("Idle")
.state("Idle", [](State& s) {
s.on("Start", "Running", nullptr, []() {
Expand All @@ -47,10 +48,36 @@ int main() {

---

## 🛠️ Building Shared Library

```bash
cmake -S . -B build
cmake --build build
```

After these command the Shared Library can be found in `build` directory

Please Note: in future release cmake will have the ability to install the library automatically, for now it is necessary to do it manually

---

## 🛠️ Building Single Header-Only Library

```bash
cmake -S . -B build -DENABLE_SINGLE_HEADER=ON
cmake --build build
```

After these command the Single Header-Only Library can be found in `single_include` directory with the name CXXStateTree.hpp

Please Note: in future release cmake will have the ability to install the library automatically, for now it is necessary to do it manually

---

## 🧪 Running Tests

```bash
cmake -S . -B build -DENABLE_COVERAGE=ON
cmake -S . -B build -DENABLE_TEST=ON -DENABLE_COVERAGE=ON
cmake --build build
cd build && ctest
```
Expand Down
11 changes: 11 additions & 0 deletions config_CXXStateTree.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"project": "CXXStateTree",
"target": "single_include/CXXStateTree.hpp",
"sources": [
"src/CXXStateTree/State.cpp",
"src/CXXStateTree/StateTree.cpp"
],
"include_paths": [
"include"
]
}
3 changes: 3 additions & 0 deletions config_CXXStateTree.prologue
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/**
* CXXStateTree Single Header (c) 2025 ZigRazor
*/
5 changes: 2 additions & 3 deletions examples/basic.cpp
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
// File: examples/basic.cpp
#include <iostream>
#include "CXXStateTree/StateTree.hpp"
#include "CXXStateTree/Builder.hpp"
#include "CXXStateTree/StateTree.h"

using namespace CXXStateTree;

int main()
{
auto machine = Builder()
auto machine = StateTree::Builder()
.initial("Idle")
.state("Idle", [](State &s)
{ s.on("Start", "Running", nullptr, [](const std::any &)
Expand Down
4 changes: 2 additions & 2 deletions examples/context_example.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#include "CXXStateTree/Builder.hpp"
#include "CXXStateTree/StateTree.h"
#include <iostream>
#include <string>
#include <any>
Expand All @@ -24,7 +24,7 @@ int main()
{
UserAuthorizedGuard auth_guard;

auto sm = Builder()
auto sm = StateTree::Builder()
.initial("Idle")
.state("Idle", [&](State &s)
{ s.on("login", "Dashboard", &auth_guard, [](const std::any &ctx)
Expand Down
5 changes: 2 additions & 3 deletions examples/export_dot.cpp
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
#include "CXXStateTree/Builder.hpp"
#include "CXXStateTree/StateTree.hpp"
#include "CXXStateTree/StateTree.h"
#include <iostream>
#include <fstream>

using namespace CXXStateTree;

int main()
{
auto tree = Builder()
auto tree = StateTree::Builder()
.initial("App")
.state("App", [](State &app)
{ app.initial_substate("Idle")
Expand Down
6 changes: 3 additions & 3 deletions examples/export_dot_context.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#include "CXXStateTree/Builder.hpp"
#include "CXXStateTree/StateTree.hpp"

#include "CXXStateTree/StateTree.h"
#include <iostream>
#include <fstream>

Expand All @@ -21,7 +21,7 @@ class UserAuthorizedGuard : public IGuard
int main()
{
UserAuthorizedGuard auth_guard;
auto tree = Builder()
auto tree = StateTree::Builder()
.initial("Idle")
.state("Idle", [&](State &s)
{ s.on("login", "Dashboard", &auth_guard, [](const std::any &ctx)
Expand Down
5 changes: 2 additions & 3 deletions examples/export_dot_nested.cpp
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
#include "CXXStateTree/Builder.hpp"
#include "CXXStateTree/StateTree.hpp"
#include "CXXStateTree/StateTree.h"
#include <iostream>
#include <fstream>

using namespace CXXStateTree;

int main()
{
auto tree = Builder()
auto tree = StateTree::Builder()
.initial("Main")
.state("Main", [](State &s)
{ s.initial_substate("Idle")
Expand Down
4 changes: 2 additions & 2 deletions examples/nested.cpp
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
// File: examples/basic.cpp
#include <iostream>
#include "CXXStateTree/Builder.hpp"
#include "CXXStateTree/StateTree.h"

using namespace CXXStateTree;

int main()
{
auto machine = Builder()
auto machine = StateTree::Builder()
.initial("Main")
.state("Main", [](State &s)
{ s.initial_substate("Idle")
Expand Down
Loading
Loading