{
    "componentChunkName": "component---src-components-page-template-jsx",
    "path": "/system/foundations/build-system",
    "result": {"data":{"mdx":{"id":"d51d0a56-68fa-5746-bab9-0ae3b235d976","body":"var _excluded = [\"components\"];\n\nfunction _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\n\nfunction _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }\n\nfunction _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }\n\n/* @jsxRuntime classic */\n\n/* @jsx mdx */\nvar _frontmatter = {\n  \"section\": \"System\",\n  \"chapter\": \"Foundations\",\n  \"title\": \"Build System\",\n  \"description\": \"The NUbots build system.\",\n  \"slug\": \"/system/foundations/build-system\",\n  \"authors\": [\"Alex Biddulph (@Bidski)\", \"Yosiah de Koeyer (@Y0sh1dk)\", \"Kip Hamiltons (@KipHamiltons)\", \"Trent Houliston (@TrentHouliston)\"]\n};\n\nvar makeShortcode = function makeShortcode(name) {\n  return function MDXDefaultShortcode(props) {\n    console.warn(\"Component \" + name + \" was not imported, exported, or provided by MDXProvider as global scope\");\n    return mdx(\"div\", props);\n  };\n};\n\nvar Alert = makeShortcode(\"Alert\");\nvar layoutProps = {\n  _frontmatter: _frontmatter\n};\nvar MDXLayout = \"wrapper\";\nreturn function MDXContent(_ref) {\n  var components = _ref.components,\n      props = _objectWithoutProperties(_ref, _excluded);\n\n  return mdx(MDXLayout, _extends({}, layoutProps, props, {\n    components: components,\n    mdxType: \"MDXLayout\"\n  }), mdx(\"h2\", {\n    \"id\": \"the-nubots-build-system\",\n    \"style\": {\n      \"position\": \"relative\"\n    }\n  }, mdx(\"a\", {\n    parentName: \"h2\",\n    \"href\": \"#the-nubots-build-system\",\n    \"aria-label\": \"the nubots build system permalink\",\n    \"className\": \"anchor before\"\n  }, mdx(\"svg\", {\n    parentName: \"a\",\n    \"aria-hidden\": \"true\",\n    \"focusable\": \"false\",\n    \"height\": \"16\",\n    \"version\": \"1.1\",\n    \"viewBox\": \"0 0 16 16\",\n    \"width\": \"16\"\n  }, mdx(\"path\", {\n    parentName: \"svg\",\n    \"fillRule\": \"evenodd\",\n    \"d\": \"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"\n  }))), \"The NUbots Build System\"), mdx(\"h3\", {\n    \"id\": \"overview\",\n    \"style\": {\n      \"position\": \"relative\"\n    }\n  }, mdx(\"a\", {\n    parentName: \"h3\",\n    \"href\": \"#overview\",\n    \"aria-label\": \"overview permalink\",\n    \"className\": \"anchor before\"\n  }, mdx(\"svg\", {\n    parentName: \"a\",\n    \"aria-hidden\": \"true\",\n    \"focusable\": \"false\",\n    \"height\": \"16\",\n    \"version\": \"1.1\",\n    \"viewBox\": \"0 0 16 16\",\n    \"width\": \"16\"\n  }, mdx(\"path\", {\n    parentName: \"svg\",\n    \"fillRule\": \"evenodd\",\n    \"d\": \"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"\n  }))), \"Overview\"), mdx(\"p\", null, \"The NUbots codebase uses a \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://cmake.org/\"\n  }, \"CMake\"), \" build system based on the \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://github.com/Fastcode/NUClearRoles\"\n  }, \"NUClear Roles framework\"), \" and the \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://ninja-build.org/\"\n  }, \"Ninja\"), \" build system.\"), mdx(\"p\", null, mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://www.docker.com/\"\n  }, \"Docker\"), \" is used to containerise our build processes so that we may mimic the build environment of the robot and impose version control over our required 3rd party dependencies while also managing operating system level configuration to ensure that all users of our codebase can achieve repeatable results.\"), mdx(\"h4\", {\n    \"id\": \"requirements-and-setup\",\n    \"style\": {\n      \"position\": \"relative\"\n    }\n  }, mdx(\"a\", {\n    parentName: \"h4\",\n    \"href\": \"#requirements-and-setup\",\n    \"aria-label\": \"requirements and setup permalink\",\n    \"className\": \"anchor before\"\n  }, mdx(\"svg\", {\n    parentName: \"a\",\n    \"aria-hidden\": \"true\",\n    \"focusable\": \"false\",\n    \"height\": \"16\",\n    \"version\": \"1.1\",\n    \"viewBox\": \"0 0 16 16\",\n    \"width\": \"16\"\n  }, mdx(\"path\", {\n    parentName: \"svg\",\n    \"fillRule\": \"evenodd\",\n    \"d\": \"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"\n  }))), \"Requirements and Setup\"), mdx(\"p\", null, \"See the \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"/guides/main/getting-started\"\n  }, \"Getting Started guide\"), \" for setup instructions and how to build the code on Linux, macOS, and Windows.\"), mdx(\"h3\", {\n    \"id\": \"nuclear-roles\",\n    \"style\": {\n      \"position\": \"relative\"\n    }\n  }, mdx(\"a\", {\n    parentName: \"h3\",\n    \"href\": \"#nuclear-roles\",\n    \"aria-label\": \"nuclear roles permalink\",\n    \"className\": \"anchor before\"\n  }, mdx(\"svg\", {\n    parentName: \"a\",\n    \"aria-hidden\": \"true\",\n    \"focusable\": \"false\",\n    \"height\": \"16\",\n    \"version\": \"1.1\",\n    \"viewBox\": \"0 0 16 16\",\n    \"width\": \"16\"\n  }, mdx(\"path\", {\n    parentName: \"svg\",\n    \"fillRule\": \"evenodd\",\n    \"d\": \"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"\n  }))), \"NUClear Roles\"), mdx(\"p\", null, \"The most complete documentation for NUClear Roles can be found in its github \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://github.com/Fastcode/NUClearRoles/blob/master/README.md\"\n  }, \"README\"), \".\"), mdx(\"p\", null, \"Six main directories are used in a NUClear Roles system:\"), mdx(\"table\", null, mdx(\"thead\", {\n    parentName: \"table\"\n  }, mdx(\"tr\", {\n    parentName: \"thead\"\n  }, mdx(\"th\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Directory\"), mdx(\"th\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Usage\"))), mdx(\"tbody\", {\n    parentName: \"table\"\n  }, mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"module\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"NUClear reactors\")), mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"roles\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Declaration of roles\")), mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"shared/extension\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"NUClear DSL extensions\")), mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"shared/message\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Protobuf messages\")), mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"shared/utility\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Utility code\")), mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"tools\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Extensions for \", mdx(\"inlineCode\", {\n    parentName: \"td\"\n  }, \"b\"))))), mdx(\"h4\", {\n    \"id\": \"modules\",\n    \"style\": {\n      \"position\": \"relative\"\n    }\n  }, mdx(\"a\", {\n    parentName: \"h4\",\n    \"href\": \"#modules\",\n    \"aria-label\": \"modules permalink\",\n    \"className\": \"anchor before\"\n  }, mdx(\"svg\", {\n    parentName: \"a\",\n    \"aria-hidden\": \"true\",\n    \"focusable\": \"false\",\n    \"height\": \"16\",\n    \"version\": \"1.1\",\n    \"viewBox\": \"0 0 16 16\",\n    \"width\": \"16\"\n  }, mdx(\"path\", {\n    parentName: \"svg\",\n    \"fillRule\": \"evenodd\",\n    \"d\": \"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"\n  }))), \"Modules\"), mdx(\"p\", null, \"The modules folder contains \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://nuclear.readthedocs.io/en/latest/components.html#reactors\"\n  }, \"NUClear reactors\"), \". Reactors are grouped into meta-modules. For instance, the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"vision\"), \" meta-module groups together reactors that perform vision processing tasks (e.g. ball and goal detection), while the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"input\"), \" meta-module groups together reactors that gather system inputs (e.g. camera and network inputs).\"), mdx(\"h4\", {\n    \"id\": \"roles\",\n    \"style\": {\n      \"position\": \"relative\"\n    }\n  }, mdx(\"a\", {\n    parentName: \"h4\",\n    \"href\": \"#roles\",\n    \"aria-label\": \"roles permalink\",\n    \"className\": \"anchor before\"\n  }, mdx(\"svg\", {\n    parentName: \"a\",\n    \"aria-hidden\": \"true\",\n    \"focusable\": \"false\",\n    \"height\": \"16\",\n    \"version\": \"1.1\",\n    \"viewBox\": \"0 0 16 16\",\n    \"width\": \"16\"\n  }, mdx(\"path\", {\n    parentName: \"svg\",\n    \"fillRule\": \"evenodd\",\n    \"d\": \"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"\n  }))), \"Roles\"), mdx(\"p\", null, \"Role files define which modules should be grouped together in order to form a single role (a binary that performs a specific role).\"), mdx(\"p\", null, \"Role files live in the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"roles\"), \" folder and have a \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \".role\"), \" extension.\"), mdx(\"p\", null, \"Every role file must call the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"nuclear_role()\"), \" function. Each argument to the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"nuclear_role()\"), \" function is a C++ namespaced path to a module that should be included in the role. For example, if the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"KinematicsConfiguration\"), \" module in \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"module/actuation/KinematicsConfiguration\"), \" should be included in the role then \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"actuation::KinematicsConfiguration\"), \" should appear as an argument to \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"nuclear_role()\"), \".\"), mdx(Alert, {\n    type: \"info\",\n    mdxType: \"Alert\"\n  }, mdx(\"p\", null, mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"module\"), \" is removed from the start of all module arguments as all modules must reside in the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"module\"), \" folder.\")), mdx(\"p\", null, \"Ideally, all modules should be independent of each other and, as such, it should not matter which order modules are specified to \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"nuclear_role()\"), \". In reality, there are a couple of modules which, if they are included in a role, should be passed to \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"nuclear_role()\"), \" first. These modules are:\"), mdx(\"ul\", null, mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"extension::FileWatcher\"), \": Needed before all other modules so that the configuration and script systems can work properly\"), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"support::SignalCatcher\"), \": Catches exceptions to print out useful stack traces. Needs to come before all other modules to allow debugging during module installation\"), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"support::logging::ConsoleLogHandler\"), \" or \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"support::logging::FileLogHandler\"), \": Install before other modules so that log messages will get printed during module installation\"), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"actuation::KinematicsConfiguration\"), \": Needs to come before other modules that require information about the robots kinematic configuration in order to set up properly\")), mdx(\"p\", null, \"Below is an example of a role file. Any line preceded by a \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"#\"), \" is a comment and will be ignored.\"), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-bash\"\n  }, \"nuclear_role(\\n  # FileWatcher, ConsoleLogHandler and Signal Catcher Must Go First. KinematicsConfiguration usually goes after these\\n  # and without it many roles do not run\\n  extension::FileWatcher\\n  support::SignalCatcher\\n  support::logging::ConsoleLogHandler\\n  # This must come first as it emits config which many roles depend on (e.g. SensorFilter, WalkEngine)\\n  actuation::KinematicsConfiguration\\n  support::configuration::GlobalConfig\\n  # Networking\\n  network::NetworkForwarder\\n  network::NUClearNet\\n  # Sensors\\n  platform::${SUBCONTROLLER}::HardwareIO\\n  input::SensorFilter\\n)\\n\")), mdx(\"h4\", {\n    \"id\": \"extensions\",\n    \"style\": {\n      \"position\": \"relative\"\n    }\n  }, mdx(\"a\", {\n    parentName: \"h4\",\n    \"href\": \"#extensions\",\n    \"aria-label\": \"extensions permalink\",\n    \"className\": \"anchor before\"\n  }, mdx(\"svg\", {\n    parentName: \"a\",\n    \"aria-hidden\": \"true\",\n    \"focusable\": \"false\",\n    \"height\": \"16\",\n    \"version\": \"1.1\",\n    \"viewBox\": \"0 0 16 16\",\n    \"width\": \"16\"\n  }, mdx(\"path\", {\n    parentName: \"svg\",\n    \"fillRule\": \"evenodd\",\n    \"d\": \"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"\n  }))), \"Extensions\"), mdx(\"p\", null, mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://nuclear.readthedocs.io/en/latest/extension.html\"\n  }, \"Extensions\"), \" add new keywords to NUClear's dictionary, allowing you to be more expressive in writing \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://nuclear.readthedocs.io/en/latest/components.html#reactions\"\n  }, \"reactions\"), \".\"), mdx(\"p\", null, \"Two common extensions are \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"Configuration\"), \" and \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"Director\"), \". \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"Configuration\"), \" allows modules to monitor their configuration file(s) and apply updates in real-time. \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"Director\"), \" contains our behaviour algorithm and framework.\"), mdx(\"h4\", {\n    \"id\": \"messages\",\n    \"style\": {\n      \"position\": \"relative\"\n    }\n  }, mdx(\"a\", {\n    parentName: \"h4\",\n    \"href\": \"#messages\",\n    \"aria-label\": \"messages permalink\",\n    \"className\": \"anchor before\"\n  }, mdx(\"svg\", {\n    parentName: \"a\",\n    \"aria-hidden\": \"true\",\n    \"focusable\": \"false\",\n    \"height\": \"16\",\n    \"version\": \"1.1\",\n    \"viewBox\": \"0 0 16 16\",\n    \"width\": \"16\"\n  }, mdx(\"path\", {\n    parentName: \"svg\",\n    \"fillRule\": \"evenodd\",\n    \"d\": \"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"\n  }))), \"Messages\"), mdx(\"p\", null, \"Every message in the NUbots codebase is a \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://developers.google.com/protocol-buffers\"\n  }, \"protobuf\"), \" message and all protobuf messages live in the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"shared/message\"), \" folder.\"), mdx(\"p\", null, \"The general convention is to groups message files into folders based on the meta-module which introduces the message to the system. For instance, \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"module/input/Camera\"), \" introduces \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"Image\"), \" messages to the system, so \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"Image.proto\"), \" lives in \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"shared/message/input\"), \".\"), mdx(\"p\", null, \"NUClear Roles provides special wrappers for certain types. Vector and matrix types are mapped to \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"http://eigen.tuxfamily.org/index.php?title=Main_Page\"\n  }, \"Eigen\"), \" types. To use these mappings simply use \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"import Vector.proto;\"), \" and \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"import Matrix.proto;\"), \". Some examples of types that you can use are:\"), mdx(\"ul\", null, mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"fvec3\"), \": A vector with 3 components, maps to an \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"Eigen::Vector3f\")), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"vec3\"), \": A vector with 3 components, maps to an \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"Eigen::Vector3d\")), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"mat3\"), \": A 3x3 matrix, maps to an \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"Eigen::Matrix3d\"))), mdx(\"p\", null, \"All messages are packaged in a similar fashion to the C++ namespaces used for modules. For instance, \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"Image.proto\"), \" is in the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"message.input\"), \" package.\"), mdx(\"p\", null, \"NUClear Roles creates a C++ wrapper class for each message to create a simpler interface for accessing and mutating message fields. The C++ namespace for a message follows its package. For instance, the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"message.input.Image\"), \" message will have a C++ namespace of \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"message::input::Image\"), \".\"), mdx(\"h4\", {\n    \"id\": \"utilities\",\n    \"style\": {\n      \"position\": \"relative\"\n    }\n  }, mdx(\"a\", {\n    parentName: \"h4\",\n    \"href\": \"#utilities\",\n    \"aria-label\": \"utilities permalink\",\n    \"className\": \"anchor before\"\n  }, mdx(\"svg\", {\n    parentName: \"a\",\n    \"aria-hidden\": \"true\",\n    \"focusable\": \"false\",\n    \"height\": \"16\",\n    \"version\": \"1.1\",\n    \"viewBox\": \"0 0 16 16\",\n    \"width\": \"16\"\n  }, mdx(\"path\", {\n    parentName: \"svg\",\n    \"fillRule\": \"evenodd\",\n    \"d\": \"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"\n  }))), \"Utilities\"), mdx(\"p\", null, \"Utilities are collections of functions that perform useful tasks. Typically, these functions are stateless and are (or feasibly could be) used by multiple different modules (or even other utilities).\"), mdx(\"p\", null, \"As is the case with modules and messages, utilities are grouped together into meta-utilities. For instance, utilities dealing with angles, coordinate system transforms, and geometrical constructs live in the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"shared/utility/math\"), \" meta-utility.\"), mdx(\"h4\", {\n    \"id\": \"tools-and-the-b-command\",\n    \"style\": {\n      \"position\": \"relative\"\n    }\n  }, mdx(\"a\", {\n    parentName: \"h4\",\n    \"href\": \"#tools-and-the-b-command\",\n    \"aria-label\": \"tools and the b command permalink\",\n    \"className\": \"anchor before\"\n  }, mdx(\"svg\", {\n    parentName: \"a\",\n    \"aria-hidden\": \"true\",\n    \"focusable\": \"false\",\n    \"height\": \"16\",\n    \"version\": \"1.1\",\n    \"viewBox\": \"0 0 16 16\",\n    \"width\": \"16\"\n  }, mdx(\"path\", {\n    parentName: \"svg\",\n    \"fillRule\": \"evenodd\",\n    \"d\": \"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"\n  }))), \"Tools and the \", mdx(\"inlineCode\", {\n    parentName: \"h4\"\n  }, \"b\"), \" command\"), mdx(\"p\", null, \"NUClear Roles introduces the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"b\"), \" command that wraps up all of the functionality needed to create modules and build the NUbots code.\"), mdx(\"table\", null, mdx(\"thead\", {\n    parentName: \"table\"\n  }, mdx(\"tr\", {\n    parentName: \"thead\"\n  }, mdx(\"th\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Command\"), mdx(\"th\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Description\"))), mdx(\"tbody\", {\n    parentName: \"table\"\n  }, mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"build\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Build the currently configured code\")), mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"configure\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Configure the CMake system for the current target\")), mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"edit\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Edit configuration files\")), mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"footdown\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Trains a neural network to detect foot down based on leg loads\")), mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"format\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Applies code formatting rules to the codebase\")), mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"install\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Install built code to the specified robot\")), mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"module\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Generate new modules\")), mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"nbs\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"For working with NBS recordings\")), mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"run\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Run a role locally\")), mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"shell\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Exposes a shell in the Docker image\")), mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"target\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Select a target to work on\")), mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"tests\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Run built unit tests\")))), mdx(\"h5\", {\n    \"id\": \"build\",\n    \"style\": {\n      \"position\": \"relative\"\n    }\n  }, mdx(\"a\", {\n    parentName: \"h5\",\n    \"href\": \"#build\",\n    \"aria-label\": \"build permalink\",\n    \"className\": \"anchor before\"\n  }, mdx(\"svg\", {\n    parentName: \"a\",\n    \"aria-hidden\": \"true\",\n    \"focusable\": \"false\",\n    \"height\": \"16\",\n    \"version\": \"1.1\",\n    \"viewBox\": \"0 0 16 16\",\n    \"width\": \"16\"\n  }, mdx(\"path\", {\n    parentName: \"svg\",\n    \"fillRule\": \"evenodd\",\n    \"d\": \"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"\n  }))), \"Build\"), mdx(\"p\", null, \"As one might expect, \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"./b build\"), \" will build all enabled roles and required dependencies using \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"ninja\"), \". If you only wish to build a single role (e.g. \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"test/sensor\"), \") then use the command\"), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-bash\"\n  }, \"./b build test/sensor\\n\")), mdx(\"p\", null, \"If unit tests are enabled in the CMake configuration (\", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"-DBUILD_TESTS=ON\"), \") then \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"./b build test\"), \" can be run to execute all of the unit tests. Test logs can be accessed by running \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"./b shell\"), \" and navigating to \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"/home/nubots/build/Testing/Temporary\"), \".\"), mdx(\"h5\", {\n    \"id\": \"configure\",\n    \"style\": {\n      \"position\": \"relative\"\n    }\n  }, mdx(\"a\", {\n    parentName: \"h5\",\n    \"href\": \"#configure\",\n    \"aria-label\": \"configure permalink\",\n    \"className\": \"anchor before\"\n  }, mdx(\"svg\", {\n    parentName: \"a\",\n    \"aria-hidden\": \"true\",\n    \"focusable\": \"false\",\n    \"height\": \"16\",\n    \"version\": \"1.1\",\n    \"viewBox\": \"0 0 16 16\",\n    \"width\": \"16\"\n  }, mdx(\"path\", {\n    parentName: \"svg\",\n    \"fillRule\": \"evenodd\",\n    \"d\": \"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"\n  }))), \"Configure\"), mdx(\"p\", null, mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"./b configure\"), \" will ensure that a build folder is created in the current Docker image and will then run \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"cmake\"), \" on the source code ensuring that CMake creates all of the necessary build files inside of the build folder.\"), mdx(\"p\", null, \"It is possible to specify extra arguments to \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"cmake\"), \" to control the configuration process. For example, to enable the building of unit tests one would run\"), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-bash\"\n  }, \"./b configure -- -DBUILD_TESTS=ON\\n\")), mdx(\"p\", null, \"Another good argument to specify is \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"CMAKE_BUILD_TYPE\"), \". By default, \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"CMAKE_BUILD_TYPE\"), \" is set to \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"Release\"), \", which has better performance than \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"Debug\"), \" but does not include debug symbols. If you would like to debug your code with debugging tools, such as GDB or ASan, then you should set \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"CMAKE_BUILD_TYPE\"), \" to \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"Debug\"), \".\"), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-bash\"\n  }, \"./b configure -- -DCMAKE_BUILD_TYPE=Debug\\n./b build\\n\")), mdx(Alert, {\n    type: \"info\",\n    mdxType: \"Alert\"\n  }, mdx(\"p\", null, mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"--\"), \" is needed to prevent python from trying to process the argument itself. This is only needed if you are specifying arguments that start with a \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"-\"), \".\")), mdx(\"p\", null, \"Passing \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"-i\"), \" to \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"./b configure\"), \" will open up an interactive window with \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"ccmake\"), \" so that you may modify the CMake configuration.\"), mdx(\"p\", null, \"You can also set and unset roles by passing \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"--set_roles\"), \" or \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"--unset_roles\"), \" followed the roles you want to toggle (this supports globbing patterns). For example, you can disable all roles ending in \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"walk\"), \", then enable keyboardwalk and all roles starting with \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"script\"), \" using the following command.\"), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-bash\"\n  }, \"  ./b configure --unset_all_roles \\\"*walk\\\" --set_roles keyboardwalk \\\"script*\\\"\\n\")), mdx(\"p\", null, \"Roles selected with \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"--unset\"), \" flags will always be disabled before roles selected with \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"--set\"), \" flags are enabled.\"), mdx(\"p\", null, \"You can also toggle groups of roles with \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"--set_<group>_roles\"), \" and \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"--unset_<group>_roles\"), \". Currently there is a role group for each subdirectory in \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"roles\"), \" and a group containing all roles. For example, you can clean all docker build volumes and enable only roles in the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"roles/webots\"), \" directory using the following command.\"), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-bash\"\n  }, \"  ./b configure --clean --unset_all_roles --set_webots_roles\\n\")), mdx(\"h5\", {\n    \"id\": \"edit\",\n    \"style\": {\n      \"position\": \"relative\"\n    }\n  }, mdx(\"a\", {\n    parentName: \"h5\",\n    \"href\": \"#edit\",\n    \"aria-label\": \"edit permalink\",\n    \"className\": \"anchor before\"\n  }, mdx(\"svg\", {\n    parentName: \"a\",\n    \"aria-hidden\": \"true\",\n    \"focusable\": \"false\",\n    \"height\": \"16\",\n    \"version\": \"1.1\",\n    \"viewBox\": \"0 0 16 16\",\n    \"width\": \"16\"\n  }, mdx(\"path\", {\n    parentName: \"svg\",\n    \"fillRule\": \"evenodd\",\n    \"d\": \"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"\n  }))), \"Edit\"), mdx(\"p\", null, \"If you are running roles on your local machine and you need to edit the configuration or data files for the modules in the role then the preferred method is to edit the file in the source tree and then rebuild the code using \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"./b build\"), \" to copy the edited file into the build folder.\"), mdx(\"p\", null, \"However, it is possible to edit the configuration file in the build tree directly. This may be useful if you want to change the configuration file during runtime. To do this, run \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"./b edit <path/to/config_file>\"), \" to open an interactive window with a text editor.\"), mdx(\"p\", null, \"For example, to edit the DataLogging configuration file run\"), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-bash\"\n  }, \"./b edit config/DataLogging.yaml\\n\")), mdx(\"p\", null, \"The \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"edit\"), \" command uses the editor that is defined in your host shell (using the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"EDITOR\"), \" environment variable). If \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"EDITOR\"), \" is not set then it will default to \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"nano\"), \". Currently, the only supported editors are \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"vim\"), \" and \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"nano\"), \", with \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"nano\"), \" used as the fallback in all cases.\"), mdx(\"h5\", {\n    \"id\": \"foot-down\",\n    \"style\": {\n      \"position\": \"relative\"\n    }\n  }, mdx(\"a\", {\n    parentName: \"h5\",\n    \"href\": \"#foot-down\",\n    \"aria-label\": \"foot down permalink\",\n    \"className\": \"anchor before\"\n  }, mdx(\"svg\", {\n    parentName: \"a\",\n    \"aria-hidden\": \"true\",\n    \"focusable\": \"false\",\n    \"height\": \"16\",\n    \"version\": \"1.1\",\n    \"viewBox\": \"0 0 16 16\",\n    \"width\": \"16\"\n  }, mdx(\"path\", {\n    parentName: \"svg\",\n    \"fillRule\": \"evenodd\",\n    \"d\": \"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"\n  }))), \"Foot down\"), mdx(\"p\", null, \"This tool uses NBS files recorded from the robot(s) to gather training and testing data to train a neural network to determine if either of the robot's feet are on the ground using leg servo and sensor data.\"), mdx(\"h5\", {\n    \"id\": \"format\",\n    \"style\": {\n      \"position\": \"relative\"\n    }\n  }, mdx(\"a\", {\n    parentName: \"h5\",\n    \"href\": \"#format\",\n    \"aria-label\": \"format permalink\",\n    \"className\": \"anchor before\"\n  }, mdx(\"svg\", {\n    parentName: \"a\",\n    \"aria-hidden\": \"true\",\n    \"focusable\": \"false\",\n    \"height\": \"16\",\n    \"version\": \"1.1\",\n    \"viewBox\": \"0 0 16 16\",\n    \"width\": \"16\"\n  }, mdx(\"path\", {\n    parentName: \"svg\",\n    \"fillRule\": \"evenodd\",\n    \"d\": \"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"\n  }))), \"Format\"), mdx(\"p\", null, \"NUbots uses several different code formatters.\"), mdx(\"ul\", null, mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"clang-format\"), \" is used to format C++ and protobuf files,\"), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"black\"), \" and \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"isort\"), \" are used to format python files, and\"), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"cmake-format\"), \" is used to format CMake files.\"), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"eslint\"), \" and \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"prettier\"), \" are used to format NUsight's TypeScript files\")), mdx(\"p\", null, \"If you want to ensure that all files in the codebase are formatted according to our defined style run\"), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-bash\"\n  }, \"./b format\\n\")), mdx(\"p\", null, \"If you are using \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://code.visualstudio.com/\"\n  }, \"Visual Studio Code\"), \" with the workspace recommended extensions installed then formatting can be set up to happen when you save or when you type.\"), mdx(\"h5\", {\n    \"id\": \"install\",\n    \"style\": {\n      \"position\": \"relative\"\n    }\n  }, mdx(\"a\", {\n    parentName: \"h5\",\n    \"href\": \"#install\",\n    \"aria-label\": \"install permalink\",\n    \"className\": \"anchor before\"\n  }, mdx(\"svg\", {\n    parentName: \"a\",\n    \"aria-hidden\": \"true\",\n    \"focusable\": \"false\",\n    \"height\": \"16\",\n    \"version\": \"1.1\",\n    \"viewBox\": \"0 0 16 16\",\n    \"width\": \"16\"\n  }, mdx(\"path\", {\n    parentName: \"svg\",\n    \"fillRule\": \"evenodd\",\n    \"d\": \"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"\n  }))), \"Install\"), mdx(\"p\", null, \"Once code is built and you are ready to install it on a robot, you can run\"), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-bash\"\n  }, \"./b install [options] <robot>\\n\")), mdx(\"p\", null, mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"<robot>\"), \" can either be a known robot designation (\", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"n1\"), \" or \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"nugus1\"), \", for instance) or an IP address of a robot.\"), mdx(\"p\", null, mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"[options]\"), \" may be one, or more, of the following\"), mdx(\"table\", null, mdx(\"thead\", {\n    parentName: \"table\"\n  }, mdx(\"tr\", {\n    parentName: \"thead\"\n  }, mdx(\"th\", {\n    parentName: \"tr\",\n    \"align\": \"center\"\n  }, \"Option\"), mdx(\"th\", {\n    parentName: \"tr\",\n    \"align\": \"left\"\n  }, \"Description\"))), mdx(\"tbody\", {\n    parentName: \"table\"\n  }, mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": \"center\"\n  }, \"-u\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": \"left\"\n  }, \"The user to install to on the target. Defaults to the user in the Docker image (this default user should almost always be correct for our robots)\")), mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": \"center\"\n  }, \"-t\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": \"left\"\n  }, \"Install toolchain to the target\")), mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": \"center\"\n  }, \"-cn\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": \"left\"\n  }, \"Only install new config files. This is the default\")), mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": \"center\"\n  }, \"-cu\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": \"left\"\n  }, \"Update config files on the target that are older than the local files\")), mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": \"center\"\n  }, \"-co\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": \"left\"\n  }, \"Overwrite all config files on the target\")), mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": \"center\"\n  }, \"-ci\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": \"left\"\n  }, \"Ignore all changes to config files (installs no config files)\")))), mdx(\"p\", null, \"The toolchain is a collection of 3rd party libraries that have been built into the Docker images. On a new robot, all roles will fail to run unless the toolchain is installed and, more often than not, if you are receiving errors on the robot saying something to the effect of \\\"cannot open shared object file: No such file or directory\\\" this will usually be solved by installing the toolchain.\"), mdx(Alert, {\n    type: \"info\",\n    mdxType: \"Alert\"\n  }, mdx(\"p\", null, \"If you have installed the toolchain and you are still getting errors like the\\none mentioned above, try running \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"sudo ldconfig\"), \" on the robot.\")), mdx(\"h5\", {\n    \"id\": \"module\",\n    \"style\": {\n      \"position\": \"relative\"\n    }\n  }, mdx(\"a\", {\n    parentName: \"h5\",\n    \"href\": \"#module\",\n    \"aria-label\": \"module permalink\",\n    \"className\": \"anchor before\"\n  }, mdx(\"svg\", {\n    parentName: \"a\",\n    \"aria-hidden\": \"true\",\n    \"focusable\": \"false\",\n    \"height\": \"16\",\n    \"version\": \"1.1\",\n    \"viewBox\": \"0 0 16 16\",\n    \"width\": \"16\"\n  }, mdx(\"path\", {\n    parentName: \"svg\",\n    \"fillRule\": \"evenodd\",\n    \"d\": \"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"\n  }))), \"Module\"), mdx(\"p\", null, \"The \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"module\"), \" command allows you to generate a new module. To generate a new line detection module one would run\"), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-bash\"\n  }, \"./b module generate vision/LineDetector\\n\")), mdx(\"p\", null, \"This will generate all necessary module files in the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"module/vision/LineDetector\"), \" folder. This includes an empty configuration file, a basic C++ source and header file implementing the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"LineDetector\"), \" reactor, and an empty unit test file.\"), mdx(\"p\", null, \"Add the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"--director\"), \" flag at the end of the command to generate a module that will use Director functionality.\"), mdx(\"h5\", {\n    \"id\": \"nbs\",\n    \"style\": {\n      \"position\": \"relative\"\n    }\n  }, mdx(\"a\", {\n    parentName: \"h5\",\n    \"href\": \"#nbs\",\n    \"aria-label\": \"nbs permalink\",\n    \"className\": \"anchor before\"\n  }, mdx(\"svg\", {\n    parentName: \"a\",\n    \"aria-hidden\": \"true\",\n    \"focusable\": \"false\",\n    \"height\": \"16\",\n    \"version\": \"1.1\",\n    \"viewBox\": \"0 0 16 16\",\n    \"width\": \"16\"\n  }, mdx(\"path\", {\n    parentName: \"svg\",\n    \"fillRule\": \"evenodd\",\n    \"d\": \"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"\n  }))), \"NBS\"), mdx(\"p\", null, \"NBS (NUClear Binary Stream) files are, effectively, concatenations of protobuf messages with a small header packet per message. They provide a simple and effective means for recording real data from the robots in real time.\"), mdx(\"p\", null, \"The \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"nbs\"), \" command provides a couple of subcommands to help you work with NBS data.\"), mdx(\"table\", null, mdx(\"thead\", {\n    parentName: \"table\"\n  }, mdx(\"tr\", {\n    parentName: \"thead\"\n  }, mdx(\"th\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Subcommand\"), mdx(\"th\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Description\"))), mdx(\"tbody\", {\n    parentName: \"table\"\n  }, mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"extract_images\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Extracts images from the NBS file and save them to disk\")), mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"filter\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Filter out messages from existing NBS files to make a new NBS file with less message types\")), mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"json\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Extracts selected messages from the NBS file and dumps them to \", mdx(\"inlineCode\", {\n    parentName: \"td\"\n  }, \"stdout\"), \" in a json format\")), mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"stats\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Calculates message statistics on the provided NBS file\")), mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"video\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Extract images from the NBS file and save them in a video file using FFmpeg\")))), mdx(\"h5\", {\n    \"id\": \"run\",\n    \"style\": {\n      \"position\": \"relative\"\n    }\n  }, mdx(\"a\", {\n    parentName: \"h5\",\n    \"href\": \"#run\",\n    \"aria-label\": \"run permalink\",\n    \"className\": \"anchor before\"\n  }, mdx(\"svg\", {\n    parentName: \"a\",\n    \"aria-hidden\": \"true\",\n    \"focusable\": \"false\",\n    \"height\": \"16\",\n    \"version\": \"1.1\",\n    \"viewBox\": \"0 0 16 16\",\n    \"width\": \"16\"\n  }, mdx(\"path\", {\n    parentName: \"svg\",\n    \"fillRule\": \"evenodd\",\n    \"d\": \"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"\n  }))), \"Run\"), mdx(\"p\", null, \"To run roles locally on your system use the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"run\"), \" command of \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"b\"), \" as follows\"), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-bash\"\n  }, \"./b run <name of role>\\n\")), mdx(Alert, {\n    type: \"warning\",\n    mdxType: \"Alert\"\n  }, mdx(\"p\", null, \"Important things to note when using the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"run\"), \" command\"), mdx(\"ul\", null, mdx(\"li\", {\n    parentName: \"ul\"\n  }, \"Be sure that you are using the \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"generic\"), \" target for this (\", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"./b target generic\"), \"), otherwise your role will likely crash (unless your CPU happens to be the same or newer than the 12th generation Core i7 that the robots are currently using).\"), mdx(\"li\", {\n    parentName: \"ul\"\n  }, \"When using the debugging utilities you should recompile your role after setting \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"CMAKE_BUILD_TYPE\"), \" to either \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"Debug\"), \" or \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"RelWithDebInfo\"), \" (\", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"./b configure -i\"), \") otherwise you will not get file or line number information in your stack traces.\"))), mdx(\"p\", null, \"The \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"run\"), \" command provides some options to help you debug your roles.\"), mdx(\"table\", null, mdx(\"thead\", {\n    parentName: \"table\"\n  }, mdx(\"tr\", {\n    parentName: \"thead\"\n  }, mdx(\"th\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Subcommand\"), mdx(\"th\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Description\"))), mdx(\"tbody\", {\n    parentName: \"table\"\n  }, mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"--gdb\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Runs selected role inside of GDB to enable debugging.\")), mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"--valgrind\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Runs selected role inside of valgrind to enable detection of memory errors.\")))), mdx(\"p\", null, \"In order to use ASan you must recompile your role after setting \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"USE_ASAN\"), \" to \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"ON\"), \" in the cmake options (\", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"./b configure -i\"), \").\"), mdx(Alert, {\n    type: \"info\",\n    mdxType: \"Alert\"\n  }, mdx(\"p\", null, \"Be sure to set \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"USE_ASAN\"), \" to \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"OFF\"), \" and \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"CMAKE_BUILD_TYPE\"), \" to \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"MinSizeRel\"), \" once you are finished debugging. Both ASan and Debug builds will slow your roles runtime down a lot.\")), mdx(\"p\", null, \"When \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"USE_ASAN=ON\"), \" an environment variable is added that will direct ASan to log all of its output to a file. This is done to ensure that even when you are running a curses-enabled role (e.g. \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"fake/keyboardwalk\"), \") you will always be able to recover the output from ASan (and it will also be clean from other log messages). There are a number of other run-time options you could set to tune the behaviour of ASan, they can be found \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://github.com/google/sanitizers/wiki/AddressSanitizerFlags\"\n  }, \"here\"), \". Just run your role as follows\"), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-bash\"\n  }, \"ASAN_OPTIONS=option1=value1:option2=value ./b run fake/keyboardwalk\\n\")), mdx(Alert, {\n    type: \"info\",\n    mdxType: \"Alert\"\n  }, mdx(\"p\", null, \"If you would like to use a different path for your ASan log file be sure to specify \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"ASAN_OPTIONS=log_path=path/to/log/file\"), \". However, there are very few locations inside of the Docker container that have persistent write access. The default log file location is \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"/home/nubots/NUbots/asan.log.PID\"), \" which corresponds to the NUbots source code directory. \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"PID\"), \" is the process ID of your role in the Docker container, ASan will always add this.\")), mdx(\"p\", null, \"ASan and GDB can be run together. For more details on how this works have a look at \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://github.com/google/sanitizers/wiki/AddressSanitizerAndDebugger\"\n  }, \"this page\"), \".\"), mdx(\"p\", null, \"Since ASan and valgrind perform the same task they cannot be used in conjunction and an exception will be thrown if you try to do so.\"), mdx(\"p\", null, \"While it is possible to run GDB and valgrind simultaneously, two separate processes need to be started and then linked together. While this is technically possible, it has currently been assigned to the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"too hard\"), \" basket and, as such, this option has been disabled and an exception will be thrown if you try to do this.\"), mdx(\"p\", null, \"When using GDB to debug curses-enabled roles (e.g. \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"keyboardwalk\"), \") and a breakpoint is triggered or an error occurs the role will be halted and control is returned to GDB. However, the role will likely be halted in a way that prevents curses from being disabled, leaving the screen in a reasonably unreadable state. To fix this, use the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"reset\"), \" command and the screen should return to normal. You can then use \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"bt\"), \" or \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"bt full\"), \" to get a stack trace and continue debugging as normal.\"), mdx(Alert, {\n    type: \"info\",\n    mdxType: \"Alert\"\n  }, mdx(\"p\", null, \"For further information on using ASan, GDB, and valgrind check out these pages\"), mdx(\"ul\", null, mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"a\", {\n    parentName: \"li\",\n    \"href\": \"https://github.com/google/sanitizers/wiki\"\n  }, \"Address Sanitiser\")), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"a\", {\n    parentName: \"li\",\n    \"href\": \"https://ftp.gnu.org/old-gnu/Manuals/gdb/html_chapter/gdb_toc.html\"\n  }, \"GDB\")), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"a\", {\n    parentName: \"li\",\n    \"href\": \"https://valgrind.org/docs/manual/quick-start.html\"\n  }, \"Valgrind\")), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"a\", {\n    parentName: \"li\",\n    \"href\": \"https://www.valgrind.org/docs/manual/manual-core-adv.html#manual-core-adv.gdbserver\"\n  }, \"Running GDB and valgrind simulataneously\"), \".\"), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"a\", {\n    parentName: \"li\",\n    \"href\": \"https://github.com/google/sanitizers/wiki/AddressSanitizerComparisonOfMemoryTools\"\n  }, \"Choosing between ASan and valgrind\"), \".\"))), mdx(\"h5\", {\n    \"id\": \"shell\",\n    \"style\": {\n      \"position\": \"relative\"\n    }\n  }, mdx(\"a\", {\n    parentName: \"h5\",\n    \"href\": \"#shell\",\n    \"aria-label\": \"shell permalink\",\n    \"className\": \"anchor before\"\n  }, mdx(\"svg\", {\n    parentName: \"a\",\n    \"aria-hidden\": \"true\",\n    \"focusable\": \"false\",\n    \"height\": \"16\",\n    \"version\": \"1.1\",\n    \"viewBox\": \"0 0 16 16\",\n    \"width\": \"16\"\n  }, mdx(\"path\", {\n    parentName: \"svg\",\n    \"fillRule\": \"evenodd\",\n    \"d\": \"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"\n  }))), \"Shell\"), mdx(\"p\", null, \"This is an undocumented and unsupported option.\"), mdx(\"details\", null, mdx(\"summary\", null, \"I know what I am doing\"), mdx(\"p\", null, \"You probably don't know what you are doing. But why would you listen to me?\"), mdx(\"p\", null, \"For some reason, if you really, really, \", mdx(\"em\", {\n    parentName: \"p\"\n  }, \"REALLY\"), \" need to access a terminal inside of Docker you can run\"), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-bash\"\n  }, \"./b shell\\n\")), mdx(Alert, {\n    type: \"warning\",\n    mdxType: \"Alert\"\n  }, mdx(\"p\", null, \"Any changes you make outside of the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"/home/nubots/NUbots\"), \" or \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"/home/nubots/build\"), \" directories will not persist after exiting the Docker shell.\"))), mdx(\"h5\", {\n    \"id\": \"target\",\n    \"style\": {\n      \"position\": \"relative\"\n    }\n  }, mdx(\"a\", {\n    parentName: \"h5\",\n    \"href\": \"#target\",\n    \"aria-label\": \"target permalink\",\n    \"className\": \"anchor before\"\n  }, mdx(\"svg\", {\n    parentName: \"a\",\n    \"aria-hidden\": \"true\",\n    \"focusable\": \"false\",\n    \"height\": \"16\",\n    \"version\": \"1.1\",\n    \"viewBox\": \"0 0 16 16\",\n    \"width\": \"16\"\n  }, mdx(\"path\", {\n    parentName: \"svg\",\n    \"fillRule\": \"evenodd\",\n    \"d\": \"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"\n  }))), \"Target\"), mdx(\"p\", null, \"The \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"target\"), \" command of \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"b\"), \" allows you to build code for a different target. Support targets are\"), mdx(\"ul\", null, mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"generic\"), \": Useful if you would like to build and run code on your local machine.\"), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"nuc7i7bnh\"), \": For use with the old nuc7i7bnh computer. This is no longer used on the robots.\"), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"nuc8i7beh\"), \": For use with the nuc8i7beh computer. This is not used on the robots.\"), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"nuc12wshi7\"), \": The current target for the robots, which use the nuc12wshi7 computer.\")), mdx(\"p\", null, \"The \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"target\"), \" command will download (or, if needed, build) the Docker image for the specified target and then mark that target as active.\"), mdx(\"h5\", {\n    \"id\": \"tests\",\n    \"style\": {\n      \"position\": \"relative\"\n    }\n  }, mdx(\"a\", {\n    parentName: \"h5\",\n    \"href\": \"#tests\",\n    \"aria-label\": \"tests permalink\",\n    \"className\": \"anchor before\"\n  }, mdx(\"svg\", {\n    parentName: \"a\",\n    \"aria-hidden\": \"true\",\n    \"focusable\": \"false\",\n    \"height\": \"16\",\n    \"version\": \"1.1\",\n    \"viewBox\": \"0 0 16 16\",\n    \"width\": \"16\"\n  }, mdx(\"path\", {\n    parentName: \"svg\",\n    \"fillRule\": \"evenodd\",\n    \"d\": \"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"\n  }))), \"Tests\"), mdx(\"p\", null, \"The \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"tests\"), \" command allows you to run built unit tests. It will automatically run tests in parallel, and dump a timestamped log file to the project directory. Currently, we use \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://cmake.org/cmake/help/latest/manual/ctest.1.html\"\n  }, \"CTest\"), \" which is included as part of CMake.\"), mdx(\"p\", null, \"In order to run unit tests, they must first be built. This can be done with:\"), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-bash\"\n  }, \"./b configure -- -DBUILD_TESTS=ON\\n./b build\\n\")), mdx(\"p\", null, \"The \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"tests\"), \" command provides the following subcommands:\"), mdx(\"table\", null, mdx(\"thead\", {\n    parentName: \"table\"\n  }, mdx(\"tr\", {\n    parentName: \"thead\"\n  }, mdx(\"th\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Subcommand\"), mdx(\"th\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Description\"))), mdx(\"tbody\", {\n    parentName: \"table\"\n  }, mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"list\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"List all built tests\")), mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"run\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Run all tests (default), or named individual tests\")))), mdx(\"p\", null, \"If you would like to run an individual test (or group of tests), you can pass the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"run\"), \" subcommand a string and it will only run tests that match the given string.\\nAlternatively, \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"run\"), \" will run all built tests if no string is passed.\"), mdx(\"p\", null, \"For example, if you would like to run all tests with the string 'vision' in their name, you would do:\"), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-bash\"\n  }, \"./b tests run vision\\n\")), mdx(\"p\", null, \"The \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"run\"), \" subcommand also accepts the following flags:\"), mdx(\"table\", null, mdx(\"thead\", {\n    parentName: \"table\"\n  }, mdx(\"tr\", {\n    parentName: \"thead\"\n  }, mdx(\"th\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Flag\"), mdx(\"th\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Description\"))), mdx(\"tbody\", {\n    parentName: \"table\"\n  }, mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, mdx(\"inlineCode\", {\n    parentName: \"td\"\n  }, \"-V\"), \" or \", mdx(\"inlineCode\", {\n    parentName: \"td\"\n  }, \"--verbose\")), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Enable verbose output from tests\")), mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, mdx(\"inlineCode\", {\n    parentName: \"td\"\n  }, \"-VV\"), \" or \", mdx(\"inlineCode\", {\n    parentName: \"td\"\n  }, \"--extra-verbose\")), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Enable more verbose output from tests\")), mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, mdx(\"inlineCode\", {\n    parentName: \"td\"\n  }, \"-Q\"), \" or \", mdx(\"inlineCode\", {\n    parentName: \"td\"\n  }, \"--quiet\")), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Make CTest not print to stdout\")), mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, mdx(\"inlineCode\", {\n    parentName: \"td\"\n  }, \"-j NUM_JOBS\"), \" or \", mdx(\"inlineCode\", {\n    parentName: \"td\"\n  }, \"--parallel NUM_JOBS\")), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Run the tests in parallel using the given number of jobs\")), mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, mdx(\"inlineCode\", {\n    parentName: \"td\"\n  }, \"--debug\")), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Displaying more verbose internals of CTest\")))), mdx(\"h4\", {\n    \"id\": \"autocomplete\",\n    \"style\": {\n      \"position\": \"relative\"\n    }\n  }, mdx(\"a\", {\n    parentName: \"h4\",\n    \"href\": \"#autocomplete\",\n    \"aria-label\": \"autocomplete permalink\",\n    \"className\": \"anchor before\"\n  }, mdx(\"svg\", {\n    parentName: \"a\",\n    \"aria-hidden\": \"true\",\n    \"focusable\": \"false\",\n    \"height\": \"16\",\n    \"version\": \"1.1\",\n    \"viewBox\": \"0 0 16 16\",\n    \"width\": \"16\"\n  }, mdx(\"path\", {\n    parentName: \"svg\",\n    \"fillRule\": \"evenodd\",\n    \"d\": \"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"\n  }))), \"Autocomplete\"), mdx(\"p\", null, \"To use autocomplete with \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"b\"), \" on bash run \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"eval \\\"$(register-python-argcomplete b)\\\"\"), \" in the NUbots folder. Now when you press tab it will finish the command you were typing.\\nIt's recommended to add it to your \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \".bashrc\"), \", but you need to provide the full path to the NUbots folder. e.g. \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"eval \\\"$(register-python-argcomplete $HOME/code/NUbots/b)\\\"\"), \".\"), mdx(\"details\", null, mdx(\"summary\", null, \"zsh\"), mdx(\"p\", null, \"You need to use \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"bashcompinit\"), \" to use the bash completions and add to \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \".zshrc\"), \" instead of \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \".bashrc\"), \".\"), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-bash\"\n  }, \"autoload -U bashcompinit\\nbashcompinit\\neval \\\"$(register-python-argcomplete b)\\\"\\n\"))), mdx(\"h2\", {\n    \"id\": \"docker-images\",\n    \"style\": {\n      \"position\": \"relative\"\n    }\n  }, mdx(\"a\", {\n    parentName: \"h2\",\n    \"href\": \"#docker-images\",\n    \"aria-label\": \"docker images permalink\",\n    \"className\": \"anchor before\"\n  }, mdx(\"svg\", {\n    parentName: \"a\",\n    \"aria-hidden\": \"true\",\n    \"focusable\": \"false\",\n    \"height\": \"16\",\n    \"version\": \"1.1\",\n    \"viewBox\": \"0 0 16 16\",\n    \"width\": \"16\"\n  }, mdx(\"path\", {\n    parentName: \"svg\",\n    \"fillRule\": \"evenodd\",\n    \"d\": \"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"\n  }))), \"Docker Images\"), mdx(\"p\", null, \"The NUbots codebase uses Docker images to containerise the build process.\\nTwo images are created, one intended for running code on your local machine, named \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"generic\"), \", and another intended for running code on the robots named \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"nuc12wshi7\"), \".\\nApart from flags provided to the build tools and the compiler both images are identical (that is, they contain the same programs and libraries).\"), mdx(Alert, {\n    type: \"info\",\n    mdxType: \"Alert\"\n  }, mdx(\"p\", null, mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"nuc12wshi7\"), \" is the name Intel has given to the Intel NUC device that the NUgus robots are currently using.\")), mdx(\"p\", null, \"The Docker images are cached on \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://hub.docker.com/r/nubots/nubots\"\n  }, \"Docker Hub\"), \" to limit the amount of building that everyone has to do. The cache will be updated whenever the main branch is updated.\"), mdx(\"p\", null, \"The Docker images use \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://www.archlinux.org/\"\n  }, \"Arch Linux\"), \" as their operating system as it is lightweight, flexible, and up-to-date.\"), mdx(\"p\", null, \"The \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://github.com/NUbots/NUbots/tree/main/docker\"\n  }, \"docker folder\"), \" contains the Dockerfile as well as some utility scripts to ease the burden of compiling multiple different libraries. Other files in this folder end up inside of the image and control either the behaviour of the compiler or build system, or the runtime behaviour of the libraries that are built.\"), mdx(\"p\", null, \"If you need to add a new library or program to the Docker image you should add it to the end of the Dockerfile to minimise the amount of rebuilding that needs to happen. Look for the following marker\"), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-bash\"\n  }, \"#######################################\\n### ADD NEW PROGRAMS/LIBRARIES HERE ###\\n#######################################\\n\")), mdx(\"h3\", {\n    \"id\": \"adding-a-new-library-to-the-robot-toolchain\",\n    \"style\": {\n      \"position\": \"relative\"\n    }\n  }, mdx(\"a\", {\n    parentName: \"h3\",\n    \"href\": \"#adding-a-new-library-to-the-robot-toolchain\",\n    \"aria-label\": \"adding a new library to the robot toolchain permalink\",\n    \"className\": \"anchor before\"\n  }, mdx(\"svg\", {\n    parentName: \"a\",\n    \"aria-hidden\": \"true\",\n    \"focusable\": \"false\",\n    \"height\": \"16\",\n    \"version\": \"1.1\",\n    \"viewBox\": \"0 0 16 16\",\n    \"width\": \"16\"\n  }, mdx(\"path\", {\n    parentName: \"svg\",\n    \"fillRule\": \"evenodd\",\n    \"d\": \"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"\n  }))), \"Adding a new library to the robot toolchain\"), mdx(\"p\", null, \"If the intention is to have the new library running on the robot then you need to build the library from source. If the library you are building is well-behaved then it should be a simple matter of adding a line like the following to the Dockerfile\"), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-docker\"\n  }, \"RUN install-from-source http://url.to.the.source.tarball.com\\n\")), mdx(\"p\", null, \"This process generally requires some studying of either the library's documentation or build system files to determine appropriate configure and build flags.\\nIf there are extra flags that need to be specified then modify the above command to\"), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-docker\"\n  }, \"RUN install-from-source http://url.to.the.source.tarball.com \\\\\\n    -DCONFIGURE_FLAG=XXX\\n\")), mdx(Alert, {\n    type: \"info\",\n    mdxType: \"Alert\"\n  }, mdx(\"p\", null, mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"\\\\\"), \" is a line continuation operator, it allows a long line to be split over multiple lines to improve readability\")), mdx(\"p\", null, \"If your library is not well-behaved you may need to do to a lot of googling and trawling through stackoverflow, bug reports, or github issue pages in order to find workarounds or patches to help you build your library.\\nAnother good source of information is the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"PKGBUILD\"), \" scripts from the Arch Linux repositories. \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://www.archlinux.org/packages/\"\n  }, \"Search\"), \" for the name of the library, then look for and click the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"Source Files\"), \" link on the package page and then click on \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"PKGBUILD\"), \".\\nThe \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"PKGBUILD\"), \" script will show you how Arch Linux builds the library including\"), mdx(\"ul\", null, mdx(\"li\", {\n    parentName: \"ul\"\n  }, \"necessary dependencies,\"), mdx(\"li\", {\n    parentName: \"ul\"\n  }, \"locations of source files and patches,\"), mdx(\"li\", {\n    parentName: \"ul\"\n  }, \"commands needed to prepare the source files for compilation,\"), mdx(\"li\", {\n    parentName: \"ul\"\n  }, \"commands needed to build the library, and\"), mdx(\"li\", {\n    parentName: \"ul\"\n  }, \"commands needed to install the library\")), mdx(\"p\", null, \"Borrowing commands from these scripts could help relieve your frustrations with the world.\"), mdx(\"h3\", {\n    \"id\": \"adding-a-new-build-utility\",\n    \"style\": {\n      \"position\": \"relative\"\n    }\n  }, mdx(\"a\", {\n    parentName: \"h3\",\n    \"href\": \"#adding-a-new-build-utility\",\n    \"aria-label\": \"adding a new build utility permalink\",\n    \"className\": \"anchor before\"\n  }, mdx(\"svg\", {\n    parentName: \"a\",\n    \"aria-hidden\": \"true\",\n    \"focusable\": \"false\",\n    \"height\": \"16\",\n    \"version\": \"1.1\",\n    \"viewBox\": \"0 0 16 16\",\n    \"width\": \"16\"\n  }, mdx(\"path\", {\n    parentName: \"svg\",\n    \"fillRule\": \"evenodd\",\n    \"d\": \"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"\n  }))), \"Adding a new build utility\"), mdx(\"p\", null, \"If the library/program is not intended to be used on the robot, but is instead intended to run inside the Docker image as an extra utility to help build the NUbots code then your first port of call should be the Arch Linux packages. Search for a \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://www.archlinux.org/packages/\"\n  }, \"package here\"), \" (or google \\\"Arch Linux\\\" and the name of the program/library) and if you meet with success add the following command to the Dockerfile at the marker near the end of the file\"), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-bash\"\n  }, \"#######################################\\n### ADD NEW PROGRAMS/LIBRARIES HERE ###\\n#######################################\\nRUN install-package <name of package>\\n\")), mdx(\"p\", null, \"If a package does not exist in the Arch Linux repositories then you will need to build it from source. However, this time, you need to add it where the marker says\"), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-bash\"\n  }, \"##############################################\\n### ADD NEW SYSTEM PROGRAMS/LIBRARIES HERE ###\\n##############################################\\n\")), mdx(\"p\", null, \"See above for details on how to build a program/library from source.\"), mdx(\"h2\", {\n    \"id\": \"the-toolchain\",\n    \"style\": {\n      \"position\": \"relative\"\n    }\n  }, mdx(\"a\", {\n    parentName: \"h2\",\n    \"href\": \"#the-toolchain\",\n    \"aria-label\": \"the toolchain permalink\",\n    \"className\": \"anchor before\"\n  }, mdx(\"svg\", {\n    parentName: \"a\",\n    \"aria-hidden\": \"true\",\n    \"focusable\": \"false\",\n    \"height\": \"16\",\n    \"version\": \"1.1\",\n    \"viewBox\": \"0 0 16 16\",\n    \"width\": \"16\"\n  }, mdx(\"path\", {\n    parentName: \"svg\",\n    \"fillRule\": \"evenodd\",\n    \"d\": \"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"\n  }))), \"The toolchain\"), mdx(\"p\", null, \"The toolchain is a collection of libraries that are used by the NUbots codebase. These libraries are essential for our code (if we don't have them then we are unable to compile anything).\"), mdx(\"p\", null, \"In order to ensure that everyone is using the same versions of every library and that everyone has compiled the libraries in the same way (enabling the correct features, etc), we use Docker to automate the build process.\\nDocker also ensures that all of the dependencies for the built libraries are either installed or are also built and that they are also built in the correct order.\\nTo see what is currently being built and installed in the toolchain have a look at the \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://github.com/NUbots/NUbots/blob/main/docker/Dockerfile\"\n  }, \"Dockerfile\"), \".\"), mdx(\"p\", null, \"In order to improve runtime performance on the robots, all libraries that are built as part of the toolchain (as well as the NUbots code) are compiled with optimisations targeting the CPU of the robot.\\nA list of the currently used compiler flags for the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"nuc12wshi7\"), \" can be seen in \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://github.com/NUbots/NUbots/blob/main/docker/usr/local/toolchain/generate_nuc12wshi7_toolchain.py\"\n  }, \"generate_nuc12wshi7_toolchain.py\"), \".\"), mdx(\"p\", null, \"If you are setting up a new toolchain targetting a robot that is using a different CPU to the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"nuc12wshi7\"), \", log on to the new robot, install \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"gcc\"), \" (\", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"sudo pacman -S gcc\"), \") and execute the following commands\"), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-bash\"\n  }, \"target=$(gcc -march=native -Q --help=target | grep -- '-march=' | cut -f3 | head -n1)\\ndiff -y --suppress-common-lines <(gcc -march=native -Q --help=target) <(gcc -march=${target} -Q --help=target)\\n\")), mdx(\"p\", null, \"The first command will determine the codename of the CPU family (i.e. for an Intel CPU it might be \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"broadwell\"), \", \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"haswell\"), \", \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"skylake\"), \", etc).\"), mdx(\"p\", null, \"For the rest of this example we will assume that \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"target=skylake\"), \".\"), mdx(\"p\", null, \"The second command compares the compiler flags that compiling with \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"-march=native\"), \" would enable compared to using \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"-march=skylake\"), \".\\nThe output of this function could look like this\"), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-bash\"\n  }, \"-mabm        [enabled]        |    -mabm        [disabled]\\n-mrtm        [enabled]        |    -mrtm        [disabled]\\n\")), mdx(\"p\", null, \"The left column are instructions that are enabled/disabled when compiling using \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"-march=native\"), \" and the right column are the instructions that are enabled/disabled when compiling using \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"-march=skylake\"), \".\\nCombining both columns tells us that to get from a generic \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"skylake\"), \" CPU to the CPU that we are using we need to enable both the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"abm\"), \" and the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"rtm\"), \" instructions using \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"-mabm\"), \" and \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"-mrtm\"), \".\"), mdx(Alert, {\n    type: \"info\",\n    mdxType: \"Alert\"\n  }, mdx(\"p\", null, \"If the output was actually\"), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-bash\"\n  }, \"-mabm        [disabled]       |    -mabm        [enabled]\\n-mrtm        [enabled]        |    -mrtm        [disabled]\\n\")), mdx(\"p\", null, \"Then we would need to disable \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"abm\"), \" using \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"-mno-abm\"), \" and enable \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"rtm\"), \" using \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"-mrtm\"), \".\")), mdx(\"p\", null, \"The final piece of information we need is about the CPU cache sizes\"), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-bash\"\n  }, \"gcc -### -E - -march=native 2>&1 | sed -r '/cc1/!d;s/(\\\")|(^.* - )//g'| grep -oP -- \\\"--param l[12]-cache(-line|)-size=[0-9]*\\\"\\n\")), mdx(\"p\", null, \"The output of this command will look like this\"), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-bash\"\n  }, \"--param l1-cache-size=32\\n--param l1-cache-line-size=64\\n--param l2-cache-size=12288\\n\")), mdx(Alert, {\n    type: \"warning\",\n    mdxType: \"Alert\"\n  }, mdx(\"p\", null, \"If you get an error saying \\\"zsh: bad pattern: -###\\\", wrap double-quotes around the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"-###\"), \" in the above command.\")), mdx(\"p\", null, \"Putting all of this together, the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"targets\"), \" dict for our example target would be\"), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\"\n  }, \"target = {\\n    \\\"flags\\\": [\\n        \\\"-march=skylake\\\",\\n        \\\"-mtune=skylake\\\",\\n        \\\"-mabm\\\",\\n        \\\"-mrtm\\\",\\n        \\\"--param l1-cache-size=32\\\",\\n        \\\"--param l1-cache-line-size=64\\\",\\n        \\\"--param l2-cache-size=12288\\\",\\n        \\\"-fPIC\\\",\\n    ],\\n    \\\"release_flags\\\": [\\\"-O3\\\", \\\"-DNDEBUG\\\"],\\n    \\\"asm_flags\\\": [\\\"-DELF\\\", \\\"-D__x86_64__\\\", \\\"-DPIC\\\"],\\n    \\\"asm_object\\\": \\\"elf64\\\",\\n}\\n\")), mdx(\"h3\", {\n    \"id\": \"dependency-declaration\",\n    \"style\": {\n      \"position\": \"relative\"\n    }\n  }, mdx(\"a\", {\n    parentName: \"h3\",\n    \"href\": \"#dependency-declaration\",\n    \"aria-label\": \"dependency declaration permalink\",\n    \"className\": \"anchor before\"\n  }, mdx(\"svg\", {\n    parentName: \"a\",\n    \"aria-hidden\": \"true\",\n    \"focusable\": \"false\",\n    \"height\": \"16\",\n    \"version\": \"1.1\",\n    \"viewBox\": \"0 0 16 16\",\n    \"width\": \"16\"\n  }, mdx(\"path\", {\n    parentName: \"svg\",\n    \"fillRule\": \"evenodd\",\n    \"d\": \"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"\n  }))), \"Dependency Declaration\"), mdx(\"p\", null, \"CMake needs to know what dependencies we have and where to find them.\\nIn a module's folder the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"CMakeLists.txt\"), \" file tells CMake what is needed to build a module.\\nThe \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"nuclear_module()\"), \" function tells CMake that this directory contains a module that may be added to a role.\\nThis function may take named parameters.\"), mdx(\"table\", null, mdx(\"thead\", {\n    parentName: \"table\"\n  }, mdx(\"tr\", {\n    parentName: \"thead\"\n  }, mdx(\"th\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Parameter\"), mdx(\"th\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Usage\"))), mdx(\"tbody\", {\n    parentName: \"table\"\n  }, mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"LANGUAGE\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"The programming language that this module is in (currently only C++)\")), mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"LIBRARIES\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"The libraries that this module depends on and must be linked with\")), mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"SOURCES\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Extra code outside the \", mdx(\"inlineCode\", {\n    parentName: \"td\"\n  }, \"src\"), \" directory that must be built\")), mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"DATA_FILES\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Extra data files outside the \", mdx(\"inlineCode\", {\n    parentName: \"td\"\n  }, \"data\"), \" directory that the module uses\")))), mdx(\"p\", null, \"CMake needs to know where libraries are located. The \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"cmake/Modules/\"), \" directory contains files called \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"FindX.cmake\"), \", where \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"X\"), \" is the name of a library. These files contain the logic for finding library files. The function \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"find_package(X)\"), \" is used to tell CMake to look for one of these \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \".cmake\"), \" files and run it.\"), mdx(\"p\", null, \"CMake can also look for build instruction files in \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"/lib/cmake/X/XConfig.cmake\"), \" where \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"X\"), \" is the name of the library.\\nAn example of one of these files, \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"FindAravis.cmake\"), \" which finds the Aravis library, is shown below\"), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-cmake\"\n  }, \"include(ToolchainLibraryFinder)\\n\\nfind_package(glib2 REQUIRED)\\n\\nToolchainLibraryFinder(\\n  NAME Aravis\\n  HEADER arv.h\\n  LIBRARY aravis-0.8\\n  PATH_SUFFIX aravis-0.8\\n)\\n\\ntarget_link_libraries(Aravis::Aravis INTERFACE glib2::glib2)\\n\")), mdx(\"p\", null, \"The first line includes a custom function for later use.\\nWe have \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"find_package\"), \" again, as this library has its own dependency.\\nThen there is \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"ToolchainLibraryFinder\"), \" which is the function that finds the library.\\nFinally there is \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"target_link_libraries\"), \" which tells CMake that we have a dependency of the library.\\n\", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"ToolchainLibraryFinder\"), \" parameters:\"), mdx(\"table\", null, mdx(\"thead\", {\n    parentName: \"table\"\n  }, mdx(\"tr\", {\n    parentName: \"thead\"\n  }, mdx(\"th\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Parameter\"), mdx(\"th\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Usage\"))), mdx(\"tbody\", {\n    parentName: \"table\"\n  }, mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"NAME\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"The name we use for the package\")), mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"HEADER\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Any header, e.g. \", mdx(\"inlineCode\", {\n    parentName: \"td\"\n  }, \".h\"), \" or \", mdx(\"inlineCode\", {\n    parentName: \"td\"\n  }, \".hpp\"), \", files that define the api of the library\")), mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"LIBRARY\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"The name of the library on disk, e.g. if we have \", mdx(\"inlineCode\", {\n    parentName: \"td\"\n  }, \"/usr/lib/libaravis-0.8.so\"), \" it'd be \", mdx(\"inlineCode\", {\n    parentName: \"td\"\n  }, \"aravis\"))), mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"LIBRARIES\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"A list instead of a single LIBRARY\")), mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"PATH_SUFFIX\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Add subdirectories to look for includes and libraries in the normal search directories\")), mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"BINARY\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"A binary that can be used to extract the version number\")), mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"VERSION_BINARY_ARGUMENTS\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"The arguments to pass to the binary that will result in a version number being printed\")), mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"VERSION_FILE\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"A file that contains information on the version number of the library\")), mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"VERSION_REGEX\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"The regex used on the version file to extract the version number\")), mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"LINK_TYPE\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"The type of linkage that the library will use: \", mdx(\"inlineCode\", {\n    parentName: \"td\"\n  }, \"UNKNOWN\"), \" is the default and will pick either, \", mdx(\"inlineCode\", {\n    parentName: \"td\"\n  }, \"SHARED\"), \" will use dynamic linkage and look for a \", mdx(\"inlineCode\", {\n    parentName: \"td\"\n  }, \".so\"), \" library file \", mdx(\"inlineCode\", {\n    parentName: \"td\"\n  }, \"STATIC\"), \" will use static linkage and look for a \", mdx(\"inlineCode\", {\n    parentName: \"td\"\n  }, \".a\"), \" library file\")))));\n}\n;\nMDXContent.isMDXComponent = true;","tableOfContents":{"items":[{"url":"#the-nubots-build-system","title":"The NUbots Build System","items":[{"url":"#overview","title":"Overview"},{"url":"#nuclear-roles","title":"NUClear Roles"}]},{"url":"#docker-images","title":"Docker Images","items":[{"url":"#adding-a-new-library-to-the-robot-toolchain","title":"Adding a new library to the robot toolchain"},{"url":"#adding-a-new-build-utility","title":"Adding a new build utility"}]},{"url":"#the-toolchain","title":"The toolchain","items":[{"url":"#dependency-declaration","title":"Dependency Declaration"}]}]},"frontmatter":{"section":"System","chapter":"Foundations","title":"Build System","description":"The NUbots build system.","keywords":null,"slug":"/system/foundations/build-system","hidden":null},"childNUbookContributions":{"authors":[{"name":"Alex Biddulph","username":"Bidski"},{"name":"Yosiah de Koeyer","username":"Y0sh1dk"},{"name":"Kip Hamiltons","username":"KipHamiltons"},{"name":"Trent Houliston","username":"TrentHouliston"}],"lastCommit":{"date":"2023-10-01T00:34:34.000Z","hash":"75aef48ccb90112bcaae0f604c7b3ea82b6602eb"}}}},"pageContext":{"mdxPath":"src/book/02-system/01-foundations/02-build-system.mdx","id":"d51d0a56-68fa-5746-bab9-0ae3b235d976","next":{"chapter":"Foundations","title":"Continuous Integration","description":"The NUbots continuous integration system.","slug":"/system/foundations/ci-system","hidden":null},"previous":{"chapter":"Foundations","title":"Overview","description":"Introduction to the NUbots codebase and high-level architecture.","slug":"/system/foundations/overview","hidden":null},"menu":[{"title":"Team","slug":"/team/introduction","chapters":[{"title":"Introduction","slug":"/team/introduction","pages":[{"title":"Introduction to NUbots","slug":"/team/introduction","hidden":null},{"title":"Areas of Research","slug":"/team/areas-of-research","hidden":null},{"title":"Current Team","slug":"/team/current-members","hidden":null}],"hidden":false},{"title":"Joining the Team","slug":"/team/how-we-work","pages":[{"title":"How We Work","slug":"/team/how-we-work","hidden":null},{"title":"How to Join NUbots","slug":"/team/how-to-join","hidden":null},{"title":"Lab Induction","slug":"/team/induction","hidden":null}],"hidden":false},{"title":"Community","slug":"/team/sponsors","pages":[{"title":"Sponsors","slug":"/team/sponsors","hidden":null},{"title":"Connect","slug":"/team/connect","hidden":null}],"hidden":false},{"title":"History","slug":"/team/history","pages":[{"title":"Team History","slug":"/team/history","hidden":null},{"title":"Past Members","slug":"/team/past-members","hidden":null},{"title":"Publications","slug":"/team/publications","hidden":null}],"hidden":false},{"title":"RoboCup","slug":"/team/robocup","pages":[{"title":"RoboCup","slug":"/team/robocup","hidden":null},{"title":"Resources","slug":"/team/robocup/resources","hidden":null},{"title":"Debriefs","slug":"/team/robocup/debriefs","hidden":null}],"hidden":false}],"hidden":false},{"title":"System","slug":"/system/foundations/overview","chapters":[{"title":"Foundations","slug":"/system/foundations/overview","pages":[{"title":"Overview","slug":"/system/foundations/overview","hidden":null},{"title":"Build System","slug":"/system/foundations/build-system","hidden":null},{"title":"Continuous Integration","slug":"/system/foundations/ci-system","hidden":null},{"title":"NUClear","slug":"/system/foundations/nuclear","hidden":null},{"title":"Mathematics","slug":"/system/foundations/mathematics","hidden":null},{"title":"Configuration and Script System","slug":"/system/foundations/config-script","hidden":null},{"title":"Director","slug":"/system/foundations/director","hidden":null}],"hidden":false},{"title":"Subsystems","slug":"/system/subsystems/input","pages":[{"title":"Input","slug":"/system/subsystems/input","hidden":null},{"title":"Odometry","slug":"/system/subsystems/odometry","hidden":null},{"title":"Localisation","slug":"/system/subsystems/localisation","hidden":null},{"title":"Motion","slug":"/system/subsystems/motion","hidden":null},{"title":"Vision","slug":"/system/subsystems/vision","hidden":null},{"title":"Behaviour","slug":"/system/subsystems/behaviour","hidden":null},{"title":"Logging","slug":"/system/subsystems/logging","hidden":null}],"hidden":false},{"title":"Tools","slug":"/system/tools/nusight","pages":[{"title":"NUsight","slug":"/system/tools/nusight","hidden":null},{"title":"NUbook","slug":"/system/tools/nubook","hidden":null},{"title":"NUpbr","slug":"/system/tools/nupbr","hidden":null},{"title":"NUgan","slug":"/system/tools/nugan","hidden":null},{"title":"System Configuration","slug":"/system/tools/system_configuration","hidden":null},{"title":"NatNet SDK","slug":"/system/tools/natnet_sdk","hidden":null}],"hidden":false},{"title":"Hardware","slug":"/system/hardware/overview","pages":[{"title":"Overview and Specifications","slug":"/system/hardware/overview","hidden":null}],"hidden":false},{"title":"Modules","slug":"/system/modules/actuation/","pages":[{"title":"Actuation","slug":"/system/modules/actuation/","hidden":null},{"title":"Extension","slug":"/system/modules/extension/","hidden":null},{"title":"Input","slug":"/system/modules/input/","hidden":null},{"title":"Localisation","slug":"/system/modules/localisation/","hidden":null},{"title":"Nbs","slug":"/system/modules/nbs/","hidden":null},{"title":"Network","slug":"/system/modules/network/","hidden":null},{"title":"Output","slug":"/system/modules/output/","hidden":null},{"title":"Planning","slug":"/system/modules/planning/","hidden":null},{"title":"Platform","slug":"/system/modules/platform/","hidden":null},{"title":"Purpose","slug":"/system/modules/purpose/","hidden":null},{"title":"Skill","slug":"/system/modules/skill/","hidden":null},{"title":"Strategy","slug":"/system/modules/strategy/","hidden":null},{"title":"Support","slug":"/system/modules/support/","hidden":null},{"title":"Tools","slug":"/system/modules/tools/","hidden":null},{"title":"Vision","slug":"/system/modules/vision/","hidden":null}],"hidden":false}],"hidden":false},{"title":"Guides","slug":"/guides/main/getting-started","chapters":[{"title":"Main Codebase","slug":"/guides/main/getting-started","pages":[{"title":"Getting Started","slug":"/guides/main/getting-started","hidden":null},{"title":"NUClear","slug":"/guides/main/nuclear-tutorial","hidden":null},{"title":"Running and Tuning Scripts","slug":"/guides/main/tuning-and-running-scripts","hidden":null},{"title":"Maintaining Subsystems","slug":"/guides/main/maintaining-subsystems","hidden":null},{"title":"Data Recording and Playback","slug":"/guides/main/data-recording-playback","hidden":null},{"title":"Camera Calibration","slug":"/guides/main/camera-calibration","hidden":null},{"title":"Onboarding Workshop","slug":"/guides/main/onboarding","hidden":null}],"hidden":false},{"title":"Tools","slug":"/guides/tools/nusight-contribution","pages":[{"title":"Contributing to NUsight","slug":"/guides/tools/nusight-contribution","hidden":null},{"title":"Setting Up Webots","slug":"/guides/tools/webots-setup","hidden":null},{"title":"Visual Mesh Getting Started","slug":"/guides/tools/visualmesh","hidden":null},{"title":"Using NUpbr","slug":"/guides/tools/nupbr-guide","hidden":null},{"title":"GameController Setup","slug":"/guides/tools/gamecontroller","hidden":null}],"hidden":false},{"title":"Hardware","slug":"/guides/hardware/working-with-robots","pages":[{"title":"Working with Robots","slug":"/guides/hardware/working-with-robots","hidden":null},{"title":"Flashing a Robot","slug":"/guides/hardware/flashing","hidden":null},{"title":"Servo Setup and Calibration","slug":"/guides/hardware/servo-calibration","hidden":null},{"title":"Batteries","slug":"/guides/hardware/batteries","hidden":null},{"title":"DARwIn Op2 Robot Restoration and Calibration Guide","slug":"/guides/hardware/darwin-op2-guide","hidden":null}],"hidden":false},{"title":"General","slug":"/guides/general/learning-resources","pages":[{"title":"Learning Resources","slug":"/guides/general/learning-resources","hidden":null},{"title":"Contribution Workflow","slug":"/guides/general/contribute","hidden":null},{"title":"RoboCup Setup","slug":"/guides/general/robocup-setup","hidden":null},{"title":"Troubleshooting","slug":"/guides/general/troubleshooting","hidden":null},{"title":"Code Conventions","slug":"/guides/general/code-conventions","hidden":null},{"title":"Glossary","slug":"/guides/general/glossary","hidden":null}],"hidden":false}],"hidden":false},{"title":"Kitchen Sink","slug":"/kitchen-sink/headers","chapters":[{"title":"Markdown","slug":"/kitchen-sink/headers","pages":[{"title":"Headers","slug":"/kitchen-sink/headers","hidden":true},{"title":"Formatting and Paragraphs","slug":"/kitchen-sink/formatting-and-paragraphs","hidden":true},{"title":"Blockquotes","slug":"/kitchen-sink/blockquotes","hidden":true},{"title":"Alerts","slug":"/kitchen-sink/alerts","hidden":true},{"title":"Images","slug":"/kitchen-sink/images","hidden":true},{"title":"Lists","slug":"/kitchen-sink/lists","hidden":true},{"title":"Code","slug":"/kitchen-sink/code","hidden":true},{"title":"Math","slug":"/kitchen-sink/math","hidden":true},{"title":"Table of Contents","slug":"/kitchen-sink/table-of-contents","hidden":true},{"title":"Tables","slug":"/kitchen-sink/tables","hidden":true},{"title":"Collapsible Content","slug":"/kitchen-sink/collapsible","hidden":true},{"title":"GraphViz Diagrams","slug":"/kitchen-sink/graphviz-diagrams","hidden":true},{"title":"Referencing","slug":"/kitchen-sink/referencing","hidden":true}],"hidden":true}],"hidden":true}],"references":null,"hidden":null}},
    "staticQueryHashes": ["3715292327","445096115","466146812"]}