From 9de84ab24c56f9037633afc979032d53ed94842c Mon Sep 17 00:00:00 2001 From: Trent Houliston Date: Tue, 9 Jan 2024 09:36:01 +1100 Subject: [PATCH 01/23] Squashed 'src/nuclear/' changes from 269f903..f6704a1 f6704a1 Prevent spurious events from poll (#96) aaa97ed Allow extra arguments to be passed to reactor constructor (#97) 5b198ee Return installed reactor (#95) b584fa4 Fix the macroguard on resolve.hpp (#94) ca947ad Fix Serialisation to properly deal with trivially copyable types (#93) 6480a09 Swap to using size_t as an id type (#92) 2fbf7e3 Make NUClear logs always emit (#91) 68e154a Address some issues found by sonarcloud (#86) b34f0be Add ccache to speed up builds (#90) 8e46684 Swap to a simpler implementation of xxhash with less undefined behaviour (#89) 2b2a540 Update demangle to fix sonar issues and see how it changes coverage (#85) d5f54e2 Fix cmake formatting (#88) 698b4bd Normalise the license files (#87) 0b78e29 Refactor tests to use an event style and fix some found bugs (#70) f08bd88 Swap to debug build for coverage counts (#84) 889ebdb Make the demangle function consistent across platforms and add a test (#83) 25274e9 Fix the `Bug` issues identified by SonarCloud (#82) 3b22a17 Add code coverage using Sonarcloud and gconvr (#81) 6fdf664 Set up a Sonarcloud workflow (#80) bcdd34a Update the networking dsl words to support IPv6 (#76) e62921c Add dependabot for GitHub actions (#78) 7d0be4b Update unsupported actions (#77) 9b705b1 Fix dynamic every (#75) 8ba1c1a Add a readthedocs yaml file (#74) 31da26c Refactor the task scheduler so it can take generic tasks (#73) 2e1a615 Add CI checks to verify clang-tidy conformance for Windows code (#71) 1ddd50f Refactor the chrono controller to have higher accuracy (#72) fe80f41 Store the identifiers in a struct to help know what they mean (#69) fceae7e Replace `reschedule` with new DSL endpoints and refactor task scheduler (#64) b692cdf Apply new clang-tidy rules (#67) 4d5a4cf Add missing includes to NUClearNetwork (#66) 419d00f Apply new formatting (#65) dceb4fa Change the sort order for tasks to be by id rather than timestamp (#62) 577ef3f Make ReactionStatistics shared (#54) 37bde67 Take shared pointers by value rather than rvalue as it's safer for multiple targets (#61) e682ea6 Prevent powerplant nullptr from inhibiting shutdown (#59) 6a818a8 Change the logic for logging so floating `NUClear::log` calls respect the reactors log level (#58) b86b62f Documentation for writting extensions (#50) 48aa321 Fix DSL words so they execute in the order they appear (#57) 7916a4d Add documentation for serialisation (#52) 572ebb1 Ensure base_clock is honored everywhere (#53) be378eb Update readme to link to docs (#51) 54a043b Fix Windows IO Controller, do proper error checking (#48) 2b7bc33 Use an action to install CMake (#49) 13fe64a Document PowerPlant Functions (#41) b57cff3 Fix build and tests on Windows (#46) 8a86ff2 Add Windows CI to the build matrix (#45) 81a715a Fix the ReadTheDocs build (#43) ca006b4 Change GitHub Actions target branch from master to main (#44) 2c43963 Add Minor PowerPlant Code Changes (#42) 1c6147b Adds @brief for Fusion type (#39) d9d18ff Fix some comment typos (#38) 80d58a8 Add warning to LogMessage so others don't make my mistakes. (#37) b36b873 Refactor UDP Multicast test into two non-conflicting tests (#40) f4a60c7 `std::weak_ptr` needs `memory` include (#36) a7cc507 Corrects old cmake dependency requirement in readme (#35) 153ccdb Add dsl word "Once". (#34) d351ca1 Fix the CI button to use GitHub actions 698174e Allow clock type to change using a macro (#33) 8b66438 Setup GitHub actions for NUClear (#32) 6c1dde8 Implement a runtime argument option for Watchdog (#31) 1d5704d Resolve pedantic compiler errors (#30) ab474cc Update Catch2 link (#29) e4aee1e Fix detection logic for multicast address 5af6118 Revert "Start NUClear thread tasks first as they are often needed by the thread pool tasks that come after" 2ff6f79 Reactors need virtual destructors to ensure the subclasses destructors are executed b923cad Start NUClear thread tasks first as they are often needed by the thread pool tasks that come after e54ceca Change the order that running is set on shutdown to avoid always missing a shutdown 42d9b0d Fix some warnings and add support for Protobuf Lite messages 0f21136 Improve cmake and add cmake config files (#28) e39f984 Refactor the files and CMake to make an easier project structure (#27) 54f9683 Provide an API for declaring a custom clock (#25) 0ab8549 Throw error only if all connection attempts failed (#24) 7e2e3f7 Fix getinterfaces finding CAN buses and segfaulting (#23) 920bcf9 Enable emit to accept a time_point as well as a duration (#22) 84de008 Fix ChronoController removing the wrong elements (#21) 4e00b12 Adds unit test to test Singles behaviour when data is not available (#20) 1d77026 Decrements active task counter when reaction call is cancelled due to missing data (#19) a20a03a Adds functionality for cmake to download single header file libraries (#18) 4d23bdb Fix the travis badge URL (#17) 393f7b9 Move where active_tasks is updated to make it less likely to fail, and if it does, fail with a drop rather than a double (#16) d14fa08 Add tests/code to ensure that ReactionStatistics is totally safe from looping (#15) git-subtree-dir: src/nuclear git-subtree-split: f6704a1f049c7a30e1b92f4cd70af219d28a4697 --- .clang-format | 64 +- .clang-tidy | 153 ++- .cmake-format.py | 218 +++++ .github/dependabot.yaml | 9 + .github/workflows/gcc.yaml | 101 ++ .github/workflows/linting.yaml | 69 ++ .github/workflows/macos.yaml | 63 ++ .github/workflows/sonarcloud.yaml | 80 ++ .github/workflows/windows.yaml | 85 ++ .readthedocs.yaml | 22 + .travis.yml | 127 --- .vscode/settings.json | 15 + CMakeLists.txt | 140 ++- LICENSE | 3 +- NUClear.sublime-project | 6 +- README.md | 8 +- cmake/Modules/CompilerSetup.cmake | 54 -- cmake/Modules/FindCATCH.cmake | 45 +- cmake/Modules/FindNUClear.cmake | 21 - cmake/Modules/FindSphinx.cmake | 42 +- cmake/Modules/HeaderLibrary.cmake | 93 ++ cmake/Modules/ToolchainLibraryFinder.cmake | 251 ++--- cmake/NUClearConfig.cmake.in | 9 + docs/CMakeLists.txt | 48 +- docs/conf.py | 2 +- docs/dsl.rst | 4 + docs/extension.rst | 201 +++- docs/networking.rst | 42 +- docs/requirements.txt | 2 +- docs/startup.rst | 2 +- sonar-project.properties | 9 + src/CMakeLists.txt | 207 ++-- src/Configuration.hpp | 41 + .../nuclear_bits => }/Environment.hpp | 16 +- src/{include/nuclear_bits => }/LogLevel.hpp | 23 +- src/PowerPlant.cpp | 135 +-- src/{include/nuclear_bits => }/PowerPlant.hpp | 197 ++-- src/{include/nuclear_bits => }/PowerPlant.ipp | 119 ++- src/{include/nuclear_bits => }/Reactor.hpp | 176 ++-- src/clock.hpp | 59 ++ src/{include/nuclear_bits => }/dsl/Fusion.hpp | 39 +- src/{include/nuclear_bits => }/dsl/Parse.hpp | 42 +- .../dsl/fusion/BindFusion.hpp | 39 +- .../dsl/fusion/GetFusion.hpp | 16 +- src/dsl/fusion/GroupFusion.hpp | 104 ++ .../nuclear_bits => }/dsl/fusion/NoOp.hpp | 57 +- src/dsl/fusion/PoolFusion.hpp | 104 ++ .../dsl/fusion/PostconditionFusion.hpp | 25 +- .../dsl/fusion/PreconditionFusion.hpp | 25 +- .../dsl/fusion/PriorityFusion.hpp | 22 +- .../nuclear_bits => }/dsl/fusion/has_bind.hpp | 16 +- .../nuclear_bits => }/dsl/fusion/has_get.hpp | 16 +- .../fusion/has_group.hpp} | 32 +- src/dsl/fusion/has_pool.hpp | 58 ++ .../dsl/fusion/has_postcondition.hpp | 16 +- .../dsl/fusion/has_precondition.hpp | 16 +- .../dsl/fusion/has_priority.hpp | 16 +- .../dsl/operation/CacheGet.hpp | 12 +- .../dsl/operation/ChronoTask.hpp | 21 +- .../dsl/operation/DSLProxy.hpp | 8 +- .../dsl/operation/TypeBind.hpp | 54 +- .../dsl/operation/Unbind.hpp | 14 +- .../nuclear_bits => }/dsl/store/DataStore.hpp | 12 +- .../dsl/store/ThreadStore.hpp | 13 +- .../dsl/store/TypeCallbackStore.hpp | 12 +- .../dsl/trait/is_transient.hpp | 8 +- .../dsl/validation/Validation.hpp | 14 +- src/dsl/word/Always.hpp | 163 ++++ .../nuclear_bits => }/dsl/word/Buffer.hpp | 20 +- .../nuclear_bits => }/dsl/word/Every.hpp | 45 +- src/dsl/word/Group.hpp | 90 ++ .../nuclear_bits => }/dsl/word/IO.hpp | 88 +- .../nuclear_bits => }/dsl/word/Last.hpp | 88 +- .../nuclear_bits => }/dsl/word/MainThread.hpp | 36 +- .../nuclear_bits => }/dsl/word/Network.hpp | 47 +- src/dsl/word/Once.hpp | 58 ++ .../nuclear_bits => }/dsl/word/Optional.hpp | 33 +- src/dsl/word/Pool.hpp | 97 ++ .../nuclear_bits => }/dsl/word/Priority.hpp | 22 +- .../nuclear_bits => }/dsl/word/Shutdown.hpp | 14 +- .../nuclear_bits => }/dsl/word/Single.hpp | 10 +- .../nuclear_bits => }/dsl/word/Startup.hpp | 10 +- src/dsl/word/Sync.hpp | 77 ++ src/dsl/word/TCP.hpp | 213 +++++ .../nuclear_bits => }/dsl/word/Trigger.hpp | 14 +- src/dsl/word/UDP.hpp | 555 +++++++++++ src/dsl/word/Watchdog.hpp | 295 ++++++ .../nuclear_bits => }/dsl/word/With.hpp | 13 +- .../nuclear_bits => }/dsl/word/emit/Delay.hpp | 36 +- .../dsl/word/emit/Direct.hpp | 39 +- .../dsl/word/emit/Initialise.hpp | 20 +- .../nuclear_bits => }/dsl/word/emit/Local.hpp | 39 +- .../dsl/word/emit/Network.hpp | 22 +- src/dsl/word/emit/UDP.hpp | 182 ++++ src/dsl/word/emit/Watchdog.hpp | 183 ++++ src/extension/ChronoController.cpp | 118 --- src/extension/ChronoController.hpp | 184 ++++ .../extension/IOController.hpp | 12 +- src/extension/IOController_Posix.cpp | 240 ----- src/extension/IOController_Posix.hpp | 393 ++++++++ src/extension/IOController_Windows.cpp | 172 ---- src/extension/IOController_Windows.hpp | 336 +++++++ src/extension/NetworkController.cpp | 163 ---- src/extension/NetworkController.hpp | 184 ++++ src/extension/network/NUClearNetwork.cpp | 514 +++++----- .../extension/network/NUClearNetwork.hpp | 132 +-- src/extension/network/wire_protocol.hpp | 119 +++ .../nuclear_bits/clock.hpp => id.hpp} | 20 +- .../dsl/fusion/RescheduleFusion.hpp | 111 --- .../operation/ReactionStatisticsDeloop.hpp | 58 -- src/include/nuclear_bits/dsl/word/Always.hpp | 90 -- src/include/nuclear_bits/dsl/word/Sync.hpp | 127 --- src/include/nuclear_bits/dsl/word/TCP.hpp | 186 ---- src/include/nuclear_bits/dsl/word/UDP.hpp | 433 --------- .../nuclear_bits/dsl/word/Watchdog.hpp | 137 --- .../nuclear_bits/dsl/word/emit/UDP.hpp | 218 ----- .../extension/IOController_Posix.hpp | 64 -- .../extension/NetworkController.hpp | 50 - .../extension/network/wire_protocol.hpp | 83 -- .../nuclear_bits/threading/ReactionTask.hpp | 115 --- .../nuclear_bits/threading/TaskScheduler.hpp | 117 --- .../nuclear_bits/threading/ThreadPoolTask.hpp | 51 - .../nuclear_bits/util/CallbackGenerator.hpp | 133 --- .../nuclear_bits/util/FileDescriptor.hpp | 90 -- src/include/nuclear_bits/util/platform.hpp | 166 ---- .../nuclear_bits/util/serialise/xxhash.h | 301 ------ .../message/CommandLineArguments.hpp | 8 +- .../nuclear_bits => }/message/LogMessage.hpp | 36 +- .../message/NetworkConfiguration.hpp | 42 +- .../message/NetworkEvent.hpp | 22 +- .../message/ReactionStatistics.hpp | 58 +- src/{include/nuclear => nuclear.in} | 12 +- src/threading/Reaction.cpp | 45 +- .../nuclear_bits => }/threading/Reaction.hpp | 63 +- src/threading/ReactionHandle.cpp | 66 -- .../threading/ReactionHandle.hpp | 51 +- src/threading/ReactionIdentifiers.hpp | 60 ++ src/threading/ReactionTask.cpp | 77 -- src/threading/ReactionTask.hpp | 170 ++++ src/threading/TaskScheduler.cpp | 265 +++++- src/threading/TaskScheduler.hpp | 262 ++++++ .../nuclear_bits => }/util/CallableInfo.hpp | 32 +- src/util/CallbackGenerator.hpp | 149 +++ .../nuclear_bits => }/util/Dereferencer.hpp | 14 +- src/util/FileDescriptor.cpp | 92 ++ src/util/FileDescriptor.hpp | 113 +++ .../nuclear_bits => }/util/FunctionFusion.hpp | 247 +++-- src/util/GeneratedCallback.hpp | 65 ++ src/util/GroupDescriptor.hpp | 59 ++ .../nuclear_bits => }/util/MergeTransient.hpp | 8 +- .../util/MetaProgramming.hpp | 8 +- .../util/RelevantArguments.hpp | 10 +- .../nuclear_bits => }/util/Sequence.hpp | 64 +- .../ThreadPoolDescriptor.cpp} | 25 +- src/util/ThreadPoolDescriptor.hpp | 62 ++ .../util/TransientDataElements.hpp | 25 +- .../nuclear_bits => }/util/TypeList.hpp | 25 +- .../nuclear_bits => }/util/TypeMap.hpp | 41 +- src/{include/nuclear_bits => }/util/apply.hpp | 11 +- src/util/demangle.cpp | 72 +- .../nuclear_bits => }/util/demangle.hpp | 8 +- .../nuclear_bits => }/util/get_hostname.hpp | 16 +- src/util/main_thread_id.cpp | 18 +- .../sock_t.hpp => util/main_thread_id.hpp} | 33 +- src/util/network/get_interfaces.cpp | 111 ++- src/util/network/get_interfaces.hpp | 74 ++ src/util/network/if_number_from_address.cpp | 64 ++ .../network/if_number_from_address.hpp} | 45 +- src/util/network/resolve.cpp | 95 ++ .../network/resolve.hpp} | 61 +- src/util/network/sock_t.hpp | 73 ++ src/util/platform.cpp | 54 +- src/util/platform.hpp | 202 ++++ src/util/precise_sleep.cpp | 72 ++ .../precise_sleep.hpp} | 18 +- .../util/serialise/Serialise.hpp | 95 +- src/util/serialise/xxhash.c | 890 ------------------ src/util/serialise/xxhash.cpp | 222 +++++ src/util/serialise/xxhash.hpp | 63 ++ .../nuclear_bits => }/util/tuplify.hpp | 14 +- .../nuclear_bits => }/util/unpack.hpp | 20 +- .../util/update_current_thread_priority.hpp | 21 +- tests/CMakeLists.txt | 133 ++- tests/api/ReactionHandle.cpp | 65 +- tests/api/ReactionStatistics.cpp | 129 ++- tests/api/ReactorArgs.cpp | 62 ++ tests/dsl/Always.cpp | 69 +- tests/dsl/ArgumentFission.cpp | 145 ++- tests/dsl/BlockNoData.cpp | 67 +- tests/dsl/Buffer.cpp | 176 ++++ tests/dsl/CommandLineArguments.cpp | 61 +- tests/dsl/CustomGet.cpp | 54 +- tests/dsl/DSLOrdering.cpp | 93 ++ tests/dsl/DSLProxy.cpp | 65 +- tests/dsl/Every.cpp | 112 +-- tests/dsl/Every_Per.cpp | 92 -- tests/dsl/FlagMessage.cpp | 82 +- tests/dsl/FusionInOrder.cpp | 57 ++ tests/dsl/IO.cpp | 128 ++- tests/dsl/Last.cpp | 83 +- tests/dsl/MainThread.cpp | 64 +- tests/dsl/MissingArguments.cpp | 59 +- tests/dsl/Once.cpp | 95 ++ tests/dsl/Optional.cpp | 101 +- tests/dsl/Priority.cpp | 139 +-- tests/dsl/Raw.cpp | 16 +- tests/dsl/RawFunction.cpp | 108 ++- tests/dsl/Shutdown.cpp | 47 +- tests/dsl/Single.cpp | 85 -- tests/dsl/Startup.cpp | 53 +- tests/dsl/Sync.cpp | 103 +- tests/dsl/SyncOrder.cpp | 76 ++ tests/dsl/TCP.cpp | 327 ++++--- tests/dsl/Transient.cpp | 165 ++++ tests/dsl/TransientMultiTrigger.cpp | 134 --- tests/dsl/Trigger.cpp | 58 +- tests/dsl/UDP.cpp | 472 +++++++++- tests/dsl/UDPBroadcast.cpp | 147 --- tests/dsl/UDPMulticast.cpp | 149 --- tests/dsl/Watchdog.cpp | 110 ++- tests/dsl/With.cpp | 100 +- tests/dsl/emit/Delay.cpp | 108 ++- tests/dsl/emit/EmitFusion.cpp | 153 ++- tests/dsl/emit/Initialise.cpp | 64 +- tests/dsl/emit/UDP.cpp | 82 -- tests/individual/BaseClock.cpp | 140 +++ tests/individual/CustomClock.cpp | 93 ++ tests/log/Log.cpp | 221 ++++- tests/networktest.cpp | 80 +- tests/test.cpp | 8 +- tests/test_util/TestBase.hpp | 74 ++ tests/test_util/diff_string.cpp | 86 ++ .../test_util/diff_string.hpp | 44 +- tests/test_util/has_ipv6.cpp | 37 + tests/test_util/has_ipv6.hpp | 32 + tests/test_util/lcs.hpp | 119 +++ tests/util/demangle.cpp | 125 +++ tests/util/network/resolve.cpp | 146 +++ tests/util/serialise/serialise.cpp | 338 +++++++ tests/util/serialise/xxhash.cpp | 182 ++++ 240 files changed, 13986 insertions(+), 8453 deletions(-) create mode 100644 .cmake-format.py create mode 100644 .github/dependabot.yaml create mode 100644 .github/workflows/gcc.yaml create mode 100644 .github/workflows/linting.yaml create mode 100644 .github/workflows/macos.yaml create mode 100644 .github/workflows/sonarcloud.yaml create mode 100644 .github/workflows/windows.yaml create mode 100644 .readthedocs.yaml delete mode 100644 .travis.yml create mode 100644 .vscode/settings.json delete mode 100644 cmake/Modules/CompilerSetup.cmake delete mode 100644 cmake/Modules/FindNUClear.cmake create mode 100644 cmake/Modules/HeaderLibrary.cmake create mode 100644 cmake/NUClearConfig.cmake.in create mode 100644 sonar-project.properties create mode 100644 src/Configuration.hpp rename src/{include/nuclear_bits => }/Environment.hpp (80%) rename src/{include/nuclear_bits => }/LogLevel.hpp (80%) rename src/{include/nuclear_bits => }/PowerPlant.hpp (53%) rename src/{include/nuclear_bits => }/PowerPlant.ipp (51%) rename src/{include/nuclear_bits => }/Reactor.hpp (68%) create mode 100644 src/clock.hpp rename src/{include/nuclear_bits => }/dsl/Fusion.hpp (58%) rename src/{include/nuclear_bits => }/dsl/Parse.hpp (65%) rename src/{include/nuclear_bits => }/dsl/fusion/BindFusion.hpp (83%) rename src/{include/nuclear_bits => }/dsl/fusion/GetFusion.hpp (92%) create mode 100644 src/dsl/fusion/GroupFusion.hpp rename src/{include/nuclear_bits => }/dsl/fusion/NoOp.hpp (56%) create mode 100644 src/dsl/fusion/PoolFusion.hpp rename src/{include/nuclear_bits => }/dsl/fusion/PostconditionFusion.hpp (82%) rename src/{include/nuclear_bits => }/dsl/fusion/PreconditionFusion.hpp (84%) rename src/{include/nuclear_bits => }/dsl/fusion/PriorityFusion.hpp (85%) rename src/{include/nuclear_bits => }/dsl/fusion/has_bind.hpp (85%) rename src/{include/nuclear_bits => }/dsl/fusion/has_get.hpp (85%) rename src/{include/nuclear_bits/dsl/fusion/has_reschedule.hpp => dsl/fusion/has_group.hpp} (67%) create mode 100644 src/dsl/fusion/has_pool.hpp rename src/{include/nuclear_bits => }/dsl/fusion/has_postcondition.hpp (85%) rename src/{include/nuclear_bits => }/dsl/fusion/has_precondition.hpp (85%) rename src/{include/nuclear_bits => }/dsl/fusion/has_priority.hpp (85%) rename src/{include/nuclear_bits => }/dsl/operation/CacheGet.hpp (87%) rename src/{include/nuclear_bits => }/dsl/operation/ChronoTask.hpp (89%) rename src/{include/nuclear_bits => }/dsl/operation/DSLProxy.hpp (91%) rename src/{include/nuclear_bits => }/dsl/operation/TypeBind.hpp (58%) rename src/{include/nuclear_bits => }/dsl/operation/Unbind.hpp (86%) rename src/{include/nuclear_bits => }/dsl/store/DataStore.hpp (86%) rename src/{include/nuclear_bits => }/dsl/store/ThreadStore.hpp (86%) rename src/{include/nuclear_bits => }/dsl/store/TypeCallbackStore.hpp (90%) rename src/{include/nuclear_bits => }/dsl/trait/is_transient.hpp (92%) rename src/{include/nuclear_bits => }/dsl/validation/Validation.hpp (84%) create mode 100644 src/dsl/word/Always.hpp rename src/{include/nuclear_bits => }/dsl/word/Buffer.hpp (76%) rename src/{include/nuclear_bits => }/dsl/word/Every.hpp (75%) create mode 100644 src/dsl/word/Group.hpp rename src/{include/nuclear_bits => }/dsl/word/IO.hpp (61%) rename src/{include/nuclear_bits => }/dsl/word/Last.hpp (69%) rename src/{include/nuclear_bits => }/dsl/word/MainThread.hpp (59%) rename src/{include/nuclear_bits => }/dsl/word/Network.hpp (77%) create mode 100644 src/dsl/word/Once.hpp rename src/{include/nuclear_bits => }/dsl/word/Optional.hpp (75%) create mode 100644 src/dsl/word/Pool.hpp rename src/{include/nuclear_bits => }/dsl/word/Priority.hpp (87%) rename src/{include/nuclear_bits => }/dsl/word/Shutdown.hpp (88%) rename src/{include/nuclear_bits => }/dsl/word/Single.hpp (87%) rename src/{include/nuclear_bits => }/dsl/word/Startup.hpp (90%) create mode 100644 src/dsl/word/Sync.hpp create mode 100644 src/dsl/word/TCP.hpp rename src/{include/nuclear_bits => }/dsl/word/Trigger.hpp (88%) create mode 100644 src/dsl/word/UDP.hpp create mode 100644 src/dsl/word/Watchdog.hpp rename src/{include/nuclear_bits => }/dsl/word/With.hpp (91%) rename src/{include/nuclear_bits => }/dsl/word/emit/Delay.hpp (72%) rename src/{include/nuclear_bits => }/dsl/word/emit/Direct.hpp (68%) rename src/{include/nuclear_bits => }/dsl/word/emit/Initialise.hpp (80%) rename src/{include/nuclear_bits => }/dsl/word/emit/Local.hpp (66%) rename src/{include/nuclear_bits => }/dsl/word/emit/Network.hpp (89%) create mode 100644 src/dsl/word/emit/UDP.hpp create mode 100644 src/dsl/word/emit/Watchdog.hpp delete mode 100644 src/extension/ChronoController.cpp create mode 100644 src/extension/ChronoController.hpp rename src/{include/nuclear_bits => }/extension/IOController.hpp (83%) delete mode 100644 src/extension/IOController_Posix.cpp create mode 100644 src/extension/IOController_Posix.hpp delete mode 100644 src/extension/IOController_Windows.cpp create mode 100644 src/extension/IOController_Windows.hpp delete mode 100644 src/extension/NetworkController.cpp create mode 100644 src/extension/NetworkController.hpp rename src/{include/nuclear_bits => }/extension/network/NUClearNetwork.hpp (76%) create mode 100644 src/extension/network/wire_protocol.hpp rename src/{include/nuclear_bits/clock.hpp => id.hpp} (74%) delete mode 100644 src/include/nuclear_bits/dsl/fusion/RescheduleFusion.hpp delete mode 100644 src/include/nuclear_bits/dsl/operation/ReactionStatisticsDeloop.hpp delete mode 100644 src/include/nuclear_bits/dsl/word/Always.hpp delete mode 100644 src/include/nuclear_bits/dsl/word/Sync.hpp delete mode 100644 src/include/nuclear_bits/dsl/word/TCP.hpp delete mode 100644 src/include/nuclear_bits/dsl/word/UDP.hpp delete mode 100644 src/include/nuclear_bits/dsl/word/Watchdog.hpp delete mode 100644 src/include/nuclear_bits/dsl/word/emit/UDP.hpp delete mode 100644 src/include/nuclear_bits/extension/IOController_Posix.hpp delete mode 100644 src/include/nuclear_bits/extension/NetworkController.hpp delete mode 100644 src/include/nuclear_bits/extension/network/wire_protocol.hpp delete mode 100644 src/include/nuclear_bits/threading/ReactionTask.hpp delete mode 100644 src/include/nuclear_bits/threading/TaskScheduler.hpp delete mode 100644 src/include/nuclear_bits/threading/ThreadPoolTask.hpp delete mode 100644 src/include/nuclear_bits/util/CallbackGenerator.hpp delete mode 100644 src/include/nuclear_bits/util/FileDescriptor.hpp delete mode 100644 src/include/nuclear_bits/util/platform.hpp delete mode 100644 src/include/nuclear_bits/util/serialise/xxhash.h rename src/{include/nuclear_bits => }/message/CommandLineArguments.hpp (90%) rename src/{include/nuclear_bits => }/message/LogMessage.hpp (56%) rename src/{include/nuclear_bits => }/message/NetworkConfiguration.hpp (52%) rename src/{include/nuclear_bits => }/message/NetworkEvent.hpp (75%) rename src/{include/nuclear_bits => }/message/ReactionStatistics.hpp (68%) rename src/{include/nuclear => nuclear.in} (79%) rename src/{include/nuclear_bits => }/threading/Reaction.hpp (63%) delete mode 100644 src/threading/ReactionHandle.cpp rename src/{include/nuclear_bits => }/threading/ReactionHandle.hpp (73%) create mode 100644 src/threading/ReactionIdentifiers.hpp delete mode 100644 src/threading/ReactionTask.cpp create mode 100644 src/threading/ReactionTask.hpp create mode 100644 src/threading/TaskScheduler.hpp rename src/{include/nuclear_bits => }/util/CallableInfo.hpp (92%) create mode 100644 src/util/CallbackGenerator.hpp rename src/{include/nuclear_bits => }/util/Dereferencer.hpp (89%) create mode 100644 src/util/FileDescriptor.cpp create mode 100644 src/util/FileDescriptor.hpp rename src/{include/nuclear_bits => }/util/FunctionFusion.hpp (55%) create mode 100644 src/util/GeneratedCallback.hpp create mode 100644 src/util/GroupDescriptor.hpp rename src/{include/nuclear_bits => }/util/MergeTransient.hpp (89%) rename src/{include/nuclear_bits => }/util/MetaProgramming.hpp (93%) rename src/{include/nuclear_bits => }/util/RelevantArguments.hpp (94%) rename src/{include/nuclear_bits => }/util/Sequence.hpp (58%) rename src/{include/nuclear_bits/message/ServiceWatchdog.hpp => util/ThreadPoolDescriptor.cpp} (67%) create mode 100644 src/util/ThreadPoolDescriptor.hpp rename src/{include/nuclear_bits => }/util/TransientDataElements.hpp (72%) rename src/{include/nuclear_bits => }/util/TypeList.hpp (67%) rename src/{include/nuclear_bits => }/util/TypeMap.hpp (70%) rename src/{include/nuclear_bits => }/util/apply.hpp (92%) rename src/{include/nuclear_bits => }/util/demangle.hpp (88%) rename src/{include/nuclear_bits => }/util/get_hostname.hpp (84%) rename src/{include/nuclear_bits/util/network/sock_t.hpp => util/main_thread_id.hpp} (64%) create mode 100644 src/util/network/get_interfaces.hpp create mode 100644 src/util/network/if_number_from_address.cpp rename src/{include/nuclear_bits/util/network/get_interfaces.hpp => util/network/if_number_from_address.hpp} (57%) create mode 100644 src/util/network/resolve.cpp rename src/{include/nuclear_bits/extension/IOController_Windows.hpp => util/network/resolve.hpp} (51%) create mode 100644 src/util/network/sock_t.hpp create mode 100644 src/util/platform.hpp create mode 100644 src/util/precise_sleep.cpp rename src/{include/nuclear_bits/util/main_thread_id.hpp => util/precise_sleep.hpp} (76%) rename src/{include/nuclear_bits => }/util/serialise/Serialise.hpp (53%) delete mode 100644 src/util/serialise/xxhash.c create mode 100644 src/util/serialise/xxhash.cpp create mode 100644 src/util/serialise/xxhash.hpp rename src/{include/nuclear_bits => }/util/tuplify.hpp (86%) rename src/{include/nuclear_bits => }/util/unpack.hpp (79%) rename src/{include/nuclear_bits => }/util/update_current_thread_priority.hpp (86%) create mode 100644 tests/api/ReactorArgs.cpp create mode 100644 tests/dsl/Buffer.cpp create mode 100644 tests/dsl/DSLOrdering.cpp delete mode 100644 tests/dsl/Every_Per.cpp create mode 100644 tests/dsl/FusionInOrder.cpp create mode 100644 tests/dsl/Once.cpp delete mode 100644 tests/dsl/Single.cpp create mode 100644 tests/dsl/SyncOrder.cpp create mode 100644 tests/dsl/Transient.cpp delete mode 100644 tests/dsl/TransientMultiTrigger.cpp delete mode 100644 tests/dsl/UDPBroadcast.cpp delete mode 100644 tests/dsl/UDPMulticast.cpp delete mode 100644 tests/dsl/emit/UDP.cpp create mode 100644 tests/individual/BaseClock.cpp create mode 100644 tests/individual/CustomClock.cpp create mode 100644 tests/test_util/TestBase.hpp create mode 100644 tests/test_util/diff_string.cpp rename src/include/nuclear_bits/extension/ChronoController.hpp => tests/test_util/diff_string.hpp (58%) create mode 100644 tests/test_util/has_ipv6.cpp create mode 100644 tests/test_util/has_ipv6.hpp create mode 100644 tests/test_util/lcs.hpp create mode 100644 tests/util/demangle.cpp create mode 100644 tests/util/network/resolve.cpp create mode 100644 tests/util/serialise/serialise.cpp create mode 100644 tests/util/serialise/xxhash.cpp diff --git a/.clang-format b/.clang-format index b73d3118..6c44c3a8 100644 --- a/.clang-format +++ b/.clang-format @@ -1,53 +1,79 @@ ---- +# C++ files +Language: Cpp BasedOnStyle: Google AccessModifierOffset: -4 AlignAfterOpenBracket: Align +AlignConsecutiveMacros: true AlignConsecutiveAssignments: true AlignConsecutiveDeclarations: false -AlignEscapedNewlinesLeft: false +AlignEscapedNewlines: Left AlignOperands: true AlignTrailingComments: true +AllowAllArgumentsOnNextLine: false +AllowAllConstructorInitializersOnNextLine: true AllowAllParametersOfDeclarationOnNextLine: false AllowShortBlocksOnASingleLine: false AllowShortCaseLabelsOnASingleLine: true AllowShortFunctionsOnASingleLine: Empty -AllowShortIfStatementsOnASingleLine: true +AllowShortLambdasOnASingleLine: All +AllowShortIfStatementsOnASingleLine: Never AllowShortLoopsOnASingleLine: false -AlwaysBreakTemplateDeclarations: true +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: true +AlwaysBreakTemplateDeclarations: Yes BinPackArguments: false BinPackParameters: false -BreakBeforeBinaryOperators: NonAssignment -BreakBeforeBraces: Custom BraceWrapping: - AfterClass: false + AfterCaseLabel: false + AfterClass: false AfterControlStatement: false - AfterEnum: false - AfterFunction: false - AfterNamespace: false - AfterObjCDeclaration: false - AfterStruct: false - AfterUnion: false - BeforeCatch: true - BeforeElse: true - IndentBraces: false + AfterEnum: false + AfterFunction: false + AfterNamespace: false + AfterStruct: false + AfterUnion: false + AfterExternBlock: false + BeforeCatch: true + BeforeElse: true + IndentBraces: false + SplitEmptyFunction: false + SplitEmptyRecord: false + SplitEmptyNamespace: false +BreakBeforeBinaryOperators: NonAssignment +BreakBeforeBraces: Custom +BreakInheritanceList: BeforeComma BreakBeforeTernaryOperators: true -BreakConstructorInitializersBeforeComma: true +BreakConstructorInitializers: BeforeComma BreakStringLiterals: true ColumnLimit: 120 +CompactNamespaces: false ConstructorInitializerAllOnOneLineOrOnePerLine: true +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 Cpp11BracedListStyle: true DerivePointerAlignment: false +FixNamespaceComments: true +IncludeBlocks: Regroup +IndentCaseLabels: true +IndentPPDirectives: BeforeHash +IndentWrappedFunctionNames: true IndentWidth: 4 KeepEmptyLinesAtTheStartOfBlocks: true -Language: Cpp MaxEmptyLinesToKeep: 2 NamespaceIndentation: Inner PointerAlignment: Left ReflowComments: true SortIncludes: true +SortUsingDeclarations: true SpaceAfterCStyleCast: true +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: true SpaceBeforeAssignmentOperators: true +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true SpaceBeforeParens: ControlStatements +SpaceBeforeRangeBasedForLoopColon: true SpaceInEmptyParentheses: false SpacesBeforeTrailingComments: 2 SpacesInAngles: false @@ -58,5 +84,3 @@ SpacesInSquareBrackets: false Standard: Cpp11 TabWidth: 4 UseTab: Never - -... diff --git a/.clang-tidy b/.clang-tidy index 76d4c714..6be676c2 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -1,87 +1,70 @@ ---- -Checks: "clang-analyzer-*\ -,cppcoreguidelines-*\ -,-cppcoreguidelines-pro-type-union-access\ -,-cppcoreguidelines-pro-type-reinterpret-cast\ -,-cppcoreguidelines-pro-type-vararg\ -,-cppcoreguidelines-pro-bounds-pointer-arithmetic\ -,-cppcoreguidelines-pro-bounds-constant-array-index\ -,cert-err60-cpp\ -,cert-flp30-c\ -,google-readability-todo\ -,google-runtime-member-string-references\ -,google-runtime-memset\ -,google-readability-casting\ -,llvm-header-guard\ -,llvm-namespace-comment\ -,misc-*\ -,modernize-*\ -,performance-*\ -,readability-*" -WarningsAsErrors: '' -HeaderFilterRegex: '' +Checks: > + -*, + bugprone-*, + -bugprone-easily-swappable-parameters, + -bugprone-implicit-widening-of-multiplication-result, + cert-*, + clang-diagnostic-*, + clang-analyzer-*, + cppcoreguidelines-*, + -cppcoreguidelines-avoid-magic-numbers, + -cppcoreguidelines-non-private-member-variables-in-classes, + -cppcoreguidelines-owning-memory, + -cppcoreguidelines-pro-bounds-array-to-pointer-decay, + -cppcoreguidelines-pro-bounds-constant-array-index, + -cppcoreguidelines-pro-bounds-pointer-arithmetic, + -cppcoreguidelines-pro-type-reinterpret-cast, + -cppcoreguidelines-pro-type-union-access, + -cppcoreguidelines-pro-type-vararg, + google-*, + -google-explicit-constructor, + -google-readability-casting, + -google-readability-function-size, + -google-runtime-references, + llvm-namespace-comment, + misc-*, + -misc-non-private-member-variables-in-classes, + -misc-no-recursion, + performance-*, + readability-*, + -readability-function-cognitive-complexity, + -readability-function-size, + -readability-identifier-length, + -readability-magic-numbers, + -readability-uppercase-literal-suffix, + modernize-*, + -modernize-use-trailing-return-type, + -modernize-use-emplace +WarningsAsErrors: "" +HeaderFilterRegex: ".*" AnalyzeTemporaryDtors: false +FormatStyle: file CheckOptions: - - key: llvm-header-guard.HeaderFileExtensions - value: ',h,hh,hpp,hxx' - - key: llvm-namespace-comment.ShortNamespaceLines - value: '1' - - key: llvm-namespace-comment.SpacesBeforeComments - value: '2' - - key: misc-definitions-in-headers.HeaderFileExtensions - value: ',h,hh,hpp,hxx,ipp' - - key: misc-definitions-in-headers.UseHeaderFileExtension - value: '1' - - key: misc-move-constructor-init.IncludeStyle - value: google - - key: modernize-loop-convert.NamingStyle - value: lower_case - - key: modernize-pass-by-value.IncludeStyle - value: google - - key: modernize-replace-auto-ptr.IncludeStyle - value: google - - key: performance-for-range-copy.WarnOnAllAutoCopies - value: '1' - - key: performance-type-promotion-in-math-fn.IncludeStyle - value: google - - key: performance-unnecessary-value-param.IncludeStyle - value: google - - key: readability-braces-around-statements.ShortStatementLines - value: '1' - - key: readability-identifier-naming.ClassCase - value: CamelCase - - key: readability-identifier-naming.ConstantCase - value: UPPER_CASE - - key: readability-identifier-naming.EnumCase - value: CamelCase - - key: readability-identifier-naming.EnumConstantCase - value: UPPER_CASE - - key: readability-identifier-naming.FunctionCase - value: lower_case - - key: readability-identifier-naming.MacroDefinitionCase - value: UPPER_CASE - - key: readability-identifier-naming.MemberCase - value: lower_case - - key: readability-identifier-naming.MethodCase - value: lower_case - - key: readability-identifier-naming.NamespaceCase - value: aNy_CasE - - key: readability-identifier-naming.ParameterCase - value: lower_case - - key: readability-identifier-naming.ParameterPackCase - value: lower_case - - key: readability-identifier-naming.StructCase - value: CamelCase - - key: readability-identifier-naming.TemplateParameterCase - value: CamelCase - - key: readability-identifier-naming.TypeAliasCase - value: CamelCase - - key: readability-identifier-naming.TypedefCase - value: CamelCase - - key: readability-identifier-naming.UnionCase - value: CamelCase - - key: readability-identifier-naming.ValueTemplateParameterCase - value: lower_case - - key: readability-identifier-naming.VariableCase - value: lower_case -... + - key: cppcoreguidelines-avoid-magic-numbers.IgnoredFloatingPointValues + value: "0.5;1.0;2.0;3.0;4.0;100.0;" + - key: readability-magic-numbers.IgnoredFloatingPointValues + value: "0.5;1.0;2.0;3.0;4.0;100.0;" + - key: cppcoreguidelines-avoid-magic-numbers.IgnoredIntegerValues + value: "1;2;3;4;" + - key: readability-magic-numbers.IgnoredIntegerValues + value: "1;2;3;4;" + - key: llvm-namespace-comment.ShortNamespaceLines + value: '1' + - key: llvm-namespace-comment.SpacesBeforeComments + value: '2' + - key: misc-move-constructor-init.IncludeStyle + value: google + - key: modernize-loop-convert.NamingStyle + value: lower_case + - key: modernize-pass-by-value.IncludeStyle + value: google + - key: modernize-replace-auto-ptr.IncludeStyle + value: google + - key: performance-for-range-copy.WarnOnAllAutoCopies + value: '1' + - key: performance-type-promotion-in-math-fn.IncludeStyle + value: google + - key: performance-unnecessary-value-param.IncludeStyle + value: google + - key: readability-braces-around-statements.ShortStatementLines + value: '1' diff --git a/.cmake-format.py b/.cmake-format.py new file mode 100644 index 00000000..521da4e0 --- /dev/null +++ b/.cmake-format.py @@ -0,0 +1,218 @@ +# ---------------------------------- +# Options affecting listfile parsing +# ---------------------------------- +with section("parse"): + + # Specify structure for custom cmake functions + additional_commands = { + "HeaderLibrary": {"kwargs": {"NAME": "*", "HEADER": "*", "PATH_SUFFIX": "*", "URL": "*"}}, + } + + # Specify variable tags. + vartags = [] + + # Specify property tags. + proptags = [] + +# ----------------------------- +# Options affecting formatting. +# ----------------------------- +with section("format"): + + # How wide to allow formatted cmake files + line_width = 120 + + # How many spaces to tab for indent + tab_size = 2 + + # If an argument group contains more than this many sub-groups (parg or kwarg + # groups) then force it to a vertical layout. + max_subgroups_hwrap = 2 + + # If a positional argument group contains more than this many arguments, then + # force it to a vertical layout. + max_pargs_hwrap = 6 + + # If a cmdline positional group consumes more than this many lines without + # nesting, then invalidate the layout (and nest) + max_rows_cmdline = 2 + + # If true, separate flow control names from their parentheses with a space + separate_ctrl_name_with_space = False + + # If true, separate function names from parentheses with a space + separate_fn_name_with_space = False + + # If a statement is wrapped to more than one line, than dangle the closing + # parenthesis on its own line. + dangle_parens = True + + # If the trailing parenthesis must be 'dangled' on its on line, then align it + # to this reference: `prefix`: the start of the statement, `prefix-indent`: + # the start of the statement, plus one indentation level, `child`: align to + # the column of the arguments + dangle_align = "prefix" + + # If the statement spelling length (including space and parenthesis) is + # smaller than this amount, then force reject nested layouts. + min_prefix_chars = 4 + + # If the statement spelling length (including space and parenthesis) is larger + # than the tab width by more than this amount, then force reject un-nested + # layouts. + max_prefix_chars = 10 + + # If a candidate layout is wrapped horizontally but it exceeds this many + # lines, then reject the layout. + max_lines_hwrap = 2 + + # What style line endings to use in the output. + line_ending = "unix" + + # Format command names consistently as 'lower' or 'upper' case + command_case = "canonical" + + # Format keywords consistently as 'lower' or 'upper' case + keyword_case = "upper" + + # If true, the argument lists which are known to be sortable will be sorted + # lexicographicall + enable_sort = True + + # If true, the parsers may infer whether or not an argument list is sortable + # (without annotation). + autosort = True + + # By default, if cmake-format cannot successfully fit everything into the + # desired linewidth it will apply the last, most agressive attempt that it + # made. If this flag is True, however, cmake-format will print error, exit + # with non-zero status code, and write-out nothing + require_valid_layout = False + + # A dictionary mapping layout nodes to a list of wrap decisions. See the + # documentation for more information. + layout_passes = {} + +# ------------------------------------------------ +# Options affecting comment reflow and formatting. +# ------------------------------------------------ +with section("markup"): + + # What character to use for bulleted lists + bullet_char = "*" + + # What character to use as punctuation after numerals in an enumerated list + enum_char = "." + + # If comment markup is enabled, don't reflow the first comment block in each + # listfile. Use this to preserve formatting of your copyright/license + # statements. + first_comment_is_literal = False + + # If comment markup is enabled, don't reflow any comment block which matches + # this (regex) pattern. Default is `None` (disabled). + literal_comment_pattern = None + + # Regular expression to match preformat fences in comments default= + # ``r'^\s*([`~]{3}[`~]*)(.*)$'`` + fence_pattern = "^\\s*([`~]{3}[`~]*)(.*)$" + + # Regular expression to match rulers in comments default= + # ``r'^\s*[^\w\s]{3}.*[^\w\s]{3}$'`` + ruler_pattern = "^\\s*[^\\w\\s]{3}.*[^\\w\\s]{3}$" + + # If a comment line matches starts with this pattern then it is explicitly a + # trailing comment for the preceeding argument. Default is '#<' + explicit_trailing_pattern = "#<" + + # If a comment line starts with at least this many consecutive hash + # characters, then don't lstrip() them off. This allows for lazy hash rulers + # where the first hash char is not separated by space + hashruler_min_length = 10 + + # If true, then insert a space between the first hash char and remaining hash + # chars in a hash ruler, and normalize its length to fill the column + canonicalize_hashrulers = True + + # enable comment markup parsing and reflow + enable_markup = False + +# ---------------------------- +# Options affecting the linter +# ---------------------------- +with section("lint"): + + # a list of lint codes to disable + disabled_codes = [] + + # regular expression pattern describing valid function names + function_pattern = "[0-9a-z_]+" + + # regular expression pattern describing valid macro names + macro_pattern = "[0-9A-Z_]+" + + # regular expression pattern describing valid names for variables with global + # scope + global_var_pattern = "[0-9A-Z][0-9A-Z_]+" + + # regular expression pattern describing valid names for variables with global + # scope (but internal semantic) + internal_var_pattern = "_[0-9A-Z][0-9A-Z_]+" + + # regular expression pattern describing valid names for variables with local + # scope + local_var_pattern = "[0-9a-z_]+" + + # regular expression pattern describing valid names for privatedirectory + # variables + private_var_pattern = "_[0-9a-z_]+" + + # regular expression pattern describing valid names for publicdirectory + # variables + public_var_pattern = "[0-9A-Z][0-9A-Z_]+" + + # regular expression pattern describing valid names for keywords used in + # functions or macros + keyword_pattern = "[0-9A-Z_]+" + + # In the heuristic for C0201, how many conditionals to match within a loop in + # before considering the loop a parser. + max_conditionals_custom_parser = 2 + + # Require at least this many newlines between statements + min_statement_spacing = 1 + + # Require no more than this many newlines between statements + max_statement_spacing = 1 + max_returns = 6 + max_branches = 12 + max_arguments = 5 + max_localvars = 15 + max_statements = 50 + +# ------------------------------- +# Options affecting file encoding +# ------------------------------- +with section("encode"): + + # If true, emit the unicode byte-order mark (BOM) at the start of the file + emit_byteorder_mark = False + + # Specify the encoding of the input file. Defaults to utf-8 + input_encoding = "utf-8" + + # Specify the encoding of the output file. Defaults to utf-8. Note that cmake + # only claims to support utf-8 so be careful when using anything else + output_encoding = "utf-8" + +# ------------------------------------- +# Miscellaneous configurations options. +# ------------------------------------- +with section("misc"): + + # A dictionary containing any per-command configuration overrides. Currently + # only `command_case` is supported. + per_command = { + "HeaderLibrary": {"command_case": "unchanged"}, + "ToolchainLibraryFinder": {"command_case": "unchanged"}, + } diff --git a/.github/dependabot.yaml b/.github/dependabot.yaml new file mode 100644 index 00000000..54779793 --- /dev/null +++ b/.github/dependabot.yaml @@ -0,0 +1,9 @@ +# Required fields are `version` and `updates` +version: 2 +updates: + # Required fields are `package-ecosystem`, `directory`, and `schedule.interval` + # Maintain dependencies for GitHub Actions + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "daily" diff --git a/.github/workflows/gcc.yaml b/.github/workflows/gcc.yaml new file mode 100644 index 00000000..4bec64c0 --- /dev/null +++ b/.github/workflows/gcc.yaml @@ -0,0 +1,101 @@ +# Continuous Integration tests +name: GCC + +on: + push: + branches: [main] + pull_request: + branches: [main] + +# Ensure that only one instance of the workflow is run at a time for each branch/tag. +# Jobs currently running on the branch/tag will be cancelled when new commits are pushed. +# See https://docs.github.com/en/actions/learn-github-actions/workflow-syntax-for-github-actions#concurrency. +concurrency: + # `github.workflow` is the workflow name, `github.ref` is the current branch/tag identifier + group: ${{ format('{0}:{1}', github.workflow, github.ref) }} + cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} + +jobs: + linux-gcc: + strategy: + matrix: + toolchain: + - container: ubuntu:22.04 + version: "13" + - container: ubuntu:22.04 + version: "12" + - container: ubuntu:22.04 + version: "11" + - container: ubuntu:22.04 + version: "10" + - container: ubuntu:22.04 + version: "9" + - container: ubuntu:20.04 + version: "8" + - container: ubuntu:20.04 + version: "7" + - container: ubuntu:18.04 + version: "6" + - container: ubuntu:18.04 + version: "5" + + name: Linux GCC-${{ matrix.toolchain.version }} + runs-on: ubuntu-latest + continue-on-error: true + + # Use the container for this specific version of gcc + container: ${{ matrix.toolchain.container }} + + steps: + - name: Checkout Code + uses: actions/checkout@v3 + + # Update for all the actions that need to install stuff + - run: | + apt-get update + apt-get install -y software-properties-common + + - name: Install GCC + run: | + add-apt-repository ppa:ubuntu-toolchain-r/test + apt-get update + apt-get install -y gcc-${{ matrix.toolchain.version }} g++-${{ matrix.toolchain.version }} + + - name: Install CMake + uses: lukka/get-cmake@latest + with: + cmakeVersion: 3.27.1 + ninjaVersion: 1.11.1 + + - name: Setup CCache + uses: hendrikmuhs/ccache-action@v1.2 + with: + key: ${{ github.job }}-gcc-${{ matrix.toolchain.version }} + max-size: 100M + + - name: Configure CMake + run: | + cmake -E make_directory build + cmake -S . -B build \ + -GNinja \ + -DCMAKE_C_COMPILER=/usr/bin/gcc-${{ matrix.toolchain.version }} \ + -DCMAKE_CXX_COMPILER=/usr/bin/g++-${{ matrix.toolchain.version }} \ + -DCMAKE_C_COMPILER_LAUNCHER=ccache \ + -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ + -DBUILD_TESTS=ON \ + -DCMAKE_BUILD_TYPE=Release \ + -DCI_BUILD=ON \ + -DENABLE_CLANG_TIDY=OFF + + - name: Build + timeout-minutes: 30 + run: cmake --build build --config Release + + - name: CCache Stats + run: ccache --show-stats + + - name: Test + timeout-minutes: 10 + run: | + build/tests/test_nuclear + for f in build/tests/individual/*; do echo "Testing $f"; ./$f; done diff --git a/.github/workflows/linting.yaml b/.github/workflows/linting.yaml new file mode 100644 index 00000000..b7f93371 --- /dev/null +++ b/.github/workflows/linting.yaml @@ -0,0 +1,69 @@ +name: Linting + +# Controls when the action will run. +on: + # Triggers the workflow on push or pull request events but only for the main branch + push: + branches: [main] + pull_request: + branches: [main] + +# Ensure that only one instance of the workflow is run at a time for each branch/tag. +# Jobs currently running on the branch/tag will be cancelled when new commits are pushed. +# See https://docs.github.com/en/actions/learn-github-actions/workflow-syntax-for-github-actions#concurrency. +concurrency: + # `github.workflow` is the workflow name, `github.ref` is the current branch/tag identifier + group: ${{ format('{0}:{1}', github.workflow, github.ref) }} + cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + linux-clang-tidy: + name: Linux Clang-Tidy + runs-on: ubuntu-latest + + steps: + - name: Checkout Code + uses: actions/checkout@v3 + + - name: Install clang-tidy-15 + run: | + wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - + echo "deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-15 main" | sudo tee /etc/apt/sources.list.d/llvm-15 + echo "deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-15 main" | sudo tee -a /etc/apt/sources.list.d/llvm-15 + sudo apt-get update + sudo apt-get install -y clang-tidy-15 + + # Download and install cmake + - name: Install CMake + uses: lukka/get-cmake@latest + with: + cmakeVersion: 3.27.1 + ninjaVersion: 1.11.1 + + # Download and setup ccache + - name: Setup CCache + uses: hendrikmuhs/ccache-action@v1.2 + with: + key: ${{ github.job }} + max-size: 100M + + - name: Configure CMake + run: | + cmake -E make_directory build + cmake -S . -B build \ + -GNinja \ + -DCMAKE_C_COMPILER_LAUNCHER=ccache \ + -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ + -DBUILD_TESTS=ON \ + -DCMAKE_BUILD_TYPE=Release \ + -DCI_BUILD=ON \ + -DENABLE_CLANG_TIDY=ON + + - name: Build + timeout-minutes: 30 + # Execute the build. You can specify a specific target with "--target " + run: cmake --build build --config Release --parallel 2 + + - name: CCache Stats + run: ccache --show-stats diff --git a/.github/workflows/macos.yaml b/.github/workflows/macos.yaml new file mode 100644 index 00000000..c9028379 --- /dev/null +++ b/.github/workflows/macos.yaml @@ -0,0 +1,63 @@ +# Continuous Integration tests +name: MacOS + +on: + # Triggers the workflow on push or pull request events but only for the main branch + push: + branches: [main] + pull_request: + branches: [main] + +# Ensure that only one instance of the workflow is run at a time for each branch/tag. +# Jobs currently running on the branch/tag will be cancelled when new commits are pushed. +# See https://docs.github.com/en/actions/learn-github-actions/workflow-syntax-for-github-actions#concurrency. +concurrency: + # `github.workflow` is the workflow name, `github.ref` is the current branch/tag identifier + group: ${{ format('{0}:{1}', github.workflow, github.ref) }} + cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} + +jobs: + macos-latest: + name: MacOS Latest + runs-on: macos-latest + + steps: + - name: Checkout Code + uses: actions/checkout@v3 + + - name: Setup CCache + uses: hendrikmuhs/ccache-action@v1.2 + with: + key: ${{ github.job }} + max-size: 100M + + - name: Install CMake + uses: lukka/get-cmake@latest + with: + cmakeVersion: 3.27.1 + ninjaVersion: 1.11.1 + + - name: Configure CMake + run: | + cmake -E make_directory build + cmake -S . -B build \ + -GNinja \ + -DCMAKE_C_COMPILER_LAUNCHER=ccache \ + -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ + -DBUILD_TESTS=ON \ + -DCMAKE_BUILD_TYPE=Release \ + -DCI_BUILD=ON \ + -DENABLE_CLANG_TIDY=OFF + + - name: Build + timeout-minutes: 30 + run: cmake --build build --config Release + + - name: CCache Stats + run: ccache --show-stats + + - name: Test + timeout-minutes: 10 + run: | + build/tests/test_nuclear + for f in build/tests/individual/*; do echo "Testing $f"; ./$f; done diff --git a/.github/workflows/sonarcloud.yaml b/.github/workflows/sonarcloud.yaml new file mode 100644 index 00000000..9f0a1d84 --- /dev/null +++ b/.github/workflows/sonarcloud.yaml @@ -0,0 +1,80 @@ +name: Sonar +on: + push: + branches: + - main + - sonar + pull_request: + types: [opened, synchronize, reopened] + +# Ensure that only one instance of the workflow is run at a time for each branch/tag. +# Jobs currently running on the branch/tag will be cancelled when new commits are pushed. +# See https://docs.github.com/en/actions/learn-github-actions/workflow-syntax-for-github-actions#concurrency. +concurrency: + # `github.workflow` is the workflow name, `github.ref` is the current branch/tag identifier + group: ${{ format('{0}:{1}', github.workflow, github.ref) }} + cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} + +jobs: + sonarcloud: + name: SonarCloud + runs-on: ubuntu-latest + env: + BUILD_WRAPPER_OUT_DIR: build_wrapper_output_directory # Directory where build-wrapper output will be placed + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis + + - name: Install gcovr + run: pip install gcovr==6.0 + + - name: Install sonar-scanner and build-wrapper + uses: SonarSource/sonarcloud-github-c-cpp@v2 + + - name: Install CMake + uses: lukka/get-cmake@latest + with: + cmakeVersion: 3.27.1 + ninjaVersion: 1.11.1 + + - name: Setup CCache + uses: hendrikmuhs/ccache-action@v1.2 + with: + key: ${{ github.job }} + max-size: 100M + + - name: Configure CMake + run: | + cmake -E make_directory build + cmake -S . -B build \ + -GNinja \ + -DCMAKE_CXX_FLAGS="--coverage" \ + -DCMAKE_C_COMPILER_LAUNCHER=ccache \ + -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ + -DBUILD_TESTS=ON \ + -DCMAKE_BUILD_TYPE=Debug \ + -DCI_BUILD=ON \ + -DENABLE_CLANG_TIDY=OFF + + - name: Build with Sonar Wrapper + timeout-minutes: 30 + run: build-wrapper-linux-x86-64 --out-dir ${{ env.BUILD_WRAPPER_OUT_DIR }} cmake --build build/ --config Debug + + - name: Run tests to generate coverage statistics + timeout-minutes: 10 + run: | + build/tests/test_nuclear + for f in build/tests/individual/*; do echo "Testing $f"; ./$f; done + + - name: Collect coverage into one XML report + run: gcovr --exclude-unreachable-branches --exclude-noncode-lines --sonarqube > coverage.xml + + - name: Run sonar-scanner + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + run: | + sonar-scanner \ + --define sonar.cfamily.build-wrapper-output="${{ env.BUILD_WRAPPER_OUT_DIR }}" \ + --define sonar.coverageReportPaths=coverage.xml diff --git a/.github/workflows/windows.yaml b/.github/workflows/windows.yaml new file mode 100644 index 00000000..500b9ea7 --- /dev/null +++ b/.github/workflows/windows.yaml @@ -0,0 +1,85 @@ +# Continuous Integration tests +name: Windows + +on: + push: + branches: [main] + pull_request: + branches: [main] + +# Ensure that only one instance of the workflow is run at a time for each branch/tag. +# Jobs currently running on the branch/tag will be cancelled when new commits are pushed. +# See https://docs.github.com/en/actions/learn-github-actions/workflow-syntax-for-github-actions#concurrency. +concurrency: + # `github.workflow` is the workflow name, `github.ref` is the current branch/tag identifier + group: ${{ format('{0}:{1}', github.workflow, github.ref) }} + cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + windows-latest: + name: Windows Latest ${{ matrix.toolchain.name }} + + strategy: + matrix: + toolchain: + - name: MSVC + c: cl + cxx: cl + # Code does not compile on GCC on windows + # - name: GCC + # c: gcc + # cxx: g++ + + runs-on: windows-latest + continue-on-error: true + + steps: + - name: Checkout Code + uses: actions/checkout@v3 + + - name: Setup CCache + uses: hendrikmuhs/ccache-action@v1.2 + with: + key: ${{ github.job }}-${{ matrix.toolchain.name }} + max-size: 100M + variant: sccache + + - name: Install CMake + uses: lukka/get-cmake@latest + with: + cmakeVersion: 3.27.1 + ninjaVersion: 1.11.1 + + # This lets ninja find MSVC + - name: Add MSVC to path + uses: ilammy/msvc-dev-cmd@v1 + + - name: Configure CMake + shell: cmd + run: | + cmake -E make_directory build + cmake -S . -B build ^ + -GNinja ^ + -DCMAKE_C_COMPILER=${{ matrix.toolchain.c }} ^ + -DCMAKE_CXX_COMPILER=${{ matrix.toolchain.cxx }} ^ + -DCMAKE_C_COMPILER_LAUNCHER=sccache ^ + -DCMAKE_CXX_COMPILER_LAUNCHER=sccache ^ + -DBUILD_TESTS=ON ^ + -DCMAKE_BUILD_TYPE=Release ^ + -DCI_BUILD=ON ^ + -DENABLE_CLANG_TIDY=OFF + + - name: Build + timeout-minutes: 30 + run: cmake --build build --config Release + + - name: SCCache Stats + run: sccache --show-stats + + - name: Test + timeout-minutes: 10 + shell: bash + run: | + build/tests/test_nuclear.exe + for f in build/tests/individual/*; do echo "Testing $f"; ./$f; done diff --git a/.readthedocs.yaml b/.readthedocs.yaml new file mode 100644 index 00000000..9712e405 --- /dev/null +++ b/.readthedocs.yaml @@ -0,0 +1,22 @@ +# .readthedocs.yaml +# Read the Docs configuration file +# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details + +# Required +version: 2 + +# Set the version of Python and other tools you might need +build: + os: ubuntu-22.04 + tools: + python: "3.11" + +# Build documentation in the docs/ directory with Sphinx +sphinx: + configuration: docs/conf.py + +# We recommend specifying your dependencies to enable reproducible builds: +# https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html +python: + install: + - requirements: docs/requirements.txt diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 9fce03f7..00000000 --- a/.travis.yml +++ /dev/null @@ -1,127 +0,0 @@ -language: cpp -sudo: false -matrix: - include: - - os: linux - dist: trusty - compiler: gcc - addons: - apt: - sources: ['ubuntu-toolchain-r-test'] - packages: ['g++-4.9'] - env: - - CXX_COMPILER=g++-4.9 - - CC_COMPILER=gcc-4.9 - - - os: linux - dist: trusty - compiler: gcc - addons: - apt: - sources: ['ubuntu-toolchain-r-test'] - packages: ['g++-5'] - env: - - CXX_COMPILER=g++-5 - - CC_COMPILER=gcc-5 - - - os: linux - dist: trusty - compiler: gcc - addons: - apt: - sources: ['ubuntu-toolchain-r-test'] - packages: ['g++-6'] - env: - - CXX_COMPILER=g++-6 - - CC_COMPILER=gcc-6 - - - os: linux - dist: trusty - compiler: gcc - addons: - apt: - sources: ['ubuntu-toolchain-r-test'] - packages: ['g++-7'] - env: - - CXX_COMPILER=g++-7 - - CC_COMPILER=gcc-7 - - - os: linux - dist: trusty - compiler: clang - addons: - apt: - sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-3.6'] - packages: ['clang-3.6', 'g++-4.9'] - env: - - CXX_COMPILER=clang++-3.6 - - CC_COMPILER=clang-3.6 - - - os: linux - dist: trusty - compiler: clang - addons: - apt: - sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.7'] - packages: ['clang-3.7', 'g++-4.9'] - env: - - CXX_COMPILER=clang++-3.7 - - CC_COMPILER=clang-3.7 - - - os: linux - dist: trusty - compiler: clang - addons: - apt: - sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-3.8'] - packages: ['clang-3.8', 'g++-4.9'] - env: - - CXX_COMPILER=clang++-3.8 - - CC_COMPILER=clang-3.8 - - - os: linux - dist: trusty - compiler: clang - addons: - apt: - sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-3.9'] - packages: ['clang-3.9', 'g++-4.9'] - env: - - CXX_COMPILER=clang++-3.9 - - CC_COMPILER=clang-3.9 - - - os: linux - dist: trusty - compiler: clang - addons: - apt: - sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-4.0'] - packages: ['clang-4.0', 'g++-4.9'] - env: - - CXX_COMPILER=clang++-4.0 - - CC_COMPILER=clang-4.0 - - - os: osx - env: - - CXX_COMPILER=clang++ - - CC_COMPILER=clang - -install: - # Catch - - wget https://raw.githubusercontent.com/philsquared/Catch/master/single_include/catch.hpp - - mkdir -p /tmp/include - - mv catch.hpp /tmp/include - - - export CC=$CC_COMPILER - - export CXX=$CXX_COMPILER - -# Before our script is run (setup build) -before_script: - - mkdir build - - cd build - - cmake -DCMAKE_BUILD_TYPE=Release -DCATCH_INCLUDE_DIR=/tmp/include .. - -# Run our build -script: - - make - - ./tests/test_nuclear exclude:[network] diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..78a6e13f --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,15 @@ +{ + "cmake.generator": "Ninja", + "editor.formatOnSave": true, + "editor.tabSize": 4, + "editor.insertSpaces": true, + "files.insertFinalNewline": true, + "files.trimFinalNewlines": true, + "files.eol": "\n", + "C_Cpp.clang_format_style": "file", + "C_Cpp.default.cppStandard": "c++14", + "C_Cpp.preferredPathSeparator": "Forward Slash", + "editor.rulers": [120], + "cmake.configureOnOpen": true, + "C_Cpp.default.configurationProvider": "vector-of-bool.cmake-tools" +} diff --git a/CMakeLists.txt b/CMakeLists.txt index d7618c19..e5e0299a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,43 +1,117 @@ -# Copyright (C) 2013 Trent Houliston , Jake Woods -# 2014-2017 Trent Houliston -# -# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated -# documentation files (the "Software"), to deal in the Software without restriction, including without limitation the -# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to -# permit persons to whom the Software is furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all copies or substantial portions of the -# Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE -# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -CMAKE_MINIMUM_REQUIRED(VERSION 2.8.10) -PROJECT(NUClear) - -SET(VERSION_MAJOR 0) -SET(VERSION_MINOR 2) -SET(VERSION_PATCH 0) +#[[ +MIT License + +Copyright (c) 2013 NUClear Contributors + +This file is part of the NUClear codebase. +See https://github.com/Fastcode/NUClear for further info. + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the +Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +]] + +cmake_minimum_required(VERSION 3.15.0) + +# Set the project after the build type as the Project command can change the build type +project( + NUClear + VERSION 1.0.0 + LANGUAGES C CXX +) # We use additional modules that cmake needs to know about -SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/") +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/") + +# Set a default build type if none was specified +set(default_build_type "Release") +if(EXISTS "${CMAKE_SOURCE_DIR}/.git") + set(default_build_type "Debug") +endif() + +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + message(STATUS "Setting build type to '${default_build_type}' as none was specified.") + set(CMAKE_BUILD_TYPE + ${default_build_type} + CACHE STRING "Choose the type of build." FORCE + ) + # Set the possible values of build type for cmake-gui + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo") +endif() + +# NUClear targets c++14 +set(CMAKE_CXX_STANDARD 14) + +# Determine if NUClear is built as a subproject (using add_subdirectory) or if it is the master project. +set(MASTER_PROJECT OFF) +if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) + set(MASTER_PROJECT ON) +endif() + +if(MSVC) + add_compile_options(/W4) +else() + add_compile_options(-Wall -Wextra -pedantic) +endif(MSVC) + +# If this option is set we are building using continous integration +option(CI_BUILD "Enable build options for building in the CI server" OFF) + +# Default not to run the clang-tidy checks, default to whatever our CI_BUILD is +option(ENABLE_CLANG_TIDY "Enable building with clang-tidy checks.") +if(ENABLE_CLANG_TIDY) + # Search for clang-tidy-15 first as this is the version installed in CI + find_program(CLANG_TIDY_EXECUTABLE NAMES clang-tidy-15 clang-tidy) + if(NOT CLANG_TIDY_EXECUTABLE) + message(FATAL_ERROR "clang-tidy-15 not found.") + endif() + + # Report clang-tidy executable details + execute_process(COMMAND "${CLANG_TIDY_EXECUTABLE}" "--version" OUTPUT_VARIABLE CLANG_TIDY_VERSION) + string(REGEX REPLACE ".*LLVM version ([0-9.]*).*" "\\1" CLANG_TIDY_VERSION "${CLANG_TIDY_VERSION}") + message(STATUS "Found clang-tidy: ${CLANG_TIDY_EXECUTABLE} ${CLANG_TIDY_VERSION}") -# This directory contains our header files and ipp files -INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/src/include) + # Build clang-tidy command line + set(CLANG_TIDY_ARGS "${CLANG_TIDY_EXECUTABLE}" "--use-color" "--config-file=${PROJECT_SOURCE_DIR}/.clang-tidy") + if(CI_BUILD) + set(CLANG_TIDY_ARGS "${CLANG_TIDY_EXECUTABLE}" "-warnings-as-errors=*") + endif(CI_BUILD) + set(CMAKE_CXX_CLANG_TIDY "${CLANG_TIDY_ARGS}" "--extra-arg=-std=c++14") + set(CMAKE_C_CLANG_TIDY "${CLANG_TIDY_ARGS}" "--extra-arg=-std=c99") +endif(ENABLE_CLANG_TIDY) -# Setup our compiler settings -INCLUDE(CompilerSetup) +# If we are doing a CI build then we want to enable -Werror when compiling warnings are bad. We will also make it fail +# if clang-tidy has an error +if(CI_BUILD) + if(CMAKE_CXX_COMPILER_ID MATCHES MSVC) + add_compile_options(/WX) + else() + add_compile_options(-Werror) + endif() +endif(CI_BUILD) -# Add the source -ADD_SUBDIRECTORY(src) +# Make the compiler display colours always (even when we build with ninja) +if(CMAKE_CXX_COMPILER_ID MATCHES GNU) + add_compile_options(-fdiagnostics-color=always) +endif() +if(CMAKE_CXX_COMPILER_ID MATCHES Clang) + add_compile_options(-fcolor-diagnostics) +endif() -# Install the headers and templates that nuclear depends on -INSTALL(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/src/include/ DESTINATION include PATTERN "*.hpp" PATTERN "*.ipp") +# Add the src directory +add_subdirectory(src) # Add the tests directory -ADD_SUBDIRECTORY(tests) +add_subdirectory(tests) # Add the documentation subdirectory -ADD_SUBDIRECTORY(docs) +add_subdirectory(docs) diff --git a/LICENSE b/LICENSE index 7ce680cf..02cd0a76 100644 --- a/LICENSE +++ b/LICENSE @@ -1,5 +1,4 @@ -Copyright (C) 2013 Trent Houliston , Jake Woods - 2014-2017 Trent Houliston +Copyright (C) 2013-2023 NUClear Contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the Software), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: diff --git a/NUClear.sublime-project b/NUClear.sublime-project index be494786..b93aa818 100644 --- a/NUClear.sublime-project +++ b/NUClear.sublime-project @@ -6,8 +6,10 @@ } ], "settings": { - "ClangFormat": { - "format_on_save": true + "ClangFormat": { + "style": "file", + "format_on_save": true, + "languages": [ "C", "C++", "C++11", "Protobuf" ], } } } diff --git a/README.md b/README.md index dbf9374f..8978133a 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -NUClear [![Build Status](https://travis-ci.org/Fastcode/NUClear.svg?branch=develop)](https://travis-ci.org/Fastcode/NUClear) +NUClear [![CI](https://github.com/Fastcode/NUClear/actions/workflows/main.yaml/badge.svg)](https://github.com/Fastcode/NUClear/actions/workflows/main.yaml) ======= NUClear is a C++ software framework designed to aid in the development of real time modular systems. @@ -8,7 +8,7 @@ It is highly extensible and provides several attachment points to develop new DS These metaprograms reduce the cost of routing messages between modules resulting in a much faster system. -For help getting started check the [wiki](https://github.com/Fastcode/NUClear/wiki) +For help getting started check the [docs](https://nuclear.readthedocs.io/en/latest/quick_start.html) If you're starting a new project using NUClear the [NUClear Roles system](https://github.com/Fastcode/NUClearRoles) is highly recommended @@ -26,6 +26,6 @@ make install ``` ### Dependencies -* g++ 4.9, clang (with c++14 support) or Visual Studio 2015 -* cmake 2.8.10 +* g++ 5.0+, clang (with c++14 support) or Visual Studio 2015 +* cmake 3.1.0 * [Catch Unit Testing Framework](https://github.com/philsquared/Catch) for building tests diff --git a/cmake/Modules/CompilerSetup.cmake b/cmake/Modules/CompilerSetup.cmake deleted file mode 100644 index c8fcabbb..00000000 --- a/cmake/Modules/CompilerSetup.cmake +++ /dev/null @@ -1,54 +0,0 @@ -# Copyright (C) 2013 Trent Houliston , Jake Woods -# 2014-2017 Trent Houliston -# -# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated -# documentation files (the "Software"), to deal in the Software without restriction, including without limitation the -# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to -# permit persons to whom the Software is furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all copies or substantial portions of the -# Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE -# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -############## -# GENERATORS # -############### - -# XCode support -IF(CMAKE_GENERATOR MATCHES Xcode) - set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libc++") - set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LANGUAGE_STANDARD "c++14") -ENDIF() - -############### -# COMPILERS # -############### - -# We use position independent code -SET(CMAKE_POSITION_INDEPENDENT_CODE ON) - -# GNU Compiler -IF(CMAKE_CXX_COMPILER_ID MATCHES GNU) - - # GCC Must be version 4.8 or greater for used features - IF(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.9) - MESSAGE(FATAL_ERROR "${PROJECT_NAME} requires g++ 4.9 or greater.") - ENDIF() - - # Enable colours always - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fdiagnostics-color=always") - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -pthread -ftemplate-backtrace-limit=0 -Wall -Wpedantic") - -# Clang Compiler -ELSEIF(CMAKE_CXX_COMPILER_ID MATCHES Clang) - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -pthread -ftemplate-backtrace-limit=0 -Wpedantic -Wextra") - -# MSVC Compiler -ELSEIF(CMAKE_CXX_COMPILER_ID MATCHES MSVC) -ELSE() - MESSAGE(WARNING "You are using an unsupported compiler! Compilation has only been tested with Clang, GCC and MSVC.") -ENDIF() diff --git a/cmake/Modules/FindCATCH.cmake b/cmake/Modules/FindCATCH.cmake index 9851d3bd..4f6181c3 100644 --- a/cmake/Modules/FindCATCH.cmake +++ b/cmake/Modules/FindCATCH.cmake @@ -1,20 +1,29 @@ -# Copyright (C) 2013 Trent Houliston , Jake Woods -# 2014-2017 Trent Houliston -# -# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated -# documentation files (the "Software"), to deal in the Software without restriction, including without limitation the -# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to -# permit persons to whom the Software is furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all copies or substantial portions of the -# Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE -# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +#[[ +MIT License -INCLUDE(ToolchainLibraryFinder) -ToolchainLibraryFinder(NAME CATCH - HEADER catch.hpp +Copyright (c) 2013 NUClear Contributors + +This file is part of the NUClear codebase. +See https://github.com/Fastcode/NUClear for further info. + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the +Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +]] + +include(HeaderLibrary) + +HeaderLibrary( + NAME CATCH + HEADER catch.hpp + URL "https://raw.githubusercontent.com/catchorg/Catch2/v2.x/single_include/catch2/catch.hpp" ) diff --git a/cmake/Modules/FindNUClear.cmake b/cmake/Modules/FindNUClear.cmake deleted file mode 100644 index 11f3552b..00000000 --- a/cmake/Modules/FindNUClear.cmake +++ /dev/null @@ -1,21 +0,0 @@ -# Copyright (C) 2013 Trent Houliston , Jake Woods -# 2014-2017 Trent Houliston -# -# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated -# documentation files (the "Software"), to deal in the Software without restriction, including without limitation the -# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to -# permit persons to whom the Software is furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all copies or substantial portions of the -# Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE -# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -INCLUDE(ToolchainLibraryFinder) -ToolchainLibraryFinder(NAME NUClear - HEADER nuclear - LIBRARY nuclear -) diff --git a/cmake/Modules/FindSphinx.cmake b/cmake/Modules/FindSphinx.cmake index 6bfdd3d2..e7f3584d 100644 --- a/cmake/Modules/FindSphinx.cmake +++ b/cmake/Modules/FindSphinx.cmake @@ -1,20 +1,24 @@ -# Copyright (C) 2013 Trent Houliston , Jake Woods -# 2014-2017 Trent Houliston -# -# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated -# documentation files (the "Software"), to deal in the Software without restriction, including without limitation the -# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to -# permit persons to whom the Software is furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all copies or substantial portions of the -# Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE -# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +#[[ +MIT License -INCLUDE(ToolchainLibraryFinder) -ToolchainLibraryFinder(NAME Sphinx - BINARY sphinx-build -) +Copyright (c) 2013 NUClear Contributors + +This file is part of the NUClear codebase. +See https://github.com/Fastcode/NUClear for further info. + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the +Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +]] + +include(ToolchainLibraryFinder) +ToolchainLibraryFinder(NAME Sphinx BINARY sphinx-build) diff --git a/cmake/Modules/HeaderLibrary.cmake b/cmake/Modules/HeaderLibrary.cmake new file mode 100644 index 00000000..6fd31852 --- /dev/null +++ b/cmake/Modules/HeaderLibrary.cmake @@ -0,0 +1,93 @@ +#[[ +MIT License + +Copyright (c) 2013 NUClear Contributors + +This file is part of the NUClear codebase. +See https://github.com/Fastcode/NUClear for further info. + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the +Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +]] + +include(CMakeParseArguments) +function(HeaderLibrary) + # Extract the arguments from our function call + set(options, "") + set(oneValueArgs "NAME") + set(multiValueArgs "HEADER" "PATH_SUFFIX" "URL") + cmake_parse_arguments(PACKAGE "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + # Clear our required_vars variable + unset(required_vars) + set(OUTPUT_DIR "${CMAKE_BINARY_DIR}/include") + + # Find our include path + find_path( + "${PACKAGE_NAME}_INCLUDE_DIR" + NAMES ${PACKAGE_HEADER} + DOC "The ${PACKAGE_NAME} include directory" + PATHS "${OUTPUT_DIR}" + PATH_SUFFIXES ${PACKAGE_PATH_SUFFIX} + ) + + # File doesn't exist in standard search paths, download it + if(NOT ${PACKAGE_NAME}_INCLUDE_DIR) + + # Create the output folder if it doesn't already exist + if(NOT EXISTS "${OUTPUT_DIR}") + file(MAKE_DIRECTORY "${OUTPUT_DIR}") + endif() + + # Download file. + file(DOWNLOAD "${PACKAGE_URL}" "${OUTPUT_DIR}/${PACKAGE_HEADER}" STATUS ${PACKAGE_NAME}_STATUS) + + list(GET ${PACKAGE_NAME}_STATUS 0 ${PACKAGE_NAME}_STATUS_CODE) + list(GET ${PACKAGE_NAME}_STATUS 1 ${PACKAGE_NAME}_ERROR_STRING) + + # Parse download status + if(${PACKAGE_NAME}_STATUS_CODE EQUAL 0) + message(STATUS "Successfully downloaded ${PACKAGE_NAME} library.") + + set(${PACKAGE_NAME}_INCLUDE_DIR "${OUTPUT_DIR}") + + else() + message(ERROR "Failed to download ${PACKAGE_NAME} library. Error: ${${PACKAGE_NAME}_ERROR_STRING}") + file(REMOVE "${OUTPUT_DIR}/${PACKAGE_HEADER}") + endif() + endif() + + # Setup and export our variables + set(required_vars ${required_vars} "${PACKAGE_NAME}_INCLUDE_DIR") + set(${PACKAGE_NAME}_INCLUDE_DIRS + ${${PACKAGE_NAME}_INCLUDE_DIR} + PARENT_SCOPE + ) + mark_as_advanced(${PACKAGE_NAME}_INCLUDE_DIR ${PACKAGE_NAME}_INCLUDE_DIRS) + + # Find the package + include(FindPackageHandleStandardArgs) + find_package_handle_standard_args( + ${PACKAGE_NAME} + FOUND_VAR ${PACKAGE_NAME}_FOUND + REQUIRED_VARS ${required_vars} + VERSION_VAR ${PACKAGE_NAME}_VERSION + ) + + # Export our found variable to parent scope + set(${PACKAGE_NAME}_FOUND + ${PACKAGE_NAME}_FOUND + PARENT_SCOPE + ) + +endfunction(HeaderLibrary) diff --git a/cmake/Modules/ToolchainLibraryFinder.cmake b/cmake/Modules/ToolchainLibraryFinder.cmake index 3898f395..17e7314d 100644 --- a/cmake/Modules/ToolchainLibraryFinder.cmake +++ b/cmake/Modules/ToolchainLibraryFinder.cmake @@ -1,113 +1,144 @@ -# Copyright (C) 2013 Trent Houliston , Jake Woods -# 2014-2017 Trent Houliston -# -# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated -# documentation files (the "Software"), to deal in the Software without restriction, including without limitation the -# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to -# permit persons to whom the Software is furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all copies or substantial portions of the -# Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE -# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -INCLUDE(CMakeParseArguments) -FUNCTION(ToolchainLibraryFinder) - - # Extract the arguments from our function call - SET(options, "") - SET(oneValueArgs "NAME") - SET(multiValueArgs "HEADER" "LIBRARY" "PATH_SUFFIX" "BINARY" "VERSION_FILE" "VERSION_BINARY_ARGUMENTS" "VERSION_REGEX") - CMAKE_PARSE_ARGUMENTS(PACKAGE "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) - - # Clear our required_vars variable - UNSET(required_vars) - - # Find our include path from our named headers - IF(PACKAGE_HEADER) - - # Find our include path - FIND_PATH("${PACKAGE_NAME}_INCLUDE_DIR" - NAMES ${PACKAGE_HEADER} - DOC "The ${PACKAGE_NAME} (${PACKAGE_LIBRARY}) include directory" - PATH_SUFFIXES ${PACKAGE_PATH_SUFFIX} - ) - - # Setup and export our variables - SET(required_vars ${required_vars} "${PACKAGE_NAME}_INCLUDE_DIR") - SET(${PACKAGE_NAME}_INCLUDE_DIRS ${${PACKAGE_NAME}_INCLUDE_DIR} PARENT_SCOPE) - MARK_AS_ADVANCED(${PACKAGE_NAME}_INCLUDE_DIR ${PACKAGE_NAME}_INCLUDE_DIRS) - - ENDIF(PACKAGE_HEADER) - - # Find our library from the named library files - IF(PACKAGE_LIBRARY) - FIND_LIBRARY("${PACKAGE_NAME}_LIBRARY" - NAMES ${PACKAGE_LIBRARY} - PATH_SUFFIXES ${PACKAGE_PATH_SUFFIX} - DOC "The ${PACKAGE_NAME} (${PACKAGE_LIBRARY}) library" - ) - - # Setup and export our variables - SET(required_vars ${required_vars} "${PACKAGE_NAME}_LIBRARY") - SET(${PACKAGE_NAME}_LIBRARIES ${${PACKAGE_NAME}_LIBRARY} PARENT_SCOPE) - MARK_AS_ADVANCED(${PACKAGE_NAME}_LIBRARY ${PACKAGE_NAME}_LIBRARIES) - - ENDIF(PACKAGE_LIBRARY) - - # Find our binary from the named binary files - IF(PACKAGE_BINARY) - FIND_PROGRAM("${PACKAGE_NAME}_BINARY" - NAMES ${PACKAGE_BINARY} - PATH_SUFFIXES ${PACKAGE_PATH_SUFFIX} - DOC "The ${PACKAGE_NAME} (${PACKAGE_BINARY}) executable prgram" - ) - - # Setup and export our variables - SET(required_vars ${required_vars} "${PACKAGE_NAME}_BINARY") - SET(${PACKAGE_NAME}_BINARY ${${PACKAGE_NAME}_BINARY} PARENT_SCOPE) - MARK_AS_ADVANCED(${PACKAGE_NAME}_BINARY) - - ENDIF(PACKAGE_BINARY) - - # Find our version if we can - IF((PACKAGE_VERSION_FILE AND PACKAGE_HEADER) OR (PACKAGE_VERSION_BINARY_ARGUMENTS AND PACKAGE_BINARY)) - UNSET(full_version_string) - - # Read our package version file into a variable - IF(PACKAGE_VERSION_FILE AND PACKAGE_HEADER) - FILE(READ "${${PACKAGE_NAME}_INCLUDE_DIR}/${PACKAGE_VERSION_FILE}" full_version_string) - ENDIF(PACKAGE_VERSION_FILE AND PACKAGE_HEADER) - - # Execute our binary to get a version string - IF(PACKAGE_VERSION_BINARY_ARGUMENTS AND PACKAGE_BINARY) - EXEC_PROGRAM(${${PACKAGE_NAME}_BINARY} - ARGS ${PACKAGE_VERSION_BINARY_ARGUMENTS} - OUTPUT_VARIABLE full_version_string) - ENDIF(PACKAGE_VERSION_BINARY_ARGUMENTS AND PACKAGE_BINARY) - - # Build up our version string - SET(${PACKAGE_NAME}_VERSION "") - FOREACH(regex ${PACKAGE_VERSION_REGEX}) - STRING(REGEX REPLACE ".*${regex}.*" "\\1" regex_output ${full_version_string}) - SET(${PACKAGE_NAME}_VERSION ${${PACKAGE_NAME}_VERSION} ${regex_output}) - ENDFOREACH(regex) - STRING(REPLACE ";" "." ${PACKAGE_NAME}_VERSION "${${PACKAGE_NAME}_VERSION}") - - ENDIF((PACKAGE_VERSION_FILE AND PACKAGE_HEADER) OR (PACKAGE_VERSION_BINARY_ARGUMENTS AND PACKAGE_BINARY)) - - INCLUDE(FindPackageHandleStandardArgs) - FIND_PACKAGE_HANDLE_STANDARD_ARGS(${PACKAGE_NAME} - FOUND_VAR ${PACKAGE_NAME}_FOUND - REQUIRED_VARS ${required_vars} - VERSION_VAR ${PACKAGE_NAME}_VERSION - #VERSION_VAR "${MAJOR}.${MINOR}.${PATCH}") +#[[ +MIT License + +Copyright (c) 2013 NUClear Contributors + +This file is part of the NUClear codebase. +See https://github.com/Fastcode/NUClear for further info. + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the +Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +]] + +include(CMakeParseArguments) +function(ToolchainLibraryFinder) + + # Extract the arguments from our function call + set(options, "") + set(oneValueArgs "NAME") + set(multiValueArgs + "HEADER" + "LIBRARY" + "PATH_SUFFIX" + "BINARY" + "VERSION_FILE" + "VERSION_BINARY_ARGUMENTS" + "VERSION_REGEX" + ) + cmake_parse_arguments(PACKAGE "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + # Clear our required_vars variable + unset(required_vars) + + # Find our include path from our named headers + if(PACKAGE_HEADER) + + # Find our include path + find_path( + "${PACKAGE_NAME}_INCLUDE_DIR" + NAMES ${PACKAGE_HEADER} + DOC "The ${PACKAGE_NAME} (${PACKAGE_LIBRARY}) include directory" + PATH_SUFFIXES ${PACKAGE_PATH_SUFFIX} ) - # Export our found variable to parent scope - SET(${PACKAGE_NAME}_FOUND ${PACKAGE_NAME}_FOUND PARENT_SCOPE) + # Setup and export our variables + set(required_vars ${required_vars} "${PACKAGE_NAME}_INCLUDE_DIR") + set(${PACKAGE_NAME}_INCLUDE_DIRS + ${${PACKAGE_NAME}_INCLUDE_DIR} + PARENT_SCOPE + ) + mark_as_advanced(${PACKAGE_NAME}_INCLUDE_DIR ${PACKAGE_NAME}_INCLUDE_DIRS) + + endif(PACKAGE_HEADER) + + # Find our library from the named library files + if(PACKAGE_LIBRARY) + find_library( + "${PACKAGE_NAME}_LIBRARY" + NAMES ${PACKAGE_LIBRARY} + PATH_SUFFIXES ${PACKAGE_PATH_SUFFIX} + DOC "The ${PACKAGE_NAME} (${PACKAGE_LIBRARY}) library" + ) + + # Setup and export our variables + set(required_vars ${required_vars} "${PACKAGE_NAME}_LIBRARY") + set(${PACKAGE_NAME}_LIBRARIES + ${${PACKAGE_NAME}_LIBRARY} + PARENT_SCOPE + ) + mark_as_advanced(${PACKAGE_NAME}_LIBRARY ${PACKAGE_NAME}_LIBRARIES) + + endif(PACKAGE_LIBRARY) -ENDFUNCTION(ToolchainLibraryFinder) + # Find our binary from the named binary files + if(PACKAGE_BINARY) + find_program( + "${PACKAGE_NAME}_BINARY" + NAMES ${PACKAGE_BINARY} + PATH_SUFFIXES ${PACKAGE_PATH_SUFFIX} + DOC "The ${PACKAGE_NAME} (${PACKAGE_BINARY}) executable prgram" + ) + + # Setup and export our variables + set(required_vars ${required_vars} "${PACKAGE_NAME}_BINARY") + set(${PACKAGE_NAME}_BINARY + ${${PACKAGE_NAME}_BINARY} + PARENT_SCOPE + ) + mark_as_advanced(${PACKAGE_NAME}_BINARY) + + endif(PACKAGE_BINARY) + + # Find our version if we can + if((PACKAGE_VERSION_FILE AND PACKAGE_HEADER) OR (PACKAGE_VERSION_BINARY_ARGUMENTS AND PACKAGE_BINARY)) + unset(full_version_string) + + # Read our package version file into a variable + if(PACKAGE_VERSION_FILE AND PACKAGE_HEADER) + file(READ "${${PACKAGE_NAME}_INCLUDE_DIR}/${PACKAGE_VERSION_FILE}" full_version_string) + endif(PACKAGE_VERSION_FILE AND PACKAGE_HEADER) + + # Execute our binary to get a version string + if(PACKAGE_VERSION_BINARY_ARGUMENTS AND PACKAGE_BINARY) + exec_program( + ${${PACKAGE_NAME}_BINARY} ARGS + ${PACKAGE_VERSION_BINARY_ARGUMENTS} + OUTPUT_VARIABLE full_version_string + ) + endif(PACKAGE_VERSION_BINARY_ARGUMENTS AND PACKAGE_BINARY) + + # Build up our version string + set(${PACKAGE_NAME}_VERSION "") + foreach(regex ${PACKAGE_VERSION_REGEX}) + string(REGEX REPLACE ".*${regex}.*" "\\1" regex_output ${full_version_string}) + set(${PACKAGE_NAME}_VERSION ${${PACKAGE_NAME}_VERSION} ${regex_output}) + endforeach(regex) + string(REPLACE ";" "." ${PACKAGE_NAME}_VERSION "${${PACKAGE_NAME}_VERSION}") + + endif((PACKAGE_VERSION_FILE AND PACKAGE_HEADER) OR (PACKAGE_VERSION_BINARY_ARGUMENTS AND PACKAGE_BINARY)) + + include(FindPackageHandleStandardArgs) + find_package_handle_standard_args( + ${PACKAGE_NAME} + FOUND_VAR ${PACKAGE_NAME}_FOUND + REQUIRED_VARS ${required_vars} + VERSION_VAR ${PACKAGE_NAME}_VERSION # VERSION_VAR "${MAJOR}.${MINOR}.${PATCH}") + ) + + # Export our found variable to parent scope + set(${PACKAGE_NAME}_FOUND + ${PACKAGE_NAME}_FOUND + PARENT_SCOPE + ) + +endfunction(ToolchainLibraryFinder) diff --git a/cmake/NUClearConfig.cmake.in b/cmake/NUClearConfig.cmake.in new file mode 100644 index 00000000..0c532c8f --- /dev/null +++ b/cmake/NUClearConfig.cmake.in @@ -0,0 +1,9 @@ +@PACKAGE_INIT@ + +INCLUDE(${CMAKE_CURRENT_LIST_DIR}/nuclear-targets.cmake) + +set_and_check(NUClear_INCLUDE_DIR "@PACKAGE_INSTALL_INCLUDE_DIR@") +set_and_check(NUClear_INCLUDE_DIRS "@PACKAGE_INSTALL_INCLUDE_DIR@") +set(NUClear_LIBRARIES NUClear::nuclear) + +CHECK_REQUIRED_COMPONENTS(NUClear) diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt index fa7ae35e..41ace683 100644 --- a/docs/CMakeLists.txt +++ b/docs/CMakeLists.txt @@ -1,16 +1,42 @@ -OPTION(BUILD_DOCUMENTATION "Create and install the HTML based API documentation (requires Doxygen and Sphinx)" FALSE) +#[[ +MIT License -IF(BUILD_DOCUMENTATION) +Copyright (c) 2017 NUClear Contributors - FIND_PACKAGE(Doxygen REQUIRED) - FIND_PACKAGE(Sphinx REQUIRED) +This file is part of the NUClear codebase. +See https://github.com/Fastcode/NUClear for further info. - ADD_CUSTOM_TARGET(docs - COMMAND ${Sphinx_BINARY} -a ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - COMMENT "Generating documentation pages using sphinx" - ) +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to the following conditions: - INSTALL(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} DESTINATION share/doc OPTIONAL) +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the +Software. -ENDIF(BUILD_DOCUMENTATION) +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +]] +option(BUILD_DOCUMENTATION "Create and install the HTML based API documentation (requires Doxygen and Sphinx)" FALSE) + +if(BUILD_DOCUMENTATION) + + find_package(Doxygen REQUIRED) + find_package(Sphinx REQUIRED) + + add_custom_target( + docs + COMMAND ${Sphinx_BINARY} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + COMMENT "Generating documentation pages using sphinx" + ) + + install( + DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + DESTINATION share/doc + OPTIONAL + ) + +endif(BUILD_DOCUMENTATION) diff --git a/docs/conf.py b/docs/conf.py index d5a52a66..65bfc3d4 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -27,7 +27,7 @@ # -- General configuration ------------------------------------------------ def setup(app): - app.add_stylesheet('colours.css') + app.add_css_file('colours.css') diff --git a/docs/dsl.rst b/docs/dsl.rst index 18b82b92..a5fd140a 100644 --- a/docs/dsl.rst +++ b/docs/dsl.rst @@ -219,6 +219,10 @@ Scope::DELAY ````````````` .. doxygenstruct:: NUClear::dsl::word::emit::Delay +Scope::WATCHDOG +`````````````` +.. doxygenstruct:: NUClear::dsl::word::emit::Watchdog + Network Emitting ---------------- diff --git a/docs/extension.rst b/docs/extension.rst index dd7ff1bf..f5b2f6ce 100644 --- a/docs/extension.rst +++ b/docs/extension.rst @@ -5,46 +5,217 @@ Extension Fusion Engine ************* -TODO what the fusion engine is and how it works +The fusion engine combines a number of templated types into a single "fused" type. This allows it to be treated as a +single type. The fused type, most importantly, exposes the methods described below which it then calls in an iterative +manner for each individual type fused. + +The parse type is used as the interface into the fusion engine, it handles calling the fused type with the correct +template and filling in undefined methods with no-operations. + +Both the fused type and parsed type only has static methods defined, so it would be pointless to instantiate it. + +This means calling `Parse, Sync, Startup>.bind()` will call `Trigger.bind()`, then a no-operation, +then will call `Startup.bind()`, using `DSL = Parse, Sync, Startup>`. + +Fusions can be nested, this can be useful for creating a DSL word that combines the functionality of multiple other +words. Extending the DSL ***************** -TODO What extending the dsl means and what bits there are +The DSL words are types, adding a word is as simple as declaring a new type with at least one of the following static +template methods defined. Each undefined static template method will automatically behave as a no-operation. + +The template of each of these static methods should be `template `, this will have the parsed DSL words +passed in. It is important to note that the type will only be considered by NUClear in a static context. If any +attributes need to be stored in the DSL word type template it and use static variables, see `Sync`. + +There are DSL words that are not meant to be used directly but as a part of other words, see `CacheGet` and `TypeBind`. +`TypeBind` adds the reaction to the list of reactions to be run when a `Local` or `Direct` emit is called for the data +type. `CacheGet` gets the last value from a thread-local cache (see `ThreadSore` below) this cache is usually populated +in the last a `Local` or `Direct` emit call for the data type. + +If the type you want to become a DSL extension word is not defined within your control specialise `DSLProxy<>` with the +type. Provide the template methods to the specialisation of `DSLProxy<>` as if it were the type. Bind ---- -TODO What extension via bind means and how it works +.. codeblock:: c++ + template + static inline void bind(const std::shared_ptr& reaction, /*More arguments can be declared*/) + +This function is called when the reaction is bound, it should be thought of as the constructor. It is used to setup +anything that is required by the DSL word. + +A common use for extensions is to setup something that will generate tasks for this reaction. This can be done by +communicating to an extension reactor via a helper type that the extension reactor triggers on. + +An unbinder, if needed, should be passed to the reaction's unbinders callback list from the bind call. This is used as a +destructor. +e.g. for the `IO` word we have +.. codeblock:: c++ + reaction->unbinders.push_back([](const threading::Reaction& r) { + r.reactor.emit(std::make_unique>(r.id)); + }); + +which will tell the extension reactor that this reaction no longer exists. + +The extra arguments are passed in, in order, from the `on` call. Get --- -TODO what extension via get means and how it works -Is used to get data to run a function with -If the type can be dereferenced, then this is also an acceptable type in the argument list +.. codeblock:: c++ + template + static inline T get(threading::Reaction&) + +This is used to get the data for the callback. The returned value is passed to the callback. + +If the return type can be dereferenced, then either the return type or the type returned by the dereference of the +return type can be used in the callback. + +If data needs to be passed to a task when it is submitted to the `Powerplant` use `ThreadStore`. The thread store is +a static variable that can be accessed from within the get method. Make sure to clear the `ThreadStore` after use to +ensure future invocations won't get stale data. Precondition ------------ -TODO what extension via precondition means and how it works -Used to determine if a reaction should run -if any of the functions return false it doesn't run +.. codeblock:: c++ + template + static inline bool precondition(threading::Reaction& reaction) + +A precondition is used to test if the reaction should run. On a true return the reaction will run as normal. On a false +return the reaction will be dropped. Postcondition ------------- -TODO what extension via postcondition means and how it works -All of these always run after a reaction has finished running +.. codeblock:: c++ + template + static void postcondition(threading::ReactionTask& task) + +This will run after the callback for a reaction task has run and finished. Reschedule ---------- -TODO what extension via reschedule means and how it works -'Steals' reactions so they can be run elsewhere -Can also be used to replace a reaction with a different reaction, or a modified one +.. codeblock:: c++ + template + static inline std::unique_ptr reschedule(std::unique_ptr&& task) + +The ownership of the reaction task is passed to the DSL word. The task returned will be run instead of the passed in +reaction task. If the returned task is the one passed in the task will be run normally. + +If a null pointer is returned, no task is run. + +When it is time to schedule the task either return it in another reschedule call or call +`task.parent.reactor.powerplant.submit(std::move(task));`. Both these will pass the ownership of the task on. + +Transient +--------- + +.. codeblock:: c++ + template <> + struct is_transient : public std::true_type {}; + +When the data returned from a `get` is falsy and its type is marked transient the latest truthy data from the `get` +return is instead used. If the data is falsy and is either not marked transient or nothing truthy has yet been returned +then the reaction is cancelled. + +Custom Emit Handler +******************* + +.. codeblock:: c++ + template + struct EmitType { + static void emit(PowerPlant& powerplant, ...) + }; + +Emit can be extended by creating a template struct that has at least one method called `emit`. This is then called from +a Reactor with `emit` and the arguments will be passed through. + +.. codeblock:: c++ + static void emit(PowerPlant& powerplant, std::shared_ptr data, ...) + +If the second parameter is a shared pointer to the templated type when calling emit a unique pointer will be +automatically converted to a shared pointer. Example Case ************ -TODO take one of the parts (sync maybe?) and explain how it is built using extensions +Sync +---- + +Here, we have an ordinary C++ class. In this case we start by defining the attributes we need in a static context. +The template is used to have multiple static contexts. +.. codeblock:: c++ + template + struct Sync { + + using task_ptr = std::unique_ptr; + + /// @brief our queue which sorts tasks by priority + static std::priority_queue queue; + /// @brief how many tasks are currently running + static volatile bool running; + /// @brief a mutex to ensure data consistency + static std::mutex mutex; + +Now we define the `reschedule` to interrupt any new tasks if we are currently running. Recall that NUClear is +multithreaded so a mutex is needed when accessing the static members. +.. codeblock:: c++ + template + static inline std::unique_ptr reschedule( + std::unique_ptr&& task) { + + // Lock our mutex + std::lock_guard lock(mutex); + + // If we are already running then queue, otherwise return and set running + if (running) { + queue.push(std::move(task)); + return std::unique_ptr(nullptr); + } + else { + running = true; + return std::move(task); + } + } + +To run any queued tasks after the current one is done we define `postcondition`. When there is a task in the queue we +resubmit it to the PowerPlant to be run. +.. codeblock:: c++ + template + static void postcondition(threading::ReactionTask& task) { + + // Lock our mutex + std::lock_guard lock(mutex); + + // We are finished running + running = false; + + // If we have another task, add it + if (!queue.empty()) { + std::unique_ptr next_task( + std::move(const_cast&>(queue.top()))); + queue.pop(); + + // Resubmit this task to the reaction queue + task.parent.reactor.powerplant.submit(std::move(next_task)); + } + } + +We need to instantiate our static members outside the class definition. +.. codeblock:: c++ + }; + template + std::priority_queue::task_ptr> Sync::queue; + + template + volatile bool Sync::running = false; + + template + std::mutex Sync::mutex; + diff --git a/docs/networking.rst b/docs/networking.rst index 97fc5bac..f80a561a 100644 --- a/docs/networking.rst +++ b/docs/networking.rst @@ -7,4 +7,44 @@ TODO Explain the NUClear network mesh Serialisation ************* -TODO explain how serialisation works and how to serialise your own types +Serialisation is used to convert data to a type that can be written to files or sent over a network connection and be +usable by the receiving device. See `Wikipedia `_ for further information. + +NUClear provides helper functions for dealing with serialisation, from the namespace ``NUClear::util::serialise`` there +are ``Searialise::serialise``, ``Searialise::deserialise`` and ``Searialise::hash`` for serialisation, +deserialisation and hashing the type's name respectively. The functions are used internally by NUClear to try to +serialise/deserialise data sent/received via ``Network`` or ``UDP``. These functions are only defined for specific +types. + +Trivial Data Types +------------------ + +NUClear defines serialisation for `Trivial Types `_ with some +caveats. The serialisation of trivial data is dependant on both the +`endianness `_ and the +`alignment `_ of the data on the computer running the code. + +NUClear also defines serialisation of iterators of trivial data types. + +Google Protobuf Types +--------------------- + +NUClear wraps the serialisation and deserialisation of google +`protobuf `_ types. Use protobuf over trivial data types when +communicating between machines or programs. + +Custom Types +------------ + +To add another type to be able to be serialised add another partial specialisation to ``Serialise`` declaring +the type of ``Check``. The easiest ``Check`` is `is_same `_ as this +checks explicitly for an explicit type. Be careful about multiple declarations. + +For this partial specialisation three static methods need to be defined. + +.. codeblock:: c++ + static inline std::vector serialise(const T& in) + + static inline T deserialise(const std::vector& in) + + static inline uint64_t hash() diff --git a/docs/requirements.txt b/docs/requirements.txt index cd6467ed..65b95c52 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1 +1 @@ -breathe +breathe==4.20 diff --git a/docs/startup.rst b/docs/startup.rst index 72eec4bf..01cc0554 100644 --- a/docs/startup.rst +++ b/docs/startup.rst @@ -22,7 +22,7 @@ file for the process. .. code-block:: C++ - NUClear::PowerPlant::Configuration config; + NUClear::Configuration config; config.thread_count = 1; NUClear::PowerPlant plant(config); diff --git a/sonar-project.properties b/sonar-project.properties new file mode 100644 index 00000000..60dc88e4 --- /dev/null +++ b/sonar-project.properties @@ -0,0 +1,9 @@ +sonar.projectName=NUClear +sonar.projectKey=Fastcode_NUClear +sonar.organization=fastcode +sonar.projectVersion=1.0 + +sonar.sources=src +sonar.tests=tests + +sonar.sourceEncoding=UTF-8 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 90e8ce28..911a429b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,119 +1,88 @@ -FILE(GLOB src - "*.cpp" - "include/nuclear" - "include/nuclear_bits/*.hpp" - "include/nuclear_bits/*.ipp") - -FILE(GLOB src_threading - "threading/*.cpp" - "include/nuclear_bits/threading/*.hpp" - "include/nuclear_bits/threading/*.ipp") - -FILE(GLOB src_extension - "extension/*.cpp" - "include/nuclear_bits/extension/*.hpp" - "include/nuclear_bits/extension/*.ipp") - -FILE(GLOB src_extension_network - "extension/network/*.cpp" - "include/nuclear_bits/extension/network/*.hpp" - "include/nuclear_bits/extension/network/*.ipp") - -FILE(GLOB src_dsl - "dsl/*.cpp" - "include/nuclear_bits/dsl/*.hpp" - "include/nuclear_bits/dsl/*.ipp") - -FILE(GLOB src_dsl_store - "dsl/store/*.cpp" - "include/nuclear_bits/dsl/store/*.hpp" - "include/nuclear_bits/dsl/store/*.ipp") - -FILE(GLOB src_dsl_trait - "dsl/trait/*.cpp" - "include/nuclear_bits/dsl/trait/*.hpp" - "include/nuclear_bits/dsl/trait/*.ipp") - -FILE(GLOB src_dsl_operation - "dsl/operation/*.cpp" - "include/nuclear_bits/dsl/operation/*.hpp" - "include/nuclear_bits/dsl/operation/*.ipp") - -FILE(GLOB src_dsl_fusion - "dsl/fusion/*.cpp" - "include/nuclear_bits/dsl/fusion/*.hpp" - "include/nuclear_bits/dsl/fusion/*.ipp") - -FILE(GLOB src_dsl_validation - "dsl/validation/*.cpp" - "include/nuclear_bits/dsl/validation/*.hpp" - "include/nuclear_bits/dsl/validation/*.ipp") - -FILE(GLOB src_dsl_word - "dsl/word/*.cpp" - "include/nuclear_bits/dsl/word/*.hpp" - "include/nuclear_bits/dsl/word/*.ipp") - -FILE(GLOB src_dsl_word_emit - "dsl/word/emit/*.cpp" - "include/nuclear_bits/dsl/word/emit/*.hpp" - "include/nuclear_bits/dsl/word/emit/*.ipp") - -FILE(GLOB src_message - "messages/*.cpp" - "include/nuclear_bits/message/*.hpp" - "include/nuclear_bits/message/*.ipp") - -FILE(GLOB src_util - "util/*.cpp" - "include/nuclear_bits/util/*.hpp" - "include/nuclear_bits/util/*.ipp") - -FILE(GLOB src_util_network - "util/network/*.cpp" - "include/nuclear_bits/util/network/*.hpp" - "include/nuclear_bits/util/network/*.ipp") - -FILE(GLOB src_util_serialise - "util/serialise/*.c" - "util/serialise/*.cpp" - "include/nuclear_bits/util/serialise/*.h" - "include/nuclear_bits/util/serialise/*.hpp" - "include/nuclear_bits/util/serialise/*.ipp") - -SOURCE_GROUP("" FILES ${src}) -SOURCE_GROUP(threading FILES ${src_threading}) -SOURCE_GROUP(extension FILES ${src_extension}) -SOURCE_GROUP(extension\\network FILES ${src_extension_network}) -SOURCE_GROUP(dsl FILES ${src_dsl}) -SOURCE_GROUP(dsl\\store FILES ${src_dsl_store}) -SOURCE_GROUP(dsl\\trait FILES ${src_dsl_trait}) -SOURCE_GROUP(dsl\\operation FILES ${src_dsl_operation}) -SOURCE_GROUP(dsl\\fusion FILES ${src_dsl_fusion}) -SOURCE_GROUP(dsl\\validation FILES ${src_dsl_validation}) -SOURCE_GROUP(dsl\\word FILES ${src_dsl_word}) -SOURCE_GROUP(dsl\\word\\emit FILES ${src_dsl_word_emit}) -SOURCE_GROUP(message FILES ${src_message}) -SOURCE_GROUP(util FILES ${src_util}) -SOURCE_GROUP(util\\network FILES ${src_util_network}) -SOURCE_GROUP(util\\serialise FILES ${src_util_serialise}) - -ADD_LIBRARY(nuclear STATIC - ${src} - ${src_threading} - ${src_extension} - ${src_extension_network} - ${src_dsl_store} - ${src_dsl_trait} - ${src_dsl_operation} - ${src_dsl_fusion} - ${src_dsl_validation} - ${src_dsl_word} - ${src_dsl_word_emit} - ${src_dsl} - ${src_message} - ${src_util} - ${src_util_network} - ${src_util_serialise}) - -INSTALL(TARGETS nuclear ARCHIVE DESTINATION lib) +#[[ +MIT License + +Copyright (c) 2013 NUClear Contributors + +This file is part of the NUClear codebase. +See https://github.com/Fastcode/NUClear for further info. + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the +Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +]] + +# Configure the two versions of the main header (in source vs nuclear_bits) +set(nuclear_include_base_directory "") +configure_file(nuclear.in ${PROJECT_BINARY_DIR}/include/nuclear) +set(nuclear_include_base_directory "nuclear_bits/") +configure_file(nuclear.in ${PROJECT_BINARY_DIR}/nuclear) + +# Build the library +find_package(Threads REQUIRED) +file(GLOB_RECURSE src "*.c" "*.cpp" "*.hpp" "*.ipp") +add_library(nuclear STATIC ${src}) +add_library(NUClear::nuclear ALIAS nuclear) + +# Set compile options for NUClear +target_link_libraries(nuclear ${CMAKE_THREAD_LIBS_INIT}) +set_target_properties(nuclear PROPERTIES POSITION_INDEPENDENT_CODE ON) +target_compile_features(nuclear PUBLIC cxx_std_14) + +# Enable warnings, and all warnings are errors +if(MSVC) + target_compile_options(nuclear PRIVATE /W4 /WX) +else() + target_compile_options(nuclear PRIVATE -Wall -Wextra -pedantic -Werror) +endif(MSVC) + +# Make the NUClearConfig files +include(GNUInstallDirs) +include(CMakePackageConfigHelpers) +set(INSTALL_INCLUDE_DIR ${CMAKE_INSTALL_FULL_INCLUDEDIR}) +write_basic_package_version_file(${PROJECT_BINARY_DIR}/NUClearConfigVersion.cmake COMPATIBILITY SameMajorVersion) +configure_package_config_file( + ${PROJECT_SOURCE_DIR}/cmake/NUClearConfig.cmake.in ${PROJECT_BINARY_DIR}/NUClearConfig.cmake + INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/NUClear + PATH_VARS INSTALL_INCLUDE_DIR +) + +# Install version, config and target files. +install(FILES ${PROJECT_BINARY_DIR}/NUClearConfigVersion.cmake ${PROJECT_BINARY_DIR}/NUClearConfig.cmake + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/NUClear +) +install( + EXPORT nuclear-targets + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/NUClear + NAMESPACE NUClear:: +) + +# Install headers and targets +install( + TARGETS nuclear + EXPORT nuclear-targets + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} +) +install( + DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/ + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/nuclear_bits + FILES_MATCHING + PATTERN "*.hpp" + PATTERN "*.ipp" + PATTERN "*.h" +) +install(FILES ${PROJECT_BINARY_DIR}/nuclear DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) + +export( + TARGETS nuclear + NAMESPACE NUClear:: + FILE nuclear-targets.cmake +) diff --git a/src/Configuration.hpp b/src/Configuration.hpp new file mode 100644 index 00000000..c51d678a --- /dev/null +++ b/src/Configuration.hpp @@ -0,0 +1,41 @@ +/* + * MIT License + * + * Copyright (c) 2023 NUClear Contributors + * + * This file is part of the NUClear codebase. + * See https://github.com/Fastcode/NUClear for further info. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef NUCLEAR_CONFIGURATION_HPP +#define NUCLEAR_CONFIGURATION_HPP + +#include +#include + +namespace NUClear { + +/** + * @brief This class holds the configuration for a PowerPlant. + */ +struct Configuration { + /// @brief The number of threads the system will use + size_t thread_count = std::thread::hardware_concurrency() == 0 ? 2 : std::thread::hardware_concurrency(); +}; + +} // namespace NUClear + +#endif // NUCLEAR_CONFIGURATION_HPP diff --git a/src/include/nuclear_bits/Environment.hpp b/src/Environment.hpp similarity index 80% rename from src/include/nuclear_bits/Environment.hpp rename to src/Environment.hpp index e6b50534..5bf2d43d 100644 --- a/src/include/nuclear_bits/Environment.hpp +++ b/src/Environment.hpp @@ -1,6 +1,10 @@ /* - * Copyright (C) 2013 Trent Houliston , Jake Woods - * 2014-2017 Trent Houliston + * MIT License + * + * Copyright (c) 2013 NUClear Contributors + * + * This file is part of the NUClear codebase. + * See https://github.com/Fastcode/NUClear for further info. * * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the @@ -21,7 +25,7 @@ #include -#include "nuclear_bits/LogLevel.hpp" +#include "LogLevel.hpp" namespace NUClear { @@ -40,8 +44,8 @@ class PowerPlant; */ class Environment { public: - Environment(PowerPlant& powerplant, std::string&& reactor_name, LogLevel log_level) - : powerplant(powerplant), log_level(log_level), reactor_name(reactor_name) {} + Environment(PowerPlant& powerplant, std::string reactor_name) + : powerplant(powerplant), reactor_name(std::move(reactor_name)) {} private: friend class PowerPlant; @@ -49,8 +53,6 @@ class Environment { /// @brief The PowerPlant to use in this reactor PowerPlant& powerplant; - /// @brief The log level to resepect for this reactor - LogLevel log_level; /// @brief The name of the reactor std::string reactor_name; }; diff --git a/src/include/nuclear_bits/LogLevel.hpp b/src/LogLevel.hpp similarity index 80% rename from src/include/nuclear_bits/LogLevel.hpp rename to src/LogLevel.hpp index 7e5e81b0..ebf1494c 100644 --- a/src/include/nuclear_bits/LogLevel.hpp +++ b/src/LogLevel.hpp @@ -1,6 +1,10 @@ /* - * Copyright (C) 2013 Trent Houliston , Jake Woods - * 2014-2017 Trent Houliston + * MIT License + * + * Copyright (c) 2013 NUClear Contributors + * + * This file is part of the NUClear codebase. + * See https://github.com/Fastcode/NUClear for further info. * * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the @@ -19,6 +23,12 @@ #ifndef NUCLEAR_LOGLEVEL_HPP #define NUCLEAR_LOGLEVEL_HPP +// Why do we need to include platform.hpp here? +// Because windows defines a bunch of things for legacy reasons, one of which is a #define for ERROR as blank +// Of course this causes a problem when we define our own token below as error as the preprocessor removes it +// The platform.hpp fixes this (and many other windows nonsense) so include it here to solve that issue +#include "util/platform.hpp" + namespace NUClear { /** @@ -29,6 +39,15 @@ namespace NUClear { * The logging level of a reactor can be changed by setting it in the install function. */ enum LogLevel { + /** + * @brief + * Don't use this log level when emitting logs, it is for setting reactor log level from non reactor sources. + * + * Specifically when a NUClear::log is called from code that is not running in a reaction (even transitively) then + * the reactor_level will be set to UNKNOWN. + */ + UNKNOWN, + /** * @brief * The Trace level contains messages that are used to trace the exact flow of execution. diff --git a/src/PowerPlant.cpp b/src/PowerPlant.cpp index 6579f1e5..4e20eb7e 100644 --- a/src/PowerPlant.cpp +++ b/src/PowerPlant.cpp @@ -1,6 +1,10 @@ /* - * Copyright (C) 2013 Trent Houliston , Jake Woods - * 2014-2017 Trent Houliston + * MIT License + * + * Copyright (c) 2013 NUClear Contributors + * + * This file is part of the NUClear codebase. + * See https://github.com/Fastcode/NUClear for further info. * * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the @@ -15,129 +19,76 @@ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#include "nuclear_bits/PowerPlant.hpp" -#include "nuclear_bits/threading/ThreadPoolTask.hpp" -#include "nuclear_bits/extension/ChronoController.hpp" -#include "nuclear_bits/extension/IOController.hpp" -#include "nuclear_bits/extension/NetworkController.hpp" +#include "PowerPlant.hpp" namespace NUClear { -PowerPlant* PowerPlant::powerplant = nullptr; // NOLINT - -PowerPlant::PowerPlant(Configuration config, int argc, const char* argv[]) : configuration(config) { - - // Stop people from making more then one powerplant - if (powerplant != nullptr) { - throw std::runtime_error("There is already a powerplant in existence (There should be a single PowerPlant)"); - } - - // Store our static variable - powerplant = this; - - // Install the Chrono reactor - install(); - install(); - install(); - - // Emit our arguments if any. - message::CommandLineArguments args; - for (int i = 0; i < argc; ++i) { - args.emplace_back(argv[i]); - } - - // We emit this twice, so the data is available for extensions - emit(std::make_unique(args)); - emit(std::make_unique(args)); -} +// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) +PowerPlant* PowerPlant::powerplant = nullptr; PowerPlant::~PowerPlant() { + // Make sure reactors are destroyed before anything else + while (!reactors.empty()) { + reactors.pop_back(); + } // Bye bye powerplant powerplant = nullptr; } -void PowerPlant::on_startup(std::function&& func) { - if (is_running) { - throw std::runtime_error("Unable to do on_startup as the PowerPlant has already started"); - } - else { - startup_tasks.push_back(func); - } -} - -void PowerPlant::add_thread_task(std::function&& task) { - tasks.push_back(std::forward>(task)); -} - void PowerPlant::start() { // We are now running - is_running = true; + is_running.store(true); - // Run all our Initialise scope tasks - for (auto&& func : startup_tasks) { - func(); - } - startup_tasks.clear(); - - // Direct emit startup event + // Direct emit startup event and command line arguments emit(std::make_unique()); + emit_shared(dsl::store::DataStore::get()); - // Start all our threads - for (size_t i = 0; i < configuration.thread_count; ++i) { - tasks.push_back(threading::make_thread_pool_task(*this, scheduler)); - } - - // Start all our tasks - for (auto& task : tasks) { - threads.push_back(std::make_unique(task)); - } + // Start all of the threads + scheduler.start(); +} - // Start our main thread using our main task scheduler - threading::make_thread_pool_task(*this, main_thread_scheduler)(); +void PowerPlant::submit(const NUClear::id_t& id, + const int& priority, + const util::GroupDescriptor& group, + const util::ThreadPoolDescriptor& pool, + const bool& immediate, + std::function&& task) { + scheduler.submit(id, priority, group, pool, immediate, std::move(task)); +} - // Now wait for all the threads to finish executing - for (auto& thread : threads) { +void PowerPlant::submit(std::unique_ptr&& task, const bool& immediate) noexcept { + // Only submit non null tasks + if (task) { try { - if (thread->joinable()) { - thread->join(); - } + const std::shared_ptr t(std::move(task)); + submit(t->id, t->priority, t->group_descriptor, t->thread_pool_descriptor, immediate, [t]() { t->run(); }); } - // This gets thrown some time if between checking if joinable and joining - // the thread is no longer joinable - catch (const std::system_error&) { + catch (const std::exception& ex) { + task->parent.reactor.log("There was an exception while submitting a reaction", ex.what()); + } + catch (...) { + task->parent.reactor.log("There was an unknown exception while submitting a reaction"); } } } -void PowerPlant::submit(std::unique_ptr&& task) { - scheduler.submit(std::forward>(task)); -} - -void PowerPlant::submit_main(std::unique_ptr&& task) { - main_thread_scheduler.submit(std::forward>(task)); -} - void PowerPlant::shutdown() { + // Stop running before we emit the Shutdown event + // Some things such as on depend on this flag and it's possible to miss it + is_running.store(false); + // Emit our shutdown event emit(std::make_unique()); - is_running = false; - // Shutdown the scheduler scheduler.shutdown(); - - // Shutdown the main threads scheduler - main_thread_scheduler.shutdown(); - - // Bye bye powerplant - powerplant = nullptr; } -bool PowerPlant::running() { - return is_running; +bool PowerPlant::running() const { + return is_running.load(); } } // namespace NUClear diff --git a/src/include/nuclear_bits/PowerPlant.hpp b/src/PowerPlant.hpp similarity index 53% rename from src/include/nuclear_bits/PowerPlant.hpp rename to src/PowerPlant.hpp index f14af85c..ca180748 100644 --- a/src/include/nuclear_bits/PowerPlant.hpp +++ b/src/PowerPlant.hpp @@ -1,6 +1,10 @@ /* - * Copyright (C) 2013 Trent Houliston , Jake Woods - * 2014-2017 Trent Houliston + * MIT License + * + * Copyright (c) 2013 NUClear Contributors + * + * This file is part of the NUClear codebase. + * See https://github.com/Fastcode/NUClear for further info. * * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the @@ -19,6 +23,7 @@ #ifndef NUCLEAR_POWERPLANT_HPP #define NUCLEAR_POWERPLANT_HPP +#include #include #include #include @@ -32,13 +37,16 @@ #include // Utilities -#include "nuclear_bits/util/FunctionFusion.hpp" -#include "nuclear_bits/util/demangle.hpp" -#include "nuclear_bits/util/unpack.hpp" - -#include "nuclear_bits/LogLevel.hpp" -#include "nuclear_bits/message/LogMessage.hpp" -#include "nuclear_bits/threading/TaskScheduler.hpp" +#include "Configuration.hpp" +#include "LogLevel.hpp" +#include "id.hpp" +#include "message/LogMessage.hpp" +#include "threading/ReactionTask.hpp" +#include "threading/TaskScheduler.hpp" +#include "util/FunctionFusion.hpp" +#include "util/demangle.hpp" +#include "util/main_thread_id.hpp" +#include "util/unpack.hpp" namespace NUClear { @@ -58,43 +66,32 @@ class PowerPlant { friend class Reactor; public: - /** - * @brief This class holds the configuration for a PowerPlant. - * - * @details - * It configures the number of threads that will be in the PowerPlants thread pool - */ - struct Configuration { - /// @brief default to the amount of hardware concurrency (or 2) threads - Configuration() - : thread_count(std::thread::hardware_concurrency() == 0 ? 2 : std::thread::hardware_concurrency()) {} - - /// @brief The number of threads the system will use - size_t thread_count; - }; - - /// @brief Holds the configuration information for this PowerPlant (such as number of pool threads) - const Configuration configuration; - - // There can only be one powerplant, so this is it - static PowerPlant* powerplant; + static PowerPlant* powerplant; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) /** * @brief * Constructs a PowerPlant with the given configuration and provides access * to argv for all reactors. * - * @details - * If PowerPlant is constructed with argc and argv then a CommandLineArguments - * message will be emitted and available to all reactors. + * @details Arguments passed to this function will be emitted as a CommandLineArguments message. + * + * @param config The PowerPlant's configuration + * @param argc The number of command line arguments + * @param argv The command line argument strings */ + // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,modernize-avoid-c-arrays) PowerPlant(Configuration config = Configuration(), int argc = 0, const char* argv[] = nullptr); - PowerPlant(const PowerPlant&) = delete; ~PowerPlant(); + // There can only be one! + PowerPlant(const PowerPlant& other) = delete; + PowerPlant(const PowerPlant&& other) = delete; + PowerPlant& operator=(const PowerPlant& other) = delete; + PowerPlant& operator=(const PowerPlant&& other) = delete; + /** - * @brief Starts up this PowerPlants components in order and begins it running. + * @brief Starts up the PowerPlant's components in order and begins it running. * * @details * Starts up the PowerPlant instance and starts all the pool threads. This @@ -111,19 +108,9 @@ class PowerPlant { void shutdown(); /** - * TODO document - */ - bool running(); - - /** - * TODO document - */ - void on_startup(std::function&& func); - - /** - * TODO document + * @brief Returns true if the PowerPlant is running or not intending to shut down soon. Returns false otherwise. */ - void add_thread_task(std::function&& task); + bool running() const; /** * @brief Installs a reactor of a particular type to the system. @@ -134,31 +121,48 @@ class PowerPlant { * in the environment of that reactor so that it can be used to filter logs. * * @tparam T The type of the reactor to build and install + * @tparam Args The types of the extra arguments to pass to the reactor constructor * @tparam level The initial logging level for this reactor to use + * + * @param arg Extra arguments to pass to the reactor constructor + * + * @return A reference to the installed reactor */ - template - void install(); + template + T& install(Args&&... args); /** - * @brief Submits a new task to the ThreadPool to be queued and then executed. + * @brief Generic submit function for submitting tasks to the thread pool. * - * @param task The Reaction task to be executed in the thread pool + * @param id an id for ordering the task + * @param priority the priority of the task between 0 and 1000 + * @param group the details of the execution group this task will run in + * @param pool the details of the thread pool this task will run from + * @param immediate if this task should run immediately in the current thread + * @param task the wrapped function to be executed */ - void submit(std::unique_ptr&& task); + void submit(const NUClear::id_t& id, + const int& priority, + const util::GroupDescriptor& group, + const util::ThreadPoolDescriptor& pool, + const bool& immediate, + std::function&& task); /** - * @brief Submits a new task to the main threads thread pool to be queued and then executed. + * @brief Submits a new task to the ThreadPool to be queued and then executed. * * @param task The Reaction task to be executed in the thread pool + * @param immediate if this task should run immediately in the current thread */ - void submit_main(std::unique_ptr&& task); + void submit(std::unique_ptr&& task, const bool& immediate = false) noexcept; /** * @brief Log a message through NUClear's system. * * @details * Logs a message through the system so the various log handlers - * can access it. + * can access it. The arguments being logged should be able to + * be added into a stringstream. * * @tparam level The level to log at (defaults to DEBUG) * @tparam Arguments The types of the arguments we are logging @@ -172,9 +176,11 @@ class PowerPlant { * @brief Emits data to the system and routes it to the other systems that use it. * * @details - * TODO + * Emits at Local scope which creates tasks using the thread pool. * - * @tparam T The type of the data that we are emitting + * @see NUClear::dsl::word::emit::Local for info about Local scope. + * + * @tparam T The type of the data that we are emitting * * @param data The data we are emitting */ @@ -187,51 +193,73 @@ class PowerPlant { * @brief Emits data to the system and routes it to the other systems that use it. * * @details - * TODO + * This is for the special case of emitting a shared_ptr. The types are Fused and the reaction is started. If the + * Fusion fails, a static_assert fails. + * + * @note Emitting shared data can be helpful for forwarding data which has already been emitted and forwarding it on + * to external parties, without needing to copy it. + * + * @see NUClear::util::FunctionFusion * - * @tparam First the first handler to use for this emit - * @tparam Remainder the remaining handlers to use for this emit - * @tparam T the type of the data that we are emitting - * @tparam Arguments the additional arguments that will be provided to the handlers + * @warning This shouldn't be used without a specific reason - usually forwarding data. + * + * @tparam First The first handler to use for this emit + * @tparam Remainder The remaining handlers to use for this emit + * @tparam T The type of the data that we are emitting + * @tparam Arguments The additional arguments that will be provided to the handlers * * @param data The data we are emitting */ template