From c0209b4095127f5daaa44ca343cc177056bae32e Mon Sep 17 00:00:00 2001 From: Gaspard Kirira Date: Tue, 12 May 2026 10:55:55 +0300 Subject: [PATCH 1/3] chore(release): prepare v2.5.5 --- CHANGELOG.md | 18 ++++++ CMakeLists.txt | 1 - examples/threadpool/CMakeLists.txt | 55 +++++++++++++++++ examples/threadpool/basic_post.cpp | 43 +++++++++++++ examples/threadpool/custom_config.cpp | 64 ++++++++++++++++++++ examples/threadpool/metrics.cpp | 55 +++++++++++++++++ examples/threadpool/parallel_for.cpp | 52 ++++++++++++++++ examples/threadpool/parallel_for_each.cpp | 48 +++++++++++++++ examples/threadpool/parallel_map.cpp | 49 +++++++++++++++ examples/threadpool/parallel_reduce.cpp | 45 ++++++++++++++ examples/threadpool/periodic_task.cpp | 63 +++++++++++++++++++ examples/threadpool/shutdown.cpp | 60 +++++++++++++++++++ examples/threadpool/submit_future.cpp | 48 +++++++++++++++ examples/threadpool/task_cancellation.cpp | 57 ++++++++++++++++++ examples/threadpool/task_group.cpp | 73 +++++++++++++++++++++++ examples/threadpool/task_priority.cpp | 73 +++++++++++++++++++++++ examples/threadpool/task_timeout.cpp | 59 ++++++++++++++++++ modules/cli | 2 +- 18 files changed, 863 insertions(+), 2 deletions(-) create mode 100644 examples/threadpool/CMakeLists.txt create mode 100644 examples/threadpool/basic_post.cpp create mode 100644 examples/threadpool/custom_config.cpp create mode 100644 examples/threadpool/metrics.cpp create mode 100644 examples/threadpool/parallel_for.cpp create mode 100644 examples/threadpool/parallel_for_each.cpp create mode 100644 examples/threadpool/parallel_map.cpp create mode 100644 examples/threadpool/parallel_reduce.cpp create mode 100644 examples/threadpool/periodic_task.cpp create mode 100644 examples/threadpool/shutdown.cpp create mode 100644 examples/threadpool/submit_future.cpp create mode 100644 examples/threadpool/task_cancellation.cpp create mode 100644 examples/threadpool/task_group.cpp create mode 100644 examples/threadpool/task_priority.cpp create mode 100644 examples/threadpool/task_timeout.cpp diff --git a/CHANGELOG.md b/CHANGELOG.md index 0869cfc..ec7f108 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,24 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## v2.5.5 + +### Fixed +- Fixed `vix run` auto-linking for installed registry dependencies. +- Fixed script builds using compiled modules such as `kv`. +- Fixed package export cleanup to avoid duplicate CMake targets in `VixTargets`. +- Fixed installed module consistency for `threadpool` and `kv`. + +### Added +- Added threadpool examples for validating script and module usage. + +### Internal +- Updated the CLI module with the latest `vix run` dependency linking fixes. +- Cleaned umbrella CMake install/export behavior. + +### Compatibility +- No breaking changes. + ## v2.5.3 ### Added diff --git a/CMakeLists.txt b/CMakeLists.txt index 4f00cc4..e491039 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1395,7 +1395,6 @@ if (VIX_ENABLE_INSTALL) DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/vix/third_party/asio" ) - # ---- Export umbrella and helper interface targets ---- install(TARGETS vix EXPORT VixTargets) if (TARGET vix_thirdparty_asio) diff --git a/examples/threadpool/CMakeLists.txt b/examples/threadpool/CMakeLists.txt new file mode 100644 index 0000000..93112cf --- /dev/null +++ b/examples/threadpool/CMakeLists.txt @@ -0,0 +1,55 @@ +# @file examples/CMakeLists.txt +# @author Gaspard Kirira +# +# Copyright 2025, Gaspard Kirira. All rights reserved. +# https://github.com/vixcpp/vix +# Use of this source code is governed by a MIT license +# that can be found in the License file. +# +# ==================================================================== +# Vix.cpp - Threadpool Examples +# ==================================================================== + +set(VIX_THREADPOOL_EXAMPLE_SOURCES + basic_post.cpp + custom_config.cpp + metrics.cpp + parallel_for.cpp + parallel_for_each.cpp + parallel_map.cpp + parallel_reduce.cpp + periodic_task.cpp + shutdown.cpp + submit_future.cpp + task_cancellation.cpp + task_group.cpp + task_priority.cpp + task_timeout.cpp +) + +foreach(example_source IN LISTS VIX_THREADPOOL_EXAMPLE_SOURCES) + get_filename_component(example_name "${example_source}" NAME_WE) + + add_executable(${example_name} + ${example_source} + ) + + target_link_libraries(${example_name} + PRIVATE + vix::threadpool + ) + + target_compile_features(${example_name} + PRIVATE + cxx_std_20 + ) + + if (NOT MSVC) + target_compile_options(${example_name} + PRIVATE + -Wall + -Wextra + -Wpedantic + ) + endif() +endforeach() diff --git a/examples/threadpool/basic_post.cpp b/examples/threadpool/basic_post.cpp new file mode 100644 index 0000000..3cb3fcd --- /dev/null +++ b/examples/threadpool/basic_post.cpp @@ -0,0 +1,43 @@ +/** + * + * @file basic_post.cpp + * @author Gaspard Kirira + * + * Copyright 2025, Gaspard Kirira. + * All rights reserved. + * https://github.com/vixcpp/vix + * + * Use of this source code is governed by a MIT license + * that can be found in the License file. + * + * Vix.cpp + * + */ +#include +#include + +#include + +int main() +{ + vix::threadpool::ThreadPool pool(4); + + std::atomic counter{0}; + + for (int i = 0; i < 10; ++i) + { + pool.post( + [&counter]() + { + counter.fetch_add(1, std::memory_order_relaxed); + }); + } + + pool.wait_idle(); + + std::cout << "Executed tasks: " << counter.load() << '\n'; + + pool.shutdown(); + + return 0; +} diff --git a/examples/threadpool/custom_config.cpp b/examples/threadpool/custom_config.cpp new file mode 100644 index 0000000..069cd96 --- /dev/null +++ b/examples/threadpool/custom_config.cpp @@ -0,0 +1,64 @@ +/** + * + * @file custom_config.cpp + * @author Gaspard Kirira + * + * Copyright 2025, Gaspard Kirira. + * All rights reserved. + * https://github.com/vixcpp/vix + * + * Use of this source code is governed by a MIT license + * that can be found in the License file. + * + * Vix.cpp + * + */ +#include +#include +#include + +#include + +int main() +{ + vix::threadpool::ThreadPoolConfig config; + + config.thread_count = 2; + config.max_thread_count = 2; + config.max_queue_size = 16; + config.default_priority = vix::threadpool::TaskPriority::normal; + config.allow_dynamic_growth = false; + config.drain_on_shutdown = true; + config.swallow_task_exceptions = true; + config.default_timeout = std::chrono::milliseconds{0}; + + vix::threadpool::ThreadPool pool(config); + + auto first = + pool.submit( + []() + { + return 10; + }); + + auto second = + pool.submit( + []() + { + return 32; + }); + + const int result = first.get() + second.get(); + + std::cout << "Thread count: " << pool.thread_count() << '\n'; + std::cout << "Result: " << result << '\n'; + + const vix::threadpool::ThreadPoolMetrics metrics = pool.metrics(); + + std::cout << "Completed tasks: " << metrics.completed_tasks << '\n'; + std::cout << "Rejected tasks: " << metrics.rejected_tasks << '\n'; + + pool.shutdown(); + + return 0; +} diff --git a/examples/threadpool/metrics.cpp b/examples/threadpool/metrics.cpp new file mode 100644 index 0000000..2c5c164 --- /dev/null +++ b/examples/threadpool/metrics.cpp @@ -0,0 +1,55 @@ +/** + * + * @file metrics.cpp + * @author Gaspard Kirira + * + * Copyright 2025, Gaspard Kirira. + * All rights reserved. + * https://github.com/vixcpp/vix + * + * Use of this source code is governed by a MIT license + * that can be found in the License file. + * + * Vix.cpp + * + */ +#include +#include +#include + +#include + +int main() +{ + vix::threadpool::ThreadPool pool(4); + + for (int i = 0; i < 8; ++i) + { + pool.post( + []() + { + std::this_thread::sleep_for(std::chrono::milliseconds{20}); + }); + } + + pool.wait_idle(); + + const vix::threadpool::ThreadPoolMetrics metrics = pool.metrics(); + const vix::threadpool::ThreadPoolStats stats = pool.stats(); + + std::cout << "Worker count: " << metrics.worker_count << '\n'; + std::cout << "Pending tasks: " << metrics.pending_tasks << '\n'; + std::cout << "Active tasks: " << metrics.active_tasks << '\n'; + std::cout << "Completed tasks: " << metrics.completed_tasks << '\n'; + std::cout << "Failed tasks: " << metrics.failed_tasks << '\n'; + std::cout << "Rejected tasks: " << metrics.rejected_tasks << '\n'; + std::cout << "Idle: " << (metrics.idle() ? "yes" : "no") << '\n'; + + std::cout << "Accepted tasks: " << stats.accepted_tasks << '\n'; + std::cout << "Finished tasks: " << stats.finished_tasks() << '\n'; + std::cout << "Error tasks: " << stats.error_tasks() << '\n'; + + pool.shutdown(); + + return 0; +} diff --git a/examples/threadpool/parallel_for.cpp b/examples/threadpool/parallel_for.cpp new file mode 100644 index 0000000..d3f9d7a --- /dev/null +++ b/examples/threadpool/parallel_for.cpp @@ -0,0 +1,52 @@ +/** + * + * @file parallel_for.cpp + * @author Gaspard Kirira + * + * Copyright 2025, Gaspard Kirira. + * All rights reserved. + * https://github.com/vixcpp/vix + * + * Use of this source code is governed by a MIT license + * that can be found in the License file. + * + * Vix.cpp + * + */ +#include +#include +#include +#include + +#include + +int main() +{ + vix::threadpool::ThreadPool pool(4); + + std::vector values(20, 0); + + vix::threadpool::parallel_for( + pool, + std::size_t{0}, + values.size(), + [&values](std::size_t index) + { + values[index] = static_cast(index * index); + }); + + pool.wait_idle(); + + std::cout << "parallel_for result:"; + + for (const int value : values) + { + std::cout << ' ' << value; + } + + std::cout << '\n'; + + pool.shutdown(); + + return 0; +} diff --git a/examples/threadpool/parallel_for_each.cpp b/examples/threadpool/parallel_for_each.cpp new file mode 100644 index 0000000..6014483 --- /dev/null +++ b/examples/threadpool/parallel_for_each.cpp @@ -0,0 +1,48 @@ +/** + * + * @file parallel_for_each.cpp + * @author Gaspard Kirira + * + * Copyright 2025, Gaspard Kirira. + * All rights reserved. + * https://github.com/vixcpp/vix + * + * Use of this source code is governed by a MIT license + * that can be found in the License file. + * + * Vix.cpp + * + */ +#include +#include +#include +#include + +#include + +int main() +{ + vix::threadpool::ThreadPool pool(4); + + std::vector names{ + "vix", + "threadpool", + "parallel", + "runtime"}; + + std::mutex mutex; + + vix::threadpool::parallel_for_each( + pool, + names, + [&mutex](const std::string &name) + { + std::lock_guard lock(mutex); + std::cout << "Processing: " << name << '\n'; + }); + + pool.wait_idle(); + pool.shutdown(); + + return 0; +} diff --git a/examples/threadpool/parallel_map.cpp b/examples/threadpool/parallel_map.cpp new file mode 100644 index 0000000..cc5215a --- /dev/null +++ b/examples/threadpool/parallel_map.cpp @@ -0,0 +1,49 @@ +/** + * + * @file parallel_map.cpp + * @author Gaspard Kirira + * + * Copyright 2025, Gaspard Kirira. + * All rights reserved. + * https://github.com/vixcpp/vix + * + * Use of this source code is governed by a MIT license + * that can be found in the License file. + * + * Vix.cpp + * + */ +#include +#include +#include + +#include + +int main() +{ + vix::threadpool::ThreadPool pool(4); + + std::vector numbers{1, 2, 3, 4, 5, 6, 7, 8}; + + std::vector squares = + vix::threadpool::parallel_map( + pool, + numbers, + [](int value) + { + return value * value; + }); + + std::cout << "Squares:"; + + for (const int value : squares) + { + std::cout << ' ' << value; + } + + std::cout << '\n'; + + pool.shutdown(); + + return 0; +} diff --git a/examples/threadpool/parallel_reduce.cpp b/examples/threadpool/parallel_reduce.cpp new file mode 100644 index 0000000..4425073 --- /dev/null +++ b/examples/threadpool/parallel_reduce.cpp @@ -0,0 +1,45 @@ +/** + * + * @file parallel_reduce.cpp + * @author Gaspard Kirira + * + * Copyright 2025, Gaspard Kirira. + * All rights reserved. + * https://github.com/vixcpp/vix + * + * Use of this source code is governed by a MIT license + * that can be found in the License file. + * + * Vix.cpp + * + */ +#include +#include +#include + +#include + +int main() +{ + vix::threadpool::ThreadPool pool(4); + + std::vector numbers(100); + + std::iota(numbers.begin(), numbers.end(), 1); + + const int sum = + vix::threadpool::parallel_reduce( + pool, + numbers, + 0, + [](int current, int value) + { + return current + value; + }); + + std::cout << "Sum: " << sum << '\n'; + + pool.shutdown(); + + return 0; +} diff --git a/examples/threadpool/periodic_task.cpp b/examples/threadpool/periodic_task.cpp new file mode 100644 index 0000000..0ae9dd0 --- /dev/null +++ b/examples/threadpool/periodic_task.cpp @@ -0,0 +1,63 @@ +/** + * + * @file periodic_task.cpp + * @author Gaspard Kirira + * + * Copyright 2025, Gaspard Kirira. + * All rights reserved. + * https://github.com/vixcpp/vix + * + * Use of this source code is governed by a MIT license + * that can be found in the License file. + * + * Vix.cpp + * + */ +#include +#include +#include +#include + +#include + +int main() +{ + vix::threadpool::ThreadPool pool(2); + + std::atomic ticks{0}; + + vix::threadpool::PeriodicTaskConfig config; + config.interval = std::chrono::milliseconds{100}; + config.run_immediately = true; + + vix::threadpool::PeriodicTask task( + pool, + [&ticks]() + { + const int current = ticks.fetch_add(1, std::memory_order_relaxed) + 1; + std::cout << "Tick: " << current << '\n'; + }, + config); + + if (!task.start()) + { + std::cout << "Failed to start periodic task\n"; + pool.shutdown(); + return 1; + } + + std::this_thread::sleep_for(std::chrono::milliseconds{450}); + + task.stop(); + task.join(); + + pool.wait_idle(); + + std::cout << "Submitted ticks: " << task.submitted_ticks() << '\n'; + std::cout << "Failed posts: " << task.failed_posts() << '\n'; + std::cout << "Observed ticks: " << ticks.load() << '\n'; + + pool.shutdown(); + + return 0; +} diff --git a/examples/threadpool/shutdown.cpp b/examples/threadpool/shutdown.cpp new file mode 100644 index 0000000..1fe4fb5 --- /dev/null +++ b/examples/threadpool/shutdown.cpp @@ -0,0 +1,60 @@ +/** + * + * @file shutdown.cpp + * @author Gaspard Kirira + * + * Copyright 2025, Gaspard Kirira. + * All rights reserved. + * https://github.com/vixcpp/vix + * + * Use of this source code is governed by a MIT license + * that can be found in the License file. + * + * Vix.cpp + * + */ +#include +#include +#include + +#include + +int main() +{ + vix::threadpool::ThreadPool pool(2); + + for (int i = 0; i < 4; ++i) + { + pool.post( + [i]() + { + std::this_thread::sleep_for(std::chrono::milliseconds{50}); + std::cout << "Task finished: " << i << '\n'; + }); + } + + pool.wait_idle(); + + std::cout << "Pool idle before shutdown: " + << (pool.idle() ? "yes" : "no") + << '\n'; + + pool.shutdown(); + + std::cout << "Pool running after shutdown: " + << (pool.running() ? "yes" : "no") + << '\n'; + + const bool accepted = + pool.post( + []() + { + std::cout << "This should not run after shutdown\n"; + }); + + std::cout << "Post after shutdown accepted: " + << (accepted ? "yes" : "no") + << '\n'; + + return 0; +} diff --git a/examples/threadpool/submit_future.cpp b/examples/threadpool/submit_future.cpp new file mode 100644 index 0000000..61b38d8 --- /dev/null +++ b/examples/threadpool/submit_future.cpp @@ -0,0 +1,48 @@ +/** + * + * @file submit_future.cpp + * @author Gaspard Kirira + * + * Copyright 2025, Gaspard Kirira. + * All rights reserved. + * https://github.com/vixcpp/vix + * + * Use of this source code is governed by a MIT license + * that can be found in the License file. + * + * Vix.cpp + * + */ +#include +#include + +#include + +int main() +{ + vix::threadpool::ThreadPool pool(4); + + auto numberFuture = + pool.submit( + []() + { + return 42; + }); + + auto textFuture = + pool.submit( + []() + { + return std::string{"Hello from Vix threadpool"}; + }); + + const int number = numberFuture.get(); + const std::string text = textFuture.get(); + + std::cout << "Number result: " << number << '\n'; + std::cout << "Text result: " << text << '\n'; + + pool.shutdown(); + + return 0; +} diff --git a/examples/threadpool/task_cancellation.cpp b/examples/threadpool/task_cancellation.cpp new file mode 100644 index 0000000..6cb759b --- /dev/null +++ b/examples/threadpool/task_cancellation.cpp @@ -0,0 +1,57 @@ +/** + * + * @file task_cancellation.cpp + * @author Gaspard Kirira + * + * Copyright 2025, Gaspard Kirira. + * All rights reserved. + * https://github.com/vixcpp/vix + * + * Use of this source code is governed by a MIT license + * that can be found in the License file. + * + * Vix.cpp + * + */ +#include +#include +#include + +#include + +int main() +{ + vix::threadpool::ThreadPool pool(2); + + auto handle = + pool.handle( + []() + { + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + return 7; + }); + + handle.cancel(); + + try + { + const int value = handle.get(); + std::cout << "Result: " << value << '\n'; + } + catch (const std::exception &e) + { + std::cout << "Task failed: " << e.what() << '\n'; + } + + std::cout << "Cancelled: " + << (handle.cancelled() ? "yes" : "no") + << '\n'; + + std::cout << "Task status: " + << vix::threadpool::to_string(handle.status()) + << '\n'; + + pool.shutdown(); + + return 0; +} diff --git a/examples/threadpool/task_group.cpp b/examples/threadpool/task_group.cpp new file mode 100644 index 0000000..d36e26c --- /dev/null +++ b/examples/threadpool/task_group.cpp @@ -0,0 +1,73 @@ +/** + * + * @file task_group.cpp + * @author Gaspard Kirira + * + * Copyright 2025, Gaspard Kirira. + * All rights reserved. + * https://github.com/vixcpp/vix + * + * Use of this source code is governed by a MIT license + * that can be found in the License file. + * + * Vix.cpp + * + */ +#include +#include +#include + +#include + +int main() +{ + vix::threadpool::TaskGroup group; + + group.add_task(1); + group.add_task(2); + group.add_task(3); + + std::thread first( + [&group]() + { + std::this_thread::sleep_for(std::chrono::milliseconds(20)); + + group.finish_task( + vix::threadpool::TaskStatus::completed, + vix::threadpool::TaskResult::success); + }); + + std::thread second( + [&group]() + { + std::this_thread::sleep_for(std::chrono::milliseconds(40)); + + group.finish_task( + vix::threadpool::TaskStatus::completed, + vix::threadpool::TaskResult::success); + }); + + std::thread third( + [&group]() + { + std::this_thread::sleep_for(std::chrono::milliseconds(60)); + + group.finish_task( + vix::threadpool::TaskStatus::cancelled, + vix::threadpool::TaskResult::cancelled); + }); + + group.close(); + group.wait(); + + first.join(); + second.join(); + third.join(); + + std::cout << "Total tasks: " << group.total_tasks() << '\n'; + std::cout << "Completed: " << group.completed_tasks() << '\n'; + std::cout << "Cancelled: " << group.cancelled_tasks() << '\n'; + std::cout << "Has error: " << (group.has_error() ? "yes" : "no") << '\n'; + + return 0; +} diff --git a/examples/threadpool/task_priority.cpp b/examples/threadpool/task_priority.cpp new file mode 100644 index 0000000..af6a078 --- /dev/null +++ b/examples/threadpool/task_priority.cpp @@ -0,0 +1,73 @@ +/** + * + * @file task_priority.cpp + * @author Gaspard Kirira + * + * Copyright 2025, Gaspard Kirira. + * All rights reserved. + * https://github.com/vixcpp/vix + * + * Use of this source code is governed by a MIT license + * that can be found in the License file. + * + * Vix.cpp + * + */ +#include +#include +#include + +#include + +int main() +{ + vix::threadpool::ThreadPool pool(2); + + std::mutex mutex; + std::vector order; + + vix::threadpool::TaskOptions lowPriority; + lowPriority.set_priority(vix::threadpool::TaskPriority::low); + + vix::threadpool::TaskOptions highPriority; + highPriority.set_priority(vix::threadpool::TaskPriority::high); + + pool.post( + [&mutex, &order]() + { + std::lock_guard lock(mutex); + order.push_back(1); + }, + lowPriority); + + pool.post( + [&mutex, &order]() + { + std::lock_guard lock(mutex); + order.push_back(2); + }, + highPriority); + + pool.post( + [&mutex, &order]() + { + std::lock_guard lock(mutex); + order.push_back(3); + }, + highPriority); + + pool.wait_idle(); + + std::cout << "Execution order:"; + + for (const int value : order) + { + std::cout << ' ' << value; + } + + std::cout << '\n'; + + pool.shutdown(); + + return 0; +} diff --git a/examples/threadpool/task_timeout.cpp b/examples/threadpool/task_timeout.cpp new file mode 100644 index 0000000..2dc600c --- /dev/null +++ b/examples/threadpool/task_timeout.cpp @@ -0,0 +1,59 @@ +/** + * + * @file task_timeout.cpp + * @author Gaspard Kirira + * + * Copyright 2025, Gaspard Kirira. + * All rights reserved. + * https://github.com/vixcpp/vix + * + * Use of this source code is governed by a MIT license + * that can be found in the License file. + * + * Vix.cpp + * + */ +#include +#include +#include + +#include + +int main() +{ + vix::threadpool::ThreadPool pool(2); + + vix::threadpool::TaskOptions options; + options.set_timeout(vix::threadpool::Timeout::milliseconds(50)); + + auto future = + pool.submit( + []() + { + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + return 42; + }, + options); + + try + { + const int value = future.get(); + std::cout << "Result: " << value << '\n'; + } + catch (const std::exception &e) + { + std::cout << "Task failed: " << e.what() << '\n'; + } + + std::cout << "Future status: " + << vix::threadpool::to_string(future.status()) + << '\n'; + + std::cout << "Future result: " + << vix::threadpool::to_string(future.result()) + << '\n'; + + pool.shutdown(); + + return 0; +} diff --git a/modules/cli b/modules/cli index 4dd47cc..88b6ff3 160000 --- a/modules/cli +++ b/modules/cli @@ -1 +1 @@ -Subproject commit 4dd47cc70cdaee45d4a1e7efe8f8732f6691a8f7 +Subproject commit 88b6ff3202f74be3a586a4ef4da4e3057a7c81bd From fe5ef52e443256aa8d12ece9f076cae30fd7b012 Mon Sep 17 00:00:00 2001 From: Gaspard Kirira Date: Tue, 12 May 2026 13:22:39 +0300 Subject: [PATCH 2/3] chore: update changelog for v2.5.5 --- CHANGELOG.md | 7 + docs/guides/vix-app.md | 1074 ++++++++++++++++++++++++++++++++++++++++ modules/cli | 2 +- modules/core | 2 +- 4 files changed, 1083 insertions(+), 2 deletions(-) create mode 100644 docs/guides/vix-app.md diff --git a/CHANGELOG.md b/CHANGELOG.md index ec7f108..ea88e43 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,13 +15,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Added threadpool examples for validating script and module usage. +- Added experimental `vix.app` support for simple C++ applications without a visible `CMakeLists.txt`. +- Added generated CMake project support for `vix.app` based builds and runs. +- Added experimental documentation for the current `vix.app` design. ### Internal - Updated the CLI module with the latest `vix run` dependency linking fixes. +- Added shared app project resolution for CMake and `vix.app` projects. +- Added internal CMake generation from `vix.app`. - Cleaned umbrella CMake install/export behavior. ### Compatibility - No breaking changes. +- Existing CMake projects keep the current build and run behavior. +- `vix.app` is experimental and only used when no `CMakeLists.txt` is present. ## v2.5.3 diff --git a/docs/guides/vix-app.md b/docs/guides/vix-app.md new file mode 100644 index 0000000..2a89b34 --- /dev/null +++ b/docs/guides/vix-app.md @@ -0,0 +1,1074 @@ +# vix.app + +`vix.app` is a simple application manifest for C++ projects built with Vix. + +It lets small and medium C++ apps start without writing a visible `CMakeLists.txt`. + +Vix reads `vix.app`, generates an internal CMake project, then uses CMake and Ninja underneath to build and run the app. + +## Goal + +`vix.app` is designed for projects that need a simple entry point: + +```bash +vix run +vix build +``` + +without requiring the user to write CMake manually. + +The generated CMake project stays internal: + +``` +.vix/generated/app/CMakeLists.txt +``` + +This means the user gets a simple project format, while Vix keeps the power of the C++ build ecosystem underneath. + +## What vix.app does + +`vix.app` describes: + +- the application name +- the target type +- the C++ standard +- source files +- include directories +- compile definitions +- linked libraries or CMake targets + +Example: + +```toml +name = "demo" +type = "executable" +standard = "c++20" + +sources = [ + "main.cpp", + "hello.cpp" +] + +include_dirs = [ + "include" +] + +defines = [ + "DEMO_APP=1" +] + +links = [ + "vix::core" +] +``` + +Then run: + +```bash +vix run +``` + +Vix generates CMake internally, builds the app, and runs the executable. + +## What vix.app does not replace + +`vix.app` does not replace `vix.json`. + +They have different roles. + +| File | Role | +|------|------| +| `vix.app` | Describes the C++ application target. | +| `vix.json` | Describes project metadata, registry dependencies, tasks, and workflows. | +| `vix.lock` | Stores resolved dependency versions. | +| `.vix/` | Stores generated files, installed dependencies, cache data, and internal metadata. | + +The rule is simple: + +- `vix.app` = app build description +- `vix.json` = registry, tasks, workflows, project metadata + +## Detection order + +Vix keeps existing project behavior intact. + +The resolution order is: + +``` +1. If CMakeLists.txt exists + -> use the existing CMake project + +2. Else if vix.app exists + -> generate an internal CMake project + +3. Else if a single .cpp file is passed + -> use single-file mode + +4. Else + -> show a clear error +``` + +This means `vix.app` is only used when there is no `CMakeLists.txt`. + +Existing CMake projects keep working as before. + +## Minimal project + +Project structure: + +``` +demo/ +├── main.cpp +└── vix.app +``` + +`main.cpp`: + +```cpp +#include + +int main() +{ + std::cout << "Hello from Vix app\n"; + return 0; +} +``` + +`vix.app`: + +```toml +name = "demo" +type = "executable" +standard = "c++20" + +sources = [ + "main.cpp" +] +``` + +Run: + +```bash +vix run +``` + +Expected output: + +``` +Hello from Vix app +``` + +## Multi-file project + +Project structure: + +``` +demo/ +├── main.cpp +├── hello.cpp +├── include/ +│ └── hello.hpp +└── vix.app +``` + +`include/hello.hpp`: + +```cpp +#ifndef DEMO_HELLO_HPP +#define DEMO_HELLO_HPP + +void say_hello(); + +#endif +``` + +`hello.cpp`: + +```cpp +#include "hello.hpp" + +#include + +void say_hello() +{ + vix::print("Hello from hello.cpp"); +} +``` + +`main.cpp`: + +```cpp +#include "hello.hpp" + +#include + +int main() +{ + vix::print("Hello from main.cpp"); + say_hello(); + return 0; +} +``` + +`vix.app`: + +```toml +name = "demo" +type = "executable" +standard = "c++20" + +sources = [ + "main.cpp", + "hello.cpp" +] + +include_dirs = [ + "include" +] +``` + +Run: + +```bash +vix run +``` + +Expected output: + +``` +Hello from main.cpp +Hello from hello.cpp +``` + +## Generated CMake + +For the previous example, Vix generates an internal file similar to this: + +```cmake +# Auto-generated by Vix from vix.app +# Do not edit this file directly. + +cmake_minimum_required(VERSION 3.24) + +project(demo LANGUAGES CXX) + +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) + +add_executable(demo + "/absolute/path/to/main.cpp" + "/absolute/path/to/hello.cpp" +) + +target_include_directories(demo PRIVATE + "/absolute/path/to/include" +) +``` + +The generated file is stored under: + +``` +.vix/generated/app/CMakeLists.txt +``` + +Users should not edit this file directly. + +Edit `vix.app` instead. + +## Commands + +### Build the app + +```bash +vix build +``` + +For a `vix.app` project, Vix does this internally: + +``` +vix.app + -> .vix/generated/app/CMakeLists.txt + -> cmake -S .vix/generated/app -B build-ninja -G Ninja + -> cmake --build build-ninja +``` + +### Run the app + +```bash +vix run +``` + +For a `vix.app` project, Vix does this internally: + +``` +vix.app + -> generate CMake + -> build + -> run build-ninja/ +``` + +### Single-file mode still works + +```bash +vix run main.cpp +``` + +This keeps the existing script mode behavior. + +Use this for quick experiments or one-file programs. + +Use `vix.app` when the app has multiple source files or needs includes, definitions, links, or registry dependencies. + +## Fields + +### name + +Required. + +Defines the CMake project name and default target name. + +```toml +name = "demo" +``` + +Valid examples: + +```toml +name = "api" +name = "hello" +name = "softadastra_agent" +``` + +The name should be simple and filesystem-friendly. + +### type + +Optional. + +Default: + +```toml +type = "executable" +``` + +Supported values: + +```toml +type = "executable" +type = "static" +type = "static-library" +type = "shared" +type = "shared-library" +type = "library" +``` + +Recommended value for apps: + +```toml +type = "executable" +``` + +Example: + +```toml +name = "demo" +type = "executable" +``` + +### standard + +Optional. + +Default: + +```toml +standard = "c++20" +``` + +Supported values: + +```toml +standard = "c++11" +standard = "c++14" +standard = "c++17" +standard = "c++20" +standard = "c++23" +standard = "c++26" +``` + +Recommended default: + +```toml +standard = "c++20" +``` + +### sources + +Required. + +Lists source files for the app. + +```toml +sources = [ + "main.cpp", + "hello.cpp" +] +``` + +Paths are relative to the project directory. + +You can also use files inside `src/`: + +```toml +sources = [ + "src/main.cpp", + "src/server.cpp", + "src/routes.cpp" +] +``` + +### include_dirs + +Optional. + +Lists include directories. + +```toml +include_dirs = [ + "include" +] +``` + +This generates: + +```cmake +target_include_directories( PRIVATE ...) +``` + +Example project: + +``` +demo/ +├── include/ +│ └── demo/server.hpp +├── src/ +│ ├── main.cpp +│ └── server.cpp +└── vix.app +``` + +`vix.app`: + +```toml +name = "demo" +type = "executable" +standard = "c++20" + +sources = [ + "src/main.cpp", + "src/server.cpp" +] + +include_dirs = [ + "include" +] +``` + +### defines + +Optional. + +Lists preprocessor definitions. + +```toml +defines = [ + "DEMO_APP=1", + "VIX_USE_FAST_PATH" +] +``` + +This generates: + +```cmake +target_compile_definitions( PRIVATE ...) +``` + +Example: + +```toml +name = "demo" +type = "executable" +standard = "c++20" + +sources = [ + "main.cpp" +] + +defines = [ + "APP_ENV=\"dev\"", + "ENABLE_LOGS=1" +] +``` + +### links + +Optional. + +Lists libraries or CMake targets linked by the app. + +```toml +links = [ + "vix::core", + "vix::json" +] +``` + +This generates: + +```cmake +target_link_libraries( PRIVATE ...) +``` + +Use this field for: + +- Vix modules +- registry package targets +- local CMake targets exposed through generated dependency files +- system libraries when appropriate + +Example: + +```toml +name = "api" +type = "executable" +standard = "c++20" + +sources = [ + "src/main.cpp" +] + +links = [ + "vix::core", + "vix::json" +] +``` + +## Registry dependencies + +Registry dependencies stay in `vix.json` and `vix.lock`. + +`vix.app` only consumes the targets after they are installed. + +Typical flow: + +```bash +vix add softadastra/kordex-runtime +vix install +vix run +``` + +The project keeps dependency metadata in: + +- `vix.json` +- `vix.lock` + +The installed dependency files live under: + +``` +.vix/ +``` + +The generated CMake project can include dependency integration files from `.vix/`, then `links` can reference the exposed CMake targets. + +Example `vix.app`: + +```toml +name = "demo" +type = "executable" +standard = "c++20" + +sources = [ + "src/main.cpp" +] + +links = [ + "softadastra::kordex-runtime" +] +``` + +The important separation is: + +- `vix.json` handles dependency declaration. +- `vix.lock` handles resolved versions. +- `vix.app` links the final targets used by the app. + +## Recommended project layout + +For a simple app: + +``` +demo/ +├── src/ +│ ├── main.cpp +│ └── app.cpp +├── include/ +│ └── demo/ +│ └── app.hpp +├── vix.app +├── vix.json +└── vix.lock +``` + +Recommended `vix.app`: + +```toml +name = "demo" +type = "executable" +standard = "c++20" + +sources = [ + "src/main.cpp", + "src/app.cpp" +] + +include_dirs = [ + "include" +] +``` + +## Full REST API example + +Project structure: + +``` +rest-api/ +├── src/ +│ └── main.cpp +└── vix.app +``` + +`vix.app`: + +```toml +name = "rest_api" +type = "executable" +standard = "c++20" + +sources = [ + "src/main.cpp" +] + +links = [ + "vix::core" +] +``` + +`src/main.cpp`: + +```cpp +#include + +using namespace vix; + +int main() +{ + App app; + + app.get("/", [](Request &, Response &res){ + res.json({ + "message", "Hello from Vix", + "framework", "Vix.cpp" + }); + }); + + app.get("/health", [](Request &, Response &res){ + res.json({ + "ok", true, + "service", "rest_api" + }); + }); + + app.run(8080); + return 0; +} +``` + +Run: + +```bash +vix run +``` + +Test: + +```bash +curl -i http://127.0.0.1:8080/ +curl -i http://127.0.0.1:8080/health +``` + +## vix.app vs CMakeLists.txt + +Use `vix.app` when: + +- the app is small or medium-sized +- you want a fast start +- you want to avoid writing CMake manually +- your app has a simple executable target +- your app has a few source files +- your app links registry dependencies through Vix + +Use `CMakeLists.txt` when: + +- the project has advanced build logic +- the project has many targets +- the project needs custom CMake functions +- the project needs advanced install rules +- the project needs custom toolchains or platform-specific build logic +- the project is a library intended for complex packaging + +The rule is: + +- `vix.app` for simple app description. +- `CMakeLists.txt` for advanced build control. + +If both files exist, `CMakeLists.txt` wins. + +## Generated files + +A `vix.app` project may create: + +``` +.vix/generated/app/CMakeLists.txt +build-ninja/ +build-dev/ +build-release/ +``` + +These are internal or build output paths. + +Recommended `.gitignore`: + +``` +build/ +build-*/ +.vix/generated/ +.vix/cache/ +.vix/runs/ +``` + +Depending on how the project handles dependencies, some `.vix/` dependency files may be local build state and should not be committed. + +## Common workflows + +### Create a simple app manually + +```bash +mkdir demo +cd demo + +cat > main.cpp <<'CPP' +#include + +int main() +{ + vix::print("Hello from Vix app"); + return 0; +} +CPP + +cat > vix.app <<'EOF' +name = "demo" +type = "executable" +standard = "c++20" + +sources = [ + "main.cpp" +] +EOF + +vix run +``` + +### Add another source file + +```bash +cat > hello.cpp <<'CPP' +#include + +void say_hello() +{ + vix::print("Hello from hello.cpp"); +} +CPP +``` + +Update `main.cpp`: + +```cpp +#include + +void say_hello(); + +int main() +{ + vix::print("Hello from main.cpp"); + + say_hello(); + + return 0; +} +``` + +Update `vix.app`: + +```toml +name = "demo" +type = "executable" +standard = "c++20" + +sources = [ + "main.cpp", + "hello.cpp" +] +``` + +Run: + +```bash +vix run +``` + +### Add an include directory + +``` +demo/ +├── include/ +│ └── hello.hpp +├── main.cpp +├── hello.cpp +└── vix.app +``` + +`vix.app`: + +```toml +name = "demo" +type = "executable" +standard = "c++20" + +sources = [ + "main.cpp", + "hello.cpp" +] + +include_dirs = [ + "include" +] +``` + +### Add registry dependencies + +```bash +vix add namespace/package +vix install +``` + +Then link the target exposed by the package: + +```toml +name = "demo" +type = "executable" +standard = "c++20" + +sources = [ + "src/main.cpp" +] + +links = [ + "namespace::package" +] +``` + +Run: + +```bash +vix run +``` + +## Error messages + +### Missing vix.app + +If no `CMakeLists.txt` and no `vix.app` exist, Vix cannot resolve a project. + +Fix: + +```bash +vix run main.cpp +``` + +or create `vix.app`: + +```toml +name = "demo" +type = "executable" +standard = "c++20" + +sources = [ + "main.cpp" +] +``` + +### Missing sources + +Invalid: + +```toml +name = "demo" +type = "executable" +standard = "c++20" +``` + +Fix: + +```toml +name = "demo" +type = "executable" +standard = "c++20" + +sources = [ + "main.cpp" +] +``` + +### Wrong source path + +Invalid: + +```toml +sources = [ + "src/missing.cpp" +] +``` + +Fix the path or create the file. + +### Unknown link target + +Invalid: + +```toml +links = [ + "missing::target" +] +``` + +Fix: + +- install the dependency +- check `vix.lock` +- check the target name exposed by the package +- check `.vix/` dependency integration files +- update the `links` field + +## Best practices + +Keep `vix.app` small. + +Recommended: + +```toml +name = "api" +type = "executable" +standard = "c++20" + +sources = [ + "src/main.cpp", + "src/routes.cpp", + "src/server.cpp" +] + +include_dirs = [ + "include" +] + +links = [ + "vix::core" +] +``` + +- Avoid turning `vix.app` into a full build system. +- Do not put registry metadata in `vix.app`. +- Keep dependencies in `vix.json`. +- Keep resolved versions in `vix.lock`. +- Use `CMakeLists.txt` when the app becomes advanced enough to need custom build logic. + +## Reference + +Complete field reference: + +| Field | Required | Default | Purpose | +|-------|----------|---------|---------| +| `name` | yes | none | Target and project name. | +| `type` | no | `executable` | Target type. | +| `standard` | no | `c++20` | C++ language standard. | +| `sources` | yes | none | Source files. | +| `include_dirs` | no | empty | Include directories. | +| `defines` | no | empty | Compile definitions. | +| `links` | no | empty | Libraries or CMake targets. | + +Supported target types: + +| Value | Meaning | +|-------|---------| +| `executable` | Builds an executable app. | +| `static` | Builds a static library. | +| `static-library` | Builds a static library. | +| `shared` | Builds a shared library. | +| `shared-library` | Builds a shared library. | +| `library` | Builds a static library by default. | + +Supported standards: + +| Value | +|-------| +| `c++11` | +| `c++14` | +| `c++17` | +| `c++20` | +| `c++23` | +| `c++26` | + +## Summary + +`vix.app` gives Vix a simple project-level entry point for C++ apps. + +The user writes: + +```toml +name = "demo" +type = "executable" +standard = "c++20" + +sources = [ + "main.cpp", + "hello.cpp" +] +``` + +Then runs: + +```bash +vix run +``` + +Vix handles: + +- manifest parsing +- CMake generation +- configure +- build +- run + +The result is a lighter first experience for C++ apps, while keeping CMake and Ninja underneath for the real build work. diff --git a/modules/cli b/modules/cli index 88b6ff3..43772ea 160000 --- a/modules/cli +++ b/modules/cli @@ -1 +1 @@ -Subproject commit 88b6ff3202f74be3a586a4ef4da4e3057a7c81bd +Subproject commit 43772ea07f85a0c05c93eb91f32ea9acd2aaf24b diff --git a/modules/core b/modules/core index c2b3b11..382d0b9 160000 --- a/modules/core +++ b/modules/core @@ -1 +1 @@ -Subproject commit c2b3b11d4a98c59253bfb58bf3f8570d5b5c1f5e +Subproject commit 382d0b9d55a8f0ff89b1d7bbecdd5827c7ba3867 From fb953f1e805fc29c32486a48f1285abf1fd8c542 Mon Sep 17 00:00:00 2001 From: Gaspard Kirira Date: Tue, 12 May 2026 20:47:36 +0300 Subject: [PATCH 3/3] chore(release): prepare v2.5.5 --- README.md | 74 +++---------------------------------------------------- 1 file changed, 4 insertions(+), 70 deletions(-) diff --git a/README.md b/README.md index a2b6ab0..24496b9 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ @@ -43,8 +43,6 @@ Vix.cpp is a modern C++ runtime for building and running real-world applications Learn more about the Vix runtime in the [documentation](https://docs.vixcpp.com). -Vix is also the runtime foundation used by [Softadastra](https://docs.softadastra.com), a local-first and offline-first system for building reliable applications that continue working when the network is slow, unstable, or unavailable. - ## Production Proof Vix is not a concept. It runs real systems. @@ -58,8 +56,9 @@ A real-time monitoring system built and running in production with Vix.cpp. - real-time WebSocket streaming - production deployment -🔗 https://pulsegrid.softadastra.com \ -🔗 https://github.com/GaspardKirira/PulseGrid +Website: 🔗 https://pulsegrid.softadastra.com \ + +Github: 🔗 https://github.com/GaspardKirira/PulseGrid Used to build production systems like PulseGrid. @@ -98,27 +97,6 @@ vix run main.cpp Done. -## Replay a previous run - -Vix can record a run and replay it later. - -```bash -vix run main.cpp -vix replay -``` - -Replay the latest failed or interrupted run: -```bash -vix replay failed -``` - -Inspect a recorded run before replaying it: -```bash -vix replay show last -``` - -Vix stores replay data locally under .vix/runs/, including the command, working directory, exit status, and captured logs. - ## Build a server ```cpp @@ -193,50 +171,6 @@ int main(){ } ``` -## API Documentation (HTTP + WebSocket) - -Vix automatically exposes a full API documentation. - -Start your app, then open: - -``` -http://localhost:8080/docs -``` - -You get: - -- HTTP API documentation -- WebSocket endpoints -- Interactive testing UI -- No external dependencies (offline Swagger UI) - -The OpenAPI spec is available at: - -``` -http://localhost:8080/openapi.json -``` - -### Control docs with `vix run` - -Documentation can be enabled or disabled at runtime: - -```bash -# Enable docs -vix run app.cpp --docs - -# Disable docs -vix run app.cpp --no-docs -``` - -### Why this matters - -Most systems treat documentation as an afterthought. Vix does not. - -- Docs are generated from the runtime -- Always reflect the real system -- Work offline -- Include HTTP and WebSocket - ## What Vix.cpp gives you - Run a single `.cpp` file instantly