├── .clang-format ├── .clang-tidy ├── .cmake-format.py ├── .gitattributes ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── pull_request_template.md └── workflows │ ├── ci.yml │ └── tag.yml ├── .gitignore ├── CMakeLists.txt ├── CMakePresets.json ├── LICENSE ├── README.md ├── deprecated └── ipc2 │ ├── CMakeLists.txt │ ├── README.md │ ├── docs │ └── media │ │ ├── sample_arch.dia │ │ └── sample_arch.png │ ├── examples │ ├── CMakeLists.txt │ ├── README.md │ ├── attachment_pub.cpp │ ├── attachment_sub.cpp │ ├── basic_example_constants.h │ ├── basic_pub_example.cpp │ ├── basic_sub_example.cpp │ ├── client_example_constants.h │ ├── client_pub_example.cpp │ ├── client_sub_example.cpp │ ├── info.cpp │ ├── liveliness_declare.cpp │ ├── liveliness_get.cpp │ ├── liveliness_sub.cpp │ ├── ping.cpp │ ├── ping_pong_constants.h │ ├── pong.cpp │ ├── pub_cache.cpp │ ├── pub_shm.cpp │ ├── pull.cpp │ ├── query_get.cpp │ ├── query_get_channel.cpp │ ├── query_get_channel_non_blocking.cpp │ ├── query_sub.cpp │ ├── queryable.cpp │ ├── router.cpp │ ├── scout.cpp │ ├── sub_shm.cpp │ ├── throughput_constants.h │ ├── throughput_pub.cpp │ ├── throughput_sub.cpp │ └── zenoh_utils.h │ ├── include │ └── grape │ │ └── ipc2 │ │ ├── common.h │ │ ├── publisher.h │ │ ├── session.h │ │ ├── subscriber.h │ │ └── topic.h │ ├── src │ ├── common.cpp │ ├── ipc_zenoh.h │ ├── publisher.cpp │ ├── session.cpp │ └── subscriber.cpp │ └── tests │ ├── CMakeLists.txt │ └── tests.cpp ├── docs ├── 01_install.md ├── 02_roadmap.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── SECURITY.md └── howto │ ├── build_cmake.md │ ├── build_gcc.md │ ├── media │ ├── microservice.dia │ └── microservice.png │ ├── profile_builds.md │ ├── reduce_wifi_latency.md │ ├── vm.md │ └── write_applications.md ├── external ├── CMakeLists.txt ├── README.md ├── sources │ └── yaml_cpp_stdint.patch └── third_party_versions.cmake ├── gbs ├── 00_utilities.cmake ├── 01_version.cmake ├── 02_build_config.cmake ├── 03_compiler_config.cmake ├── 04_code_formatter.cmake ├── 05_modules.cmake ├── 06_packager_config.cmake ├── README.md ├── clang-tidy-cache.py ├── create_module.py ├── doxyfile.in ├── gbs.cmake ├── module-config.cmake.in ├── module_template │ ├── CMakeLists.txt │ ├── README.md │ ├── examples │ │ ├── CMakeLists.txt │ │ └── example.cpp │ ├── include │ │ └── grape │ │ │ └── @module@ │ │ │ └── @module@.h │ ├── src │ │ └── @module@.cpp │ └── tests │ │ ├── CMakeLists.txt │ │ └── tests.cpp ├── project-config.cmake.in ├── py │ ├── README.md │ ├── __init__.py.in │ └── setup.py.in └── uninstall.sh.in ├── modules ├── common │ ├── app │ │ ├── CMakeLists.txt │ │ ├── README.md │ │ ├── config │ │ │ ├── CMakeLists.txt │ │ │ └── app.lua │ │ ├── examples │ │ │ ├── CMakeLists.txt │ │ │ ├── pub_example.cpp │ │ │ └── sub_example.cpp │ │ ├── include │ │ │ └── grape │ │ │ │ └── app │ │ │ │ └── app.h │ │ ├── src │ │ │ └── app.cpp │ │ └── tests │ │ │ ├── CMakeLists.txt │ │ │ └── tests.cpp │ ├── base │ │ ├── CMakeLists.txt │ │ ├── examples │ │ │ ├── CMakeLists.txt │ │ │ └── exception_example.cpp │ │ ├── include │ │ │ └── grape │ │ │ │ └── exception.h │ │ └── src │ │ │ └── exception.cpp │ ├── conio │ │ ├── CMakeLists.txt │ │ ├── README.md │ │ ├── examples │ │ │ ├── CMakeLists.txt │ │ │ └── program_options_example.cpp │ │ ├── include │ │ │ └── grape │ │ │ │ └── conio │ │ │ │ ├── conio.h │ │ │ │ └── program_options.h │ │ ├── src │ │ │ ├── conio.cpp │ │ │ └── program_options.cpp │ │ └── tests │ │ │ ├── CMakeLists.txt │ │ │ └── program_options_tests.cpp │ ├── ipc │ │ ├── CMakeLists.txt │ │ ├── README.md │ │ ├── docs │ │ │ └── ipc_options.md │ │ ├── examples │ │ │ ├── CMakeLists.txt │ │ │ ├── perf_constants.h │ │ │ ├── perf_pub.cpp │ │ │ ├── perf_sub.cpp │ │ │ ├── pub_example.cpp │ │ │ ├── py │ │ │ │ ├── pub_example.py │ │ │ │ └── sub_example.py │ │ │ ├── service_example.cpp │ │ │ └── sub_example.cpp │ │ ├── include │ │ │ └── grape │ │ │ │ └── ipc │ │ │ │ ├── config.h │ │ │ │ ├── match.h │ │ │ │ ├── publisher.h │ │ │ │ ├── session.h │ │ │ │ ├── subscriber.h │ │ │ │ └── topic.h │ │ ├── py │ │ │ ├── CMakeLists.txt │ │ │ ├── bindings.cpp │ │ │ ├── bindings.h │ │ │ ├── config_bindings.cpp │ │ │ ├── match_bindings.cpp │ │ │ ├── publisher_bindings.cpp │ │ │ ├── session_bindings.cpp │ │ │ ├── subscriber_bindings.cpp │ │ │ └── topic_bindings.cpp │ │ ├── src │ │ │ ├── publisher.cpp │ │ │ ├── session.cpp │ │ │ └── subscriber.cpp │ │ └── tests │ │ │ ├── CMakeLists.txt │ │ │ └── tests.cpp │ ├── log │ │ ├── CMakeLists.txt │ │ ├── README.md │ │ ├── examples │ │ │ ├── CMakeLists.txt │ │ │ ├── custom_sink_example.cpp │ │ │ ├── example.cpp │ │ │ ├── spdlog-1.15.2 │ │ │ │ ├── INSTALL │ │ │ │ ├── LICENSE │ │ │ │ ├── README.md │ │ │ │ └── include │ │ │ │ │ └── spdlog │ │ │ │ │ ├── async.h │ │ │ │ │ ├── async_logger-inl.h │ │ │ │ │ ├── async_logger.h │ │ │ │ │ ├── cfg │ │ │ │ │ ├── argv.h │ │ │ │ │ ├── env.h │ │ │ │ │ ├── helpers-inl.h │ │ │ │ │ └── helpers.h │ │ │ │ │ ├── common-inl.h │ │ │ │ │ ├── common.h │ │ │ │ │ ├── details │ │ │ │ │ ├── backtracer-inl.h │ │ │ │ │ ├── backtracer.h │ │ │ │ │ ├── circular_q.h │ │ │ │ │ ├── console_globals.h │ │ │ │ │ ├── file_helper-inl.h │ │ │ │ │ ├── file_helper.h │ │ │ │ │ ├── fmt_helper.h │ │ │ │ │ ├── log_msg-inl.h │ │ │ │ │ ├── log_msg.h │ │ │ │ │ ├── log_msg_buffer-inl.h │ │ │ │ │ ├── log_msg_buffer.h │ │ │ │ │ ├── mpmc_blocking_q.h │ │ │ │ │ ├── null_mutex.h │ │ │ │ │ ├── os-inl.h │ │ │ │ │ ├── os.h │ │ │ │ │ ├── periodic_worker-inl.h │ │ │ │ │ ├── periodic_worker.h │ │ │ │ │ ├── registry-inl.h │ │ │ │ │ ├── registry.h │ │ │ │ │ ├── synchronous_factory.h │ │ │ │ │ ├── tcp_client-windows.h │ │ │ │ │ ├── tcp_client.h │ │ │ │ │ ├── thread_pool-inl.h │ │ │ │ │ ├── thread_pool.h │ │ │ │ │ ├── udp_client-windows.h │ │ │ │ │ ├── udp_client.h │ │ │ │ │ └── windows_include.h │ │ │ │ │ ├── fmt │ │ │ │ │ ├── bin_to_hex.h │ │ │ │ │ ├── bundled │ │ │ │ │ │ ├── args.h │ │ │ │ │ │ ├── base.h │ │ │ │ │ │ ├── chrono.h │ │ │ │ │ │ ├── color.h │ │ │ │ │ │ ├── compile.h │ │ │ │ │ │ ├── core.h │ │ │ │ │ │ ├── fmt.license.rst │ │ │ │ │ │ ├── format-inl.h │ │ │ │ │ │ ├── format.h │ │ │ │ │ │ ├── os.h │ │ │ │ │ │ ├── ostream.h │ │ │ │ │ │ ├── printf.h │ │ │ │ │ │ ├── ranges.h │ │ │ │ │ │ ├── std.h │ │ │ │ │ │ └── xchar.h │ │ │ │ │ ├── chrono.h │ │ │ │ │ ├── compile.h │ │ │ │ │ ├── fmt.h │ │ │ │ │ ├── ostr.h │ │ │ │ │ ├── ranges.h │ │ │ │ │ ├── std.h │ │ │ │ │ └── xchar.h │ │ │ │ │ ├── formatter.h │ │ │ │ │ ├── fwd.h │ │ │ │ │ ├── logger-inl.h │ │ │ │ │ ├── logger.h │ │ │ │ │ ├── mdc.h │ │ │ │ │ ├── pattern_formatter-inl.h │ │ │ │ │ ├── pattern_formatter.h │ │ │ │ │ ├── sinks │ │ │ │ │ ├── android_sink.h │ │ │ │ │ ├── ansicolor_sink-inl.h │ │ │ │ │ ├── ansicolor_sink.h │ │ │ │ │ ├── base_sink-inl.h │ │ │ │ │ ├── base_sink.h │ │ │ │ │ ├── basic_file_sink-inl.h │ │ │ │ │ ├── basic_file_sink.h │ │ │ │ │ ├── callback_sink.h │ │ │ │ │ ├── daily_file_sink.h │ │ │ │ │ ├── dist_sink.h │ │ │ │ │ ├── dup_filter_sink.h │ │ │ │ │ ├── hourly_file_sink.h │ │ │ │ │ ├── kafka_sink.h │ │ │ │ │ ├── mongo_sink.h │ │ │ │ │ ├── msvc_sink.h │ │ │ │ │ ├── null_sink.h │ │ │ │ │ ├── ostream_sink.h │ │ │ │ │ ├── qt_sinks.h │ │ │ │ │ ├── ringbuffer_sink.h │ │ │ │ │ ├── rotating_file_sink-inl.h │ │ │ │ │ ├── rotating_file_sink.h │ │ │ │ │ ├── sink-inl.h │ │ │ │ │ ├── sink.h │ │ │ │ │ ├── stdout_color_sinks-inl.h │ │ │ │ │ ├── stdout_color_sinks.h │ │ │ │ │ ├── stdout_sinks-inl.h │ │ │ │ │ ├── stdout_sinks.h │ │ │ │ │ ├── syslog_sink.h │ │ │ │ │ ├── systemd_sink.h │ │ │ │ │ ├── tcp_sink.h │ │ │ │ │ ├── udp_sink.h │ │ │ │ │ ├── win_eventlog_sink.h │ │ │ │ │ ├── wincolor_sink-inl.h │ │ │ │ │ └── wincolor_sink.h │ │ │ │ │ ├── spdlog-inl.h │ │ │ │ │ ├── spdlog.h │ │ │ │ │ ├── stopwatch.h │ │ │ │ │ ├── tweakme.h │ │ │ │ │ └── version.h │ │ │ └── spdlog_bench.cpp │ │ ├── include │ │ │ └── grape │ │ │ │ └── log │ │ │ │ ├── config.h │ │ │ │ ├── formatters │ │ │ │ └── default_formatter.h │ │ │ │ ├── logger.h │ │ │ │ ├── record.h │ │ │ │ ├── severity.h │ │ │ │ ├── sinks │ │ │ │ ├── console_sink.h │ │ │ │ ├── file_sink.h │ │ │ │ └── sink.h │ │ │ │ └── syslog.h │ │ ├── src │ │ │ ├── logger.cpp │ │ │ └── syslog.cpp │ │ └── tests │ │ │ ├── CMakeLists.txt │ │ │ └── tests.cpp │ ├── realtime │ │ ├── CMakeLists.txt │ │ ├── README.md │ │ ├── docs │ │ │ └── media │ │ │ │ ├── 2020-10-26-john-ogness-rt-checklist.pdf │ │ │ │ ├── 2023-11-29-ubuntu-rtl-whitepaper.pdf │ │ │ │ ├── rt-application.dia │ │ │ │ └── rt-application.png │ │ ├── examples │ │ │ ├── CMakeLists.txt │ │ │ ├── error_example.cpp │ │ │ ├── fifo_bench.cpp │ │ │ ├── fifo_example.cpp │ │ │ ├── mpscq_bench.cpp │ │ │ ├── mpscq_example.cpp │ │ │ ├── schedule_example.cpp │ │ │ ├── string_example.cpp │ │ │ └── thread_example.cpp │ │ ├── include │ │ │ └── grape │ │ │ │ └── realtime │ │ │ │ ├── error.h │ │ │ │ ├── fifo_buffer.h │ │ │ │ ├── fixed_string.h │ │ │ │ ├── mpsc_queue.h │ │ │ │ ├── mutex.h │ │ │ │ ├── schedule.h │ │ │ │ └── thread.h │ │ ├── src │ │ │ └── schedule.cpp │ │ └── tests │ │ │ ├── CMakeLists.txt │ │ │ ├── fifo_buffer_tests.cpp │ │ │ ├── mpscq_tests.cpp │ │ │ ├── mutex_tests.cpp │ │ │ └── string_tests.cpp │ ├── script │ │ ├── CMakeLists.txt │ │ ├── README.md │ │ ├── examples │ │ │ ├── CMakeLists.txt │ │ │ ├── config_array_example.cpp │ │ │ └── config_example.cpp │ │ ├── include │ │ │ └── grape │ │ │ │ └── script │ │ │ │ └── script.h │ │ ├── src │ │ │ └── script.cpp │ │ ├── tests │ │ │ ├── CMakeLists.txt │ │ │ └── tests.cpp │ │ └── third_party │ │ │ ├── CMakeLists.txt │ │ │ ├── README.md │ │ │ └── lua-5.4.7 │ │ │ ├── Makefile │ │ │ ├── README │ │ │ ├── doc │ │ │ ├── OSIApproved_100X125.png │ │ │ ├── contents.html │ │ │ ├── index.css │ │ │ ├── logo.gif │ │ │ ├── lua.1 │ │ │ ├── lua.css │ │ │ ├── luac.1 │ │ │ ├── manual.css │ │ │ ├── manual.html │ │ │ └── readme.html │ │ │ └── src │ │ │ ├── Makefile │ │ │ ├── lapi.c │ │ │ ├── lapi.h │ │ │ ├── lauxlib.c │ │ │ ├── lauxlib.h │ │ │ ├── lbaselib.c │ │ │ ├── lcode.c │ │ │ ├── lcode.h │ │ │ ├── lcorolib.c │ │ │ ├── lctype.c │ │ │ ├── lctype.h │ │ │ ├── ldblib.c │ │ │ ├── ldebug.c │ │ │ ├── ldebug.h │ │ │ ├── ldo.c │ │ │ ├── ldo.h │ │ │ ├── ldump.c │ │ │ ├── lfunc.c │ │ │ ├── lfunc.h │ │ │ ├── lgc.c │ │ │ ├── lgc.h │ │ │ ├── linit.c │ │ │ ├── liolib.c │ │ │ ├── ljumptab.h │ │ │ ├── llex.c │ │ │ ├── llex.h │ │ │ ├── llimits.h │ │ │ ├── lmathlib.c │ │ │ ├── lmem.c │ │ │ ├── lmem.h │ │ │ ├── loadlib.c │ │ │ ├── lobject.c │ │ │ ├── lobject.h │ │ │ ├── lopcodes.c │ │ │ ├── lopcodes.h │ │ │ ├── lopnames.h │ │ │ ├── loslib.c │ │ │ ├── lparser.c │ │ │ ├── lparser.h │ │ │ ├── lprefix.h │ │ │ ├── lstate.c │ │ │ ├── lstate.h │ │ │ ├── lstring.c │ │ │ ├── lstring.h │ │ │ ├── lstrlib.c │ │ │ ├── ltable.c │ │ │ ├── ltable.h │ │ │ ├── ltablib.c │ │ │ ├── ltm.c │ │ │ ├── ltm.h │ │ │ ├── lua.c │ │ │ ├── lua.h │ │ │ ├── lua.hpp │ │ │ ├── luac.c │ │ │ ├── luaconf.h │ │ │ ├── lualib.h │ │ │ ├── lundump.c │ │ │ ├── lundump.h │ │ │ ├── lutf8lib.c │ │ │ ├── lvm.c │ │ │ ├── lvm.h │ │ │ ├── lzio.c │ │ │ └── lzio.h │ ├── serdes │ │ ├── CMakeLists.txt │ │ ├── README.md │ │ ├── docs │ │ │ └── benchmarking │ │ │ │ ├── CMakeLists.txt │ │ │ │ ├── bench.cpp │ │ │ │ └── benchmarking.md │ │ ├── examples │ │ │ ├── CMakeLists.txt │ │ │ ├── advanced_example.cpp │ │ │ ├── advanced_example.h │ │ │ ├── bench.cpp │ │ │ ├── deserialize_example.py │ │ │ └── example.cpp │ │ ├── include │ │ │ └── grape │ │ │ │ └── serdes │ │ │ │ ├── concepts.h │ │ │ │ ├── serdes.h │ │ │ │ └── stream.h │ │ └── tests │ │ │ ├── CMakeLists.txt │ │ │ ├── serdes_tests.cpp │ │ │ └── stream_tests.cpp │ └── utils │ │ ├── CMakeLists.txt │ │ ├── README.md │ │ ├── apps │ │ ├── CMakeLists.txt │ │ └── show_version.cpp │ │ ├── examples │ │ ├── CMakeLists.txt │ │ ├── enums_example.cpp │ │ └── usage_example.cpp │ │ ├── include │ │ └── grape │ │ │ └── utils │ │ │ ├── detail │ │ │ └── enums_detail.h │ │ │ ├── enums.h │ │ │ ├── file_system.h │ │ │ ├── ip.h │ │ │ ├── stacktrace.h │ │ │ ├── utils.h │ │ │ └── version.h │ │ ├── src │ │ ├── file_system.cpp │ │ ├── ip.cpp │ │ ├── stacktrace.cpp │ │ ├── utils.cpp │ │ ├── version.cpp │ │ └── version.in │ │ └── tests │ │ ├── CMakeLists.txt │ │ ├── enum_tests.cpp │ │ ├── file_system_tests.cpp │ │ ├── ip_tests.cpp │ │ └── utils_tests.cpp └── probe │ ├── controller │ ├── CMakeLists.txt │ ├── README.md │ ├── docs │ │ └── requirements.md │ ├── examples │ │ ├── CMakeLists.txt │ │ └── example.cpp │ ├── include │ │ └── grape │ │ │ └── probe │ │ │ ├── controller.h │ │ │ ├── signal.h │ │ │ └── type_id.h │ ├── src │ │ └── controller.cpp │ └── tests │ │ ├── CMakeLists.txt │ │ └── tests.cpp │ └── monitor │ ├── CMakeLists.txt │ ├── README.md │ ├── examples │ ├── CMakeLists.txt │ └── example.cpp │ ├── include │ └── grape │ │ └── probe │ │ └── monitor.h │ ├── src │ └── monitor.cpp │ └── third_party │ ├── CMakeLists.txt │ ├── README.md │ ├── imgui │ ├── LICENSE.txt │ ├── backends │ │ ├── imgui_impl_sdl3.cpp │ │ ├── imgui_impl_sdl3.h │ │ ├── imgui_impl_sdlrenderer3.cpp │ │ └── imgui_impl_sdlrenderer3.h │ ├── examples │ │ └── demo.cpp │ ├── imconfig.h │ ├── imgui.cpp │ ├── imgui.h │ ├── imgui_demo.cpp │ ├── imgui_draw.cpp │ ├── imgui_internal.h │ ├── imgui_tables.cpp │ ├── imgui_widgets.cpp │ ├── imstb_rectpack.h │ ├── imstb_textedit.h │ ├── imstb_truetype.h │ └── misc │ │ └── cpp │ │ ├── README.txt │ │ ├── imgui_stdlib.cpp │ │ └── imgui_stdlib.h │ └── implot │ ├── LICENSE │ ├── README.md │ ├── TODO.md │ ├── examples │ ├── implot_demo_main.cpp │ └── implot_example.cpp │ ├── implot.cpp │ ├── implot.h │ ├── implot_demo.cpp │ ├── implot_internal.h │ └── implot_items.cpp └── toolchains ├── install_base.sh ├── install_cmake.sh ├── install_gcc.sh ├── install_llvm.sh ├── toolchain_clang.cmake ├── toolchain_clang_aarch64.cmake └── toolchain_gcc_aarch64.cmake /.gitattributes: -------------------------------------------------------------------------------- 1 | *.pdf filter=lfs diff=lfs merge=lfs -text 2 | *.png filter=lfs diff=lfs merge=lfs -text 3 | *.dia filter=lfs diff=lfs merge=lfs -text 4 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Development Environment:** 27 | - GRAPE: 28 | - OS: 29 | - Compiler: 30 | - CMake: 31 | 32 | **Additional context** 33 | Add any other context about the problem here. 34 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ## Description 2 | 3 | Please include a summary of the change and which issue is fixed. 4 | 5 | ## Checklist 6 | 7 | - [ ] My work follows [coding guidelines](https://github.com/cvilas/guidance/blob/main/process/developer_guide.md) 8 | - [ ] I have added example programs, where appropriate, to clarify usage 9 | - [ ] I have added unit tests, where appropriate, to test newly added functionality 10 | - [ ] My commits are rebased over `main` branch and commit messages are [formatted correctly](https://github.com/cvilas/guidance/blob/main/process/commit_messages.md) 11 | 12 | ## References 13 | (Related issue #s) -------------------------------------------------------------------------------- /.github/workflows/tag.yml: -------------------------------------------------------------------------------- 1 | # Tags on commit to main branch 2 | # - Checks out the repository. 3 | # - Determines the latest tag in the repository. 4 | # - Creates a new tag from the latest tag, and increments patch version by 1. 5 | # - Pushes the new tag to the remote repository. 6 | 7 | name: Tag on Merge 8 | 9 | on: 10 | push: 11 | branches: 12 | - main 13 | 14 | jobs: 15 | tag: 16 | runs-on: ubuntu-latest 17 | 18 | steps: 19 | - name: Checkout repository 20 | uses: actions/checkout@v4 21 | with: 22 | fetch-depth: 0 23 | 24 | - name: Determine latest tag 25 | id: latest_tag 26 | run: | 27 | latest_tag=$(git describe --tags --abbrev=0) 28 | echo "::set-output name=tag::$latest_tag" 29 | 30 | - name: Determine incremented tag 31 | id: incremented_tag 32 | run: | 33 | IFS='.' read -r -a version_parts <<< "${{ steps.latest_tag.outputs.tag }}" 34 | major="${version_parts[0]}" 35 | minor="${version_parts[1]}" 36 | patch="${version_parts[2]}" 37 | patch=$((patch + 1)) 38 | incremented_tag="${major}.${minor}.${patch}" 39 | echo "::set-output name=tag::$incremented_tag" 40 | 41 | - name: Create and push tag 42 | run: | 43 | git tag "${{ steps.incremented_tag.outputs.tag }}" 44 | git push origin "${{ steps.incremented_tag.outputs.tag }}" 45 | 46 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /build/ 2 | .cache/ 3 | .idea/ 4 | .vscode/ 5 | .DS_Store 6 | **/CMakeLists.txt.user 7 | *-workspace 8 | modules/common/utils/src/version_impl.h 9 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # ================================================================================================= 2 | # Copyright (C) 2023 GRAPE Contributors 3 | # ================================================================================================= 4 | 5 | cmake_minimum_required(VERSION 3.31.6) 6 | project(grape LANGUAGES CXX C) 7 | 8 | set(CMAKE_CXX_STANDARD 23) 9 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 10 | set(CMAKE_CXX_EXTENSIONS OFF) 11 | 12 | set(CMAKE_POSITION_INDEPENDENT_CODE ON) 13 | set(CMAKE_UNITY_BUILD ON) 14 | 15 | # Integrate the Grape Build System to setup the project 16 | include(${CMAKE_SOURCE_DIR}/external/third_party_versions.cmake) 17 | include(${CMAKE_SOURCE_DIR}/gbs/gbs.cmake) 18 | -------------------------------------------------------------------------------- /CMakePresets.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 7, 3 | "cmakeMinimumRequired": { "major": 3, "minor": 28, "patch": 0 }, 4 | "configurePresets": [ 5 | { 6 | "name": "base", 7 | "hidden": true, 8 | "description": "Common configuration settings [hidden]", 9 | "generator": "Ninja", 10 | "binaryDir": "${sourceDir}/build/${presetName}", 11 | "cacheVariables": { 12 | "BUILD_MODULES": "all", 13 | "CMAKE_BUILD_TYPE": "RelWithDebInfo", 14 | "CMAKE_INSTALL_PREFIX": "/opt/${sourceDirName}", 15 | "PACKAGE_SUFFIX": "${presetName}" 16 | } 17 | }, 18 | { 19 | "name": "clang", 20 | "inherits": "base", 21 | "description": "Configure all modules with clang toolchain", 22 | "toolchainFile": "${sourceDir}/toolchains/toolchain_clang.cmake" 23 | }, 24 | { 25 | "name": "native", 26 | "inherits": "base", 27 | "description": "Configure all modules with native toolchain", 28 | "generator": "Unix Makefiles" 29 | } 30 | ] 31 | } 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 GRAPE Contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GRAPE- Graphical Real-time Application Prototyping Environment 2 | 3 | [![MIT License](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE) 4 | [![Contributor Covenant](https://img.shields.io/badge/Contributor%20Covenant-2.1-4baaaa.svg)](./docs/CODE_OF_CONDUCT.md) 5 | 6 | ## What is Grape? 7 | 8 | - A monorepo that implements building blocks for highly distributed robotic systems. Specifically, GRAPE can be used to build systems consisting of hundreds of process nodes running on hundreds of compute units (Linux X86_64/Aarch64) across a LAN. 9 | - A playground to evaluate modern C++ techniques in writing simple, expressive, and performant code for industrial applications 10 | - A hobby project that demonstrates the application of systems engineering [guidelines](https://github.com/cvilas/guidance) that I developed over decades in the industry as a technical and people leader in industrial robotics. ([Author's profile](https://cvilas.github.io/)) 11 | 12 | Selected features: 13 | 14 | - A [modular build system](./gbs/README.md) 15 | - A fast [logging library](./modules/common/log/README.md) 16 | - A fast [serialisation library](./modules/common/serdes/README.md) 17 | - A powerful [configuration and scripting system](./modules/common/script/README.md) 18 | - Facilities for low latency [realtime systems](./modules/common/realtime/README.md) 19 | - A stubbornly strict [command line parser](./modules/common/conio/README.md) 20 | - A high performance [inter-process communication library](./modules/common/ipc/README.md) 21 | - An [application development framework](./docs/howto/write_applications.md) 22 | - Support for the latest C++ standard, compilers and tooling 23 | - Focus on [Raspberry Pi](https://www.raspberrypi.com/) as the target embedded hardware platform 24 | 25 | ## Getting Started 26 | 27 | - [Installation](docs/01_install.md) 28 | - [Roadmap](docs/02_roadmap.md) 29 | - [Developer's Guide](https://github.com/cvilas/guidance/blob/main/process/developer_guide.md) -------------------------------------------------------------------------------- /deprecated/ipc2/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # ================================================================================================= 2 | # Copyright (C) 2023 GRAPE Contributors 3 | # ================================================================================================= 4 | 5 | declare_module(NAME ipc2 DEPENDS_ON_MODULES "base" DEPENDS_ON_EXTERNAL_PROJECTS "zenohc;zenohcxx") 6 | 7 | find_package(zenohc ${ZENOHC_VERSION_REQUIRED} REQUIRED) 8 | find_package(zenohcxx ${ZENOHCXX_VERSION_REQUIRED} REQUIRED) 9 | 10 | # library sources 11 | set(SOURCES 12 | src/common.cpp 13 | src/ipc_zenoh.h 14 | src/session.cpp 15 | src/publisher.cpp 16 | src/subscriber.cpp 17 | include/grape/ipc2/common.h 18 | include/grape/ipc2/session.h 19 | include/grape/ipc2/topic.h 20 | include/grape/ipc2/publisher.h 21 | include/grape/ipc2/subscriber.h 22 | README.md) 23 | 24 | # library target 25 | define_module_library( 26 | NAME ipc2 27 | PUBLIC_LINK_LIBS grape::base 28 | PRIVATE_LINK_LIBS "" 29 | SOURCES ${SOURCES} 30 | PUBLIC_INCLUDE_PATHS $ 31 | $ 32 | PRIVATE_INCLUDE_PATHS "" 33 | SYSTEM_PRIVATE_INCLUDE_PATHS "" 34 | PUBLIC_LINK_LIBS zenohc::lib) 35 | 36 | # Subprojects 37 | add_subdirectory(examples) 38 | add_subdirectory(tests) 39 | -------------------------------------------------------------------------------- /deprecated/ipc2/docs/media/sample_arch.dia: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:a7b6cc31bbdbef6af2740e6c77e84d4e0fe6e7abaedb696ef5f1cdf09839db8c 3 | size 5237 4 | -------------------------------------------------------------------------------- /deprecated/ipc2/docs/media/sample_arch.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:1eab8978d32bda4c1f2d26587c7978f31b328ef32725b47992bb43c9ae4206a0 3 | size 41437 4 | -------------------------------------------------------------------------------- /deprecated/ipc2/examples/basic_example_constants.h: -------------------------------------------------------------------------------- 1 | //================================================================================================= 2 | // Copyright (C) 2024 GRAPE Contributors 3 | //================================================================================================= 4 | 5 | #pragma once 6 | 7 | namespace grape::ipc2::ex { 8 | static constexpr auto DEFAULT_TOPIC = "grape/ipc2/example/basic"; 9 | } // namespace grape::ipc2::ex 10 | -------------------------------------------------------------------------------- /deprecated/ipc2/examples/client_example_constants.h: -------------------------------------------------------------------------------- 1 | //================================================================================================= 2 | // Copyright (C) 2024 GRAPE Contributors 3 | //================================================================================================= 4 | 5 | #pragma once 6 | 7 | #include 8 | 9 | namespace grape::ipc2::ex::client { 10 | static constexpr auto TOPIC = "grape/ipc2/example/routed"; 11 | static constexpr auto DEFAULT_ROUTER = "tcp/127.0.0.1:7447"; 12 | } // namespace grape::ipc2::ex::client 13 | -------------------------------------------------------------------------------- /deprecated/ipc2/examples/info.cpp: -------------------------------------------------------------------------------- 1 | //================================================================================================= 2 | // Copyright (C) 2023 GRAPE Contributors 3 | //================================================================================================= 4 | 5 | #include 6 | 7 | #include "grape/conio/program_options.h" 8 | #include "grape/exception.h" 9 | #include "grape/ipc2/session.h" 10 | 11 | //================================================================================================= 12 | // Example program gets unique IDs of endpoints the Zenoh session knows about. 13 | // 14 | // Derived from: https://github.com/eclipse-zenoh/zenoh-cpp/blob/main/examples/universal/z_info.cxx 15 | //================================================================================================= 16 | 17 | //================================================================================================= 18 | auto main(int argc, const char* argv[]) -> int { 19 | try { 20 | const auto maybe_args = grape::conio::ProgramDescription( 21 | "Prints unique IDs of all endpoints this session is aware of") 22 | .parse(argc, argv); 23 | if (not maybe_args) { 24 | grape::panic(toString(maybe_args.error())); 25 | } 26 | std::println("Opening session..."); 27 | auto session = grape::ipc2::Session({}); 28 | 29 | const auto print_id = [](const grape::ipc2::UUID& id) { 30 | std::println("\t{}", grape::ipc2::toString(id)); 31 | }; 32 | std::println("Own id:"); 33 | print_id(session.id()); 34 | 35 | std::println("Router ids:"); 36 | for (const auto id : session.routers()) { 37 | print_id(id); 38 | } 39 | 40 | std::println("Peer ids:"); 41 | for (const auto id : session.peers()) { 42 | print_id(id); 43 | } 44 | return EXIT_SUCCESS; 45 | } catch (...) { 46 | grape::Exception::print(); 47 | return EXIT_FAILURE; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /deprecated/ipc2/examples/ping_pong_constants.h: -------------------------------------------------------------------------------- 1 | //================================================================================================= 2 | // Copyright (C) 2023 GRAPE Contributors 3 | //================================================================================================= 4 | 5 | #pragma once 6 | 7 | namespace grape::ipc2::ex::ping { 8 | static constexpr auto PING_TOPIC = "grape/ipc2/example/ping"; 9 | static constexpr auto PONG_TOPIC = "grape/ipc2/example/pong"; 10 | } // namespace grape::ipc2::ex::ping 11 | -------------------------------------------------------------------------------- /deprecated/ipc2/examples/throughput_constants.h: -------------------------------------------------------------------------------- 1 | //================================================================================================= 2 | // Copyright (C) 2023 GRAPE Contributors 3 | //================================================================================================= 4 | 5 | #pragma once 6 | 7 | namespace grape::ipc2::ex::throughput { 8 | static constexpr auto TOPIC = "grape/ipc2/example/throughput"; 9 | } 10 | -------------------------------------------------------------------------------- /deprecated/ipc2/include/grape/ipc2/publisher.h: -------------------------------------------------------------------------------- 1 | //================================================================================================= 2 | // Copyright (C) 2024 GRAPE Contributors 3 | //================================================================================================= 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | 10 | namespace zenoh { 11 | class Publisher; 12 | } // namespace zenoh 13 | 14 | namespace grape::ipc2 { 15 | 16 | class Session; 17 | 18 | //================================================================================================= 19 | /// Publishers post topic data. Created by Session. See also Topic. 20 | class Publisher { 21 | public: 22 | void publish(std::span bytes); 23 | void publish(std::span bytes); 24 | 25 | ~Publisher(); 26 | Publisher(const Publisher&) = delete; 27 | auto operator=(const Publisher&) = delete; 28 | Publisher(Publisher&&) noexcept = default; 29 | auto operator=(Publisher&&) noexcept = delete; 30 | 31 | private: 32 | friend class Session; 33 | explicit Publisher(std::unique_ptr zp); 34 | std::unique_ptr impl_; 35 | }; 36 | 37 | } // namespace grape::ipc2 38 | -------------------------------------------------------------------------------- /deprecated/ipc2/include/grape/ipc2/subscriber.h: -------------------------------------------------------------------------------- 1 | //================================================================================================= 2 | // Copyright (C) 2024 GRAPE Contributors 3 | //================================================================================================= 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | namespace zenoh { 12 | class Session; 13 | template 14 | class Subscriber; 15 | } // namespace zenoh 16 | 17 | namespace grape::ipc2 { 18 | 19 | class Session; 20 | 21 | //------------------------------------------------------------------------------------------------- 22 | using DataCallback = std::function)>; 23 | 24 | //================================================================================================= 25 | /// Subscribers reciver topic data. Created by Session. See also Topic. 26 | class Subscriber { 27 | public: 28 | ~Subscriber(); 29 | Subscriber(const Subscriber&) = delete; 30 | auto operator=(const Subscriber&) = delete; 31 | Subscriber(Subscriber&&) noexcept = default; 32 | auto operator=(Subscriber&&) noexcept = delete; 33 | 34 | private: 35 | friend class Session; 36 | explicit Subscriber(std::unique_ptr> zs); 37 | std::unique_ptr> impl_; 38 | }; 39 | 40 | } // namespace grape::ipc2 41 | -------------------------------------------------------------------------------- /deprecated/ipc2/include/grape/ipc2/topic.h: -------------------------------------------------------------------------------- 1 | //================================================================================================= 2 | // Copyright (C) 2024 GRAPE Contributors 3 | //================================================================================================= 4 | 5 | #pragma once 6 | 7 | #include 8 | 9 | namespace grape::ipc2 { 10 | 11 | //------------------------------------------------------------------------------------------------- 12 | struct Topic { 13 | std::string key; 14 | }; 15 | 16 | } // namespace grape::ipc2 17 | -------------------------------------------------------------------------------- /deprecated/ipc2/src/ipc_zenoh.h: -------------------------------------------------------------------------------- 1 | //================================================================================================= 2 | // Copyright (C) 2023 GRAPE Contributors 3 | //================================================================================================= 4 | 5 | #pragma once 6 | #define ZENOHCXX_ZENOHC // Use the C backend for Zenoh 7 | 8 | #include 9 | #include 10 | 11 | namespace grape::ipc2 { 12 | 13 | //------------------------------------------------------------------------------------------------- 14 | inline auto toString(const zenoh::ZResult& code) -> std::string_view { 15 | static const auto zenoh_error_strings = std::unordered_map{ 16 | { Z_OK, "OK" }, // 17 | { Z_EINVAL, "Invalid data or argument" }, // 18 | { Z_EPARSE, "Parsing error" }, // 19 | { Z_EIO, "I/O error" }, // 20 | { Z_ENETWORK, "Network/connection failure" }, // 21 | { Z_ENULL, "Null value" }, // 22 | { Z_EUNAVAILABLE, "Unavailable" }, // 23 | { Z_EDESERIALIZE, "Deserialisation error" }, // 24 | { Z_ESESSION_CLOSED, "Session closed" }, // 25 | { Z_EUTF8, "UTF8 error" }, // 26 | { Z_EBUSY_MUTEX, "Mutex busy" }, // 27 | { Z_EINVAL_MUTEX, "Mutex invalid" }, // 28 | { Z_EAGAIN_MUTEX, "Mutex unavailable (try again)" }, // 29 | { Z_EPOISON_MUTEX, "Mutex poisoned" } // 30 | }; 31 | return zenoh_error_strings.at(code); 32 | } 33 | } // namespace grape::ipc2 34 | -------------------------------------------------------------------------------- /deprecated/ipc2/src/publisher.cpp: -------------------------------------------------------------------------------- 1 | //================================================================================================= 2 | // Copyright (C) 2024 GRAPE Contributors 3 | //================================================================================================= 4 | 5 | #include "grape/ipc2/publisher.h" 6 | 7 | #include "ipc_zenoh.h" // should be included before zenoh headers 8 | 9 | namespace grape::ipc2 { 10 | //------------------------------------------------------------------------------------------------- 11 | Publisher::~Publisher() = default; 12 | 13 | //------------------------------------------------------------------------------------------------- 14 | void Publisher::publish(std::span bytes) { 15 | const auto bytes_view = std::string_view( 16 | // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) 17 | reinterpret_cast(bytes.data()), // 18 | bytes.size_bytes()); 19 | impl_->put(bytes_view); 20 | } 21 | 22 | //------------------------------------------------------------------------------------------------- 23 | void Publisher::publish(std::span bytes) { 24 | impl_->put(std::string_view{ bytes.data(), bytes.size() }); 25 | } 26 | 27 | //------------------------------------------------------------------------------------------------- 28 | Publisher::Publisher(std::unique_ptr zp) : impl_(std::move(zp)) { 29 | } 30 | } // namespace grape::ipc2 31 | -------------------------------------------------------------------------------- /deprecated/ipc2/src/subscriber.cpp: -------------------------------------------------------------------------------- 1 | //================================================================================================= 2 | // Copyright (C) 2024 GRAPE Contributors 3 | //================================================================================================= 4 | 5 | #include "grape/ipc2/subscriber.h" 6 | 7 | #include "ipc_zenoh.h" // should be included before zenoh headers 8 | 9 | namespace {} 10 | 11 | namespace grape::ipc2 { 12 | 13 | //------------------------------------------------------------------------------------------------- 14 | Subscriber::~Subscriber() = default; 15 | 16 | //------------------------------------------------------------------------------------------------- 17 | Subscriber::Subscriber(std::unique_ptr> zs) : impl_(std::move(zs)) { 18 | } 19 | } // namespace grape::ipc2 20 | -------------------------------------------------------------------------------- /deprecated/ipc2/tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # ================================================================================================= 2 | # Copyright (C) 2023 GRAPE Contributors 3 | # ================================================================================================= 4 | 5 | define_module_test( 6 | NAME tests 7 | SOURCES tests.cpp 8 | PUBLIC_INCLUDE_PATHS $ 9 | PUBLIC_LINK_LIBS "") 10 | -------------------------------------------------------------------------------- /deprecated/ipc2/tests/tests.cpp: -------------------------------------------------------------------------------- 1 | //================================================================================================= 2 | // Copyright (C) 2023 GRAPE Contributors 3 | //================================================================================================= 4 | 5 | #include "catch2/catch_test_macros.hpp" 6 | 7 | namespace { 8 | 9 | TEST_CASE("[example test]", "[ipc2]") { 10 | WARN("No IPC tests implemented"); 11 | } 12 | 13 | } // namespace 14 | -------------------------------------------------------------------------------- /docs/01_install.md: -------------------------------------------------------------------------------- 1 | # Installation 2 | 3 | ## Supported platforms 4 | 5 | OS | Architecture | Toolchain 6 | -----------------|-----------------|---------------- 7 | Ubuntu 24.04 LTS | Aarch64, X86_64 | CMake-4, clang-21/libc++, gcc-15/libstdc++ 8 | 9 | ## Setup development environment 10 | 11 | - Install base system utilities and development tools 12 | ```bash 13 | chmod +x ./toolchains/install_base.sh 14 | ./toolchains/install_base.sh 15 | ``` 16 | 17 | - Install CMake 18 | 19 | If the required version is available from repositories: 20 | ```bash 21 | chmod +x ./toolchains/install_cmake.sh 22 | ./toolchains/install_cmake.sh 23 | ``` 24 | Otherwise, [build from source](./howto/build_cmake.md) 25 | 26 | - Install LLVM toolchain 27 | 28 | ```bash 29 | chmod +x ./toolchains/install_llvm.sh 30 | ./toolchains/install_llvm.sh 31 | ``` 32 | 33 | - Install GCC toolchain 34 | 35 | If the required version is available from repositories: 36 | ```bash 37 | chmod +x ./toolchains/install_gcc.sh 38 | ./toolchains/install_gcc.sh 39 | ``` 40 | Otherwise, [build from source](./howto/build_gcc.md) 41 | 42 | ## Configure and build 43 | 44 | Using Clang toolchain: 45 | 46 | ```bash 47 | git clone git@github.com:cvilas/grape 48 | cmake --preset clang 49 | cmake --build build/clang --target all examples check 50 | ``` 51 | 52 | Using GCC: 53 | 54 | ```bash 55 | git clone git@github.com:cvilas/grape 56 | cmake --preset native 57 | cmake --build build/native --target all examples check 58 | ``` 59 | -------------------------------------------------------------------------------- /docs/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # GRAPE - Contribution Guide 2 | 3 | Firstly, thank you for even considering contributing to this project, which mostly exists to 4 | scratch the author's personal creative itches. I hope you found something useful to you here. 5 | 6 | Please raise an Issue if you must discuss anything related to this project. A discussion provides 7 | the opportunity to clarify the problem, the surrounding context, and potential approaches to a 8 | solution. This could be followed by a Pull Request if appropriate. 9 | 10 | Please follow the [code of conduct](./CODE_OF_CONDUCT.md) in all your interactions. -------------------------------------------------------------------------------- /docs/SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Reporting a Vulnerability 4 | 5 | If you discover a security vulnerability in this project, please get in touch with the author 6 | privately. Please avoid opening a public issue for security vulnerabilities. 7 | 8 | ## What to Include 9 | 10 | When reporting a vulnerability, please include: 11 | 12 | - Description of the vulnerability 13 | - Steps to reproduce 14 | - Affected versions 15 | - Any potential impact 16 | 17 | ## Response Time 18 | 19 | The authors shall aim to respond to security reports within 48 hours and provide a fix or 20 | mitigation within a reasonable timeframe based on severity. 21 | 22 | ## Security Best Practices 23 | 24 | This project follows standard C++ security practices including: 25 | 26 | - Input validation 27 | - Memory safety considerations 28 | - Avoiding common vulnerabilities (buffer overflows, etc.) 29 | 30 | Thank you for helping keep this project secure! -------------------------------------------------------------------------------- /docs/howto/build_cmake.md: -------------------------------------------------------------------------------- 1 | # How to build CMake from source 2 | 3 | ```bash 4 | sudo apt install libssl-dev 5 | 6 | # Choose verson. Note: Bleeding edge may break third party dependencies (CMake often deprecates 7 | # features in older versions). Choose wisely 8 | CMAKE_VERSION=4.0.2 9 | 10 | # Download and extract 11 | wget https://github.com/Kitware/CMake/releases/download/v$CMAKE_VERSION/cmake-$CMAKE_VERSION.tar.gz 12 | tar zxvf cmake-$CMAKE_VERSION.tar.gz 13 | cd cmake-$CMAKE_VERSION 14 | 15 | # Build (See README.rst) 16 | ./bootstrap && make && sudo make install 17 | 18 | # You might have to add the following to your shell configuration (~/.bashrc or ~/.zshrc) 19 | export PATH=/usr/local/bin:${PATH} 20 | export LD_LIBRARY_PATH=/usr/local/lib:/usr/local/lib64:${LD_LIBRARY_PATH} 21 | ``` -------------------------------------------------------------------------------- /docs/howto/build_gcc.md: -------------------------------------------------------------------------------- 1 | # How to build GCC from source 2 | 3 | ```bash 4 | GCC_VERSION=15.1.1 5 | 6 | # Download sources 7 | wget https://ftp.gnu.org/gnu/gcc/gcc-$GCC_VERSION/gcc-$GCC_VERSION.tar.xz 8 | tar xf gcc-$GCC_VERSION.tar.xz 9 | cd gcc-$GCC_VERSION 10 | ./contrib/download_prerequisites 11 | 12 | # Configure, build (many hours for Pi5/4GB), install 13 | cd .. 14 | mkdir gcc-build && cd gcc-build 15 | ../gcc-$GCC_VERSION/configure --enable-languages=c,c++,fortran --disable-multilib 16 | make 17 | sudo make install 18 | 19 | # Configure platform to prefer this new version of GCC 20 | PRIORITY=$((${GCC_VERSION%%.*} * 10)) 21 | sudo update-alternatives --remove-all gcc 22 | sudo update-alternatives --remove-all gfortran 23 | sudo update-alternatives --install /usr/bin/gfortran gfortran /usr/local/bin/gfortran $PRIORITY 24 | sudo update-alternatives --install /usr/bin/gcc gcc /usr/local/bin/gcc $PRIORITY \ 25 | --slave /usr/bin/g++ g++ /usr/local/bin/g++ \ 26 | --slave /usr/bin/gcov gcov /usr/local/bin/gcov 27 | 28 | # You might have to add the following to your shell configuration (~/.bashrc or ~/.zshrc) 29 | export PATH=/usr/local/bin:${PATH} 30 | export LD_LIBRARY_PATH=/usr/local/lib:/usr/local/lib64:${LD_LIBRARY_PATH} 31 | ``` 32 | -------------------------------------------------------------------------------- /docs/howto/media/microservice.dia: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:0e068a86a91a54b8236274544195fd7d13c57edacfc9f495603436f9c89841fe 3 | size 58639 4 | -------------------------------------------------------------------------------- /docs/howto/media/microservice.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:84b227db26f15e48a569d38e14a0c193d795a0e6c563f769113b5373b2a220f4 3 | size 16654 4 | -------------------------------------------------------------------------------- /docs/howto/profile_builds.md: -------------------------------------------------------------------------------- 1 | # How to profile builds 2 | 3 | To profile the build process and determine bottlenecks: 4 | 5 | * Configure to use `Ninja` as the build system generator 6 | * Build. The profiling information gets logged in `.ninja_log` in the build directory 7 | * Process `.ninja_log` into a json trace file using [`ninjatracing`](https://github.com/nico/ninjatracing) 8 | * View the trace file in [Perfetto](https://ui.perfetto.dev/) -------------------------------------------------------------------------------- /docs/howto/reduce_wifi_latency.md: -------------------------------------------------------------------------------- 1 | # How to reduce latency over WiFi 2 | 3 | Intel and Qualcomm Atheros WiFi modules included in most laptops support Dynamic Power Saving (DPS). When enabled (which is the default) the kernel puts the WiFi module to sleep if there is no network traffic for few milliseconds. This leads to data transport latency as high as 300ms over WiFi. To reduce average latency, turn off DPS. 4 | 5 | > Note that this may significantly reduce your battery life. 6 | 7 | - Turn off DPS (Replace `wlp0s20f3` with your WiFi interface) 8 | 9 | ```bash 10 | sudo iw dev wlp0s20f3 set power_save off 11 | ``` 12 | 13 | - Confirm 14 | 15 | ```bash 16 | sudo iw dev wlp0s20f3 get power_save 17 | ``` 18 | 19 | - Make it persistent across reboots 20 | - Open the file `/etc/NetworkManager/conf.d/default-wifi-powersave-on.conf` for editing. 21 | - Change `wifi.powersave=3` (default: power management on) to `2` (power management off): 22 | 23 | ```toml 24 | [connection] 25 | wifi.powersave = 2 26 | ``` 27 | 28 | - Restart `NetworkManager` 29 | 30 | ```bash 31 | systemctl restart NetworkManager 32 | ``` 33 | -------------------------------------------------------------------------------- /external/README.md: -------------------------------------------------------------------------------- 1 | # README - grape/external 2 | 3 | This directory defines an independent CMake project to configure and build external dependencies. 4 | Note that configuration is not shared with the main project in either direction, except those 5 | parameters that are passed manually across the two projects. 6 | -------------------------------------------------------------------------------- /external/sources/yaml_cpp_stdint.patch: -------------------------------------------------------------------------------- 1 | diff --git a/src/emitterutils.cpp b/src/emitterutils.cpp 2 | index 6cdf6de..dbd2590 100644 3 | --- a/src/emitterutils.cpp 4 | +++ b/src/emitterutils.cpp 5 | @@ -1,4 +1,5 @@ 6 | #include 7 | +#include 8 | #include 9 | #include 10 | 11 | -------------------------------------------------------------------------------- /external/third_party_versions.cmake: -------------------------------------------------------------------------------- 1 | # ================================================================================================= 2 | # Copyright (C) 2024 GRAPE Contributors 3 | # ================================================================================================= 4 | 5 | # List of all third-party dependency versions 6 | 7 | set(CATCH2_VERSION_REQUIRED 3.8.1) 8 | set(BENCHMARK_VERSION_REQUIRED 1.9.2) 9 | set(SDL3_VERSION_REQUIRED 3.2.12) 10 | set(YAML_CPP_VERSION_REQUIRED 0.8.0) 11 | set(ECAL_VERSION_REQUIRED 6.0.0) 12 | -------------------------------------------------------------------------------- /gbs/00_utilities.cmake: -------------------------------------------------------------------------------- 1 | # ================================================================================================= 2 | # Copyright (C) 2024 GRAPE Contributors 3 | # ================================================================================================= 4 | 5 | #================================================================================================== 6 | # Print all variables generated during configuration 7 | function(print_cmake_variables) 8 | get_cmake_property(variable_names VARIABLES) 9 | list (SORT variable_names) 10 | foreach (var ${variable_names}) 11 | message(STATUS "${var}=${${var}}") 12 | endforeach() 13 | endfunction() 14 | 15 | include(CheckCXXSourceCompiles) 16 | 17 | #================================================================================================== 18 | # Detect which standard library is in use 19 | # USING_LIBSTDCXX is set if libstdc++ is in use 20 | # USING_LIBCPP is set if libc++ is in use 21 | function(detect_cxx_stdlib) 22 | # Save the current compiler flags 23 | set(CMAKE_REQUIRED_FLAGS_SAVED ${CMAKE_REQUIRED_FLAGS}) 24 | 25 | # Test for libstdc++ 26 | set(CMAKE_REQUIRED_FLAGS "${CMAKE_CXX_FLAGS}") 27 | check_cxx_source_compiles(" 28 | #include 29 | #if !defined(__GLIBCXX__) 30 | #error Not using libstdc++ 31 | #endif 32 | int main() { return 0; } 33 | " USING_LIBSTDCXX) 34 | 35 | # Test for libc++ 36 | check_cxx_source_compiles(" 37 | #include 38 | #if !defined(_LIBCPP_VERSION) 39 | #error Not using libc++ 40 | #endif 41 | int main() { return 0; } 42 | " USING_LIBCPP) 43 | 44 | # Restore compiler flags 45 | set(CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS_SAVED}) 46 | 47 | # Set results in parent scope 48 | set(USING_LIBSTDCXX ${USING_LIBSTDCXX} PARENT_SCOPE) 49 | set(USING_LIBCPP ${USING_LIBCPP} PARENT_SCOPE) 50 | endfunction() -------------------------------------------------------------------------------- /gbs/06_packager_config.cmake: -------------------------------------------------------------------------------- 1 | # ================================================================================================= 2 | # Copyright (C) 2018 GRAPE Contributors 3 | # ================================================================================================= 4 | 5 | # Define packaging rules 6 | set(CPACK_PACKAGE_NAME ${PROJECT_NAME}) 7 | set(CPACK_PACKAGE_VENDOR "Vilas Kumar Chitrakaran") 8 | if(DEFINED PACKAGE_SUFFIX) 9 | set(CPACK_PACKAGE_NAME "${CPACK_PACKAGE_NAME}-${PACKAGE_SUFFIX}") 10 | endif() 11 | set(CPACK_PACKAGE_VERSION ${VERSION}) 12 | set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-${CMAKE_SYSTEM_NAME}-${CMAKE_SYSTEM_PROCESSOR}") 13 | set(CPACK_PACKAGE_DIRECTORY ${PROJECT_BINARY_DIR}/package) 14 | set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/LICENSE") 15 | 16 | set(CPACK_SET_DESTDIR ON) # ON: Create tmp staging area for packaging. Don't modify host filesystem 17 | set(CPACK_INSTALL_PREFIX "") 18 | 19 | set(CPACK_GENERATOR "TBZ2") 20 | 21 | include(CPack) 22 | 23 | # ================================================================================================== 24 | # Adds a custom target to build and package up all artifacts for deployment on `make pack` 25 | add_custom_target( 26 | pack 27 | COMMENT "Build and package all artifacts for deployment" 28 | COMMAND ${CMAKE_COMMAND} -E env cpack 29 | WORKING_DIRECTORY ${CMAKE_BINARY_DIR} 30 | DEPENDS all 31 | ) 32 | -------------------------------------------------------------------------------- /gbs/module_template/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # ================================================================================================= 2 | # Copyright (C) @year@ @project@ Contributors 3 | # ================================================================================================= 4 | 5 | declare_module( 6 | NAME @module@ 7 | DEPENDS_ON_MODULES "" 8 | DEPENDS_ON_EXTERNAL_PROJECTS "") 9 | 10 | # library sources 11 | set(SOURCES src/@module@.cpp README.md include/@project@/@module@/@module@.h) 12 | 13 | # library target 14 | define_module_library( 15 | NAME @module@ 16 | PUBLIC_LINK_LIBS "" 17 | PRIVATE_LINK_LIBS "" 18 | SOURCES ${SOURCES} 19 | PUBLIC_INCLUDE_PATHS $ 20 | $ 21 | PRIVATE_INCLUDE_PATHS "" 22 | SYSTEM_PRIVATE_INCLUDE_PATHS "") 23 | 24 | # Subprojects 25 | add_subdirectory(tests) 26 | add_subdirectory(examples) 27 | -------------------------------------------------------------------------------- /gbs/module_template/README.md: -------------------------------------------------------------------------------- 1 | # README: @module@ 2 | 3 | ## Brief 4 | 5 | @module@ provides .. 6 | 7 | ## Detailed description 8 | 9 | See documentation inline -------------------------------------------------------------------------------- /gbs/module_template/examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # ================================================================================================= 2 | # Copyright (C) @year@ @project@ Contributors 3 | # ================================================================================================= 4 | 5 | define_module_example( 6 | NAME example 7 | SOURCES example.cpp 8 | PUBLIC_INCLUDE_PATHS $ 9 | PUBLIC_LINK_LIBS "") 10 | -------------------------------------------------------------------------------- /gbs/module_template/examples/example.cpp: -------------------------------------------------------------------------------- 1 | //================================================================================================= 2 | // Copyright (C) @year@ @project@ Contributors 3 | //================================================================================================= 4 | 5 | #include "@project@/@module@/@module@.h" 6 | 7 | #include 8 | 9 | //================================================================================================= 10 | auto main(int argc, const char* argv[]) -> int { 11 | (void)argc; 12 | (void)argv; 13 | return EXIT_SUCCESS; 14 | } 15 | -------------------------------------------------------------------------------- /gbs/module_template/include/grape/@module@/@module@.h: -------------------------------------------------------------------------------- 1 | //================================================================================================= 2 | // Copyright (C) @year@ @project@ Contributors 3 | //================================================================================================= 4 | 5 | #pragma once 6 | 7 | namespace @project@::@module@ { 8 | /// \addtogroup @module@ @module@ module 9 | /// @{ 10 | 11 | /// TODO Implement module interface here 12 | 13 | ///@} 14 | } 15 | -------------------------------------------------------------------------------- /gbs/module_template/src/@module@.cpp: -------------------------------------------------------------------------------- 1 | //================================================================================================= 2 | // Copyright (C) @year@ @project@ Contributors 3 | //================================================================================================= 4 | 5 | #include "@project@/@module@/@module@.h" 6 | 7 | namespace @project@::@module@ { 8 | 9 | } 10 | -------------------------------------------------------------------------------- /gbs/module_template/tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # ================================================================================================= 2 | # Copyright (C) @year@ @project@ Contributors 3 | # ================================================================================================= 4 | 5 | define_module_test( 6 | NAME tests 7 | SOURCES tests.cpp 8 | PUBLIC_INCLUDE_PATHS $ 9 | PUBLIC_LINK_LIBS "") 10 | -------------------------------------------------------------------------------- /gbs/module_template/tests/tests.cpp: -------------------------------------------------------------------------------- 1 | //================================================================================================= 2 | // Copyright (C) @year@ @project@ Contributors 3 | //================================================================================================= 4 | 5 | #include "catch2/catch_test_macros.hpp" 6 | 7 | namespace { 8 | 9 | TEST_CASE("[Test]", "[@module@]") { 10 | WARN("No tests implemented"); 11 | } 12 | 13 | 14 | } // namespace 15 | -------------------------------------------------------------------------------- /gbs/project-config.cmake.in: -------------------------------------------------------------------------------- 1 | #================================================================================================= 2 | # Copyright (C) 2018 GRAPE Contributors 3 | #================================================================================================= 4 | 5 | # @CMAKE_PROJECT_NAME@ top level cmake config file 6 | 7 | @PACKAGE_INIT@ 8 | 9 | foreach(component ${@CMAKE_PROJECT_NAME@_FIND_COMPONENTS}) 10 | # For requested component, execute its "config" script 11 | include(${CMAKE_CURRENT_LIST_DIR}/../@CMAKE_PROJECT_NAME@_${component}/@CMAKE_PROJECT_NAME@_${component}-config.cmake 12 | OPTIONAL 13 | RESULT_VARIABLE is_found) 14 | if(NOT is_found) 15 | set(@CMAKE_PROJECT_NAME@_FOUND FALSE) 16 | set(@CMAKE_PROJECT_NAME@_NOT_FOUND_MESSAGE "Could not find component \"${component}\" for \"@CMAKE_PROJECT_NAME@\"") 17 | endif() 18 | endforeach() 19 | -------------------------------------------------------------------------------- /gbs/py/README.md: -------------------------------------------------------------------------------- 1 | # gbs/py 2 | 3 | Template files for Python bindings to C++ libraries -------------------------------------------------------------------------------- /gbs/py/__init__.py.in: -------------------------------------------------------------------------------- 1 | #================================================================================================= 2 | # Copyright (C) 2025 GRAPE Contributors 3 | #================================================================================================= 4 | 5 | # Python bindings for @MODULE_NAME@ 6 | 7 | from .@PY_MODULE_NAME@ import * 8 | 9 | __version__ = "@VERSION@" -------------------------------------------------------------------------------- /gbs/py/setup.py.in: -------------------------------------------------------------------------------- 1 | #================================================================================================= 2 | # Copyright (C) 2025 GRAPE Contributors 3 | #================================================================================================= 4 | 5 | from setuptools import setup, find_packages 6 | from setuptools.dist import Distribution 7 | 8 | class BinaryDistribution(Distribution): 9 | """Distribution which always forces a binary package""" 10 | def has_ext_modules(self): 11 | return True 12 | 13 | setup( 14 | name="@PY_MODULE_NAME@", 15 | version="@VERSION@", 16 | description="Python bindings for @MODULE_NAME@", 17 | packages=find_packages(), 18 | package_data={ 19 | "@PY_MODULE_NAME@": ["*.so", "*.pyd", "*.dll"], # Include the binary extension 20 | }, 21 | include_package_data=True, # Ensure package_data is included 22 | distclass=BinaryDistribution, # Mark as binary distribution 23 | python_requires=">=3.6", 24 | zip_safe=False, # Required for extensions 25 | ) -------------------------------------------------------------------------------- /gbs/uninstall.sh.in: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #================================================================================================= 3 | # Copyright (C) 2018 GRAPE Contributors 4 | #================================================================================================= 5 | 6 | INSTALL_MANIFEST=@CMAKE_INSTALL_FULL_DATAROOTDIR@/@CMAKE_PROJECT_NAME@/manifest.txt 7 | 8 | echo "***** Uninstalling @CMAKE_PROJECT_NAME@ files *****" 9 | if [ -f $INSTALL_MANIFEST ]; then 10 | 11 | # Remove services 12 | # - Get the list of service unit files we installed by filtering manifest for items in lib/systemd/system 13 | # - For each file, call sudo systemctl disable 14 | echo "Disabling services.." 15 | SYSTEMD_UNITS=( $(cat $INSTALL_MANIFEST | grep "lib/systemd/system") ) 16 | for path in "${SYSTEMD_UNITS[@]}" 17 | do 18 | service_name=$(basename "$path") 19 | sudo systemctl disable $service_name # sudo used to avoid prompt for every element in array 20 | done 21 | echo "OK" 22 | 23 | # Remove files 24 | echo "Removing files.." 25 | cat $INSTALL_MANIFEST | xargs rm 26 | echo "OK" 27 | 28 | # Remove directories we created (these should be empty now) 29 | # Note: This is safe. rmdir leaves non-empty directories alone 30 | echo "Removing directories.." 31 | cat $INSTALL_MANIFEST | xargs -L1 dirname | xargs rmdir -p --ignore-fail-on-non-empty 2>/dev/null 32 | echo "OK" 33 | 34 | # remove the install manifest and its directory too 35 | echo "Removing manifest.." 36 | rm $INSTALL_MANIFEST 37 | dirpath=$(dirname "$INSTALL_MANIFEST") 38 | rmdir "$dirpath" 39 | echo "OK" 40 | else 41 | echo "Cannot find install manifest: $INSTALL_MANIFEST" 42 | fi 43 | echo "***** Uninstall completed *****" 44 | -------------------------------------------------------------------------------- /modules/common/app/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # ================================================================================================= 2 | # Copyright (C) 2024 GRAPE Contributors 3 | # ================================================================================================= 4 | 5 | declare_module( 6 | NAME app 7 | DEPENDS_ON_MODULES "conio;log;script;serdes;ipc" 8 | DEPENDS_ON_EXTERNAL_PROJECTS "") 9 | 10 | # library sources 11 | set(SOURCES 12 | src/app.cpp 13 | README.md 14 | include/grape/app/app.h) 15 | 16 | # library target 17 | define_module_library( 18 | NAME app 19 | PUBLIC_LINK_LIBS grape::conio grape::log grape::script grape::serdes grape::ipc 20 | PRIVATE_LINK_LIBS "" 21 | SOURCES ${SOURCES} 22 | PUBLIC_INCLUDE_PATHS $ 23 | $ 24 | PRIVATE_INCLUDE_PATHS "" 25 | SYSTEM_PRIVATE_INCLUDE_PATHS "") 26 | 27 | # Subprojects 28 | add_subdirectory(config) 29 | add_subdirectory(tests) 30 | add_subdirectory(examples) 31 | -------------------------------------------------------------------------------- /modules/common/app/README.md: -------------------------------------------------------------------------------- 1 | # README: app 2 | 3 | ## Brief 4 | 5 | Application services 6 | 7 | ## Detailed Description 8 | 9 | The `app` API enables application development by encapsulating the following features: 10 | 11 | - Configuration 12 | - Logging 13 | - Inter-process communication 14 | - Signal handling 15 | - Exception handling 16 | 17 | See example programs for reference 18 | - simple_example: Most barebones example that just executes a user-specified function 19 | - pub_example/sub_example: Demonstrates application with IPC support 20 | 21 | -------------------------------------------------------------------------------- /modules/common/app/config/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # ================================================================================================= 2 | # Copyright (C) 2024 GRAPE Contributors 3 | # ================================================================================================= 4 | 5 | set(CONFIG_SOURCES app.lua) 6 | foreach(f ${CONFIG_SOURCES}) 7 | configure_file(${f} ${CMAKE_BINARY_DIR}/share/${CMAKE_PROJECT_NAME}/config/${f}) 8 | endforeach() 9 | install(FILES ${CONFIG_SOURCES} 10 | DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/${CMAKE_PROJECT_NAME}/config) 11 | -------------------------------------------------------------------------------- /modules/common/app/config/app.lua: -------------------------------------------------------------------------------- 1 | --[[=============================================================================================== 2 | Copyright (C) 2024 GRAPE Contributors 3 | =================================================================================================]] 4 | 5 | --[[Top level application configuration script in Lua programming language syntax ]] 6 | 7 | -- Logger configuration 8 | logger = { 9 | severity_threshold = "Debug", -- See grape::log::Severity 10 | } 11 | 12 | -- IPC (inter-process communication) configuration 13 | ipc = { 14 | scope = "Host", -- See grape::ipc::Config::Scope 15 | } 16 | -------------------------------------------------------------------------------- /modules/common/app/examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # ================================================================================================= 2 | # Copyright (C) 2024 GRAPE Contributors 3 | # ================================================================================================= 4 | 5 | define_module_example(NAME pub_example SOURCES pub_example.cpp) 6 | define_module_example(NAME sub_example SOURCES sub_example.cpp) 7 | -------------------------------------------------------------------------------- /modules/common/app/examples/pub_example.cpp: -------------------------------------------------------------------------------- 1 | //================================================================================================= 2 | // Copyright (C) 2024 GRAPE Contributors 3 | //================================================================================================= 4 | 5 | #include 6 | #include 7 | 8 | #include "grape/app/app.h" 9 | #include "grape/ipc/publisher.h" 10 | #include "grape/log/syslog.h" 11 | 12 | //================================================================================================= 13 | auto main(int argc, const char* argv[]) -> int { // NOLINT(bugprone-exception-escape) 14 | // initialise application 15 | grape::app::init(argc, argv, "GRAPE publisher application example"); 16 | 17 | // dummy data serializer 18 | const auto serialise = [](const std::string& msg) -> std::span { 19 | // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) 20 | return { reinterpret_cast(msg.data()), msg.size() }; 21 | }; 22 | 23 | // create publisher 24 | static constexpr auto TOPIC = grape::ipc::Topic{ .name = "hello" }; 25 | auto pub = grape::ipc::Publisher(TOPIC); 26 | 27 | // publish messages 28 | auto count = 0U; 29 | static constexpr auto LOOP_SLEEP = std::chrono::milliseconds(100); 30 | while (grape::app::ok()) { 31 | std::this_thread::sleep_for(LOOP_SLEEP); 32 | 33 | auto msg = std::format("Hello World {}", ++count); 34 | grape::syslog::Info("{}", msg); 35 | pub.publish(serialise(msg)); 36 | } 37 | 38 | return EXIT_SUCCESS; 39 | } 40 | -------------------------------------------------------------------------------- /modules/common/app/examples/sub_example.cpp: -------------------------------------------------------------------------------- 1 | //================================================================================================= 2 | // Copyright (C) 2024 GRAPE Contributors 3 | //================================================================================================= 4 | 5 | #include "grape/app/app.h" 6 | #include "grape/ipc/subscriber.h" 7 | #include "grape/log/syslog.h" 8 | 9 | //================================================================================================= 10 | auto main(int argc, const char* argv[]) -> int { // NOLINT(bugprone-exception-escape) 11 | // initialise application 12 | grape::app::init(argc, argv, "GRAPE subscriber application example"); 13 | 14 | // dummy data deserializer 15 | const auto deserialise = [](std::span bytes) -> std::string { 16 | // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) 17 | return { reinterpret_cast(bytes.data()), bytes.size() }; 18 | }; 19 | 20 | // subsription callback 21 | const auto callback = [&deserialise](const grape::ipc::Sample& sample) { 22 | const auto msg = deserialise(sample.data); 23 | grape::syslog::Info("{}", msg); 24 | }; 25 | 26 | // create subscriber 27 | static constexpr auto TOPIC = "hello"; 28 | auto sub = grape::ipc::Subscriber(TOPIC, callback); 29 | 30 | std::println(stderr, "Press ctrl-c to exit"); 31 | grape::app::waitForExit(); 32 | 33 | return EXIT_SUCCESS; 34 | } 35 | -------------------------------------------------------------------------------- /modules/common/app/include/grape/app/app.h: -------------------------------------------------------------------------------- 1 | //================================================================================================= 2 | // Copyright (C) 2024 GRAPE Contributors 3 | //================================================================================================= 4 | 5 | #pragma once 6 | 7 | #include "grape/utils/file_system.h" 8 | 9 | namespace grape::app { 10 | 11 | //================================================================================================= 12 | // User API for application-wide services 13 | //================================================================================================= 14 | 15 | /// Initialise application directly from command line arguments 16 | /// @param argc Number of command line arguments 17 | /// @param argv Array of command line arguments 18 | /// @param description A brief text describing the application 19 | /// @note This function will parse the command line arguments and look for a configuration file 20 | /// specified by the --config option. 21 | void init(int argc, const char** argv, const std::string& description = utils::getProgramName()); 22 | 23 | /// Initialise and configure the application. 24 | /// This should be the first function called in any GRAPE application 25 | /// @param config Top level configuration file 26 | void init(const std::filesystem::path& config); 27 | 28 | /// @return true if application should continue executing. False indicates that the node should exit 29 | [[nodiscard]] auto ok() -> bool; 30 | 31 | /// Wait for signal to exit application 32 | void waitForExit(); 33 | 34 | } // namespace grape::app 35 | -------------------------------------------------------------------------------- /modules/common/app/tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # ================================================================================================= 2 | # Copyright (C) 2024 GRAPE Contributors 3 | # ================================================================================================= 4 | 5 | define_module_test(NAME tests SOURCES tests.cpp) 6 | -------------------------------------------------------------------------------- /modules/common/app/tests/tests.cpp: -------------------------------------------------------------------------------- 1 | //================================================================================================= 2 | // Copyright (C) 2024 GRAPE Contributors 3 | //================================================================================================= 4 | 5 | #include "catch2/catch_test_macros.hpp" 6 | #include "grape/app/app.h" 7 | 8 | namespace { 9 | 10 | //------------------------------------------------------------------------------------------------- 11 | TEST_CASE("Must initialise once", "[app]") { 12 | REQUIRE_THROWS(grape::app::ok()); 13 | } 14 | 15 | //------------------------------------------------------------------------------------------------- 16 | TEST_CASE("Initialising with default configuration works", "[app]") { 17 | constexpr auto CONFIG_FILE = "config/app.lua"; 18 | 19 | // Must initialise without exceptions 20 | REQUIRE_NOTHROW(grape::app::init(CONFIG_FILE)); 21 | 22 | // But cannot initialise twice 23 | REQUIRE_THROWS(grape::app::init(CONFIG_FILE)); 24 | } 25 | 26 | } // namespace 27 | -------------------------------------------------------------------------------- /modules/common/base/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # ================================================================================================= 2 | # Copyright (C) 2023 GRAPE Contributors 3 | # ================================================================================================= 4 | 5 | declare_module( 6 | NAME base 7 | DEPENDS_ON_MODULES "utils" 8 | DEPENDS_ON_EXTERNAL_PROJECTS "") 9 | 10 | set(SOURCES 11 | include/grape/exception.h 12 | src/exception.cpp) 13 | 14 | define_module_library( 15 | NAME base 16 | SOURCES ${SOURCES} 17 | PUBLIC_INCLUDE_PATHS $ 18 | $ 19 | PUBLIC_LINK_LIBS grape::utils) 20 | 21 | add_subdirectory(examples) 22 | -------------------------------------------------------------------------------- /modules/common/base/examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # ================================================================================================= 2 | # Copyright (C) 2023 GRAPE Contributors 3 | # ================================================================================================= 4 | 5 | define_module_example(NAME exception_example SOURCES exception_example.cpp) 6 | -------------------------------------------------------------------------------- /modules/common/base/examples/exception_example.cpp: -------------------------------------------------------------------------------- 1 | //================================================================================================= 2 | // Copyright (C) 2023 GRAPE Contributors 3 | //================================================================================================= 4 | 5 | #include 6 | 7 | #include "grape/exception.h" 8 | #include "grape/utils/enums.h" 9 | 10 | namespace { 11 | enum class MyException : std::uint8_t { Bad, RealBad }; 12 | 13 | void functionThatThrows() { 14 | grape::panic( 15 | std::format("Boom!! [{}]", grape::enums::name(MyException::RealBad))); 16 | } 17 | 18 | void doWork() { 19 | functionThatThrows(); 20 | } 21 | } // namespace 22 | 23 | //================================================================================================= 24 | /// Demonstrates usage and handling of exceptions 25 | auto main() -> int { 26 | try { 27 | doWork(); 28 | return EXIT_SUCCESS; 29 | } catch (...) { 30 | grape::Exception::print(); 31 | return EXIT_FAILURE; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /modules/common/base/src/exception.cpp: -------------------------------------------------------------------------------- 1 | //================================================================================================= 2 | // Copyright (C) 2023 GRAPE Contributors 3 | // MIT License 4 | //================================================================================================= 5 | 6 | #include "grape/exception.h" 7 | 8 | #include 9 | 10 | #include "grape/utils/utils.h" 11 | 12 | namespace grape { 13 | 14 | //------------------------------------------------------------------------------------------------- 15 | void Exception::print() noexcept { 16 | // NOLINTBEGIN(cppcoreguidelines-pro-type-vararg) 17 | try { 18 | if (std::current_exception() != nullptr) { 19 | throw; 20 | } 21 | } catch (const grape::Exception& ex) { 22 | const auto& loc = ex.location(); 23 | const auto loc_fname = utils::truncate(loc.file_name(), "modules"); 24 | (void)fprintf(stderr, "\nException: %s\nin\n%s\nat\n%.*s:%u", ex.what(), loc.function_name(), 25 | static_cast(loc_fname.length()), loc_fname.data(), loc.line()); 26 | (void)fprintf(stderr, "\nBacktrace:"); 27 | auto idx = 0U; 28 | for (const auto& trace : ex.trace().trace()) { 29 | (void)fprintf(stderr, "\n#%u: %s", idx++, trace.c_str()); 30 | } 31 | } catch (const std::exception& ex) { 32 | (void)fprintf(stderr, "\nException: %s\n", ex.what()); 33 | } catch (...) { 34 | (void)fputs("\nUnknown exception\n", stderr); 35 | } 36 | // NOLINTEND(cppcoreguidelines-pro-type-vararg) 37 | } 38 | 39 | } // namespace grape 40 | -------------------------------------------------------------------------------- /modules/common/conio/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # ================================================================================================= 2 | # Copyright (C) 2023 GRAPE Contributors 3 | # ================================================================================================= 4 | 5 | declare_module( 6 | NAME conio 7 | ALWAYS_BUILD 8 | DEPENDS_ON_MODULES "base;utils" 9 | DEPENDS_ON_EXTERNAL_PROJECTS "") 10 | 11 | # library sources 12 | set(SOURCES README.md src/program_options.cpp src/conio.cpp include/grape/conio/program_options.h 13 | include/grape/conio/conio.h) 14 | 15 | # library target 16 | define_module_library( 17 | NAME conio 18 | PUBLIC_LINK_LIBS grape::base grape::utils 19 | PRIVATE_LINK_LIBS "" 20 | SOURCES ${SOURCES} 21 | PUBLIC_INCLUDE_PATHS $ 22 | $ 23 | PRIVATE_INCLUDE_PATHS "" 24 | SYSTEM_PRIVATE_INCLUDE_PATHS "") 25 | 26 | # Subprojects 27 | add_subdirectory(tests) 28 | add_subdirectory(examples) 29 | -------------------------------------------------------------------------------- /modules/common/conio/README.md: -------------------------------------------------------------------------------- 1 | # README: conio 2 | 3 | ## Brief 4 | 5 | Console input/output utilitie 6 | 7 | ## Detailed description 8 | 9 | Provides a set of utilities for console input/output. -------------------------------------------------------------------------------- /modules/common/conio/examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # ================================================================================================= 2 | # Copyright (C) 2023 GRAPE Contributors 3 | # ================================================================================================= 4 | 5 | define_module_example( 6 | NAME program_options_example 7 | SOURCES program_options_example.cpp 8 | PUBLIC_INCLUDE_PATHS $ 9 | PUBLIC_LINK_LIBS "") 10 | -------------------------------------------------------------------------------- /modules/common/conio/examples/program_options_example.cpp: -------------------------------------------------------------------------------- 1 | //================================================================================================= 2 | // Copyright (C) 2023 GRAPE Contributors 3 | //================================================================================================= 4 | 5 | #include 6 | 7 | #include "grape/conio/program_options.h" 8 | 9 | //================================================================================================= 10 | auto main(int argc, const char* argv[]) -> int { 11 | try { 12 | // describe the program and all it's command line options, then parse the command line args 13 | const auto args_opt = 14 | grape::conio::ProgramDescription("A dummy service that does nothing") 15 | .declareOption("port", "The port this service is available on") 16 | .declareOption("address", "The IP address of this service", "[::]") 17 | .parse(argc, argv); 18 | 19 | if (not args_opt.has_value()) { 20 | throw std::runtime_error(toString(args_opt.error())); 21 | } 22 | const auto& args = args_opt.value(); 23 | 24 | const auto port = args.getOptionOrThrow("port"); 25 | const auto addr = args.getOptionOrThrow("address"); 26 | 27 | // help is always available. Specify '--help' on command line or get it directly as here. 28 | std::println("Help text:\n{}\n", args.getOption("help").value()); 29 | 30 | // print the arguments passed. At this point, they have all been validated. 31 | std::println("You specified port = {}", port); 32 | std::println("The IP address in use is {}", addr); 33 | 34 | return EXIT_SUCCESS; 35 | } catch (...) { 36 | grape::Exception::print(); 37 | return EXIT_FAILURE; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /modules/common/conio/include/grape/conio/conio.h: -------------------------------------------------------------------------------- 1 | //================================================================================================= 2 | // Copyright (C) 2018 GRAPE Contributors 3 | //================================================================================================= 4 | 5 | #pragma once 6 | 7 | namespace grape::conio { 8 | 9 | /// @return true if key was pressed on the terminal console. use getch() to read the key stroke. 10 | auto kbhit() -> bool; 11 | 12 | /// @return Code for the last keypress from the terminal console without blocking 13 | auto getch() -> int; 14 | 15 | } // namespace grape::conio 16 | -------------------------------------------------------------------------------- /modules/common/conio/src/conio.cpp: -------------------------------------------------------------------------------- 1 | //================================================================================================= 2 | // Copyright (C) 2018 GRAPE Contributors 3 | //================================================================================================= 4 | 5 | #include "grape/conio/conio.h" 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | namespace grape::conio { 14 | 15 | //------------------------------------------------------------------------------------------------- 16 | auto kbhit() -> bool { 17 | /// reference: http://cboard.cprogramming.com/c-programming/63166-kbhit-linux.html 18 | timeval tv{}; 19 | fd_set fds{}; 20 | tv.tv_sec = 0; 21 | tv.tv_usec = 0; 22 | // NOLINTNEXTLINE(hicpp-no-assembler,readability-isolate-declaration,cppcoreguidelines-pro-bounds-constant-array-index) 23 | FD_ZERO(&fds); 24 | FD_SET(STDIN_FILENO, &fds); // NOLINT(hicpp-signed-bitwise) 25 | select(STDIN_FILENO + 1, &fds, nullptr, nullptr, &tv); 26 | return FD_ISSET(STDIN_FILENO, &fds); // NOLINT(hicpp-signed-bitwise) 27 | } 28 | 29 | //------------------------------------------------------------------------------------------------- 30 | auto getch() -> int { 31 | /// reference: 32 | /// https://stackoverflow.com/questions/3276546/how-to-implement-getch-function-of-c-in-linux 33 | struct termios oldt = {}; 34 | tcgetattr(STDIN_FILENO, &oldt); // grab old terminal io settings 35 | struct termios newt = oldt; 36 | // disable buffered io 37 | newt.c_lflag &= static_cast(~(ICANON | ECHO)); // NOLINT(hicpp-signed-bitwise) 38 | tcsetattr(STDERR_FILENO, TCSANOW, &newt); // new settings set 39 | const int ch = getchar(); 40 | tcsetattr(STDERR_FILENO, TCSANOW, &oldt); // terminal settings restored 41 | return ch; 42 | } 43 | 44 | } // namespace grape::conio 45 | -------------------------------------------------------------------------------- /modules/common/conio/tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # ================================================================================================= 2 | # Copyright (C) 2023 GRAPE Contributors 3 | # ================================================================================================= 4 | 5 | define_module_test( 6 | NAME tests 7 | SOURCES program_options_tests.cpp 8 | PUBLIC_INCLUDE_PATHS $ 9 | PUBLIC_LINK_LIBS "") 10 | -------------------------------------------------------------------------------- /modules/common/ipc/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # ================================================================================================= 2 | # Copyright (C) 2025 GRAPE Contributors 3 | # ================================================================================================= 4 | 5 | declare_module( 6 | NAME ipc 7 | DEPENDS_ON_MODULES "base;utils;conio" 8 | DEPENDS_ON_EXTERNAL_PROJECTS "eCAL") 9 | 10 | find_package(eCAL REQUIRED) # TODO(vilas): ${ECAL_VERSION_REQUIRED} REQUIRED) 11 | 12 | # library sources 13 | set(SOURCES 14 | src/publisher.cpp 15 | src/session.cpp 16 | src/subscriber.cpp 17 | README.md 18 | include/grape/ipc/config.h 19 | include/grape/ipc/match.h 20 | include/grape/ipc/publisher.h 21 | include/grape/ipc/session.h 22 | include/grape/ipc/subscriber.h 23 | include/grape/ipc/topic.h) 24 | 25 | # library target 26 | define_module_library( 27 | NAME ipc 28 | PUBLIC_LINK_LIBS grape::base grape::utils eCAL::core 29 | PRIVATE_LINK_LIBS "" 30 | SOURCES ${SOURCES} 31 | PUBLIC_INCLUDE_PATHS $ 32 | $ 33 | PRIVATE_INCLUDE_PATHS "" 34 | SYSTEM_PRIVATE_INCLUDE_PATHS "") 35 | 36 | # Subprojects 37 | add_subdirectory(py) 38 | add_subdirectory(tests) 39 | add_subdirectory(examples) 40 | -------------------------------------------------------------------------------- /modules/common/ipc/examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # ================================================================================================= 2 | # Copyright (C) 2025 GRAPE Contributors 3 | # ================================================================================================= 4 | 5 | define_module_example(NAME pub_example SOURCES pub_example.cpp) 6 | 7 | define_module_example(NAME sub_example SOURCES sub_example.cpp) 8 | 9 | define_module_example( 10 | NAME perf_pub 11 | SOURCES perf_pub.cpp perf_constants.h 12 | PUBLIC_LINK_LIBS grape::conio) 13 | 14 | define_module_example( 15 | NAME perf_sub 16 | SOURCES perf_sub.cpp perf_constants.h 17 | PUBLIC_LINK_LIBS grape::conio) 18 | 19 | define_module_example(NAME service_example SOURCES service_example.cpp) 20 | -------------------------------------------------------------------------------- /modules/common/ipc/examples/perf_constants.h: -------------------------------------------------------------------------------- 1 | //================================================================================================= 2 | // Copyright (C) 2025 GRAPE Contributors 3 | //================================================================================================= 4 | 5 | #pragma once 6 | 7 | namespace grape::ipc::ex::perf { 8 | static constexpr auto TOPIC = "grape/ipc/example/perf"; 9 | } 10 | -------------------------------------------------------------------------------- /modules/common/ipc/examples/pub_example.cpp: -------------------------------------------------------------------------------- 1 | //================================================================================================= 2 | // Copyright (C) 2025 GRAPE Contributors 3 | //================================================================================================= 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include "grape/exception.h" 10 | #include "grape/ipc/publisher.h" 11 | #include "grape/ipc/session.h" 12 | 13 | //================================================================================================= 14 | // Demonstrates a basic IPC publisher. See sub_example.cpp for the corresponding subscriber. 15 | auto main() -> int { 16 | try { 17 | grape::ipc::init(grape::ipc::Config{}); 18 | const auto topic = grape::ipc::Topic{ .name = "hello_world" }; 19 | 20 | const auto match_cb = [](const grape::ipc::Match& match) { 21 | if (match.status == grape::ipc::Match::Status::Matched) { 22 | std::println("\nMatched"); 23 | } else if (match.status == grape::ipc::Match::Status::Unmatched) { 24 | std::println("\nUnmatched"); 25 | } 26 | }; 27 | 28 | auto publisher = grape::ipc::Publisher(topic, match_cb); 29 | 30 | const auto to_bytes = [](const std::string& msg) -> std::span { 31 | // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) 32 | return { reinterpret_cast(msg.data()), msg.size() }; 33 | }; 34 | auto counter = 0U; 35 | constexpr auto SLEEP_TIME = std::chrono::milliseconds(500); 36 | while (grape::ipc::ok()) { 37 | const auto message = std::string("Hello World ") + std::to_string(++counter); 38 | std::println("Sending message: '{}'", message); 39 | publisher.publish(to_bytes(message)); 40 | std::this_thread::sleep_for(SLEEP_TIME); 41 | } 42 | return EXIT_SUCCESS; 43 | } catch (...) { 44 | grape::Exception::print(); 45 | return EXIT_FAILURE; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /modules/common/ipc/examples/py/pub_example.py: -------------------------------------------------------------------------------- 1 | # ================================================================================================= 2 | # Copyright (C) 2025 GRAPE Contributors 3 | # ================================================================================================= 4 | 5 | import time 6 | from grape_ipc_py import init, Config, Topic, Publisher, ok 7 | 8 | 9 | def to_bytes(msg: str) -> bytes: 10 | """Convert a string to bytes.""" 11 | return msg.encode("utf-8") 12 | 13 | 14 | def match_callback(match): 15 | """Callback for match/unmatch events.""" 16 | print(f"Match status: {match.status}") 17 | 18 | 19 | def main(): 20 | try: 21 | # Initialize the IPC session 22 | config = Config() 23 | config.name = "Python IPC publisher example" 24 | init(config) 25 | 26 | # Define the topic 27 | topic = Topic() 28 | topic.name="hello_world" 29 | 30 | # Create the publisher 31 | publisher = Publisher(topic, match_callback) 32 | 33 | # Publish messages in a loop 34 | counter = 0 35 | SLEEP_TIME = 0.5 # 500 milliseconds 36 | while ok(): 37 | counter += 1 38 | message = f"Hello World {counter}" 39 | print(f"Sending message: '{message}'") 40 | publisher.publish(to_bytes(message)) 41 | time.sleep(SLEEP_TIME) 42 | 43 | except Exception as e: 44 | print(f"An error occurred: {e}") 45 | 46 | 47 | if __name__ == "__main__": 48 | main() 49 | -------------------------------------------------------------------------------- /modules/common/ipc/examples/py/sub_example.py: -------------------------------------------------------------------------------- 1 | # ================================================================================================= 2 | # Copyright (C) 2025 GRAPE Contributors 3 | # ================================================================================================= 4 | 5 | import time 6 | from datetime import datetime 7 | from grape_ipc_py import init, Config, Topic, Subscriber, ok 8 | 9 | 10 | def from_bytes(data: bytes) -> str: 11 | """Convert bytes to a string.""" 12 | return data.decode("utf-8") 13 | 14 | 15 | def data_callback(sample): 16 | """Callback for received data.""" 17 | message = from_bytes(sample.data) 18 | publish_time = sample.publish_time 19 | print(f"Received message: '{message}' at {publish_time}") 20 | 21 | 22 | def match_callback(match): 23 | """Callback for match/unmatch events.""" 24 | print(f"Match status: {match.status}") 25 | 26 | 27 | def main(): 28 | try: 29 | # Initialize the IPC session 30 | config = Config() 31 | config.name = "Python IPC subscriber example" 32 | init(config) 33 | 34 | # Define the topic 35 | topic = Topic() 36 | topic.name="hello_world" 37 | 38 | # Create the subscriber 39 | subscriber = Subscriber(topic.name, data_callback, match_callback) 40 | 41 | # Sleep loop to keep the subscriber running 42 | SLEEP_TIME = 0.5 # 500 milliseconds 43 | while ok(): 44 | time.sleep(SLEEP_TIME) 45 | 46 | except Exception as e: 47 | print(f"An error occurred: {e}") 48 | 49 | 50 | if __name__ == "__main__": 51 | main() 52 | -------------------------------------------------------------------------------- /modules/common/ipc/examples/sub_example.cpp: -------------------------------------------------------------------------------- 1 | //================================================================================================= 2 | // Copyright (C) 2025 GRAPE Contributors 3 | //================================================================================================= 4 | 5 | #include 6 | #include 7 | 8 | #include "grape/exception.h" 9 | #include "grape/ipc/session.h" 10 | #include "grape/ipc/subscriber.h" 11 | 12 | //================================================================================================= 13 | // Demonstrates a basic IPC subscriber. See pub_example.cpp for the corresponding publisher. 14 | auto main() -> int { 15 | try { 16 | grape::ipc::init(grape::ipc::Config{}); 17 | const auto topic = grape::ipc::Topic{ .name = "hello_world" }; 18 | const auto from_bytes = [](std::span bytes) -> std::string { 19 | // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) 20 | return { reinterpret_cast(bytes.data()), bytes.size() }; 21 | }; 22 | 23 | const auto data_cb = [&from_bytes](const grape::ipc::Sample& sample) { 24 | std::println("Received message: '{}'", from_bytes(sample.data)); 25 | }; 26 | 27 | const auto match_cb = [](const grape::ipc::Match& match) { 28 | if (match.status == grape::ipc::Match::Status::Matched) { 29 | std::println("\nMatched"); 30 | } else if (match.status == grape::ipc::Match::Status::Unmatched) { 31 | std::println("\nUnmatched"); 32 | } 33 | }; 34 | 35 | auto subscriber = grape::ipc::Subscriber(topic.name, data_cb, match_cb); 36 | 37 | constexpr auto SLEEP_TIME = std::chrono::milliseconds(500); 38 | while (grape::ipc::ok()) { 39 | std::this_thread::sleep_for(SLEEP_TIME); 40 | } 41 | return EXIT_SUCCESS; 42 | } catch (...) { 43 | grape::Exception::print(); 44 | return EXIT_FAILURE; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /modules/common/ipc/include/grape/ipc/config.h: -------------------------------------------------------------------------------- 1 | //================================================================================================= 2 | // Copyright (C) 2025 GRAPE Contributors 3 | //================================================================================================= 4 | 5 | #pragma once 6 | 7 | #include "grape/utils/file_system.h" 8 | 9 | namespace grape::ipc { 10 | 11 | /// IPC session configuration parameters 12 | struct Config { 13 | /// Operating scope of publishers and subscribers in the session 14 | enum class Scope : std::uint8_t { 15 | Host, //!< Messages confined to host 16 | Network //!< Messages can be exchanged across LAN 17 | }; 18 | std::string name = utils::getProgramName(); //!< user-defined identifier 19 | Scope scope = Scope::Host; 20 | }; 21 | 22 | } // namespace grape::ipc 23 | -------------------------------------------------------------------------------- /modules/common/ipc/include/grape/ipc/match.h: -------------------------------------------------------------------------------- 1 | //================================================================================================= 2 | // Copyright (C) 2025 GRAPE Contributors 3 | //================================================================================================= 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | 10 | namespace grape::ipc { 11 | 12 | /// Represents a match event between a subscriber and a publisher 13 | struct Match { 14 | enum class Status : std::uint8_t { 15 | Undefined, //!< unknown status 16 | Unmatched, //!< a previously matched remote endpoint is no longer available 17 | Matched //!< matched a new remote endpoint 18 | }; 19 | 20 | Status status{}; 21 | }; 22 | 23 | /// Function signature for callback on match event 24 | using MatchCallback = std::function; 25 | } // namespace grape::ipc 26 | -------------------------------------------------------------------------------- /modules/common/ipc/include/grape/ipc/publisher.h: -------------------------------------------------------------------------------- 1 | //================================================================================================= 2 | // Copyright (C) 2025 GRAPE Contributors 3 | //================================================================================================= 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | 10 | #include "grape/ipc/match.h" 11 | #include "grape/ipc/topic.h" 12 | 13 | namespace grape::ipc { 14 | 15 | //================================================================================================= 16 | /// Publishers post topic data. Created by Session. See also Topic. 17 | class Publisher { 18 | public: 19 | /// Creates a publisher 20 | /// @param topic topic attributes 21 | /// @param match_cb Match callback, triggered on matched/unmatched with a remote subscriber 22 | explicit Publisher(const Topic& topic, MatchCallback&& match_cb = nullptr); 23 | 24 | /// Publish data on topic specified at creation by Session 25 | void publish(std::span bytes) const; 26 | 27 | ~Publisher(); 28 | Publisher(Publisher&&) noexcept; 29 | Publisher(const Publisher&) = delete; 30 | auto operator=(const Publisher&) = delete; 31 | auto operator=(Publisher&&) noexcept = delete; 32 | 33 | private: 34 | struct Impl; 35 | std::unique_ptr impl_; 36 | }; 37 | 38 | } // namespace grape::ipc 39 | -------------------------------------------------------------------------------- /modules/common/ipc/include/grape/ipc/session.h: -------------------------------------------------------------------------------- 1 | //================================================================================================= 2 | // Copyright (C) 2025 GRAPE Contributors 3 | //================================================================================================= 4 | 5 | #pragma once 6 | 7 | #include "grape/ipc/config.h" 8 | 9 | namespace grape::ipc { 10 | 11 | /// Initialise IPC session for the process 12 | /// @param config Process IPC configuration 13 | void init(Config&& config); 14 | 15 | /// @return true if session state is nominal and error-free 16 | [[nodiscard]] auto ok() -> bool; 17 | } // namespace grape::ipc 18 | -------------------------------------------------------------------------------- /modules/common/ipc/include/grape/ipc/topic.h: -------------------------------------------------------------------------------- 1 | //================================================================================================= 2 | // Copyright (C) 2025 GRAPE Contributors 3 | //================================================================================================= 4 | 5 | #pragma once 6 | 7 | #include 8 | 9 | namespace grape::ipc { 10 | 11 | struct Topic { 12 | std::string name; 13 | }; 14 | } // namespace grape::ipc 15 | -------------------------------------------------------------------------------- /modules/common/ipc/py/bindings.cpp: -------------------------------------------------------------------------------- 1 | //================================================================================================= 2 | // Copyright (C) 2025 GRAPE Contributors 3 | //================================================================================================= 4 | 5 | #include "bindings.h" 6 | 7 | PYBIND11_MODULE(grape_ipc_py, module) { 8 | module.doc() = "Python bindings for grape::ipc"; 9 | grape::ipc::py::bindConfig(module); 10 | grape::ipc::py::bindSession(module); 11 | grape::ipc::py::bindMatch(module); 12 | grape::ipc::py::bindTopic(module); 13 | grape::ipc::py::bindPublisher(module); 14 | grape::ipc::py::bindSubscriber(module); 15 | } 16 | -------------------------------------------------------------------------------- /modules/common/ipc/py/bindings.h: -------------------------------------------------------------------------------- 1 | //================================================================================================= 2 | // Copyright (C) 2025 GRAPE Contributors 3 | //================================================================================================= 4 | 5 | #pragma once 6 | 7 | #include 8 | 9 | namespace grape::ipc::py { 10 | void bindConfig(pybind11::module_& module); 11 | void bindSession(pybind11::module_& module); 12 | void bindMatch(pybind11::module_& module); 13 | void bindTopic(pybind11::module_& module); 14 | void bindPublisher(pybind11::module_& module); 15 | void bindSubscriber(pybind11::module_& module); 16 | } // namespace grape::ipc::py 17 | -------------------------------------------------------------------------------- /modules/common/ipc/py/config_bindings.cpp: -------------------------------------------------------------------------------- 1 | //================================================================================================= 2 | // Copyright (C) 2025 GRAPE Contributors 3 | //================================================================================================= 4 | 5 | #include 6 | 7 | #include "bindings.h" 8 | #include "grape/ipc/config.h" 9 | 10 | namespace grape::ipc::py { 11 | 12 | void bindConfig(pybind11::module_& module) { 13 | pybind11::enum_(module, "Scope") 14 | .value("Host", Config::Scope::Host) 15 | .value("Network", Config::Scope::Network) 16 | .export_values(); 17 | 18 | pybind11::class_(module, "Config") 19 | .def(pybind11::init<>()) 20 | .def_readwrite("name", &Config::name) 21 | .def_readwrite("scope", &Config::scope) 22 | .def("__repr__", [](const Config& config) { 23 | return "Config(name='" + config.name + 24 | "', scope=" + (config.scope == Config::Scope::Host ? "Host" : "Network") + ")"; 25 | }); 26 | } 27 | } // namespace grape::ipc::py 28 | -------------------------------------------------------------------------------- /modules/common/ipc/py/match_bindings.cpp: -------------------------------------------------------------------------------- 1 | //================================================================================================= 2 | // Copyright (C) 2025 GRAPE Contributors 3 | //================================================================================================= 4 | 5 | #include "bindings.h" 6 | #include "grape/ipc/match.h" 7 | 8 | namespace grape::ipc::py { 9 | 10 | void bindMatch(pybind11::module_& module) { 11 | pybind11::enum_(module, "MatchStatus") 12 | .value("Undefined", Match::Status::Undefined) 13 | .value("Unmatched", Match::Status::Unmatched) 14 | .value("Matched", Match::Status::Matched) 15 | .export_values(); 16 | 17 | pybind11::class_(module, "Match") 18 | .def(pybind11::init<>()) 19 | .def_readwrite("status", &Match::status); 20 | } 21 | } // namespace grape::ipc::py 22 | -------------------------------------------------------------------------------- /modules/common/ipc/py/publisher_bindings.cpp: -------------------------------------------------------------------------------- 1 | //================================================================================================= 2 | // Copyright (C) 2025 GRAPE Contributors 3 | //================================================================================================= 4 | 5 | #include 6 | #include 7 | 8 | #include "bindings.h" 9 | #include "grape/ipc/publisher.h" 10 | 11 | namespace grape::ipc::py { 12 | 13 | void bindPublisher(pybind11::module_& module) { 14 | pybind11::class_(module, "Publisher") 15 | .def(pybind11::init(), pybind11::arg("topic"), 16 | pybind11::arg("match_cb") = nullptr, 17 | "Create a Publisher with the specified topic and optional match callback.") 18 | .def( 19 | "publish", 20 | [](const Publisher& self, const pybind11::bytes& data) { 21 | const std::string& data_str = data.cast(); 22 | // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) 23 | const auto* raw_data = reinterpret_cast(data_str.data()); 24 | const std::size_t size = data_str.size(); 25 | const std::span bytes(raw_data, size); 26 | self.publish(bytes); 27 | }, 28 | pybind11::arg("data"), "Publish data on the topic specified at creation."); 29 | } 30 | } // namespace grape::ipc::py 31 | -------------------------------------------------------------------------------- /modules/common/ipc/py/session_bindings.cpp: -------------------------------------------------------------------------------- 1 | //================================================================================================= 2 | // Copyright (C) 2025 GRAPE Contributors 3 | //================================================================================================= 4 | 5 | #include 6 | 7 | #include "bindings.h" 8 | #include "grape/ipc/config.h" 9 | #include "grape/ipc/session.h" 10 | 11 | namespace grape::ipc::py { 12 | 13 | void bindSession(pybind11::module_& module) { 14 | module.def( 15 | "init", [](Config config) { init(std::move(config)); }, 16 | "Initialize IPC session for the process", pybind11::arg("config")); 17 | 18 | module.def("ok", &ok, "Check if session state is nominal and error-free"); 19 | } 20 | } // namespace grape::ipc::py 21 | -------------------------------------------------------------------------------- /modules/common/ipc/py/subscriber_bindings.cpp: -------------------------------------------------------------------------------- 1 | //================================================================================================= 2 | // Copyright (C) 2025 GRAPE Contributors 3 | //================================================================================================= 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include "bindings.h" 10 | #include "grape/ipc/subscriber.h" 11 | 12 | namespace grape::ipc::py { 13 | 14 | void bindSubscriber(pybind11::module_& module) { 15 | // Bind the Sample struct 16 | pybind11::class_(module, "Sample") 17 | .def_property_readonly( 18 | "data", 19 | [](const Sample& sample) { 20 | // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) 21 | return pybind11::bytes(reinterpret_cast(sample.data.data()), 22 | sample.data.size()); 23 | }, 24 | "The data received by the subscriber") 25 | .def_readonly("publish_time", &Sample::publish_time, "The time the data was published"); 26 | 27 | // Bind the Subscriber class 28 | pybind11::class_(module, "Subscriber") 29 | .def(pybind11::init(), 30 | pybind11::arg("topic"), pybind11::arg("data_cb"), pybind11::arg("match_cb") = nullptr, 31 | "Create a Subscriber with the specified topic, data callback, and optional match " 32 | "callback.") 33 | .def("get_publisher_count", &Subscriber::getPublisherCount, 34 | "Get the number of publishers currently matched to this subscriber."); 35 | } 36 | 37 | } // namespace grape::ipc::py 38 | -------------------------------------------------------------------------------- /modules/common/ipc/py/topic_bindings.cpp: -------------------------------------------------------------------------------- 1 | //================================================================================================= 2 | // Copyright (C) 2025 GRAPE Contributors 3 | //================================================================================================= 4 | 5 | #include "bindings.h" 6 | #include "grape/ipc/topic.h" 7 | 8 | namespace grape::ipc::py { 9 | 10 | void bindTopic(pybind11::module_& module) { 11 | pybind11::class_(module, "Topic") 12 | .def(pybind11::init<>()) 13 | .def_readwrite("name", &Topic::name); 14 | } 15 | } // namespace grape::ipc::py 16 | -------------------------------------------------------------------------------- /modules/common/ipc/tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # ================================================================================================= 2 | # Copyright (C) 2025 GRAPE Contributors 3 | # ================================================================================================= 4 | 5 | define_module_test(NAME tests SOURCES tests.cpp) 6 | -------------------------------------------------------------------------------- /modules/common/log/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # ================================================================================================= 2 | # Copyright (C) 2023 GRAPE Contributors 3 | # ================================================================================================= 4 | 5 | declare_module( 6 | NAME log 7 | DEPENDS_ON_MODULES "realtime;utils;base" 8 | DEPENDS_ON_EXTERNAL_PROJECTS "") 9 | 10 | # library sources 11 | set(SOURCES 12 | README.md 13 | include/grape/log/formatters/default_formatter.h 14 | include/grape/log/sinks/sink.h 15 | include/grape/log/sinks/console_sink.h 16 | include/grape/log/sinks/file_sink.h 17 | include/grape/log/config.h 18 | include/grape/log/logger.h 19 | include/grape/log/record.h 20 | include/grape/log/severity.h 21 | include/grape/log/syslog.h 22 | src/logger.cpp 23 | src/syslog.cpp) 24 | 25 | # library target 26 | define_module_library( 27 | NAME log 28 | PUBLIC_LINK_LIBS grape::base grape::utils grape::realtime 29 | PRIVATE_LINK_LIBS "" 30 | SOURCES ${SOURCES} 31 | PUBLIC_INCLUDE_PATHS $ 32 | $ 33 | PRIVATE_INCLUDE_PATHS "" 34 | SYSTEM_PRIVATE_INCLUDE_PATHS "") 35 | 36 | # Subprojects 37 | add_subdirectory(tests) 38 | add_subdirectory(examples) 39 | -------------------------------------------------------------------------------- /modules/common/log/README.md: -------------------------------------------------------------------------------- 1 | # README: log 2 | 3 | ## Brief 4 | 5 | Logging services 6 | 7 | ## Features 8 | 9 | - Usable in low-latency and realtime contexts 10 | - Lock free 11 | - No memory allocation 12 | - Performant (throughput comparable or better than third party solutions such as spdlog at default settings) 13 | - Reports timestamp and source location from where the log was fired 14 | - Threshold severity level settable at runtime 15 | - User definable log sinks (file, network, console) 16 | - User definable data format at sink 17 | - Simple API 18 | ```c++ 19 | log(severity, message); 20 | ``` 21 | 22 | Missing features: 23 | - Throttling (rate-limiting) based on location 24 | - Tools to filter logs by severity, location -------------------------------------------------------------------------------- /modules/common/log/examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # ================================================================================================= 2 | # Copyright (C) 2023 GRAPE Contributors 3 | # ================================================================================================= 4 | 5 | define_module_example(NAME example SOURCES example.cpp) 6 | 7 | define_module_example(NAME custom_sink_example SOURCES custom_sink_example.cpp) 8 | 9 | define_module_example( 10 | NAME spdlog_bench 11 | SOURCES spdlog_bench.cpp 12 | PRIVATE_INCLUDE_PATHS ${CMAKE_CURRENT_SOURCE_DIR}/spdlog-1.15.2/include 13 | $ 14 | PRIVATE_LINK_LIBS benchmark::benchmark 15 | PUBLIC_LINK_LIBS "") 16 | set_target_properties(grape_log_spdlog_bench PROPERTIES CXX_CLANG_TIDY "") # disable spdlog warnings 17 | set_target_properties(grape_log_spdlog_bench PROPERTIES COMPILE_OPTIONS 18 | "${THIRD_PARTY_COMPILER_WARNINGS}") 19 | -------------------------------------------------------------------------------- /modules/common/log/examples/custom_sink_example.cpp: -------------------------------------------------------------------------------- 1 | //================================================================================================= 2 | // Copyright (C) 2023 GRAPE Contributors 3 | //================================================================================================= 4 | 5 | #include 6 | 7 | #include "grape/exception.h" 8 | #include "grape/log/logger.h" 9 | 10 | //================================================================================================= 11 | // Custom log sink implementation 12 | struct CustomSink : public grape::log::Sink { 13 | void write(const grape::log::Record& rec) override { 14 | std::println("[{}] {}", rec.timestamp, rec.message.cStr()); 15 | } 16 | }; 17 | 18 | //================================================================================================= 19 | // Demonstrates how to redirect logs to a custom output stream in a custom format 20 | auto main() -> int { 21 | try { 22 | auto log_file = std::ofstream("logs.txt"); 23 | grape::log::Config config; 24 | config.sink = std::make_shared(); 25 | auto logger = grape::log::Logger(std::move(config)); 26 | grape::log::Log(logger, grape::log::Severity::Info, "{}", "Message to custom output stream"); 27 | return EXIT_SUCCESS; 28 | } catch (...) { 29 | grape::Exception::print(); 30 | return EXIT_FAILURE; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /modules/common/log/examples/example.cpp: -------------------------------------------------------------------------------- 1 | //================================================================================================= 2 | // Copyright (C) 2023 GRAPE Contributors 3 | //================================================================================================= 4 | 5 | #include "grape/exception.h" 6 | #include "grape/log/syslog.h" 7 | 8 | //================================================================================================= 9 | auto main(int /*argc*/, const char** /*argv[]*/) -> int { 10 | try { 11 | auto config = grape::log::Config{}; 12 | config.threshold = grape::log::Severity::Debug; 13 | grape::syslog::init(std::move(config)); 14 | grape::syslog::Critical("A critical error message"); 15 | grape::syslog::Error("An error message"); 16 | grape::syslog::Warn("A warning message"); 17 | grape::syslog::Note("message='{}'", "A note message"); 18 | grape::syslog::Info("An informational message"); 19 | grape::syslog::Debug("A debug message"); 20 | return EXIT_SUCCESS; 21 | } catch (...) { 22 | grape::Exception::print(); 23 | return EXIT_FAILURE; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /modules/common/log/examples/spdlog-1.15.2/INSTALL: -------------------------------------------------------------------------------- 1 | Header Only Version 2 | ================================================================== 3 | Just copy the files to your build tree and use a C++11 compiler. 4 | Or use CMake: 5 | ``` 6 | add_executable(example_header_only example.cpp) 7 | target_link_libraries(example_header_only spdlog::spdlog_header_only) 8 | ``` 9 | 10 | Compiled Library Version 11 | ================================================================== 12 | CMake: 13 | ``` 14 | add_executable(example example.cpp) 15 | target_link_libraries(example spdlog::spdlog) 16 | ``` 17 | 18 | Or copy files src/*.cpp to your build tree and pass the -DSPDLOG_COMPILED_LIB to the compiler. 19 | 20 | Important Information for Compilation: 21 | ================================================================== 22 | * If you encounter compilation errors with gcc 4.8.x, please note that gcc 4.8.x does not fully support C++11. In such cases, consider upgrading your compiler or using a different version that fully supports C++11 standards 23 | 24 | Tested on: 25 | gcc 4.8.1 and above 26 | clang 3.5 27 | Visual Studio 2013 -------------------------------------------------------------------------------- /modules/common/log/examples/spdlog-1.15.2/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Gabi Melman. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | 23 | -- NOTE: Third party dependency used by this software -- 24 | This software depends on the fmt lib (MIT License), 25 | and users must comply to its license: https://raw.githubusercontent.com/fmtlib/fmt/master/LICENSE 26 | 27 | -------------------------------------------------------------------------------- /modules/common/log/examples/spdlog-1.15.2/include/spdlog/cfg/argv.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | #include 6 | #include 7 | 8 | // 9 | // Init log levels using each argv entry that starts with "SPDLOG_LEVEL=" 10 | // 11 | // set all loggers to debug level: 12 | // example.exe "SPDLOG_LEVEL=debug" 13 | 14 | // set logger1 to trace level 15 | // example.exe "SPDLOG_LEVEL=logger1=trace" 16 | 17 | // turn off all logging except for logger1 and logger2: 18 | // example.exe "SPDLOG_LEVEL=off,logger1=debug,logger2=info" 19 | 20 | namespace spdlog { 21 | namespace cfg { 22 | 23 | // search for SPDLOG_LEVEL= in the args and use it to init the levels 24 | inline void load_argv_levels(int argc, const char **argv) { 25 | const std::string spdlog_level_prefix = "SPDLOG_LEVEL="; 26 | for (int i = 1; i < argc; i++) { 27 | std::string arg = argv[i]; 28 | if (arg.find(spdlog_level_prefix) == 0) { 29 | auto levels_string = arg.substr(spdlog_level_prefix.size()); 30 | helpers::load_levels(levels_string); 31 | } 32 | } 33 | } 34 | 35 | inline void load_argv_levels(int argc, char **argv) { 36 | load_argv_levels(argc, const_cast(argv)); 37 | } 38 | 39 | } // namespace cfg 40 | } // namespace spdlog 41 | -------------------------------------------------------------------------------- /modules/common/log/examples/spdlog-1.15.2/include/spdlog/cfg/env.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | #include 6 | #include 7 | #include 8 | 9 | // 10 | // Init levels and patterns from env variables SPDLOG_LEVEL 11 | // Inspired from Rust's "env_logger" crate (https://crates.io/crates/env_logger). 12 | // Note - fallback to "info" level on unrecognized levels 13 | // 14 | // Examples: 15 | // 16 | // set global level to debug: 17 | // export SPDLOG_LEVEL=debug 18 | // 19 | // turn off all logging except for logger1: 20 | // export SPDLOG_LEVEL="*=off,logger1=debug" 21 | // 22 | 23 | // turn off all logging except for logger1 and logger2: 24 | // export SPDLOG_LEVEL="off,logger1=debug,logger2=info" 25 | 26 | namespace spdlog { 27 | namespace cfg { 28 | inline void load_env_levels(const char* var = "SPDLOG_LEVEL") { 29 | auto env_val = details::os::getenv(var); 30 | if (!env_val.empty()) { 31 | helpers::load_levels(env_val); 32 | } 33 | } 34 | 35 | } // namespace cfg 36 | } // namespace spdlog 37 | -------------------------------------------------------------------------------- /modules/common/log/examples/spdlog-1.15.2/include/spdlog/cfg/helpers.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | 9 | namespace spdlog { 10 | namespace cfg { 11 | namespace helpers { 12 | // 13 | // Init levels from given string 14 | // 15 | // Examples: 16 | // 17 | // set global level to debug: "debug" 18 | // turn off all logging except for logger1: "off,logger1=debug" 19 | // turn off all logging except for logger1 and logger2: "off,logger1=debug,logger2=info" 20 | // 21 | SPDLOG_API void load_levels(const std::string &txt); 22 | } // namespace helpers 23 | 24 | } // namespace cfg 25 | } // namespace spdlog 26 | 27 | #ifdef SPDLOG_HEADER_ONLY 28 | #include "helpers-inl.h" 29 | #endif // SPDLOG_HEADER_ONLY 30 | -------------------------------------------------------------------------------- /modules/common/log/examples/spdlog-1.15.2/include/spdlog/details/backtracer.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | // Store log messages in circular buffer. 14 | // Useful for storing debug data in case of error/warning happens. 15 | 16 | namespace spdlog { 17 | namespace details { 18 | class SPDLOG_API backtracer { 19 | mutable std::mutex mutex_; 20 | std::atomic enabled_{false}; 21 | circular_q messages_; 22 | 23 | public: 24 | backtracer() = default; 25 | backtracer(const backtracer &other); 26 | 27 | backtracer(backtracer &&other) SPDLOG_NOEXCEPT; 28 | backtracer &operator=(backtracer other); 29 | 30 | void enable(size_t size); 31 | void disable(); 32 | bool enabled() const; 33 | void push_back(const log_msg &msg); 34 | bool empty() const; 35 | 36 | // pop all items in the q and apply the given fun on each of them. 37 | void foreach_pop(std::function fun); 38 | }; 39 | 40 | } // namespace details 41 | } // namespace spdlog 42 | 43 | #ifdef SPDLOG_HEADER_ONLY 44 | #include "backtracer-inl.h" 45 | #endif 46 | -------------------------------------------------------------------------------- /modules/common/log/examples/spdlog-1.15.2/include/spdlog/details/console_globals.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | 9 | namespace spdlog { 10 | namespace details { 11 | 12 | struct console_mutex { 13 | using mutex_t = std::mutex; 14 | static mutex_t &mutex() { 15 | static mutex_t s_mutex; 16 | return s_mutex; 17 | } 18 | }; 19 | 20 | struct console_nullmutex { 21 | using mutex_t = null_mutex; 22 | static mutex_t &mutex() { 23 | static mutex_t s_mutex; 24 | return s_mutex; 25 | } 26 | }; 27 | } // namespace details 28 | } // namespace spdlog 29 | -------------------------------------------------------------------------------- /modules/common/log/examples/spdlog-1.15.2/include/spdlog/details/log_msg-inl.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #ifndef SPDLOG_HEADER_ONLY 7 | #include 8 | #endif 9 | 10 | #include 11 | 12 | namespace spdlog { 13 | namespace details { 14 | 15 | SPDLOG_INLINE log_msg::log_msg(spdlog::log_clock::time_point log_time, 16 | spdlog::source_loc loc, 17 | string_view_t a_logger_name, 18 | spdlog::level::level_enum lvl, 19 | spdlog::string_view_t msg) 20 | : logger_name(a_logger_name), 21 | level(lvl), 22 | time(log_time) 23 | #ifndef SPDLOG_NO_THREAD_ID 24 | , 25 | thread_id(os::thread_id()) 26 | #endif 27 | , 28 | source(loc), 29 | payload(msg) { 30 | } 31 | 32 | SPDLOG_INLINE log_msg::log_msg(spdlog::source_loc loc, 33 | string_view_t a_logger_name, 34 | spdlog::level::level_enum lvl, 35 | spdlog::string_view_t msg) 36 | : log_msg(os::now(), loc, a_logger_name, lvl, msg) {} 37 | 38 | SPDLOG_INLINE log_msg::log_msg(string_view_t a_logger_name, 39 | spdlog::level::level_enum lvl, 40 | spdlog::string_view_t msg) 41 | : log_msg(os::now(), source_loc{}, a_logger_name, lvl, msg) {} 42 | 43 | } // namespace details 44 | } // namespace spdlog 45 | -------------------------------------------------------------------------------- /modules/common/log/examples/spdlog-1.15.2/include/spdlog/details/log_msg.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | 9 | namespace spdlog { 10 | namespace details { 11 | struct SPDLOG_API log_msg { 12 | log_msg() = default; 13 | log_msg(log_clock::time_point log_time, 14 | source_loc loc, 15 | string_view_t logger_name, 16 | level::level_enum lvl, 17 | string_view_t msg); 18 | log_msg(source_loc loc, string_view_t logger_name, level::level_enum lvl, string_view_t msg); 19 | log_msg(string_view_t logger_name, level::level_enum lvl, string_view_t msg); 20 | log_msg(const log_msg &other) = default; 21 | log_msg &operator=(const log_msg &other) = default; 22 | 23 | string_view_t logger_name; 24 | level::level_enum level{level::off}; 25 | log_clock::time_point time; 26 | size_t thread_id{0}; 27 | 28 | // wrapping the formatted text with color (updated by pattern_formatter). 29 | mutable size_t color_range_start{0}; 30 | mutable size_t color_range_end{0}; 31 | 32 | source_loc source; 33 | string_view_t payload; 34 | }; 35 | } // namespace details 36 | } // namespace spdlog 37 | 38 | #ifdef SPDLOG_HEADER_ONLY 39 | #include "log_msg-inl.h" 40 | #endif 41 | -------------------------------------------------------------------------------- /modules/common/log/examples/spdlog-1.15.2/include/spdlog/details/log_msg_buffer-inl.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #ifndef SPDLOG_HEADER_ONLY 7 | #include 8 | #endif 9 | 10 | namespace spdlog { 11 | namespace details { 12 | 13 | SPDLOG_INLINE log_msg_buffer::log_msg_buffer(const log_msg &orig_msg) 14 | : log_msg{orig_msg} { 15 | buffer.append(logger_name.begin(), logger_name.end()); 16 | buffer.append(payload.begin(), payload.end()); 17 | update_string_views(); 18 | } 19 | 20 | SPDLOG_INLINE log_msg_buffer::log_msg_buffer(const log_msg_buffer &other) 21 | : log_msg{other} { 22 | buffer.append(logger_name.begin(), logger_name.end()); 23 | buffer.append(payload.begin(), payload.end()); 24 | update_string_views(); 25 | } 26 | 27 | SPDLOG_INLINE log_msg_buffer::log_msg_buffer(log_msg_buffer &&other) SPDLOG_NOEXCEPT 28 | : log_msg{other}, 29 | buffer{std::move(other.buffer)} { 30 | update_string_views(); 31 | } 32 | 33 | SPDLOG_INLINE log_msg_buffer &log_msg_buffer::operator=(const log_msg_buffer &other) { 34 | log_msg::operator=(other); 35 | buffer.clear(); 36 | buffer.append(other.buffer.data(), other.buffer.data() + other.buffer.size()); 37 | update_string_views(); 38 | return *this; 39 | } 40 | 41 | SPDLOG_INLINE log_msg_buffer &log_msg_buffer::operator=(log_msg_buffer &&other) SPDLOG_NOEXCEPT { 42 | log_msg::operator=(other); 43 | buffer = std::move(other.buffer); 44 | update_string_views(); 45 | return *this; 46 | } 47 | 48 | SPDLOG_INLINE void log_msg_buffer::update_string_views() { 49 | logger_name = string_view_t{buffer.data(), logger_name.size()}; 50 | payload = string_view_t{buffer.data() + logger_name.size(), payload.size()}; 51 | } 52 | 53 | } // namespace details 54 | } // namespace spdlog 55 | -------------------------------------------------------------------------------- /modules/common/log/examples/spdlog-1.15.2/include/spdlog/details/log_msg_buffer.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | 8 | namespace spdlog { 9 | namespace details { 10 | 11 | // Extend log_msg with internal buffer to store its payload. 12 | // This is needed since log_msg holds string_views that points to stack data. 13 | 14 | class SPDLOG_API log_msg_buffer : public log_msg { 15 | memory_buf_t buffer; 16 | void update_string_views(); 17 | 18 | public: 19 | log_msg_buffer() = default; 20 | explicit log_msg_buffer(const log_msg &orig_msg); 21 | log_msg_buffer(const log_msg_buffer &other); 22 | log_msg_buffer(log_msg_buffer &&other) SPDLOG_NOEXCEPT; 23 | log_msg_buffer &operator=(const log_msg_buffer &other); 24 | log_msg_buffer &operator=(log_msg_buffer &&other) SPDLOG_NOEXCEPT; 25 | }; 26 | 27 | } // namespace details 28 | } // namespace spdlog 29 | 30 | #ifdef SPDLOG_HEADER_ONLY 31 | #include "log_msg_buffer-inl.h" 32 | #endif 33 | -------------------------------------------------------------------------------- /modules/common/log/examples/spdlog-1.15.2/include/spdlog/details/null_mutex.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | // null, no cost dummy "mutex" and dummy "atomic" int 9 | 10 | namespace spdlog { 11 | namespace details { 12 | struct null_mutex { 13 | void lock() const {} 14 | void unlock() const {} 15 | }; 16 | 17 | struct null_atomic_int { 18 | int value; 19 | null_atomic_int() = default; 20 | 21 | explicit null_atomic_int(int new_value) 22 | : value(new_value) {} 23 | 24 | int load(std::memory_order = std::memory_order_relaxed) const { return value; } 25 | 26 | void store(int new_value, std::memory_order = std::memory_order_relaxed) { value = new_value; } 27 | 28 | int exchange(int new_value, std::memory_order = std::memory_order_relaxed) { 29 | std::swap(new_value, value); 30 | return new_value; // return value before the call 31 | } 32 | }; 33 | 34 | } // namespace details 35 | } // namespace spdlog 36 | -------------------------------------------------------------------------------- /modules/common/log/examples/spdlog-1.15.2/include/spdlog/details/periodic_worker-inl.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #ifndef SPDLOG_HEADER_ONLY 7 | #include 8 | #endif 9 | 10 | namespace spdlog { 11 | namespace details { 12 | 13 | // stop the worker thread and join it 14 | SPDLOG_INLINE periodic_worker::~periodic_worker() { 15 | if (worker_thread_.joinable()) { 16 | { 17 | std::lock_guard lock(mutex_); 18 | active_ = false; 19 | } 20 | cv_.notify_one(); 21 | worker_thread_.join(); 22 | } 23 | } 24 | 25 | } // namespace details 26 | } // namespace spdlog 27 | -------------------------------------------------------------------------------- /modules/common/log/examples/spdlog-1.15.2/include/spdlog/details/synchronous_factory.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include "registry.h" 7 | 8 | namespace spdlog { 9 | 10 | // Default logger factory- creates synchronous loggers 11 | class logger; 12 | 13 | struct synchronous_factory { 14 | template 15 | static std::shared_ptr create(std::string logger_name, SinkArgs &&...args) { 16 | auto sink = std::make_shared(std::forward(args)...); 17 | auto new_logger = std::make_shared(std::move(logger_name), std::move(sink)); 18 | details::registry::instance().initialize_logger(new_logger); 19 | return new_logger; 20 | } 21 | }; 22 | } // namespace spdlog 23 | -------------------------------------------------------------------------------- /modules/common/log/examples/spdlog-1.15.2/include/spdlog/details/windows_include.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef NOMINMAX 4 | #define NOMINMAX // prevent windows redefining min/max 5 | #endif 6 | 7 | #ifndef WIN32_LEAN_AND_MEAN 8 | #define WIN32_LEAN_AND_MEAN 9 | #endif 10 | 11 | #include 12 | -------------------------------------------------------------------------------- /modules/common/log/examples/spdlog-1.15.2/include/spdlog/fmt/bundled/core.h: -------------------------------------------------------------------------------- 1 | // This file is only provided for compatibility and may be removed in future 2 | // versions. Use fmt/base.h if you don't need fmt::format and fmt/format.h 3 | // otherwise. 4 | 5 | #include "format.h" 6 | -------------------------------------------------------------------------------- /modules/common/log/examples/spdlog-1.15.2/include/spdlog/fmt/bundled/fmt.license.rst: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 - present, Victor Zverovich 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | --- Optional exception to the license --- 23 | 24 | As an exception, if, as a result of your compiling your source code, portions 25 | of this Software are embedded into a machine-executable object form of such 26 | source code, you may redistribute such embedded portions in such object form 27 | without including the above copyright and permission notices. 28 | -------------------------------------------------------------------------------- /modules/common/log/examples/spdlog-1.15.2/include/spdlog/fmt/chrono.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright(c) 2016 Gabi Melman. 3 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 4 | // 5 | 6 | #pragma once 7 | // 8 | // include bundled or external copy of fmtlib's chrono support 9 | // 10 | #include 11 | 12 | #if !defined(SPDLOG_USE_STD_FORMAT) 13 | #if !defined(SPDLOG_FMT_EXTERNAL) 14 | #ifdef SPDLOG_HEADER_ONLY 15 | #ifndef FMT_HEADER_ONLY 16 | #define FMT_HEADER_ONLY 17 | #endif 18 | #endif 19 | #include 20 | #else 21 | #include 22 | #endif 23 | #endif 24 | -------------------------------------------------------------------------------- /modules/common/log/examples/spdlog-1.15.2/include/spdlog/fmt/compile.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright(c) 2016 Gabi Melman. 3 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 4 | // 5 | 6 | #pragma once 7 | // 8 | // include bundled or external copy of fmtlib's compile-time support 9 | // 10 | #include 11 | 12 | #if !defined(SPDLOG_USE_STD_FORMAT) 13 | #if !defined(SPDLOG_FMT_EXTERNAL) 14 | #ifdef SPDLOG_HEADER_ONLY 15 | #ifndef FMT_HEADER_ONLY 16 | #define FMT_HEADER_ONLY 17 | #endif 18 | #endif 19 | #include 20 | #else 21 | #include 22 | #endif 23 | #endif 24 | -------------------------------------------------------------------------------- /modules/common/log/examples/spdlog-1.15.2/include/spdlog/fmt/fmt.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright(c) 2016-2018 Gabi Melman. 3 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 4 | // 5 | 6 | #pragma once 7 | 8 | // 9 | // Include a bundled header-only copy of fmtlib or an external one. 10 | // By default spdlog include its own copy. 11 | // 12 | #include 13 | 14 | #if defined(SPDLOG_USE_STD_FORMAT) // SPDLOG_USE_STD_FORMAT is defined - use std::format 15 | #include 16 | #elif !defined(SPDLOG_FMT_EXTERNAL) 17 | #if !defined(SPDLOG_COMPILED_LIB) && !defined(FMT_HEADER_ONLY) 18 | #define FMT_HEADER_ONLY 19 | #endif 20 | #ifndef FMT_USE_WINDOWS_H 21 | #define FMT_USE_WINDOWS_H 0 22 | #endif 23 | 24 | #include 25 | #include 26 | 27 | #else // SPDLOG_FMT_EXTERNAL is defined - use external fmtlib 28 | #include 29 | #include 30 | #endif 31 | -------------------------------------------------------------------------------- /modules/common/log/examples/spdlog-1.15.2/include/spdlog/fmt/ostr.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright(c) 2016 Gabi Melman. 3 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 4 | // 5 | 6 | #pragma once 7 | // 8 | // include bundled or external copy of fmtlib's ostream support 9 | // 10 | #include 11 | 12 | #if !defined(SPDLOG_USE_STD_FORMAT) 13 | #if !defined(SPDLOG_FMT_EXTERNAL) 14 | #ifdef SPDLOG_HEADER_ONLY 15 | #ifndef FMT_HEADER_ONLY 16 | #define FMT_HEADER_ONLY 17 | #endif 18 | #endif 19 | #include 20 | #else 21 | #include 22 | #endif 23 | #endif 24 | -------------------------------------------------------------------------------- /modules/common/log/examples/spdlog-1.15.2/include/spdlog/fmt/ranges.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright(c) 2016 Gabi Melman. 3 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 4 | // 5 | 6 | #pragma once 7 | // 8 | // include bundled or external copy of fmtlib's ranges support 9 | // 10 | #include 11 | 12 | #if !defined(SPDLOG_USE_STD_FORMAT) 13 | #if !defined(SPDLOG_FMT_EXTERNAL) 14 | #ifdef SPDLOG_HEADER_ONLY 15 | #ifndef FMT_HEADER_ONLY 16 | #define FMT_HEADER_ONLY 17 | #endif 18 | #endif 19 | #include 20 | #else 21 | #include 22 | #endif 23 | #endif 24 | -------------------------------------------------------------------------------- /modules/common/log/examples/spdlog-1.15.2/include/spdlog/fmt/std.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright(c) 2016 Gabi Melman. 3 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 4 | // 5 | 6 | #pragma once 7 | // 8 | // include bundled or external copy of fmtlib's std support (for formatting e.g. 9 | // std::filesystem::path, std::thread::id, std::monostate, std::variant, ...) 10 | // 11 | #include 12 | 13 | #if !defined(SPDLOG_USE_STD_FORMAT) 14 | #if !defined(SPDLOG_FMT_EXTERNAL) 15 | #ifdef SPDLOG_HEADER_ONLY 16 | #ifndef FMT_HEADER_ONLY 17 | #define FMT_HEADER_ONLY 18 | #endif 19 | #endif 20 | #include 21 | #else 22 | #include 23 | #endif 24 | #endif 25 | -------------------------------------------------------------------------------- /modules/common/log/examples/spdlog-1.15.2/include/spdlog/fmt/xchar.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright(c) 2016 Gabi Melman. 3 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 4 | // 5 | 6 | #pragma once 7 | // 8 | // include bundled or external copy of fmtlib's xchar support 9 | // 10 | #include 11 | 12 | #if !defined(SPDLOG_USE_STD_FORMAT) 13 | #if !defined(SPDLOG_FMT_EXTERNAL) 14 | #ifdef SPDLOG_HEADER_ONLY 15 | #ifndef FMT_HEADER_ONLY 16 | #define FMT_HEADER_ONLY 17 | #endif 18 | #endif 19 | #include 20 | #else 21 | #include 22 | #endif 23 | #endif 24 | -------------------------------------------------------------------------------- /modules/common/log/examples/spdlog-1.15.2/include/spdlog/formatter.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | 9 | namespace spdlog { 10 | 11 | class formatter { 12 | public: 13 | virtual ~formatter() = default; 14 | virtual void format(const details::log_msg &msg, memory_buf_t &dest) = 0; 15 | virtual std::unique_ptr clone() const = 0; 16 | }; 17 | } // namespace spdlog 18 | -------------------------------------------------------------------------------- /modules/common/log/examples/spdlog-1.15.2/include/spdlog/fwd.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | namespace spdlog { 7 | class logger; 8 | class formatter; 9 | 10 | namespace sinks { 11 | class sink; 12 | } 13 | 14 | namespace level { 15 | enum level_enum : int; 16 | } 17 | 18 | } // namespace spdlog 19 | -------------------------------------------------------------------------------- /modules/common/log/examples/spdlog-1.15.2/include/spdlog/mdc.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #if defined(SPDLOG_NO_TLS) 7 | #error "This header requires thread local storage support, but SPDLOG_NO_TLS is defined." 8 | #endif 9 | 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | // MDC is a simple map of key->string values stored in thread local storage whose content will be printed by the loggers. 16 | // Note: Not supported in async mode (thread local storage - so the async thread pool have different copy). 17 | // 18 | // Usage example: 19 | // spdlog::mdc::put("mdc_key_1", "mdc_value_1"); 20 | // spdlog::info("Hello, {}", "World!"); // => [2024-04-26 02:08:05.040] [info] [mdc_key_1:mdc_value_1] Hello, World! 21 | 22 | namespace spdlog { 23 | class SPDLOG_API mdc { 24 | public: 25 | using mdc_map_t = std::map; 26 | 27 | static void put(const std::string &key, const std::string &value) { 28 | get_context()[key] = value; 29 | } 30 | 31 | static std::string get(const std::string &key) { 32 | auto &context = get_context(); 33 | auto it = context.find(key); 34 | if (it != context.end()) { 35 | return it->second; 36 | } 37 | return ""; 38 | } 39 | 40 | static void remove(const std::string &key) { get_context().erase(key); } 41 | 42 | static void clear() { get_context().clear(); } 43 | 44 | static mdc_map_t &get_context() { 45 | static thread_local mdc_map_t context; 46 | return context; 47 | } 48 | }; 49 | 50 | } // namespace spdlog 51 | -------------------------------------------------------------------------------- /modules/common/log/examples/spdlog-1.15.2/include/spdlog/sinks/base_sink.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | // 6 | // base sink templated over a mutex (either dummy or real) 7 | // concrete implementation should override the sink_it_() and flush_() methods. 8 | // locking is taken care of in this class - no locking needed by the 9 | // implementers.. 10 | // 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | namespace spdlog { 17 | namespace sinks { 18 | template 19 | class SPDLOG_API base_sink : public sink { 20 | public: 21 | base_sink(); 22 | explicit base_sink(std::unique_ptr formatter); 23 | ~base_sink() override = default; 24 | 25 | base_sink(const base_sink &) = delete; 26 | base_sink(base_sink &&) = delete; 27 | 28 | base_sink &operator=(const base_sink &) = delete; 29 | base_sink &operator=(base_sink &&) = delete; 30 | 31 | void log(const details::log_msg &msg) final override; 32 | void flush() final override; 33 | void set_pattern(const std::string &pattern) final override; 34 | void set_formatter(std::unique_ptr sink_formatter) final override; 35 | 36 | protected: 37 | // sink formatter 38 | std::unique_ptr formatter_; 39 | Mutex mutex_; 40 | 41 | virtual void sink_it_(const details::log_msg &msg) = 0; 42 | virtual void flush_() = 0; 43 | virtual void set_pattern_(const std::string &pattern); 44 | virtual void set_formatter_(std::unique_ptr sink_formatter); 45 | }; 46 | } // namespace sinks 47 | } // namespace spdlog 48 | 49 | #ifdef SPDLOG_HEADER_ONLY 50 | #include "base_sink-inl.h" 51 | #endif 52 | -------------------------------------------------------------------------------- /modules/common/log/examples/spdlog-1.15.2/include/spdlog/sinks/basic_file_sink-inl.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #ifndef SPDLOG_HEADER_ONLY 7 | #include 8 | #endif 9 | 10 | #include 11 | #include 12 | 13 | namespace spdlog { 14 | namespace sinks { 15 | 16 | template 17 | SPDLOG_INLINE basic_file_sink::basic_file_sink(const filename_t &filename, 18 | bool truncate, 19 | const file_event_handlers &event_handlers) 20 | : file_helper_{event_handlers} { 21 | file_helper_.open(filename, truncate); 22 | } 23 | 24 | template 25 | SPDLOG_INLINE const filename_t &basic_file_sink::filename() const { 26 | return file_helper_.filename(); 27 | } 28 | 29 | template 30 | SPDLOG_INLINE void basic_file_sink::truncate() { 31 | std::lock_guard lock(base_sink::mutex_); 32 | file_helper_.reopen(true); 33 | } 34 | 35 | template 36 | SPDLOG_INLINE void basic_file_sink::sink_it_(const details::log_msg &msg) { 37 | memory_buf_t formatted; 38 | base_sink::formatter_->format(msg, formatted); 39 | file_helper_.write(formatted); 40 | } 41 | 42 | template 43 | SPDLOG_INLINE void basic_file_sink::flush_() { 44 | file_helper_.flush(); 45 | } 46 | 47 | } // namespace sinks 48 | } // namespace spdlog 49 | -------------------------------------------------------------------------------- /modules/common/log/examples/spdlog-1.15.2/include/spdlog/sinks/callback_sink.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | namespace spdlog { 14 | 15 | // callbacks type 16 | typedef std::function custom_log_callback; 17 | 18 | namespace sinks { 19 | /* 20 | * Trivial callback sink, gets a callback function and calls it on each log 21 | */ 22 | template 23 | class callback_sink final : public base_sink { 24 | public: 25 | explicit callback_sink(const custom_log_callback &callback) 26 | : callback_{callback} {} 27 | 28 | protected: 29 | void sink_it_(const details::log_msg &msg) override { callback_(msg); } 30 | void flush_() override{} 31 | 32 | private: 33 | custom_log_callback callback_; 34 | }; 35 | 36 | using callback_sink_mt = callback_sink; 37 | using callback_sink_st = callback_sink; 38 | 39 | } // namespace sinks 40 | 41 | // 42 | // factory functions 43 | // 44 | template 45 | inline std::shared_ptr callback_logger_mt(const std::string &logger_name, 46 | const custom_log_callback &callback) { 47 | return Factory::template create(logger_name, callback); 48 | } 49 | 50 | template 51 | inline std::shared_ptr callback_logger_st(const std::string &logger_name, 52 | const custom_log_callback &callback) { 53 | return Factory::template create(logger_name, callback); 54 | } 55 | 56 | } // namespace spdlog 57 | -------------------------------------------------------------------------------- /modules/common/log/examples/spdlog-1.15.2/include/spdlog/sinks/null_sink.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | namespace spdlog { 13 | namespace sinks { 14 | 15 | template 16 | class null_sink final : public base_sink { 17 | protected: 18 | void sink_it_(const details::log_msg &) override {} 19 | void flush_() override {} 20 | }; 21 | 22 | using null_sink_mt = null_sink; 23 | using null_sink_st = null_sink; 24 | 25 | } // namespace sinks 26 | 27 | template 28 | inline std::shared_ptr null_logger_mt(const std::string &logger_name) { 29 | auto null_logger = Factory::template create(logger_name); 30 | null_logger->set_level(level::off); 31 | return null_logger; 32 | } 33 | 34 | template 35 | inline std::shared_ptr null_logger_st(const std::string &logger_name) { 36 | auto null_logger = Factory::template create(logger_name); 37 | null_logger->set_level(level::off); 38 | return null_logger; 39 | } 40 | 41 | } // namespace spdlog 42 | -------------------------------------------------------------------------------- /modules/common/log/examples/spdlog-1.15.2/include/spdlog/sinks/ostream_sink.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | namespace spdlog { 13 | namespace sinks { 14 | template 15 | class ostream_sink final : public base_sink { 16 | public: 17 | explicit ostream_sink(std::ostream &os, bool force_flush = false) 18 | : ostream_(os), 19 | force_flush_(force_flush) {} 20 | ostream_sink(const ostream_sink &) = delete; 21 | ostream_sink &operator=(const ostream_sink &) = delete; 22 | 23 | protected: 24 | void sink_it_(const details::log_msg &msg) override { 25 | memory_buf_t formatted; 26 | base_sink::formatter_->format(msg, formatted); 27 | ostream_.write(formatted.data(), static_cast(formatted.size())); 28 | if (force_flush_) { 29 | ostream_.flush(); 30 | } 31 | } 32 | 33 | void flush_() override { ostream_.flush(); } 34 | 35 | std::ostream &ostream_; 36 | bool force_flush_; 37 | }; 38 | 39 | using ostream_sink_mt = ostream_sink; 40 | using ostream_sink_st = ostream_sink; 41 | 42 | } // namespace sinks 43 | } // namespace spdlog 44 | -------------------------------------------------------------------------------- /modules/common/log/examples/spdlog-1.15.2/include/spdlog/sinks/sink-inl.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #ifndef SPDLOG_HEADER_ONLY 7 | #include 8 | #endif 9 | 10 | #include 11 | 12 | SPDLOG_INLINE bool spdlog::sinks::sink::should_log(spdlog::level::level_enum msg_level) const { 13 | return msg_level >= level_.load(std::memory_order_relaxed); 14 | } 15 | 16 | SPDLOG_INLINE void spdlog::sinks::sink::set_level(level::level_enum log_level) { 17 | level_.store(log_level, std::memory_order_relaxed); 18 | } 19 | 20 | SPDLOG_INLINE spdlog::level::level_enum spdlog::sinks::sink::level() const { 21 | return static_cast(level_.load(std::memory_order_relaxed)); 22 | } 23 | -------------------------------------------------------------------------------- /modules/common/log/examples/spdlog-1.15.2/include/spdlog/sinks/sink.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | 9 | namespace spdlog { 10 | 11 | namespace sinks { 12 | class SPDLOG_API sink { 13 | public: 14 | virtual ~sink() = default; 15 | virtual void log(const details::log_msg &msg) = 0; 16 | virtual void flush() = 0; 17 | virtual void set_pattern(const std::string &pattern) = 0; 18 | virtual void set_formatter(std::unique_ptr sink_formatter) = 0; 19 | 20 | void set_level(level::level_enum log_level); 21 | level::level_enum level() const; 22 | bool should_log(level::level_enum msg_level) const; 23 | 24 | protected: 25 | // sink log level - default is all 26 | level_t level_{level::trace}; 27 | }; 28 | 29 | } // namespace sinks 30 | } // namespace spdlog 31 | 32 | #ifdef SPDLOG_HEADER_ONLY 33 | #include "sink-inl.h" 34 | #endif 35 | -------------------------------------------------------------------------------- /modules/common/log/examples/spdlog-1.15.2/include/spdlog/sinks/stdout_color_sinks-inl.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #ifndef SPDLOG_HEADER_ONLY 7 | #include 8 | #endif 9 | 10 | #include 11 | #include 12 | 13 | namespace spdlog { 14 | 15 | template 16 | SPDLOG_INLINE std::shared_ptr stdout_color_mt(const std::string &logger_name, 17 | color_mode mode) { 18 | return Factory::template create(logger_name, mode); 19 | } 20 | 21 | template 22 | SPDLOG_INLINE std::shared_ptr stdout_color_st(const std::string &logger_name, 23 | color_mode mode) { 24 | return Factory::template create(logger_name, mode); 25 | } 26 | 27 | template 28 | SPDLOG_INLINE std::shared_ptr stderr_color_mt(const std::string &logger_name, 29 | color_mode mode) { 30 | return Factory::template create(logger_name, mode); 31 | } 32 | 33 | template 34 | SPDLOG_INLINE std::shared_ptr stderr_color_st(const std::string &logger_name, 35 | color_mode mode) { 36 | return Factory::template create(logger_name, mode); 37 | } 38 | } // namespace spdlog 39 | -------------------------------------------------------------------------------- /modules/common/log/examples/spdlog-1.15.2/include/spdlog/version.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #define SPDLOG_VER_MAJOR 1 7 | #define SPDLOG_VER_MINOR 15 8 | #define SPDLOG_VER_PATCH 2 9 | 10 | #define SPDLOG_TO_VERSION(major, minor, patch) (major * 10000 + minor * 100 + patch) 11 | #define SPDLOG_VERSION SPDLOG_TO_VERSION(SPDLOG_VER_MAJOR, SPDLOG_VER_MINOR, SPDLOG_VER_PATCH) 12 | -------------------------------------------------------------------------------- /modules/common/log/include/grape/log/config.h: -------------------------------------------------------------------------------- 1 | //================================================================================================= 2 | // Copyright (C) 2023 GRAPE Contributors 3 | //================================================================================================= 4 | 5 | #pragma once 6 | 7 | #include "grape/log/formatters/default_formatter.h" 8 | #include "grape/log/sinks/console_sink.h" 9 | #include "grape/utils/file_system.h" 10 | 11 | namespace grape::log { 12 | 13 | /// @brief Logger configuration 14 | struct Config { 15 | static constexpr auto DEFAULT_QUEUE_CAPACITY = 1000U; 16 | static constexpr auto DEFAULT_FLUSH_PERIOD = std::chrono::microseconds(1000); 17 | 18 | /// Threshold severity at which messages are logged. Eg: if set to 'Warn', only 'Warn', 'Error' 19 | /// and 'Critical' messages are logged 20 | Severity threshold{ Severity::Debug }; 21 | 22 | /// The log receiver function 23 | std::shared_ptr sink{ std::make_shared>() }; 24 | 25 | /// The maximum number of records the internal buffer can hold without flushing the queue. 26 | /// @note To avoid overflow resulting in missed logs, set this to (>= max_logs_per_second * 27 | /// flush_period) 28 | std::size_t queue_capacity{ DEFAULT_QUEUE_CAPACITY }; 29 | 30 | /// Interval between flushing logs into sink. 31 | /// @note To avoid overflowing the queue, set this to (<= queue_capacity/max_logs_per_second) 32 | std::chrono::microseconds flush_period{ DEFAULT_FLUSH_PERIOD }; 33 | 34 | /// Identifying name for the logger 35 | std::string logger_name = utils::getProgramName(); 36 | }; 37 | 38 | } // namespace grape::log 39 | -------------------------------------------------------------------------------- /modules/common/log/include/grape/log/formatters/default_formatter.h: -------------------------------------------------------------------------------- 1 | //================================================================================================= 2 | // Copyright (C) 2023 GRAPE Contributors 3 | //================================================================================================= 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | 10 | #include "grape/log/record.h" 11 | 12 | namespace grape::log { 13 | 14 | /// Default log formatter implementation. 15 | struct DefaultFormatter { 16 | static auto format(const Record& record) -> std::string { 17 | const auto file_name = std::filesystem::path(record.location.file_name()).filename().string(); 18 | return std::format("[{}] [{}] [{}] [{}:{}] {}", record.timestamp, record.logger_name.cStr(), 19 | toString(record.severity), file_name, record.location.line(), 20 | record.message.cStr()); 21 | } 22 | }; 23 | 24 | } // namespace grape::log 25 | -------------------------------------------------------------------------------- /modules/common/log/include/grape/log/record.h: -------------------------------------------------------------------------------- 1 | //================================================================================================= 2 | // Copyright (C) 2023 GRAPE Contributors 3 | //================================================================================================= 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include "grape/log/severity.h" 12 | #include "grape/realtime/fixed_string.h" 13 | 14 | namespace grape::log { 15 | 16 | /// A single log record 17 | struct [[nodiscard]] Record { 18 | static constexpr auto MAX_LOGGER_NAME_LEN = 63U; 19 | static constexpr auto MAX_LOG_MESSAGE_LEN = 255U; 20 | 21 | std::chrono::time_point timestamp; 22 | std::source_location location; 23 | realtime::FixedString logger_name; 24 | realtime::FixedString message; 25 | Severity severity{ Severity::Debug }; 26 | }; 27 | 28 | // Ensure any future changes maintains triviality for the sake of performance 29 | // Logger class relies on this being trivially copyable 30 | static_assert(std::is_trivially_copyable_v); 31 | static_assert(std::is_trivially_move_constructible_v); 32 | 33 | } // namespace grape::log 34 | -------------------------------------------------------------------------------- /modules/common/log/include/grape/log/severity.h: -------------------------------------------------------------------------------- 1 | //================================================================================================= 2 | // Copyright (C) 2023 GRAPE Contributors 3 | //================================================================================================= 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | 10 | #include "grape/utils/enums.h" 11 | 12 | namespace grape::log { 13 | 14 | /// Logging severity levels 15 | enum class [[nodiscard]] Severity : std::uint8_t { 16 | Critical, //!< For non-recoverable errors. System may be unusable. 17 | Error, //!< For conditions outside normal operating envelope. 18 | Warn, //!< For conditions within but approaching limits of operating envelope. 19 | Note, //!< For significant events that may or may not be unusual. 20 | Info, //!< For general informational messages. 21 | Debug //!< For debugging information. 22 | }; 23 | 24 | /// @return String representation of Severity 25 | constexpr auto toString(Severity sev) -> std::string_view { 26 | return enums::name(sev); 27 | } 28 | } // namespace grape::log 29 | -------------------------------------------------------------------------------- /modules/common/log/include/grape/log/sinks/console_sink.h: -------------------------------------------------------------------------------- 1 | //================================================================================================= 2 | // Copyright (C) 2023 GRAPE Contributors 3 | //================================================================================================= 4 | 5 | #pragma once 6 | 7 | #include 8 | 9 | #include 10 | 11 | #include "grape/log/record.h" 12 | #include "grape/log/sinks/sink.h" 13 | 14 | namespace grape::log { 15 | 16 | /// Log sink that just writes to standard error output 17 | template 18 | struct ConsoleSink : public Sink { 19 | void write(const Record& record) override { 20 | if (::isatty(STDERR_FILENO) != 0) { // color format the logs if going to terminal 21 | const auto* const color = [](Severity sev) { 22 | switch (sev) { 23 | // clang-format off 24 | case Severity::Critical: return "\033[37;41m"; // white on red 25 | case Severity::Error: return "\033[31m"; // red 26 | case Severity::Warn: return "\033[33m"; // yellow 27 | case Severity::Note: [[fallthrough]]; 28 | case Severity::Info: [[fallthrough]]; 29 | case Severity::Debug: return ""; 30 | // clang-format on 31 | } 32 | return ""; 33 | }(record.severity); 34 | static constexpr auto RESET_COLOR = "\033[0m"; 35 | std::println(stderr, "{}{}{}", color, F::format(record), RESET_COLOR); 36 | } else { 37 | std::println(stderr, "{}", F::format(record)); 38 | } 39 | } 40 | }; 41 | } // namespace grape::log 42 | -------------------------------------------------------------------------------- /modules/common/log/include/grape/log/sinks/file_sink.h: -------------------------------------------------------------------------------- 1 | //================================================================================================= 2 | // Copyright (C) 2023 GRAPE Contributors 3 | //================================================================================================= 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include "grape/exception.h" 12 | #include "grape/log/sinks/sink.h" 13 | 14 | namespace grape::log { 15 | 16 | /// Log sink that writes to a file 17 | template 18 | class FileSink : public Sink { 19 | private: 20 | std::ofstream fstream_; 21 | 22 | public: 23 | /// Constructs a log sink that writes to the specified file. 24 | /// @param file_path Path to the file to write to 25 | /// @param append If true, appends to the file. Otherwise, overwrites it. 26 | /// @throws Exception if the file cannot be opened 27 | /// @note The file is opened in append mode by default. 28 | explicit FileSink(const std::filesystem::path& file_path, bool append = true) { 29 | const auto mode = std::ofstream::out | (append ? std::ofstream::app : std::ofstream::trunc); 30 | fstream_.open(file_path, mode); 31 | if (fstream_.fail()) { 32 | panic(std::format("Unable to open {}", file_path.string())); 33 | } 34 | fstream_.exceptions(std::ios_base::failbit | std::ios_base::badbit); 35 | } 36 | 37 | void write(const Record& rec) { 38 | fstream_ << F::format(rec) << '\n' << std::flush; 39 | } 40 | }; 41 | 42 | } // namespace grape::log 43 | -------------------------------------------------------------------------------- /modules/common/log/include/grape/log/sinks/sink.h: -------------------------------------------------------------------------------- 1 | //================================================================================================= 2 | // Copyright (C) 2023 GRAPE Contributors 3 | //================================================================================================= 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | 10 | namespace grape::log { 11 | 12 | struct Record; 13 | 14 | //================================================================================================= 15 | /// Interface for log record text formatters, for use with log sinks 16 | template 17 | concept Formatter = requires(const Record& record) { 18 | { T::format(record) } -> std::same_as; 19 | }; 20 | 21 | //================================================================================================= 22 | /// Abstract interface for log sinks 23 | struct Sink { 24 | virtual ~Sink() = default; 25 | virtual void write(const Record& record) = 0; 26 | 27 | Sink(Sink const&) = delete; 28 | Sink(Sink&&) = default; 29 | auto operator=(Sink const&) = delete; 30 | auto operator=(Sink&&) -> Sink& = default; 31 | 32 | protected: 33 | Sink() = default; 34 | }; 35 | } // namespace grape::log 36 | -------------------------------------------------------------------------------- /modules/common/log/src/syslog.cpp: -------------------------------------------------------------------------------- 1 | //================================================================================================= 2 | // Copyright (C) 2025 GRAPE Contributors 3 | //================================================================================================= 4 | 5 | #include "grape/log/syslog.h" 6 | 7 | #include "grape/exception.h" 8 | 9 | namespace { 10 | // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) 11 | std::optional s_logger = std::nullopt; 12 | } // namespace 13 | 14 | namespace grape::syslog { 15 | 16 | //------------------------------------------------------------------------------------------------- 17 | void init(log::Config&& config) { 18 | if (s_logger.has_value()) { 19 | panic("Already initialised"); 20 | } 21 | s_logger.emplace(std::move(config)); 22 | } 23 | 24 | //------------------------------------------------------------------------------------------------- 25 | auto instance() -> log::Logger& { 26 | if (not s_logger) { 27 | panic("Not initialised"); 28 | } 29 | return s_logger.value(); // NOLINT(bugprone-unchecked-optional-access) 30 | } 31 | 32 | } // namespace grape::syslog 33 | -------------------------------------------------------------------------------- /modules/common/log/tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # ================================================================================================= 2 | # Copyright (C) 2023 GRAPE Contributors 3 | # ================================================================================================= 4 | 5 | define_module_test(NAME tests SOURCES tests.cpp) 6 | -------------------------------------------------------------------------------- /modules/common/realtime/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # ================================================================================================= 2 | # Copyright (C) 2023 GRAPE Contributors 3 | # ================================================================================================= 4 | 5 | declare_module( 6 | NAME realtime 7 | DEPENDS_ON_MODULES "base" 8 | DEPENDS_ON_EXTERNAL_PROJECTS "") 9 | 10 | # library sources 11 | set(SOURCES 12 | src/schedule.cpp 13 | README.md 14 | include/grape/realtime/error.h 15 | include/grape/realtime/fifo_buffer.h 16 | include/grape/realtime/fixed_string.h 17 | include/grape/realtime/mpsc_queue.h 18 | include/grape/realtime/mutex.h 19 | include/grape/realtime/schedule.h 20 | include/grape/realtime/thread.h) 21 | 22 | # library target 23 | define_module_library( 24 | NAME realtime 25 | PUBLIC_LINK_LIBS grape::base 26 | PRIVATE_LINK_LIBS "" 27 | SOURCES ${SOURCES} 28 | PUBLIC_INCLUDE_PATHS $ 29 | $ 30 | PRIVATE_INCLUDE_PATHS "" 31 | SYSTEM_PRIVATE_INCLUDE_PATHS "") 32 | 33 | # Subprojects 34 | add_subdirectory(tests) 35 | add_subdirectory(examples) 36 | -------------------------------------------------------------------------------- /modules/common/realtime/docs/media/2020-10-26-john-ogness-rt-checklist.pdf: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:ec13bd2d46da05d304ff9b939c5fb237ef92e3a7d9f119129ba8439716a12643 3 | size 247772 4 | -------------------------------------------------------------------------------- /modules/common/realtime/docs/media/2023-11-29-ubuntu-rtl-whitepaper.pdf: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:13a553b2b3469ccd38a68f14909fdd722ee6572e2d082658f3322e973f747b7d 3 | size 2183293 4 | -------------------------------------------------------------------------------- /modules/common/realtime/docs/media/rt-application.dia: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:180d8c50f2ab5b4c3fec6e625d7039b8852287b2a8fbb59b5275ac98813e6373 3 | size 2092 4 | -------------------------------------------------------------------------------- /modules/common/realtime/docs/media/rt-application.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:1066befbd5833f96af706e891b1d1e73a0e228085f41770e95b4a83e2f01cd6f 3 | size 8840 4 | -------------------------------------------------------------------------------- /modules/common/realtime/examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # ================================================================================================= 2 | # Copyright (C) 2023 GRAPE Contributors 3 | # ================================================================================================= 4 | 5 | define_module_example(NAME mpscq_example SOURCES mpscq_example.cpp) 6 | 7 | define_module_example( 8 | NAME mpscq_bench 9 | SOURCES mpscq_bench.cpp 10 | PRIVATE_LINK_LIBS benchmark::benchmark 11 | PUBLIC_LINK_LIBS "") 12 | 13 | define_module_example(NAME fifo_example SOURCES fifo_example.cpp) 14 | 15 | define_module_example( 16 | NAME fifo_bench 17 | SOURCES fifo_bench.cpp 18 | PRIVATE_LINK_LIBS benchmark::benchmark 19 | PUBLIC_LINK_LIBS "") 20 | 21 | define_module_example(NAME string_example SOURCES string_example.cpp) 22 | 23 | define_module_example(NAME schedule_example SOURCES schedule_example.cpp) 24 | 25 | define_module_example(NAME thread_example SOURCES thread_example.cpp) 26 | 27 | define_module_example(NAME error_example SOURCES error_example.cpp) 28 | -------------------------------------------------------------------------------- /modules/common/realtime/examples/error_example.cpp: -------------------------------------------------------------------------------- 1 | //================================================================================================= 2 | // Copyright (C) 2025 GRAPE Contributors 3 | //================================================================================================= 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "grape/realtime/error.h" 11 | 12 | namespace { 13 | 14 | //================================================================================================= 15 | // An example function that returns an error on failure 16 | auto doWork() -> std::expected { 17 | const auto err = std::make_error_code(std::errc::invalid_argument); 18 | return std::unexpected(grape::realtime::Error{ err.message() }); 19 | } 20 | } // namespace 21 | 22 | //================================================================================================= 23 | auto main() -> int { 24 | try { 25 | const auto result = doWork(); 26 | if (not result) { 27 | const auto& err = result.error(); 28 | const auto& loc = err.location(); 29 | std::println("[{} ({})] : {}", loc.function_name(), loc.line(), err.message()); 30 | } 31 | return EXIT_SUCCESS; 32 | } catch (...) { 33 | (void)fputs("An exception occured\n", stderr); 34 | return EXIT_FAILURE; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /modules/common/realtime/examples/schedule_example.cpp: -------------------------------------------------------------------------------- 1 | //================================================================================================= 2 | // Copyright (C) 2023 GRAPE Contributors 3 | //================================================================================================= 4 | 5 | #include 6 | #include 7 | 8 | #include "grape/exception.h" 9 | #include "grape/realtime/schedule.h" 10 | 11 | //================================================================================================= 12 | auto main() -> int { 13 | try { 14 | static constexpr auto CPUS = { 1U, 2U, 3U }; 15 | 16 | // Set CPU affinity 17 | const auto cpu_set_err = grape::realtime::setCpuAffinity(CPUS); 18 | if (not cpu_set_err) { 19 | std::println("Could not set CPU affinity: {}", cpu_set_err.error().message()); 20 | return EXIT_FAILURE; 21 | } 22 | std::println("Set to run on CPUs {}", CPUS); 23 | 24 | // set real-time schedule 25 | static constexpr auto RT_PRIORITY = 20; 26 | const auto is_scheduled = grape::realtime::setSchedule( 27 | { .policy = grape::realtime::Schedule::Policy::Realtime, .priority = RT_PRIORITY }); 28 | if (not is_scheduled) { 29 | std::println("Could not set RT schedule: {}", is_scheduled.error().message()); 30 | return EXIT_FAILURE; 31 | } 32 | std::println("Scheduled to run at RT priority {}", RT_PRIORITY); 33 | return EXIT_SUCCESS; 34 | 35 | } catch (...) { 36 | grape::Exception::print(); 37 | } 38 | return EXIT_SUCCESS; 39 | } 40 | -------------------------------------------------------------------------------- /modules/common/realtime/examples/string_example.cpp: -------------------------------------------------------------------------------- 1 | //================================================================================================= 2 | // Copyright (C) 2024 GRAPE Contributors 3 | //================================================================================================= 4 | 5 | #include 6 | 7 | #include "grape/exception.h" 8 | #include "grape/realtime/fixed_string.h" 9 | 10 | //================================================================================================= 11 | auto main() -> int { 12 | try { 13 | // NOLINTBEGIN(cppcoreguidelines-avoid-magic-numbers) 14 | using FixedString8 = grape::realtime::FixedString<7>; 15 | using FixedString64 = grape::realtime::FixedString<63>; 16 | // NOLINTEND(cppcoreguidelines-avoid-magic-numbers) 17 | 18 | static constexpr FixedString8 STRING("abcdefghij"); //!< this will get truncated to fit 19 | constexpr auto SUB_STRING = STRING.str().substr(0, 2); 20 | constexpr auto STRING_LENGTH = STRING.length(); 21 | std::println("String='{}', length={}", STRING.str(), STRING_LENGTH); 22 | std::println("Sub-string='{}'", SUB_STRING); 23 | 24 | const FixedString64 string64{ "{} + {} = {}", 2, 3, 5 }; 25 | std::println("{}", string64.str()); 26 | } catch (...) { 27 | grape::Exception::print(); 28 | return EXIT_FAILURE; 29 | } 30 | return EXIT_SUCCESS; 31 | } 32 | -------------------------------------------------------------------------------- /modules/common/realtime/tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # ================================================================================================= 2 | # Copyright (C) 2023 GRAPE Contributors 3 | # ================================================================================================= 4 | 5 | define_module_test( 6 | NAME tests 7 | SOURCES mpscq_tests.cpp fifo_buffer_tests.cpp string_tests.cpp mutex_tests.cpp) 8 | -------------------------------------------------------------------------------- /modules/common/realtime/tests/mutex_tests.cpp: -------------------------------------------------------------------------------- 1 | //================================================================================================= 2 | // Copyright (C) 2023 GRAPE Contributors 3 | //================================================================================================= 4 | 5 | #include "catch2/catch_test_macros.hpp" 6 | #include "grape/realtime/mutex.h" 7 | 8 | namespace { 9 | 10 | TEST_CASE("Mutex functionality", "[Mutex]") { 11 | grape::realtime::Mutex mutex; 12 | 13 | SECTION("Lock and Unlock") { 14 | mutex.lock(); 15 | REQUIRE_NOTHROW(mutex.unlock()); 16 | } 17 | 18 | SECTION("Try Lock") { 19 | REQUIRE(mutex.try_lock()); 20 | REQUIRE_FALSE(mutex.try_lock()); // Second try should fail 21 | mutex.unlock(); // Release the lock for future tests 22 | } 23 | 24 | SECTION("Native Handle") { 25 | grape::realtime::Mutex::native_handle_type handle = mutex.native_handle(); 26 | REQUIRE(handle != nullptr); 27 | } 28 | 29 | SECTION("Multiple Lock/Unlock") { 30 | mutex.lock(); 31 | REQUIRE_FALSE(mutex.try_lock()); // Try lock while already locked should fail 32 | mutex.unlock(); 33 | REQUIRE_NOTHROW(mutex.lock()); 34 | REQUIRE_FALSE(mutex.try_lock()); // Try lock while already locked should fail 35 | REQUIRE_NOTHROW(mutex.unlock()); 36 | } 37 | } 38 | 39 | } // namespace 40 | -------------------------------------------------------------------------------- /modules/common/script/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # ================================================================================================= 2 | # Copyright (C) 2023 GRAPE Contributors 3 | # ================================================================================================= 4 | 5 | declare_module( 6 | NAME script 7 | DEPENDS_ON_MODULES base 8 | DEPENDS_ON_EXTERNAL_PROJECTS "") 9 | 10 | # library sources 11 | set(SOURCES src/script.cpp README.md include/grape/script/script.h) 12 | 13 | # library target 14 | define_module_library( 15 | NAME script 16 | PUBLIC_LINK_LIBS grape::base 17 | PRIVATE_LINK_LIBS $ 18 | SOURCES ${SOURCES} 19 | PUBLIC_INCLUDE_PATHS $ 20 | $ 21 | PRIVATE_INCLUDE_PATHS "" 22 | SYSTEM_PRIVATE_INCLUDE_PATHS ${CMAKE_CURRENT_SOURCE_DIR}/third_party/lua-5.4.7/src/) 23 | 24 | # Subprojects 25 | add_subdirectory(third_party) 26 | add_subdirectory(tests) 27 | add_subdirectory(examples) 28 | -------------------------------------------------------------------------------- /modules/common/script/examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # ================================================================================================= 2 | # Copyright (C) 2023 GRAPE Contributors 3 | # ================================================================================================= 4 | 5 | define_module_example(NAME config_example SOURCES config_example.cpp) 6 | 7 | define_module_example(NAME config_array_example SOURCES config_array_example.cpp) 8 | -------------------------------------------------------------------------------- /modules/common/script/tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # ================================================================================================= 2 | # Copyright (C) 2023 GRAPE Contributors 3 | # ================================================================================================= 4 | 5 | define_module_test(NAME tests SOURCES tests.cpp) 6 | -------------------------------------------------------------------------------- /modules/common/script/third_party/README.md: -------------------------------------------------------------------------------- 1 | This subdirectory contains lua source code obtained and expanded as follows 2 | 3 | ```bash 4 | wget https://www.lua.org/ftp/lua-5.4.7.tar.gz 5 | tar zxvf lua-5.4.7.tar.gz 6 | ``` 7 | -------------------------------------------------------------------------------- /modules/common/script/third_party/lua-5.4.7/README: -------------------------------------------------------------------------------- 1 | 2 | This is Lua 5.4.7, released on 13 Jun 2024. 3 | 4 | For installation instructions, license details, and 5 | further information about Lua, see doc/readme.html. 6 | 7 | -------------------------------------------------------------------------------- /modules/common/script/third_party/lua-5.4.7/doc/OSIApproved_100X125.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:0f6cc3aaa68597034efda8bb6bfa214fc2fde99bd1e67d0bb32d7fe75a5dc777 3 | size 12127 4 | -------------------------------------------------------------------------------- /modules/common/script/third_party/lua-5.4.7/doc/index.css: -------------------------------------------------------------------------------- 1 | ul { 2 | list-style-type: none ; 3 | } 4 | 5 | ul.contents { 6 | padding: 0 ; 7 | } 8 | 9 | table { 10 | border: none ; 11 | border-spacing: 0 ; 12 | border-collapse: collapse ; 13 | } 14 | 15 | td { 16 | vertical-align: top ; 17 | padding: 0 ; 18 | text-align: left ; 19 | line-height: 1.25 ; 20 | width: 15% ; 21 | } 22 | -------------------------------------------------------------------------------- /modules/common/script/third_party/lua-5.4.7/doc/logo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cvilas/grape/58a2733d274a944760156e20ee9f2914c2cf64d2/modules/common/script/third_party/lua-5.4.7/doc/logo.gif -------------------------------------------------------------------------------- /modules/common/script/third_party/lua-5.4.7/doc/manual.css: -------------------------------------------------------------------------------- 1 | h3 code { 2 | font-family: inherit ; 3 | font-size: inherit ; 4 | } 5 | 6 | pre, code { 7 | font-size: 12pt ; 8 | } 9 | 10 | span.apii { 11 | color: gray ; 12 | float: right ; 13 | font-family: inherit ; 14 | font-style: normal ; 15 | font-size: small ; 16 | } 17 | 18 | h2:before { 19 | content: "" ; 20 | padding-right: 0em ; 21 | } 22 | -------------------------------------------------------------------------------- /modules/common/script/third_party/lua-5.4.7/src/lapi.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lapi.h $ 3 | ** Auxiliary functions from Lua API 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #ifndef lapi_h 8 | #define lapi_h 9 | 10 | 11 | #include "llimits.h" 12 | #include "lstate.h" 13 | 14 | 15 | /* Increments 'L->top.p', checking for stack overflows */ 16 | #define api_incr_top(L) {L->top.p++; \ 17 | api_check(L, L->top.p <= L->ci->top.p, \ 18 | "stack overflow");} 19 | 20 | 21 | /* 22 | ** If a call returns too many multiple returns, the callee may not have 23 | ** stack space to accommodate all results. In this case, this macro 24 | ** increases its stack space ('L->ci->top.p'). 25 | */ 26 | #define adjustresults(L,nres) \ 27 | { if ((nres) <= LUA_MULTRET && L->ci->top.p < L->top.p) \ 28 | L->ci->top.p = L->top.p; } 29 | 30 | 31 | /* Ensure the stack has at least 'n' elements */ 32 | #define api_checknelems(L,n) \ 33 | api_check(L, (n) < (L->top.p - L->ci->func.p), \ 34 | "not enough elements in the stack") 35 | 36 | 37 | /* 38 | ** To reduce the overhead of returning from C functions, the presence of 39 | ** to-be-closed variables in these functions is coded in the CallInfo's 40 | ** field 'nresults', in a way that functions with no to-be-closed variables 41 | ** with zero, one, or "all" wanted results have no overhead. Functions 42 | ** with other number of wanted results, as well as functions with 43 | ** variables to be closed, have an extra check. 44 | */ 45 | 46 | #define hastocloseCfunc(n) ((n) < LUA_MULTRET) 47 | 48 | /* Map [-1, inf) (range of 'nresults') into (-inf, -2] */ 49 | #define codeNresults(n) (-(n) - 3) 50 | #define decodeNresults(n) (-(n) - 3) 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /modules/common/script/third_party/lua-5.4.7/src/linit.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: linit.c $ 3 | ** Initialization of libraries for lua.c and other clients 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | 8 | #define linit_c 9 | #define LUA_LIB 10 | 11 | /* 12 | ** If you embed Lua in your program and need to open the standard 13 | ** libraries, call luaL_openlibs in your program. If you need a 14 | ** different set of libraries, copy this file to your project and edit 15 | ** it to suit your needs. 16 | ** 17 | ** You can also *preload* libraries, so that a later 'require' can 18 | ** open the library, which is already linked to the application. 19 | ** For that, do the following code: 20 | ** 21 | ** luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE); 22 | ** lua_pushcfunction(L, luaopen_modname); 23 | ** lua_setfield(L, -2, modname); 24 | ** lua_pop(L, 1); // remove PRELOAD table 25 | */ 26 | 27 | #include "lprefix.h" 28 | 29 | 30 | #include 31 | 32 | #include "lua.h" 33 | 34 | #include "lualib.h" 35 | #include "lauxlib.h" 36 | 37 | 38 | /* 39 | ** these libs are loaded by lua.c and are readily available to any Lua 40 | ** program 41 | */ 42 | static const luaL_Reg loadedlibs[] = { 43 | {LUA_GNAME, luaopen_base}, 44 | {LUA_LOADLIBNAME, luaopen_package}, 45 | {LUA_COLIBNAME, luaopen_coroutine}, 46 | {LUA_TABLIBNAME, luaopen_table}, 47 | {LUA_IOLIBNAME, luaopen_io}, 48 | {LUA_OSLIBNAME, luaopen_os}, 49 | {LUA_STRLIBNAME, luaopen_string}, 50 | {LUA_MATHLIBNAME, luaopen_math}, 51 | {LUA_UTF8LIBNAME, luaopen_utf8}, 52 | {LUA_DBLIBNAME, luaopen_debug}, 53 | {NULL, NULL} 54 | }; 55 | 56 | 57 | LUALIB_API void luaL_openlibs (lua_State *L) { 58 | const luaL_Reg *lib; 59 | /* "require" functions from 'loadedlibs' and set results to global table */ 60 | for (lib = loadedlibs; lib->func; lib++) { 61 | luaL_requiref(L, lib->name, lib->func, 1); 62 | lua_pop(L, 1); /* remove lib */ 63 | } 64 | } 65 | 66 | -------------------------------------------------------------------------------- /modules/common/script/third_party/lua-5.4.7/src/lopnames.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lopnames.h $ 3 | ** Opcode names 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #if !defined(lopnames_h) 8 | #define lopnames_h 9 | 10 | #include 11 | 12 | 13 | /* ORDER OP */ 14 | 15 | static const char *const opnames[] = { 16 | "MOVE", 17 | "LOADI", 18 | "LOADF", 19 | "LOADK", 20 | "LOADKX", 21 | "LOADFALSE", 22 | "LFALSESKIP", 23 | "LOADTRUE", 24 | "LOADNIL", 25 | "GETUPVAL", 26 | "SETUPVAL", 27 | "GETTABUP", 28 | "GETTABLE", 29 | "GETI", 30 | "GETFIELD", 31 | "SETTABUP", 32 | "SETTABLE", 33 | "SETI", 34 | "SETFIELD", 35 | "NEWTABLE", 36 | "SELF", 37 | "ADDI", 38 | "ADDK", 39 | "SUBK", 40 | "MULK", 41 | "MODK", 42 | "POWK", 43 | "DIVK", 44 | "IDIVK", 45 | "BANDK", 46 | "BORK", 47 | "BXORK", 48 | "SHRI", 49 | "SHLI", 50 | "ADD", 51 | "SUB", 52 | "MUL", 53 | "MOD", 54 | "POW", 55 | "DIV", 56 | "IDIV", 57 | "BAND", 58 | "BOR", 59 | "BXOR", 60 | "SHL", 61 | "SHR", 62 | "MMBIN", 63 | "MMBINI", 64 | "MMBINK", 65 | "UNM", 66 | "BNOT", 67 | "NOT", 68 | "LEN", 69 | "CONCAT", 70 | "CLOSE", 71 | "TBC", 72 | "JMP", 73 | "EQ", 74 | "LT", 75 | "LE", 76 | "EQK", 77 | "EQI", 78 | "LTI", 79 | "LEI", 80 | "GTI", 81 | "GEI", 82 | "TEST", 83 | "TESTSET", 84 | "CALL", 85 | "TAILCALL", 86 | "RETURN", 87 | "RETURN0", 88 | "RETURN1", 89 | "FORLOOP", 90 | "FORPREP", 91 | "TFORPREP", 92 | "TFORCALL", 93 | "TFORLOOP", 94 | "SETLIST", 95 | "CLOSURE", 96 | "VARARG", 97 | "VARARGPREP", 98 | "EXTRAARG", 99 | NULL 100 | }; 101 | 102 | #endif 103 | 104 | -------------------------------------------------------------------------------- /modules/common/script/third_party/lua-5.4.7/src/lprefix.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lprefix.h $ 3 | ** Definitions for Lua code that must come before any other header file 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #ifndef lprefix_h 8 | #define lprefix_h 9 | 10 | 11 | /* 12 | ** Allows POSIX/XSI stuff 13 | */ 14 | #if !defined(LUA_USE_C89) /* { */ 15 | 16 | #if !defined(_XOPEN_SOURCE) 17 | #define _XOPEN_SOURCE 600 18 | #elif _XOPEN_SOURCE == 0 19 | #undef _XOPEN_SOURCE /* use -D_XOPEN_SOURCE=0 to undefine it */ 20 | #endif 21 | 22 | /* 23 | ** Allows manipulation of large files in gcc and some other compilers 24 | */ 25 | #if !defined(LUA_32BITS) && !defined(_FILE_OFFSET_BITS) 26 | #define _LARGEFILE_SOURCE 1 27 | #define _FILE_OFFSET_BITS 64 28 | #endif 29 | 30 | #endif /* } */ 31 | 32 | 33 | /* 34 | ** Windows stuff 35 | */ 36 | #if defined(_WIN32) /* { */ 37 | 38 | #if !defined(_CRT_SECURE_NO_WARNINGS) 39 | #define _CRT_SECURE_NO_WARNINGS /* avoid warnings about ISO C functions */ 40 | #endif 41 | 42 | #endif /* } */ 43 | 44 | #endif 45 | 46 | -------------------------------------------------------------------------------- /modules/common/script/third_party/lua-5.4.7/src/lstring.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lstring.h $ 3 | ** String table (keep all strings handled by Lua) 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #ifndef lstring_h 8 | #define lstring_h 9 | 10 | #include "lgc.h" 11 | #include "lobject.h" 12 | #include "lstate.h" 13 | 14 | 15 | /* 16 | ** Memory-allocation error message must be preallocated (it cannot 17 | ** be created after memory is exhausted) 18 | */ 19 | #define MEMERRMSG "not enough memory" 20 | 21 | 22 | /* 23 | ** Size of a TString: Size of the header plus space for the string 24 | ** itself (including final '\0'). 25 | */ 26 | #define sizelstring(l) (offsetof(TString, contents) + ((l) + 1) * sizeof(char)) 27 | 28 | #define luaS_newliteral(L, s) (luaS_newlstr(L, "" s, \ 29 | (sizeof(s)/sizeof(char))-1)) 30 | 31 | 32 | /* 33 | ** test whether a string is a reserved word 34 | */ 35 | #define isreserved(s) ((s)->tt == LUA_VSHRSTR && (s)->extra > 0) 36 | 37 | 38 | /* 39 | ** equality for short strings, which are always internalized 40 | */ 41 | #define eqshrstr(a,b) check_exp((a)->tt == LUA_VSHRSTR, (a) == (b)) 42 | 43 | 44 | LUAI_FUNC unsigned int luaS_hash (const char *str, size_t l, unsigned int seed); 45 | LUAI_FUNC unsigned int luaS_hashlongstr (TString *ts); 46 | LUAI_FUNC int luaS_eqlngstr (TString *a, TString *b); 47 | LUAI_FUNC void luaS_resize (lua_State *L, int newsize); 48 | LUAI_FUNC void luaS_clearcache (global_State *g); 49 | LUAI_FUNC void luaS_init (lua_State *L); 50 | LUAI_FUNC void luaS_remove (lua_State *L, TString *ts); 51 | LUAI_FUNC Udata *luaS_newudata (lua_State *L, size_t s, int nuvalue); 52 | LUAI_FUNC TString *luaS_newlstr (lua_State *L, const char *str, size_t l); 53 | LUAI_FUNC TString *luaS_new (lua_State *L, const char *str); 54 | LUAI_FUNC TString *luaS_createlngstrobj (lua_State *L, size_t l); 55 | 56 | 57 | #endif 58 | -------------------------------------------------------------------------------- /modules/common/script/third_party/lua-5.4.7/src/lua.hpp: -------------------------------------------------------------------------------- 1 | // lua.hpp 2 | // Lua header files for C++ 3 | // <> not supplied automatically because Lua also compiles as C++ 4 | 5 | extern "C" { 6 | #include "lua.h" 7 | #include "lualib.h" 8 | #include "lauxlib.h" 9 | } 10 | -------------------------------------------------------------------------------- /modules/common/script/third_party/lua-5.4.7/src/lualib.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lualib.h $ 3 | ** Lua standard libraries 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | 8 | #ifndef lualib_h 9 | #define lualib_h 10 | 11 | #include "lua.h" 12 | 13 | 14 | /* version suffix for environment variable names */ 15 | #define LUA_VERSUFFIX "_" LUA_VERSION_MAJOR "_" LUA_VERSION_MINOR 16 | 17 | 18 | LUAMOD_API int (luaopen_base) (lua_State *L); 19 | 20 | #define LUA_COLIBNAME "coroutine" 21 | LUAMOD_API int (luaopen_coroutine) (lua_State *L); 22 | 23 | #define LUA_TABLIBNAME "table" 24 | LUAMOD_API int (luaopen_table) (lua_State *L); 25 | 26 | #define LUA_IOLIBNAME "io" 27 | LUAMOD_API int (luaopen_io) (lua_State *L); 28 | 29 | #define LUA_OSLIBNAME "os" 30 | LUAMOD_API int (luaopen_os) (lua_State *L); 31 | 32 | #define LUA_STRLIBNAME "string" 33 | LUAMOD_API int (luaopen_string) (lua_State *L); 34 | 35 | #define LUA_UTF8LIBNAME "utf8" 36 | LUAMOD_API int (luaopen_utf8) (lua_State *L); 37 | 38 | #define LUA_MATHLIBNAME "math" 39 | LUAMOD_API int (luaopen_math) (lua_State *L); 40 | 41 | #define LUA_DBLIBNAME "debug" 42 | LUAMOD_API int (luaopen_debug) (lua_State *L); 43 | 44 | #define LUA_LOADLIBNAME "package" 45 | LUAMOD_API int (luaopen_package) (lua_State *L); 46 | 47 | 48 | /* open all previous libraries */ 49 | LUALIB_API void (luaL_openlibs) (lua_State *L); 50 | 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /modules/common/script/third_party/lua-5.4.7/src/lundump.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lundump.h $ 3 | ** load precompiled Lua chunks 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #ifndef lundump_h 8 | #define lundump_h 9 | 10 | #include "llimits.h" 11 | #include "lobject.h" 12 | #include "lzio.h" 13 | 14 | 15 | /* data to catch conversion errors */ 16 | #define LUAC_DATA "\x19\x93\r\n\x1a\n" 17 | 18 | #define LUAC_INT 0x5678 19 | #define LUAC_NUM cast_num(370.5) 20 | 21 | /* 22 | ** Encode major-minor version in one byte, one nibble for each 23 | */ 24 | #define LUAC_VERSION (((LUA_VERSION_NUM / 100) * 16) + LUA_VERSION_NUM % 100) 25 | 26 | #define LUAC_FORMAT 0 /* this is the official format */ 27 | 28 | /* load one chunk; from lundump.c */ 29 | LUAI_FUNC LClosure* luaU_undump (lua_State* L, ZIO* Z, const char* name); 30 | 31 | /* dump one chunk; from ldump.c */ 32 | LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, 33 | void* data, int strip); 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /modules/common/script/third_party/lua-5.4.7/src/lzio.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lzio.c $ 3 | ** Buffered streams 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #define lzio_c 8 | #define LUA_CORE 9 | 10 | #include "lprefix.h" 11 | 12 | 13 | #include 14 | 15 | #include "lua.h" 16 | 17 | #include "llimits.h" 18 | #include "lmem.h" 19 | #include "lstate.h" 20 | #include "lzio.h" 21 | 22 | 23 | int luaZ_fill (ZIO *z) { 24 | size_t size; 25 | lua_State *L = z->L; 26 | const char *buff; 27 | lua_unlock(L); 28 | buff = z->reader(L, z->data, &size); 29 | lua_lock(L); 30 | if (buff == NULL || size == 0) 31 | return EOZ; 32 | z->n = size - 1; /* discount char being returned */ 33 | z->p = buff; 34 | return cast_uchar(*(z->p++)); 35 | } 36 | 37 | 38 | void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader, void *data) { 39 | z->L = L; 40 | z->reader = reader; 41 | z->data = data; 42 | z->n = 0; 43 | z->p = NULL; 44 | } 45 | 46 | 47 | /* --------------------------------------------------------------- read --- */ 48 | size_t luaZ_read (ZIO *z, void *b, size_t n) { 49 | while (n) { 50 | size_t m; 51 | if (z->n == 0) { /* no bytes in buffer? */ 52 | if (luaZ_fill(z) == EOZ) /* try to read more */ 53 | return n; /* no more input; return number of missing bytes */ 54 | else { 55 | z->n++; /* luaZ_fill consumed first byte; put it back */ 56 | z->p--; 57 | } 58 | } 59 | m = (n <= z->n) ? n : z->n; /* min. between n and z->n */ 60 | memcpy(b, z->p, m); 61 | z->n -= m; 62 | z->p += m; 63 | b = (char *)b + m; 64 | n -= m; 65 | } 66 | return 0; 67 | } 68 | 69 | -------------------------------------------------------------------------------- /modules/common/script/third_party/lua-5.4.7/src/lzio.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lzio.h $ 3 | ** Buffered streams 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | 8 | #ifndef lzio_h 9 | #define lzio_h 10 | 11 | #include "lua.h" 12 | 13 | #include "lmem.h" 14 | 15 | 16 | #define EOZ (-1) /* end of stream */ 17 | 18 | typedef struct Zio ZIO; 19 | 20 | #define zgetc(z) (((z)->n--)>0 ? cast_uchar(*(z)->p++) : luaZ_fill(z)) 21 | 22 | 23 | typedef struct Mbuffer { 24 | char *buffer; 25 | size_t n; 26 | size_t buffsize; 27 | } Mbuffer; 28 | 29 | #define luaZ_initbuffer(L, buff) ((buff)->buffer = NULL, (buff)->buffsize = 0) 30 | 31 | #define luaZ_buffer(buff) ((buff)->buffer) 32 | #define luaZ_sizebuffer(buff) ((buff)->buffsize) 33 | #define luaZ_bufflen(buff) ((buff)->n) 34 | 35 | #define luaZ_buffremove(buff,i) ((buff)->n -= (i)) 36 | #define luaZ_resetbuffer(buff) ((buff)->n = 0) 37 | 38 | 39 | #define luaZ_resizebuffer(L, buff, size) \ 40 | ((buff)->buffer = luaM_reallocvchar(L, (buff)->buffer, \ 41 | (buff)->buffsize, size), \ 42 | (buff)->buffsize = size) 43 | 44 | #define luaZ_freebuffer(L, buff) luaZ_resizebuffer(L, buff, 0) 45 | 46 | 47 | LUAI_FUNC void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader, 48 | void *data); 49 | LUAI_FUNC size_t luaZ_read (ZIO* z, void *b, size_t n); /* read next n bytes */ 50 | 51 | 52 | 53 | /* --------- Private Part ------------------ */ 54 | 55 | struct Zio { 56 | size_t n; /* bytes still unread */ 57 | const char *p; /* current position in buffer */ 58 | lua_Reader reader; /* reader function */ 59 | void *data; /* additional data */ 60 | lua_State *L; /* Lua state (for reader) */ 61 | }; 62 | 63 | 64 | LUAI_FUNC int luaZ_fill (ZIO *z); 65 | 66 | #endif 67 | -------------------------------------------------------------------------------- /modules/common/serdes/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # ================================================================================================= 2 | # Copyright (C) 2024 GRAPE Contributors 3 | # ================================================================================================= 4 | 5 | declare_module( 6 | NAME serdes 7 | DEPENDS_ON_MODULES "" 8 | DEPENDS_ON_EXTERNAL_PROJECTS "") 9 | 10 | # library sources 11 | set(SOURCES 12 | README.md 13 | include/grape/serdes/concepts.h 14 | include/grape/serdes/serdes.h 15 | include/grape/serdes/stream.h) 16 | 17 | # library target 18 | define_module_library( 19 | NAME serdes 20 | PUBLIC_LINK_LIBS "" 21 | PRIVATE_LINK_LIBS "" 22 | SOURCES ${SOURCES} 23 | PUBLIC_INCLUDE_PATHS $ 24 | $ 25 | PRIVATE_INCLUDE_PATHS "" 26 | SYSTEM_PRIVATE_INCLUDE_PATHS "") 27 | 28 | # Subprojects 29 | add_subdirectory(tests) 30 | add_subdirectory(examples) 31 | -------------------------------------------------------------------------------- /modules/common/serdes/docs/benchmarking/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # ================================================================================================= 2 | # Copyright (C) 2024 GRAPE Contributors 3 | # ================================================================================================= 4 | 5 | find_package(flatbuffers ${FLATBUFFERS_VERSION_REQUIRED} REQUIRED) 6 | find_package(fastcdr ${FASTCDR_VERSION_REQUIRED} REQUIRED) 7 | find_package(msgpack-cxx ${MSGPACK_VERSION_REQUIRED} REQUIRED) 8 | 9 | define_module_example( 10 | NAME bench 11 | SOURCES bench.cpp 12 | PRIVATE_INCLUDE_PATHS "" 13 | PRIVATE_LINK_LIBS benchmark::benchmark flatbuffers::flatbuffers fastcdr msgpack-cxx 14 | PUBLIC_LINK_LIBS "") 15 | -------------------------------------------------------------------------------- /modules/common/serdes/examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # ================================================================================================= 2 | # Copyright (C) 2024 GRAPE Contributors 3 | # ================================================================================================= 4 | 5 | define_module_example(NAME example SOURCES example.cpp) 6 | 7 | define_module_example(NAME advanced_example SOURCES advanced_example.cpp advanced_example.h) 8 | 9 | define_module_example( 10 | NAME bench 11 | SOURCES bench.cpp advanced_example.h 12 | PRIVATE_LINK_LIBS benchmark::benchmark) 13 | -------------------------------------------------------------------------------- /modules/common/serdes/include/grape/serdes/concepts.h: -------------------------------------------------------------------------------- 1 | //================================================================================================= 2 | // Copyright (C) 2024 GRAPE Contributors 3 | //================================================================================================= 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | 10 | namespace grape::serdes { 11 | 12 | //------------------------------------------------------------------------------------------------- 13 | // Concept of a generic writable buffer stream 14 | template 15 | concept WritableStream = requires(Stream strm, const char* data, std::size_t size) { 16 | { strm.write(data, size) } -> std::same_as; 17 | /* Writes 'size' bytes from 'data' into stream 's'. Return false on failure */ 18 | }; 19 | 20 | //------------------------------------------------------------------------------------------------- 21 | // Concept of a generic readable buffer stream 22 | template 23 | concept ReadableStream = requires(Stream strm, char* const data, std::size_t size) { 24 | { strm.read(data, size) } -> std::same_as; 25 | /* Reads 'size' bytes into 'data' from stream 's'. Return false on failure */ 26 | }; 27 | 28 | } // namespace grape::serdes 29 | -------------------------------------------------------------------------------- /modules/common/serdes/tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # ================================================================================================= 2 | # Copyright (C) 2024 GRAPE Contributors 3 | # ================================================================================================= 4 | 5 | define_module_test(NAME tests SOURCES stream_tests.cpp serdes_tests.cpp) 6 | -------------------------------------------------------------------------------- /modules/common/utils/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # ================================================================================================= 2 | # Copyright (C) 2023 GRAPE Contributors 3 | # ================================================================================================= 4 | 5 | declare_module( 6 | NAME utils 7 | ALWAYS_BUILD 8 | DEPENDS_ON_MODULES "" # **Note**: This module should not depend on any other module 9 | DEPENDS_ON_EXTERNAL_PROJECTS "") 10 | 11 | # generate version header 12 | configure_file(src/version.in ${CMAKE_CURRENT_SOURCE_DIR}/src/version_impl.h @ONLY) 13 | 14 | # library sources 15 | set(SOURCES 16 | src/ip.cpp 17 | src/file_system.cpp 18 | src/stacktrace.cpp 19 | src/utils.cpp 20 | src/version.cpp 21 | README.md 22 | include/grape/utils/detail/enums_detail.h 23 | include/grape/utils/enums.h 24 | include/grape/utils/file_system.h 25 | include/grape/utils/ip.h 26 | include/grape/utils/stacktrace.h 27 | include/grape/utils/utils.h 28 | include/grape/utils/version.h) 29 | 30 | # library target 31 | define_module_library( 32 | NAME utils 33 | PUBLIC_LINK_LIBS "" 34 | PRIVATE_LINK_LIBS "" 35 | SOURCES ${SOURCES} 36 | PUBLIC_INCLUDE_PATHS $ 37 | $ 38 | PRIVATE_INCLUDE_PATHS "" 39 | SYSTEM_PRIVATE_INCLUDE_PATHS "") 40 | 41 | # Subprojects 42 | add_subdirectory(examples) 43 | add_subdirectory(tests) 44 | add_subdirectory(apps) 45 | -------------------------------------------------------------------------------- /modules/common/utils/README.md: -------------------------------------------------------------------------------- 1 | # README: utils 2 | 3 | ## Brief 4 | 5 | Utilities library. 6 | 7 | ## Detailed description 8 | 9 | Provides a set of common and often-used functionality across the codebase. -------------------------------------------------------------------------------- /modules/common/utils/apps/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # ================================================================================================= 2 | # Copyright (C) 2023 GRAPE Contributors 3 | # ================================================================================================= 4 | 5 | define_module_app(NAME show_version SOURCES show_version.cpp) 6 | -------------------------------------------------------------------------------- /modules/common/utils/apps/show_version.cpp: -------------------------------------------------------------------------------- 1 | //================================================================================================= 2 | // Copyright (C) 2023 GRAPE Contributors 3 | //================================================================================================= 4 | 5 | #include 6 | 7 | #include "grape/utils/version.h" 8 | 9 | //================================================================================================= 10 | auto main() -> int { 11 | try { 12 | const auto vn = grape::utils::getVersion(); 13 | const auto bi = grape::utils::getBuildInfo(); 14 | std::println("Version : {:d}.{:d}.{:d}", vn.major, vn.minor, vn.patch); 15 | std::println("Build Info : '{}' branch, '{}' profile, '{}' hash", bi.branch, bi.profile, 16 | bi.hash); 17 | return EXIT_SUCCESS; 18 | } catch (...) { 19 | std::ignore = std::fputs("Exception occurred", stderr); 20 | return EXIT_FAILURE; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /modules/common/utils/examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # ================================================================================================= 2 | # Copyright (C) 2023 GRAPE Contributors 3 | # ================================================================================================= 4 | 5 | define_module_example(NAME usage_example SOURCES usage_example.cpp) 6 | define_module_example(NAME enums_example SOURCES enums_example.cpp) 7 | -------------------------------------------------------------------------------- /modules/common/utils/examples/usage_example.cpp: -------------------------------------------------------------------------------- 1 | //================================================================================================= 2 | // Copyright (C) 2024 GRAPE Contributors 3 | //================================================================================================= 4 | 5 | #include 6 | 7 | #include "grape/utils/file_system.h" 8 | #include "grape/utils/ip.h" 9 | 10 | //================================================================================================= 11 | auto main() -> int { 12 | try { 13 | const auto path = grape::utils::getProgramPath(); 14 | const auto host_name = grape::utils::getHostName(); 15 | const auto home_dir = grape::utils::getUserHomePath(); 16 | std::println("Host name: {}", host_name); 17 | std::println("User's home: {}", home_dir.string()); 18 | std::println("Program name: {}", grape::utils::getProgramName()); 19 | std::println("Program path: {}", path.parent_path().string()); 20 | std::println("Data search directories for this application:"); 21 | for (const auto& dir : grape::utils::getSearchPaths()) { 22 | std::println("\t{}", dir.string()); 23 | } 24 | return EXIT_SUCCESS; 25 | } catch (...) { 26 | std::ignore = std::fputs("Exception occurred", stderr); 27 | return EXIT_FAILURE; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /modules/common/utils/include/grape/utils/file_system.h: -------------------------------------------------------------------------------- 1 | //================================================================================================= 2 | // Copyright (C) 2024 GRAPE Contributors 3 | //================================================================================================= 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | namespace grape::utils { 13 | 14 | /// @return Full path of the program being executed 15 | [[nodiscard]] auto getProgramPath() -> std::filesystem::path; 16 | 17 | /// @return Name of the program being executed 18 | [[nodiscard]] auto getProgramName() -> std::string; 19 | 20 | /// @return Full path to current user's home directory 21 | [[nodiscard]] auto getUserHomePath() -> std::filesystem::path; 22 | 23 | /// @return Ordered list of 'standard' search paths for supporting data files (config, models, etc) 24 | /// @note Config/data file search order: 25 | /// - User-specific application configuration: $HOME/.$APP_NAME/ 26 | /// - Host-specific application configuration: /etc/opt/$APP_NAME/ 27 | /// - Default application configuration: $APP_PATH/../share/$APP_NAME/ 28 | /// - User-specific GRAPE configuration: $HOME/.grape/ 29 | /// - Host-specific GRAPE configuration: /etc/opt/grape/ 30 | /// - Default GRAPE configuration: $GRAPE_INSTALL_PATH/share/grape/ 31 | [[nodiscard]] auto getSearchPaths() -> const std::vector&; 32 | 33 | /// Search in standard locations to resolve absolute path to a file. 34 | /// @param file_name Name of the file to search, which may include a relative path 35 | /// @return Absolute path to the file, if found 36 | [[nodiscard]] auto resolveFilePath(const std::filesystem::path& file_name) 37 | -> std::optional; 38 | 39 | } // namespace grape::utils 40 | -------------------------------------------------------------------------------- /modules/common/utils/include/grape/utils/ip.h: -------------------------------------------------------------------------------- 1 | //================================================================================================= 2 | // Copyright (C) 2024 GRAPE Contributors 3 | //================================================================================================= 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | namespace grape::utils { 13 | 14 | /// Holds an IP Address and associated methods 15 | struct [[nodiscard]] IPAddress { 16 | enum class Version : std::uint8_t { IPv4, IPv6 }; 17 | static constexpr auto MAX_SEGMENTS = 16U; 18 | 19 | Version version{ Version::IPv4 }; 20 | std::array bytes{}; 21 | 22 | /// Construct from string representation. String must be formatted as follows: 23 | /// - ipv6 format example: "fe80::2145:12c5:9fc3:3c71" 24 | /// - ipv4 format example: "192.168.0.2" 25 | /// @param ip_str String specification of IP address 26 | /// @return IP address on success, nothing on parsing error 27 | [[nodiscard]] static auto fromString(const std::string& ip_str) -> std::optional; 28 | }; 29 | 30 | /// @return string representation of an IP address 31 | [[nodiscard]] auto toString(const IPAddress& addr) -> std::string; 32 | 33 | /// @return host name 34 | [[nodiscard]] auto getHostName() -> std::string; 35 | 36 | } // namespace grape::utils 37 | -------------------------------------------------------------------------------- /modules/common/utils/include/grape/utils/stacktrace.h: -------------------------------------------------------------------------------- 1 | //================================================================================================= 2 | // Copyright (C) 2023 GRAPE Contributors 3 | //================================================================================================= 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | 10 | namespace grape::utils { 11 | 12 | //================================================================================================= 13 | /// Captures stack trace (similar to std::stacktrace) 14 | /// @todo Deprecate when compiler support for std::stacktrace becomes available 15 | class StackTrace { 16 | public: 17 | [[nodiscard]] static auto current() -> StackTrace; 18 | [[nodiscard]] auto trace() const -> const std::vector&; 19 | 20 | private: 21 | static constexpr auto MAX_FRAMES = 16U; 22 | std::vector symbol_list_; 23 | }; 24 | } // namespace grape::utils 25 | -------------------------------------------------------------------------------- /modules/common/utils/include/grape/utils/version.h: -------------------------------------------------------------------------------- 1 | //================================================================================================= 2 | // Copyright (C) 2023 GRAPE Contributors 3 | // MIT License 4 | //================================================================================================= 5 | 6 | #pragma once 7 | 8 | #include 9 | #include 10 | 11 | namespace grape::utils { 12 | 13 | /// Software version data 14 | struct [[nodiscard]] Version { 15 | std::uint8_t major{}; 16 | std::uint8_t minor{}; 17 | std::uint16_t patch{}; 18 | constexpr auto operator<=>(const Version&) const = default; 19 | }; 20 | 21 | /// Source configuration data 22 | struct [[nodiscard]] BuildInfo { 23 | std::string_view branch; 24 | std::string_view profile; 25 | std::string_view hash; 26 | }; 27 | 28 | /// @return Software version of project binaries 29 | auto getVersion() -> Version; 30 | 31 | /// @return Source configuration that generated project binaries 32 | auto getBuildInfo() -> BuildInfo; 33 | 34 | } // namespace grape::utils 35 | -------------------------------------------------------------------------------- /modules/common/utils/src/utils.cpp: -------------------------------------------------------------------------------- 1 | //================================================================================================= 2 | // Copyright (C) 2024 GRAPE Contributors 3 | //================================================================================================= 4 | 5 | #include "grape/utils/utils.h" 6 | 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | namespace grape::utils { 13 | 14 | //------------------------------------------------------------------------------------------------- 15 | auto demangle(const char* mangled_name) -> std::string { 16 | auto status = -1; 17 | const auto result = std::unique_ptr{ 18 | abi::__cxa_demangle(mangled_name, nullptr, nullptr, &status), // 19 | std::free // 20 | }; 21 | return { (status == 0) ? result.get() : mangled_name }; 22 | } 23 | 24 | } // namespace grape::utils 25 | -------------------------------------------------------------------------------- /modules/common/utils/src/version.cpp: -------------------------------------------------------------------------------- 1 | //================================================================================================= 2 | // Copyright (C) 2023 GRAPE Contributors 3 | // MIT License 4 | //================================================================================================= 5 | 6 | #include "grape/utils/version.h" 7 | 8 | #include "version_impl.h" 9 | 10 | namespace grape::utils { 11 | auto getBuildInfo() -> BuildInfo { 12 | return { .branch = REPO_BRANCH, .profile = BUILD_PROFILE, .hash = REPO_HASH }; 13 | } 14 | 15 | auto getVersion() -> Version { 16 | return { .major = VERSION_MAJOR, .minor = VERSION_MINOR, .patch = VERSION_PATCH }; 17 | } 18 | 19 | } // namespace grape::utils 20 | -------------------------------------------------------------------------------- /modules/common/utils/src/version.in: -------------------------------------------------------------------------------- 1 | //================================================================================================= 2 | // Copyright (C) 2023 GRAPE Contributors 3 | // MIT License 4 | //================================================================================================= 5 | 6 | #pragma once 7 | 8 | #include 9 | #include 10 | 11 | namespace grape::utils 12 | { 13 | 14 | // These are autogenerated by the build system from version.in 15 | 16 | static constexpr std::uint8_t VERSION_MAJOR = @VERSION_MAJOR@; 17 | static constexpr std::uint8_t VERSION_MINOR = @VERSION_MINOR@; 18 | static constexpr std::uint16_t VERSION_PATCH = @VERSION_PATCH@; 19 | 20 | static constexpr std::string_view REPO_BRANCH = "@REPO_BRANCH@"; 21 | static constexpr std::string_view BUILD_PROFILE = "@CMAKE_BUILD_TYPE@"; 22 | static constexpr std::string_view REPO_HASH = "@REPO_HASH@"; 23 | 24 | } // namespace grape::utils 25 | -------------------------------------------------------------------------------- /modules/common/utils/tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # ================================================================================================= 2 | # Copyright (C) 2023 GRAPE Contributors 3 | # ================================================================================================= 4 | 5 | define_module_test( 6 | NAME tests 7 | SOURCES utils_tests.cpp enum_tests.cpp ip_tests.cpp file_system_tests.cpp) 8 | -------------------------------------------------------------------------------- /modules/common/utils/tests/utils_tests.cpp: -------------------------------------------------------------------------------- 1 | //================================================================================================= 2 | // Copyright (C) 2023 GRAPE Contributors 3 | //================================================================================================= 4 | 5 | #include "catch2/catch_test_macros.hpp" 6 | #include "grape/utils/utils.h" 7 | 8 | namespace my_ns { 9 | template 10 | struct CustomType {}; 11 | } // namespace my_ns 12 | 13 | namespace { 14 | 15 | //------------------------------------------------------------------------------------------------- 16 | TEST_CASE("string trimming") { 17 | constexpr auto STR = "/path/to/some/file.txt"; 18 | constexpr auto START_TOKEN = "to"; 19 | constexpr auto END_TOKEN = ".txt"; 20 | constexpr auto TRUNCATED = grape::utils::truncate(STR, START_TOKEN, END_TOKEN); 21 | constexpr auto EXPECTED = "to/some/file"; 22 | CHECK(TRUNCATED == EXPECTED); 23 | } 24 | 25 | //------------------------------------------------------------------------------------------------- 26 | TEST_CASE("get type name") { 27 | CHECK("int" == grape::utils::getTypeName()); 28 | CHECK("my_ns::CustomType" == grape::utils::getTypeName>()); 29 | } 30 | 31 | } // namespace 32 | -------------------------------------------------------------------------------- /modules/probe/controller/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # ================================================================================================= 2 | # Copyright (C) 2023 GRAPE Contributors 3 | # ================================================================================================= 4 | 5 | declare_module( 6 | NAME probe_controller 7 | DEPENDS_ON_MODULES "realtime;utils" 8 | DEPENDS_ON_EXTERNAL_PROJECTS "") 9 | 10 | # library sources 11 | set(SOURCES src/controller.cpp README.md include/grape/probe/controller.h 12 | include/grape/probe/signal.h include/grape/probe/type_id.h) 13 | 14 | # library target 15 | define_module_library( 16 | NAME probe_controller 17 | PUBLIC_LINK_LIBS grape::utils grape::realtime 18 | PRIVATE_LINK_LIBS "" 19 | SOURCES ${SOURCES} 20 | PUBLIC_INCLUDE_PATHS $ 21 | $ 22 | PRIVATE_INCLUDE_PATHS "" 23 | SYSTEM_PRIVATE_INCLUDE_PATHS "") 24 | 25 | # Subprojects 26 | add_subdirectory(tests) 27 | add_subdirectory(examples) 28 | -------------------------------------------------------------------------------- /modules/probe/controller/README.md: -------------------------------------------------------------------------------- 1 | # README: Probe Controller 2 | 3 | ## Brief 4 | 5 | Probe provides a Controller-Monitor system for remote monitoring and control of embedded processes. 6 | 7 | This module implements the Controller API that can be integrated into the embedded process for monitoring and control of process variables. 8 | 9 | ## Detailed description 10 | 11 | - Probe system [requirements](./docs/requirements.md) -------------------------------------------------------------------------------- /modules/probe/controller/examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # ================================================================================================= 2 | # Copyright (C) 2023 GRAPE Contributors 3 | # ================================================================================================= 4 | 5 | define_module_example(NAME example SOURCES example.cpp) 6 | -------------------------------------------------------------------------------- /modules/probe/controller/include/grape/probe/signal.h: -------------------------------------------------------------------------------- 1 | //================================================================================================= 2 | // Copyright (C) 2023 GRAPE Contributors 3 | //================================================================================================= 4 | 5 | #pragma once 6 | 7 | #include "grape/probe/type_id.h" 8 | #include "grape/realtime/fixed_string.h" 9 | 10 | namespace grape::probe { 11 | 12 | //================================================================================================= 13 | /// Details of a monitored variable in the application. The variable can be a scalar or a sequence. 14 | struct Signal { 15 | static_assert(sizeof(std::uintptr_t) == sizeof(std::int64_t), "Only 64-bit arch. supported"); 16 | static_assert(sizeof(std::size_t) == sizeof(std::uint64_t), "Only 64-bit arch. supported"); 17 | 18 | /// Describes how the signal is utilised 19 | enum class Role : std::uint8_t { 20 | Timestamp, //!< Signal designated as timestamp. Only one such instance should exist 21 | Watch, //!< Signal designated for logging only (read only) 22 | Control //!< Signal designated for logging _and_ remote control (read and write) 23 | }; 24 | 25 | static constexpr auto MAX_NAME_LENGTH = 63; 26 | 27 | realtime::FixedString name; //!< Unique identifier name for the signal 28 | std::uintptr_t address{ 0 }; //!< Address of the signal in the process address space 29 | std::size_t num_elements{ 0 }; //!< Number of elements in the signal sequence 30 | TypeId type{}; //!< Data type of elements in the signal sequence 31 | Role role{}; //!< Mode of usage of the signal 32 | }; 33 | 34 | // Ensure any future changes maintains triviality for the sake of performance 35 | static_assert(std::is_trivially_copyable_v); 36 | static_assert(std::is_trivially_move_constructible_v); 37 | 38 | } // namespace grape::probe 39 | -------------------------------------------------------------------------------- /modules/probe/controller/tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # ================================================================================================= 2 | # Copyright (C) 2023 GRAPE Contributors 3 | # ================================================================================================= 4 | 5 | define_module_test(NAME tests SOURCES tests.cpp) 6 | -------------------------------------------------------------------------------- /modules/probe/monitor/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # ================================================================================================= 2 | # Copyright (C) 2024 GRAPE Contributors 3 | # ================================================================================================= 4 | 5 | declare_module( 6 | NAME probe_monitor 7 | DEPENDS_ON_MODULES "probe_controller" 8 | DEPENDS_ON_EXTERNAL_PROJECTS "SDL3") 9 | 10 | find_package(SDL3 ${SDL3_VERSION_REQUIRED} REQUIRED) 11 | 12 | # library sources 13 | set(SOURCES src/monitor.cpp README.md include/grape/probe/monitor.h) 14 | 15 | # library target 16 | define_module_library( 17 | NAME probe_monitor 18 | PUBLIC_LINK_LIBS grape::probe_controller 19 | PRIVATE_LINK_LIBS $ $ 20 | SOURCES ${SOURCES} 21 | PUBLIC_INCLUDE_PATHS $ 22 | $ 23 | PRIVATE_INCLUDE_PATHS "" 24 | SYSTEM_PRIVATE_INCLUDE_PATHS ${CMAKE_CURRENT_SOURCE_DIR}/third_party/imgui/ 25 | ${CMAKE_CURRENT_SOURCE_DIR}/third_party/implot/) 26 | 27 | # Subprojects 28 | add_subdirectory(third_party) 29 | add_subdirectory(examples) 30 | -------------------------------------------------------------------------------- /modules/probe/monitor/examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # ================================================================================================= 2 | # Copyright (C) 2024 GRAPE Contributors 3 | # ================================================================================================= 4 | 5 | define_module_example(NAME example SOURCES example.cpp) 6 | -------------------------------------------------------------------------------- /modules/probe/monitor/include/grape/probe/monitor.h: -------------------------------------------------------------------------------- 1 | //================================================================================================= 2 | // Copyright (C) 2024 GRAPE Contributors 3 | //================================================================================================= 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "grape/probe/signal.h" 13 | #include "grape/utils/enums.h" 14 | 15 | namespace grape::probe { 16 | 17 | // Proof of concept 18 | class Monitor { 19 | public: 20 | enum class Error : std::uint8_t { Renderer, SignalNotFound, SizeMismatch }; 21 | 22 | /// Signature for function to receive log records 23 | using Sender = std::function)>; 24 | 25 | Monitor(); 26 | ~Monitor(); 27 | void setSender(Sender&& sender); 28 | void run(); 29 | 30 | // receives a snapshot frame 31 | void recv(const std::vector& signals, std::span frame); 32 | 33 | Monitor(const Monitor&) = delete; 34 | auto operator=(const Monitor&) = delete; 35 | Monitor(Monitor&&) = delete; 36 | auto operator=(Monitor&&) = delete; 37 | 38 | private: 39 | void drawPlots(); 40 | void drawControls(); 41 | struct Impl; 42 | std::unique_ptr impl_; 43 | }; 44 | 45 | //------------------------------------------------------------------------------------------------- 46 | [[nodiscard]] constexpr auto toString(const Monitor::Error& code) -> std::string_view { 47 | return enums::name(code); 48 | } 49 | 50 | } // namespace grape::probe 51 | -------------------------------------------------------------------------------- /modules/probe/monitor/third_party/README.md: -------------------------------------------------------------------------------- 1 | # README monitor/third_party 2 | 3 | ## Dear ImGui and Implot 4 | 5 | - [ImGui](https://github.com/ocornut/imgui/) v1.90.5 SHA: 1db579d458da29fa43376af9d88d486910d9406a 6 | - [ImPlot](https://github.com/epezent/implot/) SHA: f156599faefe316f7dd20fe6c783bf87c8bb6fd9 -------------------------------------------------------------------------------- /modules/probe/monitor/third_party/imgui/LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014-2025 Omar Cornut 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /modules/probe/monitor/third_party/imgui/misc/cpp/README.txt: -------------------------------------------------------------------------------- 1 | 2 | imgui_stdlib.h + imgui_stdlib.cpp 3 | InputText() wrappers for C++ standard library (STL) type: std::string. 4 | This is also an example of how you may wrap your own similar types. 5 | 6 | imgui_scoped.h 7 | [Experimental, not currently in main repository] 8 | Additional header file with some RAII-style wrappers for common Dear ImGui functions. 9 | Try by merging: https://github.com/ocornut/imgui/pull/2197 10 | Discuss at: https://github.com/ocornut/imgui/issues/2096 11 | 12 | See more C++ related extension (fmt, RAII, syntaxis sugar) on Wiki: 13 | https://github.com/ocornut/imgui/wiki/Useful-Extensions#cness 14 | -------------------------------------------------------------------------------- /modules/probe/monitor/third_party/imgui/misc/cpp/imgui_stdlib.h: -------------------------------------------------------------------------------- 1 | // dear imgui: wrappers for C++ standard library (STL) types (std::string, etc.) 2 | // This is also an example of how you may wrap your own similar types. 3 | 4 | // Changelog: 5 | // - v0.10: Initial version. Added InputText() / InputTextMultiline() calls with std::string 6 | 7 | // See more C++ related extension (fmt, RAII, syntaxis sugar) on Wiki: 8 | // https://github.com/ocornut/imgui/wiki/Useful-Extensions#cness 9 | 10 | #pragma once 11 | 12 | #ifndef IMGUI_DISABLE 13 | 14 | #include 15 | 16 | namespace ImGui 17 | { 18 | // ImGui::InputText() with std::string 19 | // Because text input needs dynamic resizing, we need to setup a callback to grow the capacity 20 | IMGUI_API bool InputText(const char* label, std::string* str, ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = nullptr, void* user_data = nullptr); 21 | IMGUI_API bool InputTextMultiline(const char* label, std::string* str, const ImVec2& size = ImVec2(0, 0), ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = nullptr, void* user_data = nullptr); 22 | IMGUI_API bool InputTextWithHint(const char* label, const char* hint, std::string* str, ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = nullptr, void* user_data = nullptr); 23 | } 24 | 25 | #endif // #ifndef IMGUI_DISABLE 26 | -------------------------------------------------------------------------------- /modules/probe/monitor/third_party/implot/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Evan Pezent 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /toolchains/install_base.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | # Install baseline system utilities and development tools 6 | sudo apt-get update 7 | sudo apt-get install -y \ 8 | software-properties-common build-essential pkg-config gpg wget ca-certificates \ 9 | git-lfs curl ninja-build ccache doxygen graphviz python3-full python3-dev \ 10 | python-is-python3 pybind11-dev python3-wheel python3-setuptools python3-build pipx avahi-daemon \ 11 | avahi-utils iproute2 iputils-ping net-tools iftop htop nvtop patch 12 | 13 | # Install Python tool for CMake formatting 14 | pipx install cmakelang 15 | 16 | # Install support libraries for 3D graphics and GUIs 17 | sudo apt-get install -y \ 18 | libxrandr-dev libxinerama-dev libxcursor-dev libxi-dev libxkbcommon-dev libwayland-dev wayland-protocols -------------------------------------------------------------------------------- /toolchains/install_cmake.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Installs CMake on Ubuntu/Debian from Kitware's APT repository. 4 | # Usage: ./install_cmake.sh 5 | # Requires sudo privileges. 6 | 7 | set -e 8 | 9 | wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | \ 10 | gpg --dearmor - | sudo tee /usr/share/keyrings/kitware-archive-keyring.gpg >/dev/null 11 | 12 | echo "deb [signed-by=/usr/share/keyrings/kitware-archive-keyring.gpg] https://apt.kitware.com/ubuntu/ $(lsb_release -cs) main" | \ 13 | sudo tee /etc/apt/sources.list.d/kitware.list >/dev/null 14 | 15 | sudo apt update 16 | sudo rm /usr/share/keyrings/kitware-archive-keyring.gpg 17 | sudo apt install -y kitware-archive-keyring 18 | sudo apt install -y cmake -------------------------------------------------------------------------------- /toolchains/install_gcc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Install GCC toolchain from Ubuntu Toolchain PPA 4 | # Usage: ./install_gcc.sh 5 | 6 | set -e 7 | 8 | GCC_VERSION=15 9 | 10 | sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test 11 | sudo apt update 12 | sudo apt install -y g++-$GCC_VERSION gcc-$GCC_VERSION gfortran-$GCC_VERSION 13 | 14 | PRIORITY=$((${GCC_VERSION%%.*} * 10)) 15 | sudo update-alternatives --remove-all gcc || true 16 | sudo update-alternatives --remove-all gfortran || true 17 | sudo update-alternatives --install /usr/bin/gfortran gfortran /usr/bin/gfortran-$GCC_VERSION $PRIORITY 18 | sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-$GCC_VERSION $PRIORITY \ 19 | --slave /usr/bin/g++ g++ /usr/bin/g++-$GCC_VERSION \ 20 | --slave /usr/bin/gcov gcov /usr/bin/gcov-$GCC_VERSION -------------------------------------------------------------------------------- /toolchains/install_llvm.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Installs the LLVM toolchain on a Debian-based system. 4 | # Usage: ./install_llvm.sh 5 | # This script is intended to be run with root privileges. 6 | 7 | # Exit on error 8 | set -e 9 | 10 | # Supported LLVM version 11 | LLVM_VERSION=21 12 | 13 | # Download 14 | wget https://apt.llvm.org/llvm.sh 15 | wget -O- https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - 16 | 17 | # Install 18 | chmod +x llvm.sh 19 | sudo ./llvm.sh $LLVM_VERSION 20 | 21 | sudo apt install -y \ 22 | clang-$LLVM_VERSION clang-tidy-$LLVM_VERSION clang-format-$LLVM_VERSION \ 23 | llvm-$LLVM_VERSION-dev libc++-$LLVM_VERSION-dev libc++abi-$LLVM_VERSION-dev \ 24 | libomp-$LLVM_VERSION-dev libunwind-$LLVM_VERSION-dev lld-$LLVM_VERSION 25 | 26 | # Set this version as the default 27 | PRIORITY=$((${LLVM_VERSION%%.*} * 10)) 28 | sudo update-alternatives --remove-all clang || true 29 | sudo update-alternatives --remove-all clang++ || true 30 | sudo update-alternatives --remove-all clang-tidy || true 31 | sudo update-alternatives --remove-all clang-format || true 32 | sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-$LLVM_VERSION $PRIORITY 33 | sudo update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-$LLVM_VERSION $PRIORITY 34 | sudo update-alternatives --install /usr/bin/clang-tidy clang-tidy /usr/bin/clang-tidy-$LLVM_VERSION $PRIORITY 35 | sudo update-alternatives --install /usr/bin/clang-format clang-format /usr/bin/clang-format-$LLVM_VERSION $PRIORITY 36 | 37 | # Clean up downloaded files 38 | rm -f llvm.sh -------------------------------------------------------------------------------- /toolchains/toolchain_clang.cmake: -------------------------------------------------------------------------------- 1 | #================================================================================================= 2 | # Copyright (C) 2023 GRAPE Contributors 3 | #================================================================================================= 4 | 5 | set(CMAKE_C_COMPILER clang) 6 | set(CMAKE_CXX_COMPILER clang++) 7 | set(CMAKE_CXX_FLAGS "-stdlib=libc++") 8 | set(CMAKE_EXE_LINKER_FLAGS "-stdlib=libc++ -lc++abi") 9 | set(CMAKE_CROSSCOMPILING FALSE) 10 | 11 | # Additional configuration for MacOS 12 | # LLVM must be installed: `brew install llvm` 13 | # LLVM binaries should be in path: `export PATH="/opt/homebrew/opt/llvm/bin:$PATH"` 14 | if(CMAKE_SYSTEM_NAME MATCHES "Darwin") 15 | execute_process(COMMAND xcrun --show-sdk-path OUTPUT_VARIABLE CMAKE_OSX_SYSROOT OUTPUT_STRIP_TRAILING_WHITESPACE) 16 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -isysroot ${CMAKE_OSX_SYSROOT}") 17 | endif() 18 | --------------------------------------------------------------------------------