1"use strict";(self.webpackChunkmeshtastic=self.webpackChunkmeshtastic||[]).push([["18825"],{82295(e,t,n){n.r(t),n.d(t,{metadata:()=>i,default:()=>f,frontMatter:()=>c,contentTitle:()=>d,toc:()=>p,assets:()=>h});var i=JSON.parse('{"id":"development/linux","title":"Linux Development","description":"Building and packaging Meshtastic for Linux.","source":"@site/docs/development/linux.mdx","sourceDirName":"development","slug":"/development/linux","permalink":"/docs/development/linux","draft":false,"unlisted":false,"editUrl":"https://github.com/meshtastic/meshtastic/edit/master/docs/development/linux.mdx","tags":[],"version":"current","lastUpdatedBy":"rcarteraz","sidebarPosition":2,"frontMatter":{"id":"linux","title":"Linux Development","sidebar_label":"Linux","sidebar_position":2,"description":"Building and packaging Meshtastic for Linux."},"sidebar":"Sidebar","previous":{"title":"GitHub","permalink":"/docs/development/github"},"next":{"title":"Web Client","permalink":"/docs/development/web/"}}'),r=n(91987),o=n(67008),a=n(87622),s=n(42506),l=n(69671),u=n(82374);let c={id:"linux",title:"Linux Development",sidebar_label:"Linux",sidebar_position:2,description:"Building and packaging Meshtastic for Linux."},d,h={},p=[{value:"Building With VS Code",id:"building-with-vs-code",level:2},{value:"Building in the Command line",id:"building-in-the-command-line",level:2}];function m(e){let t={a:"a",code:"code",h2:"h2",p:"p",pre:"pre",...(0,o.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsxs)(t.p,{children:["The device software can also run on a native Linux machine thanks to the ",(0,r.jsx)(t.a,{href:"https://github.com/meshtastic/framework-portduino",children:"Portduino framework"}),"."]}),"\n",(0,r.jsxs)(t.p,{children:["The application either simulates s
1ome of the interfaces, or uses the real hardware of your machine.\nDevice firmware from 1.3.42 and on even allows you to simulate the ",(0,r.jsx)(a.A,{term:"LoRa",definition:"A low-power, long-range wireless communication technology used by Meshtastic devices to enable communication over distances of several kilometers without the need for cellular, Wi-Fi, or other traditional network infrastructures.",routePath:"/docs/terms/",children:"LoRa"})," chip by sending and receiving Meshtastic packets via a local ",(0,r.jsx)(a.A,{term:"TCP",definition:"One of the three ways a client reaches a node, alongside serial and Bluetooth. Clients connect over TCP on port 4403.",routePath:"/docs/terms/",children:"TCP"})," port.\nIn this way, you can let multiple instances of the application communicate with each other as if they did via ",(0,r.jsx)(a.A,{term:"LoRa",definition:"A low-power, long-range wireless communication technology used by Meshtastic devices to enable communication over distances of several kilometers without the need for cellular, Wi-Fi, or other traditional network infrastructures.",routePath:"/docs/terms/",children:"LoRa"}),".\nFor instructions on how to use it, see the ",(0,r.jsx)(t.a,{href:"https://github.com/GUVWAF/Meshtasticator/blob/master/INTERACTIVE_SIM.md",children:"interactive simulator"})," that also emulates a wireless environment using simulated positions of the nodes."]}),"\n",(0,r.jsxs)(t.p,{children:["The following libraries must be installed before building ",(0,r.jsx)(t.code,{children:"meshtasticd"})," or ",(0,r.jsx)(t.code,{children:"native-mui"}),":"]}),"\n",(0,r.jsxs)(s.A,{groupId:"operating-systems",queryString:"os",children:[(0,r.jsx)(l.A,{value:"debian",label:(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(u.In,{icon:"mdi:debian",style:{marginRight:"0.25rem"},height:"1.5rem"})," Debian"]}),default:!0,children:(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-shell",children:"# Base dependencies\nsudo apt install libgpiod-dev libyaml-cpp-dev libjsoncpp-dev libbluetooth-dev libusb-1.0-0-dev libi2c-dev libuv1-dev libxkbcommon-dev libinput-dev libsqlite3-dev libbsd-dev\n# Optional dependencies for web server support\nsudo apt install openssl libssl-dev libulfius-dev liborcania-dev\n# Optional dependencies for sdl support\nsudo apt install libsdl2-dev\n"})})}),(0,r.jsx)(l.A,{value:"fedora",label:(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(u.In,{icon:"mdi:fedora",style:{marginRight:"0.25rem"},height:"1.5rem"})," Fedora"]}),children:(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-shell",children:"# Enable the Meshtastic build tools COPR repository\nsudo dnf copr enable @meshtastic/build-tools\n# Base dependencies\nsudo dnf install gcc-c++ pkgconfig(yaml-cpp) pkgconfig(libgpiod) pkgconfig(bluez) pkgconfig(libusb-1.0) libi2c-devel pkgconfig(libuv) pkgconfig(jsoncpp)\n# Optional dependencies for web server support\nsudo dnf install pkgconfig(openssl) pkgconfig(liborcania) pkgconfig(libyder) pkgconfig(libulfius)\n# Optional dependencies for sdl support\nsudo dnf install sdl2-compat-dev\n"})})})]}),"\n",(0,r.jsx)(t.h2,{id:"building-with-vs-code",children:"Building With VS Code"}),"\n",(0,r.jsxs)(t.p,{children:["The easiest way of building the native application is using Visual Studio Code with the PlatformIO extension.\nSee the ",(0,r.jsx)(t.a,{href:"/docs/development/firmware/build",children:"instructions for creating such a building environment"}),"."]}),"\n",(0,r.jsxs)(t.p,{children:["Then after opening the firmware repository in Visual Studio Code, simply click on the PlatformIO extension in the left bar, select ",(0,r.jsx)(t.code,{children:"native"})," and click on 'Build'.\nThis will generate the binary file 'meshtasticd' which you can find in ",(0,r.jsx)(t.code,{children:".pio/build/native/"}),".\nOnce in this directory or when you copied the file to your current directory, launch the application with ",(0,r.jsx)(t.code,{children:"./meshtasticd"}),"."]}),"\n",(0,r.jsx)(t.h2,{id:"building-in-the-command-line",children:"Building in the Command line"}),"\n",(0,r.jsx)(t.p,{children:"To manually install and build with PIO:"}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-shell",children:"python3 -m venv venv\nsource venv/bin/activate\ngit clone https://github.com/meshtastic/firmware.git\ncd firmware; git submodule init; git submodule update\npip install platformio\npio run -e native;\n"})}),"\n",(0,r.jsxs)(t.p,{children:["This will generate the binary file 'meshtasticd' which you can find in ",(0,r.jsx)(t.code,{children:".pio/build/native/"}),".\nOnce in this directory or when you copied the file to your current directory, launch the application with ",(0,r.jsx)(t.code,{children:"./meshtasticd"}),"."]})]})}function f(e={}){let{wrapper:t}={...(0,o.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(m,{...e})}):m(e)}},69671(e,t,n){n.d(t,{A:()=>s});var i=n(91987);n(71763);var r=n(13526),o=n(13897);function a({children:e,className:t,hidden:n}){return(0,i.jsx)("div",{role:"tabpanel",className:(0,r.A)("tabItem_q_8M",t),hidden:n,children:e})}function s({children:e,className:t,value:n}){let{selectedValue:r,lazy:l}=(0,o.uc)(),u=n===r;return!u&&l?null:(0,i.jsx)(a,{className:t,hidden:!u,children:e})}},42506(e,t,n){n.d(t,{A:()=>h});var i=n(91987);n(71763);var r=n(13526),o=n(66977),a=n(13897),s=n(42714),l=n(66928);function u({className:e}){let{selectedValue:t,selectValue:n,tabValues:o,block:l}=(0,a.uc)(),c=[],{blockElementScrollPositionUntilNextRender:d}
1=(0,s.a_)(),h=e=>{let i=e.currentTarget,r=o[c.indexOf(i)].value;r!==t&&(d(i),n(r))},p=e=>{let t=null;switch(e.key){case"Enter":h(e);break;case"ArrowRight":{let n=c.indexOf(e.currentTarget)+1;t=c[n]??c[0];break}case"ArrowLeft":{let n=c.indexOf(e.currentTarget)-1;t=c[n]??c[c.length-1]}}t?.focus()};return(0,i.jsx)("ul",{role:"tablist","aria-orientation":"horizontal",className:(0,r.A)("tabs",{"tabs--block":l},e),children:o.map(({value:e,label:n,attributes:o})=>(0,i.jsx)("li",{role:"tab",tabIndex:t===e?0:-1,"aria-selected":t===e,ref:e=>{c.push(e)},onKeyDown:p,onClick:h,...o,className:(0,r.A)("tabs__item","tabItem_Nk8A",o?.className,{"tabs__item--active":t===e}),children:n??e},e))})}function c({children:e}){return(0,i.jsx)("div",{className:"margin-top--md",children:e})}function d({className:e,children:t}){return(0,i.jsxs)("div",{className:(0,r.A)(o.G.tabs.container,"tabs-container","tabList_m28i"),children:[(0,i.jsx)(u,{className:e}),(0,i.jsx)(c,{children:t})]})}function h(e){let t=(0,l.A)(),n=(0,a.OC)(e);return(0,i.jsx)(a.O_,{value:n,children:(0,i.jsx)(d,{className:e.className,children:(0,a.vT)(e.children)})},String(t))}},13897(e,t,n){n.d(t,{OC:()=>h,O_:()=>f,uc:()=>m,vT:()=>c});var i=n(91987),r=n(71763),o=n(66532),a=n(98532),s=n(50191),l=n(10644),u=n(16957);function c(e){return r.Children.toArray(e).filter(e=>"\n"!==e)}function d({value:e,tabValues:t}){return t.some(t=>t.value===e)}function h(e){let t,{defaultValue:n,queryString:i=!1,groupId:c}=e,h=function(e){let{values:t,children:n}=e;return(0,r.useMemo)(()=>{let e=t??r.Children.toArray(n).flatMap(e=>{if(!e)return[];if((0,r.isValidElement)(e)&&function(e){let{props:t}=e;return!!t&&"object"==typeof t&&"value"in t}(e))return[e];let t="string"==typeof e.type?e.type:e.type.name;throw Error(`Docusaurus error: Bad <Tabs> child <${t}>: all children of the <Tabs> component should be <TabItem>, and every <TabItem> should have a unique "value" prop. 2If you do not want to pass on a "value" prop to the direct children of <Tabs>, you can also pass an explicit <Tabs values={...}> prop.`)}).map(({props:{value:e,label:t,attributes:n,default:i}})=>({value:e,label:t,attributes:n,default:i})),i=(0,l.XI)(e,(e,t)=>e.value===t.value);if(i.length>0)throw Error(`Docusaurus error: Duplicate values "${i.map(e=>`'${e.value}'`).join(", ")}" found in <Tabs>. Every value needs to be unique.`);return e},[t,n])}(e),[p,m]=(0,r.useState)(()=>(function({defaultValue:e,tabValues:t}){if(0===t.length)throw Error("Docusaurus error: the <Tabs> component requires at least one <TabItem> children component");if(e){if(!d({value:e,tabValues:t}))throw Error(`Docusaurus error: The <Tabs> has a defaultValue "${e}" but none of its children has the corresponding value. Available values are: ${t.map(e=>e.value).join(", ")}. If you intend to show no default tab, use defaultValue={null} instead.`);return e}let n=t.find(e=>e.default)??t[0];if(!n)throw Error("Unexpected error: 0 tabValues");return n.value})({defaultValue:n,tabValues:h})),[f,b]=function({queryString:e=!1,groupId:t}){let n=(0,o.W6)(),i=function({queryString:e=!1,groupId:t}){if("string"==typeof e)return e;if(!1===e)return null;if(!0===e&&!t)throw Error('Docusaurus error: The <Tabs> component groupId prop is required if queryString=true, because this value is used as the search param name. You can also provide an explicit value such as queryString="my-search-param".');return t??null}({queryString:e,groupId:t});return[(0,s.aZ)(i),(0,r.useCallback)(e=>{if(!i)return;let t=new URLSearchParams(n.location.search);t.set(i,e),n.replace({...n.location,search:t.toString()})},[i,n])]}({queryString:i,groupId:c}),[g,v]=function({groupId:e}){let t=e?`docusaurus.tab.${e}`:null,[n,i]=(0,u.Dv)(t);return[n,(0,r.useCallback)(e=>{t&&i.set(e)},[t,i])]}({groupId:c}),x=d({value:t=f??g,tabValues:h})?t:null;return(0,a.A)(()=>{x&&m(x)},[x]),{selectedValue:p,selectValue:(0,r.useCallback)(e=>{if(!d({value:e,tabValues:h}))throw Error(`Can't select invalid tab value=${e}`);m(e),b(e),v(e)},[b,v,h]),tabValues:h,lazy:e.lazy??!1,block:e.block??!1}}let p=(0,r.createContext)(null);function m(){let e=r.useContext(p);if(!e)throw Error("useTabsContext() must be used within a Tabs component");return e}function f(e){return(0,i.jsx)(p.Provider,{value:e.value,children:e.children})}},87622(e,t,n){n.d(t,{A:()=>a});var i=n(71763),r=n(37773),o=n(91987);function a({term:e,definition:t,abbreviation:n,routePath:s="/glossary",children:l}){let[u,c]=(0,i.useState)(!1),[d,h]=(0,i.useState)(null),[p,m]=(0,i.useState)("top"),f=(0,i.useRef)(null),b=(0,i.useRef)(null),g=(0,i.useCallback)(()=>{let e;if(!f.current||!b.current)return;let t=f.current.getBoundingClientRect(),n=b.current.getBoundingClientRect(),i=window.innerWidth,r=window.innerHeight,o=document.querySelector(".navbar"),a=o?o.getBoundingClientRect().bottom:0,s=t.top-a>=n.height+8,l=r-t.bottom>=n.height+8,u=s||!l?"top":"bottom";e="top"===u?t.top-n.height-8:t.bottom+8;let c=t.left+t.width/2-n.width/2;c=Math.max(8,Math.min(c,i-n.width-8)),m(u),h({top:Math.max(a+4,e),left:c})},[]);(0,i.useEffect)(()=>{let e;if(!u)return;let t=requestAnimationFrame(()=>{e=requestAnimationFrame(()=>{g()})}),n=()=>g(),i=()=>g();return window.addEventListener("scroll",n,!0),window.addEventListener("resize",i),()=>{cancelAnimationFrame(t),e&&cancelAnimationFrame(e),window.removeEventListener("scroll",n,!0),window.removeEventListener("resize",i)}},[u,g]);let v=(0,r.P_)("docusaurus-plugin-glossary"),x=(0,i.useMemo)(()=>
2{if(t&&"string"==typeof t&&t.length>0)return t;let n=(v&&v.terms||[]).find(t=>"string"==typeof t.term&&t.term.toLowerCase()===String(e).toLowerCase());return n&&n.definition?n.definition:void 0},[t,v,e]),w=(0,i.useMemo)(()=>{let t=n;if(!t){let n=(v&&v.terms||[]).find(t=>"string"==typeof t.term&&t.term.toLowerCase()===String(e).toLowerCase());t=n&&n.abbreviation}if("string"!=typeof t)return;let i=t.trim();if(i&&i.toLowerCase()!==String(e).toLowerCase())return i},[n,v,e]),y=(0,i.useMemo)(()=>s&&"string"==typeof s&&s.length>0?s:v&&v.routePath||"/glossary",[v,s]),j=l||e,k=e.toLowerCase().replace(/\s+/g,"-");return(0,o.jsxs)("span",{ref:f,className:"glossaryTermWrapper_ud7W",children:[(0,o.jsx)("a",{href:`${y}#${k}`,className:"glossaryTerm_x2nJ",onMouseEnter:()=>c(!0),onMouseLeave:()=>c(!1),onFocus:()=>c(!0),onBlur:()=>c(!1),"aria-describedby":`tooltip-${k}`,children:j}),x&&(0,o.jsxs)("span",{ref:b,id:`tooltip-${k}`,className:`tooltip_WjgA ${u?"tooltipVisible_AjfD":""} ${"top"===p?"tooltipTop_uMN4":"tooltipBottom_U9P5"} tooltipFloating_nLk7`,role:"tooltip",style:u&&d?{top:`${d.top}px`,left:`${d.left}px`}:void 0,children:[(0,o.jsx)("strong",{children:e}),w?` (${w}). `:"",x]})]})}}}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.