From 2a6e6401ad953ea5ff83e0be56fa17dbc94f40c4 Mon Sep 17 00:00:00 2001 From: Mollusk Date: Sat, 20 Jun 2026 16:27:03 -0400 Subject: [PATCH] Add Windows installer (Inno Setup) + GUI-subsystem release builds Package PeerSpeak for Windows as a single self-contained binary. The GUI icon, notification chimes, and avatar presets are already embedded via include_bytes!, and the cross-compiled .exe is statically linked (no extra DLLs), so the installer payload is just peerspeak.exe plus an .ico. - src/main.rs: set windows_subsystem = "windows" for release builds so the GUI launches without a stray console window (debug keeps the console for stderr/panics). - packaging/windows/: Inno Setup script (peerspeak.iss), multi-resolution app icon (peerspeak.ico), and a build README. The installer drops a Start-menu/desktop shortcut, optionally adds a Windows Firewall allow-rule (iroh UDP hole-punching), and provides an uninstaller. - win-cross-build.sh: promote the cross-build helper from a throwaway to the documented installer build step; .gitignore the staged exe + compiled setup.exe build artifacts. Built with Inno Setup 6.7.1 under Wine; binary is unsigned (SmartScreen will warn until code-signed). Co-Authored-By: Claude Opus 4.8 --- .gitignore | 5 +++ packaging/windows/README.md | 72 ++++++++++++++++++++++++++++++++ packaging/windows/peerspeak.ico | Bin 0 -> 372526 bytes packaging/windows/peerspeak.iss | 63 ++++++++++++++++++++++++++++ src/main.rs | 4 ++ win-cross-build.sh | 17 ++++++++ 6 files changed, 161 insertions(+) create mode 100644 packaging/windows/README.md create mode 100644 packaging/windows/peerspeak.ico create mode 100644 packaging/windows/peerspeak.iss create mode 100755 win-cross-build.sh diff --git a/.gitignore b/.gitignore index 3d44015..c6d90c5 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,8 @@ /packaging/peerspeak/ /packaging/*.pkg.tar.* /packaging/*.log + +# Windows installer build artifacts (the staged exe + compiled setup.exe); +# the .iss script and .ico are the tracked sources. +/packaging/windows/peerspeak.exe +/packaging/windows/output/ diff --git a/packaging/windows/README.md b/packaging/windows/README.md new file mode 100644 index 0000000..0efa542 --- /dev/null +++ b/packaging/windows/README.md @@ -0,0 +1,72 @@ +# PeerSpeak — Windows installer + +This directory builds a Windows setup installer for PeerSpeak using +[Inno Setup](https://jrsoftware.org/isinfo.php). + +PeerSpeak ships as a **single self-contained `peerspeak.exe`** — the GUI icon, +notification chimes, and avatar presets are all embedded in the binary +(`include_bytes!`), and the executable is statically linked against the GNU +runtime, so there are no extra DLLs to bundle. The installer payload is just the +`.exe` plus an `.ico` for the Start-menu / desktop shortcuts. + +## Files + +| File | Tracked | Purpose | +|------|---------|---------| +| `peerspeak.iss` | yes | Inno Setup script | +| `peerspeak.ico` | yes | multi-resolution app icon (from `assets/icons/*.png`) | +| `README.md` | yes | this file | +| `peerspeak.exe` | no (gitignored) | staged build artifact, copied from `target/x86_64-pc-windows-gnu/release/` | +| `output/peerspeak--setup.exe` | no (gitignored) | the compiled installer | + +## Build steps + +1. **Cross-compile the Windows binary** (from the repo root, inside the + `peerspeak-win` archlinux distrobox): + + ```sh + RUSTC_BOOTSTRAP=1 ./win-cross-build.sh -Z build-std=std,panic_abort + ``` + + This needs the `rust-src` component and the `x86_64-pc-windows-gnu` target + installed in that toolchain. The result is a statically-linked, + GUI-subsystem `.exe` (no stray console window). + +2. **Stage the binary** next to the script: + + ```sh + cp target/x86_64-pc-windows-gnu/release/peerspeak.exe packaging/windows/ + ``` + +3. **Regenerate the icon** if the source PNGs changed: + + ```sh + magick assets/icons/peerspeak-16.png assets/icons/peerspeak-24.png \ + assets/icons/peerspeak-32.png assets/icons/peerspeak-48.png \ + assets/icons/peerspeak-64.png assets/icons/peerspeak-128.png \ + assets/icons/peerspeak-256.png packaging/windows/peerspeak.ico + ``` + +4. **Compile the installer** with Inno Setup. On Linux this runs under Wine: + + ```sh + cd packaging/windows + wine ~/.wine/drive_c/InnoSetup6/ISCC.exe peerspeak.iss + ``` + + The installer lands at `output/peerspeak--setup.exe`. + +## What the installer does + +- Installs `peerspeak.exe` to `Program Files\PeerSpeak` (requires admin / one + UAC prompt). +- Creates a Start-menu shortcut, with an optional desktop shortcut. +- Optionally adds a Windows Firewall allow-rule for PeerSpeak (recommended — + iroh uses UDP hole-punching, so this avoids a mid-call firewall prompt). The + rule is removed on uninstall. +- Provides a standard uninstaller. + +> **Note:** the installer and the binary are **not code-signed**, so Windows +> SmartScreen will show an "unknown publisher" warning on first run. The user +> clicks *More info → Run anyway*. Removing this warning requires a paid +> code-signing certificate. diff --git a/packaging/windows/peerspeak.ico b/packaging/windows/peerspeak.ico new file mode 100644 index 0000000000000000000000000000000000000000..880f70d4d9d7494c9f9a43e1412f48bba74caf69 GIT binary patch literal 372526 zcmeHw378etnRYXof0E2R&tztve`XRDnx&him%Db;^a8zigMiAuFM=$}BC@a20s`WW z8Z{z|f+C397-Q6AjDHfNPBIydlDHs=8cm{3B%(xt^M7x3pWD^dRkxN~b-U``ub=01 z)vdFA+xykoD<`L0&R28(>7R1w+B0YV-{$13%*o05<~Lh^Z~uBu&M|t{vuEq?gOqOW zKj!2_B5l9(b8`MMHz%j2ruBFKx}2OR8gg=4TH1bpty|8qtyCcWq5S?m|2F6EZtRxR zpMFzO^rZDUU2<}$9e1tHac=I<==y?QXp1{MFfXrJO$YK0IQQJo`hM$M z!b+gDC)H&{a&r&MeErWkM=7JEPfyVp9-xGh-aVCPG7f3Oy>cIvG=zKfc(ETn8$fwK zdhC8Nqq$z}x?-|;{q8kNxNFHI3wl zS9vzJszOPFbjYKZA92WA9S(_TuUrx7nXB9voOfO#uQosN{}SquA)MPoOs+0X&_AiV zMBtf>#}#>G{kSinXEMCBbBVZj`BbrZRFk-TRHJhLUpucz#3P+Lf3#PxmkNnK8J^j8 zsd(-Uo7h09WoUkKlXsQcvzFT?1DOReBU|>>&5)xwPF@M`{=QQN*bg^9$9}$ z@7{-t=@|m)Rk`9m-m9k)^x}|5<}dHpZ)i9-_cNK!>`G}*B9F|ED}I;cT>Mf3z3ua>{rO2bh8(b2YKOV$d%=gyHfm*Qa|}LKl}}j6@`Wr6ilfa zFkqUMfV9YCMtfEN{v*l$o*!`Dd0*s{FUbGqH?0Nu7|MgZgQyI>dMf($yO8klabGGk zl~C0EypKSqwhprUpGjYt>NVD<&-3c?Ya)>d(f%d;qYOoab@(p)j*&mB5A_%4#|xE! zdptuN(jcwOhihT??q3WkE-sdJ)D#v@?5`>tID7xde(|e4w~Ijo`in<4&K6%heocpf zXNY@k?;T27yB9$h^My96U#=` zir?L{UW}})Py+7p?CGoL38azf6IUJj^~zs4re3^z?*_4X`f%~{#^YV*}r@+4O{#1vu{NCcd{TsydH!cyc+`b|ahkHDGm*UFudMBPI@={rZ zuXg)1C?B-0n>13Kd~}=m`0!@2aQG0ha749ok7sKpjuc^PrzFai^qG{8a$mXoHt~~N zuNQ;*_Y-R;G>cP@Z5JON+N1>BuNmL0#QpSE!WX4QoOGD99T6&d4}gl$v+@%jPl6*C`;`h8p*#!di3~G#^W08*^_wh znaG1@<$d#%piYN0NUM4Fh30+Jtt>zP1=QDB9_VzhHo2vo+$ z)rEzf-Y>F_vc7#^i00;g34NhmW+_lwsKtE9VLkE!mOeGMH$Nx`d zalt(DLA&W)ex#&t-Xl%|@}dlsg)&VmrUX^R#SNwTc|WIj^jXX8NR##^%0ihaI~fg? zMMaH-h)45GTU^_TVQ`$#`(W2!@GULU2L zvp;-X9KLFuXey11DGh_g4fDq<;rI8o2n6{XaY*yvru71OKsU-zmx+7SrB{EV9gVhb zTUc_@NU?Y26=GU*qw-#t&vAX__T@@YKMT=29clNiS}KrN9VhSY)Gza(+zYBIJJ9gc z8x{$KWNBoa`s$>9zVP8>Q&{vU( zd}fv(@u*9y|MCI-9_iFyK%YS;G{-~Yl{;4@aPaaSt3-3GSU0U+e$-{R{+gox)LzV0 z>Ui}!(%cdyL5Qlyq(i)Y6=T7QJ-|j~{E)(M`V@h4$UOWY3hJxNH0{8Gkh_o-6+H@K$lz@M@*5t7nW%q}?)ogz{|Rh#K+fBU{B2o8~0q^vcuYzk+Nc z(T|b+CDnC$?LeiDm)q>_swu+~{T|$de`%9bX{7eSE&be9au3{ zpr46w-^!_p=Z81U#aOCq^ziYr^fsA5qB&cpQuay?!oQGMOICzKPU4nPY(19gNIC|G=@%dxh#L-==m4JTftKV6bh(EGvL*o5| zGSp?_Ua$W00sW7t`+~TKuX~NgvOvSi@naO;Alu=kVeyMwmL}xz^IMmS^Gm{s_*E0e zDtTU|ym%jL%SByU{Z|ecuveQ-(m?*QQyGY>4;6^I&;Z>yE0^<}B3NtAr z#wqgX2mi4I(ky|NoSeU@i$p30heB(H6cyb)Bvf?JlYp|r;nnrgXgTUkmCc%(ny=AV z=Jtw$g4d{hZ~|>k^mE-BKhlswgaYjePaiVR?C9b;3t|INWz|QQ^yl-OoF% zttVZ-X%6K}&;VNO@PPDHg#(UZtR&gES32TA185l%iO>om^FP>3RdLZP&}FJ)T5jbB zErW}TUbbROHR0mzG>7@6TXnlt4z+PlSBHwWCeuI*VV^nsn9*BJ^MLBHSDAhytzlX;vN{nkXN#bIhBPw0yrL|W zDSsPXK^w_f+)97!%aXi)WA#>XG5yL-&YbWdoIP`KX~Z#$Lr2;U7P^M_Eg=YRW`q z&5Sx;-jA7C(c&IMyCqAP!7YMjl)8T}65J0ZqX~ptgh+1p4smLl?A%+TpZX85GpB*t zy5hl&^Ax+6?=7r7I(+3kdiNAKE*JEmZ(}O|6zP9*OZ!;5q+eb!f8bOuUeFJ}GHFOj zf+nXpH&_BJl zOrZgEVDHLXd)F(!4-pPzo$`ujNQX3gmbK68O|2Q&DXq+-y;`9keH`e?YIyG2g$iAN zCEDI;!}DRHRhu8rKtIwTE$)A~{jyH!wE5J(L7SQU?b3fid0hPI&}M}m(1h^lm9sk0 zg=ekt+m-7dAJ`-=q`YeS% zn!rE$FW6UrGMCd@C`qf{)e8NXOVrK_%ik5$#*}^S*8bz2qBasvge#|xOwj)kt-r?J zCkqrpz*_j`S~Z*dHi%w z^W-O*l8hg=(AX%gM?dPudH^rVs46Nv3L1^%kLR_aq8((Xr@g2@l`?6a(HR>1+@6ef z#Fdwqf4!RKFMyR)>T@+O(K3YQFEF=aMnB?fL!o|yi;9k6pOnG}cy%R$|s!7lAmN3f;ZNN5L*SsxwPH~$3o{9u2yT{^6$r!`2*z9QP! zasqyY-p|)qwHZmX-nE4=Py1Oa@qVE9-|m`l=%5z?W!FVQ>rfZ!)T4!;u>{o%gxE5^+vSfsQr2zziFjHwp_LROSwonNx6xZ zRylT(Z=1ZaPOF9jC2L=&g$Mk{5?~3i1X7ehO=;;jv1X$o78^}rZWo2oprO93=-*Rh z$5QrT(dfU{MZ?!o8|`)Kv%OF4!4K&SjZ;xt@&9Xy85@bP zzPm0Q-bQWqcWIBnX{?V+*IGZT^?)X#?JUvw0kx;MxwU>AI9f5Yr~;qPVoTyp+4q+1(A2DCmN$88HE2E`0b=z zlLzo~@jksjcYCd3y2}F=;15jL?GO#SCqME&*0!aaUbpL0*5`$bf8P`e{aXhnll-9Z zjT>l8_>9}MbX9r8%W1qDld#+&swNVCBNKEl+; zmj}-V_3QT`wb2J97&W+Qh(^cIIfbW;%F#Z*oX$-6^ob+NJlS8q`=D5K;fM}&56tT& zK5AQ2A?FLNT#*NP)%BUxrB188FUimQ9DNl7wiAyVW09FL)%hLTa@4<}3(32jKgDmX zOTwCBgfW$I!+BFPIUuhrr>3|_eEPkII?U5T-bOa3rW5zz3A`m3HMp_EKWtv|t-h|C zF-1(K{ogViTt8R5zI%O#@bQCN5^}-4HXeCoeq2$ex(;~{8nnFX{kF}&&N^|qURz$V zzg?^UlTSV@Xg`T^rXbE0GzyPg*?!g`?v2vP=QT8cjwRxQwKhkt7Kby(Z0 zUgxX5zhcw{2^pLu`@DJaWuhUjzph-JSFZa325_&A)4Q*aMa9m`7YNiLc{e(*MK3>i zvTFZ!_(xqOWCvp^%atqWguR-{zz+ZFGSzkI@oDtTOa8TWs_E6n$=_D_w^EiYGubtr z{DTfNx;IX0PWV6E>(OpjhF%_{XX)nOiVWt_T3rM^n%(3b<#z@DR%DP4-tF>VLcY?@ z{sFVJYF)aS)~qabJb1F||J~*vbf{%eNb97re`6J$D~o`8JX5Dp)9%K-E&k~YHmhs@ z?WC)xcEQd?(>kn4m2Kd6_g^V)S~yiSl*B!$yM%bMtbdRAzmwJ)N`8&5x6^q^c4TTb zZCCS;bC|U}<1E1U?`vP5EaR74SnIkB(#1c{vtB)}Q8Y!`_cURxB+jCi{JleGNiQDV zoao;y88bAo=LKo7mKp1mrEXCc%0$`nncb^h{>}Dm7{%j^Meu;N&EEIvrs`nc#Z95Zv^VIVbJiLDQ z+62FnPALP#NnVi$@he8xC7wY(GLPMBy7R0sv709@*F%_ zZU3dpKfarUZxl#gu-8Z4Tjl=`2d_%xL0RMItW+y}8l_1m|Da*-^63fsCGWUe@$v=Gg6gt!NneDB6Al1BJUoU+7g=Jw;N$oj=i^?L(vl9=skBQ4XPj9*C?lIo zMx%_g#XrgB9l#E8HA{o@cz;=hn>W# zWD5T@XMCof)^jFdxkD7zKhk=G_cOr;zyqB<`g^;31RyWkSAHt!HbC#k&+8+RYdR>{ z!Vj!}u8V|!LF;GFU<@aSfzCTVLwk(>+sgU0dLqG^Sy~JGcC=6Lz{vo5BifIpx(5I< zAUpUa+7DLuOLt{DeE*rgSM@n)PL+3Q6R;oh2iL=o(085BppLHOQLk>$RGOD}mi7Vt zv6g6cvgTj%YjlMz&^Ll_B)fWp&T{yG&I0?8*2?~s_8?I^ybA)=4H`fTXreXFH`rO{ zZp5dR=V&MTW&fMicAXWzI1NjHC6GN5Xgxn5$^X`a2ZT5dnS52?+yR_CKu0*>PblXR z&`AzTGCIjYUX^nT=tKwYRXN{)PI%y}BEL>@(8^2xmU5L>DR-%dgkFxLT+)-0usVri zTcdDJL<_QXQ=JomANUG<7Hi@Fc&JuJTVSQV*Z^#NVgY4Su;2o@Awj}&6OoaCr(fJf;9zwni>w&HE%<1&c z-h~Y5dl-rxG{hp`$NH2mRIy>zbY#1u8 z&b2yQ$++(tpC|o*(pOAxdjRcxwDqb(q0=}sRlz=dKZmr+0J5k3f3ycI@)7NWJ2wGN zk8h~G_cYp~XzQ`gyVmXtx}VoJUKIJh$7)xKr~ds!ymv5;$GY!Y-Ano7ylUu#aA~>^ zJQW*h9n+1xhjA&TtBbXZ^#^`Z(Y`ALyzv z78}(;i7EV$bA0&Th@W|9+PRNf>vlIG=k9#zrF=1#d~su)*fwjr z5@t5kDraI_tux-cr?_kJc=75TE5xxqYm4xW}_(`QD;3e}2mq zN*$=nDqX4aWwjo4I;<(hy5bH>OyLLF(-EvYP}kw+{iN!_;@Ew6cRF+RtpmHn#35Ct zvMxC9T=8FYhQ9XfO|O2VF4SozgH-u4E8i%d&Wbus`ahh4$~$Bw|NnhDJ5yQTVN|En z=aXv&i&IZM(n~lFptBTI-XW`3 z`oFlb-c56fqM0Gfna#(y(gQ5Nr=SCgN#*MMe*G%g3W~=_O z5AgW?drW2Z&Y^vxkjAy#kkizfQbYYC&W$?2*Sm-AG35(=-U3SNMxE+1yu!cUH;q$$ zHl?;YY5(u9Pd_SJX3r4K151@}WTsl*v?TgRT&m?Ge`9HhxQb{7?Xvxhny~KlpY_zFz3xE!wQ=*DPHo>fbFJz&FZ`#s(2*CR=U1-*gZ9GFAU>*udZc`NHTs zm59^oH`#AL>ORx;?}iN=STVJe55Tizy4J?|RrlGT|5R-N-_+eUV}y9&rpuLpdpy(X z*yy*Pb)PNzPt^vDbZhq9@4C+>{ioXof}s0s(|@{bASk-`QvU;}Z{gR_q#Ad{IN?y5 zFDRffA~)#uvTQf#)0W{?|4&XwO_R|NOyX-?GW#>81l;4<{9#o}8t`aTMiBVVcKvJhH~*sZ#Y0!l z5hotHy3@Fib}aalBU{Ab^_Pgb7oMM($5q-AWIsXBJ!oY8xB4ky_>L=Ph)*o&U26w_ zK616VeaVd0c4UBb&-!oGeG%;~v?UkFfkGK1Z*0x-8S!pNz;~CbVCTlaIZ-_AjJsSW`pba#F zR?w`ME*;Oj&_8{HL>W)Vn0h*c-n;z2c3z>JMWdzTvf+ab@%y74mx&_k$6=n|NdJgK z8t6~H_qA7y5oznixj3Lnn-;Wd)28D$bmjK`uddSnyZbkEk}Kpqueq|5Z0}t@MK>+d zj~Wzd)&0Qs_4(5G%WE^m!3M^ZM-9ulhx!#-9fB6E?(rM6YtyFVcc$n++OvnQTp?Sm z+0n}K85+mc)59BguTj$Kjp;V)%p1Z6aNdhvS*Sx>@AjD^b<-k0c+jTz`gf-2A9~PR zs|mU8oHx3YT>t0W`t3L9Oi%YHAG*+s`@yzLb#;n41FimUy>yIj+Rq=`ruY+Wdar+H zivA&|j}LFsl`VX|R*t~A9%i53wxC0M599e#_p%JF4LrSVp>A2ym&km$9$49VJt^ow zpHZDIUH6%!|D$)U($&Lr*DmNJTO<8Hcl{L!{p;yo>P2k>$fIXVdipnNFTQ%`%1$)O zy1cw*lK!9EGFMj*ACX@urv92*j%NB#rh8eAv;nL72MwS_&sLt;G^Yc7vJS7WnWX=n z^GEB-7V;ij5$zz~Wcs(Fd#M-LfK~lZsEQlXce73#Mb_cvHIwu|y=I`He0R}!i&~CG z`p3Im`@UD_)4NBTK@Zbf|Bo>xy>xgsh4z!_mF@L2&-9P>a+*Vg#@md>^FO%1Ma1YV zPDzuI{vW+^b|Q^TYj#B*J-sUWZ<7J){=-52xr2{s4kDaOeZMrz3-x7^{=v_Ybu)E! z0sU;5K0G1gxA*Cf6}hSZ<5UOEB>-Jpll1!!6U|+r`%KjTjQT-_`u`)H-CNl|U+KgD zj^_0AFzcrNQOD4-fugFQuX2X4UVV5ry{;_d^pAIFR|L$E9*O zzg@bG{6Ffzc<~Q+7|#*>57BD3J~z{Q<^SEJ(Qa9n(|no{*6@7S@{2{f^uK$>tfaIo z8d=TyciC6K2fRr8b&YHQ-jK-uv+w(VGuFNCbt44M`x()8;lQwMTXR$QC@WL-58keueW9+7_4F>E zxv76yrrveOtP8qa_nEGLjN`p{>k3;okPiL7c*}AzY*1O3`~FPUznrU|HDajv&F*!U zZQ%JE7As>hkd2jqahvC9U8o+$^`0HwwN_kAG@)OBz9HHwR_gI8O(yz(se8FrXMF8o z@hke)kDfmCp8bKw3gHJfP97$v*OrN;qgNPDR&EgWk8g@!GPF@#bID94 z%x-Q_zB6tn*AV&YI~R>NZ2Nm*2j~OrqrGJjs#~oGJzB%`U2Z+T)cM@L51Rg`*45~K z|Lb=T>=iBaJviy}CGPd)bt&!Z{xhx5_Cnw4GXG5TI#>g&M+2UzZ2;$%ndG98%V2bcGFAIse@&8}Lg1SR3zV z2$RpZ^8GLPfe86gv${)YKK3sUoA2>g<&pWFUcKhah_0G&*yZoPM|RgmBVQWT=f-pR zOtc4fP@ez+_jY~08672kdWnT2s>Oc#*26Qjzw_nWmn#AHc(!1~5P>vi<=BZ&2VYux zpsU7sbXSLuc&G5AAr@O#AB&#Fx6HJ4@o)F~LvF|tI%=SAkT=Amt5Z;UhphF{=vb5) z#n_k2ZB;JMUHggl>eZ_MSZs6$C8qGBAs+7m{g?Gk{hi4Ac30n8d6xCfSM*;OjpnAH z@=jSBqLJfOg$2r z^(`r?yHobMNTdSqfYQ7?*1u2v-@yDl#rHSG<7J%`nEHcmZ6g@Q&+Wq3Dggq3m*{g-J5-Y&wN06HvUwf%P9hR5()y7!#_pq~&&-l-3 zpG0jkjQJAw-yK(2_;;ym+PH+qXmpa&7tGIRAK()VpkEH1G{z(2j5X(842=c;fNbq_ zl*Vkc8h1X>KgO4-&3~H4=$>*2)|G7V$%Odb>Z;2 z$+hNgY(qRU9CHFyMTKXJX?`5z&K%Mx1Clw7^_+zcXsmCTyV|u@T4OA>0Pmfu0vZ=& z8%Ur1ldLfo3)#~=&!yJ1Rb*ax)XUeP_x%X*_#d!^RLBbUJs z)zZ5tM)OZ-6L4@}254_n+v_yx{w$5fTwza3-lj%-fZ8Gdi+({_zrG^OHsBftAWO&; zvTck;K5i_DobRnRot55HTH2j#^BMRiv`b59Op5(LYJQ+3uTN_mAMg5T^cnQMoM|V0 zxiChAaYDroXue<|jTK>^6Wf9{TY#(v(mX!qS|CI6tMApvViVG*!PINQI3&$O&!Kj~ zn{7Ot!QAv98mo%+?#1??dOt$nkO{`|l==JCIb7iV4I0zC#OpEL)U}x!|qd`NMT$ff|E!8>H2mI=Mz-=?EIF4n?0;|K2Essyd}YRdqQzxgDxkekZ6$ImE$nb$LXP_V=@z_zu5`V6)#X>ionI z|5gcv<-zu#GKUZbCx5RNi1I#A z5vaT`R0I(@9UOixeyb|1#_#q5mEu$!w7t)iM1J|#AL8gn;csy1iC^^hx2+fc&k|q> zumo5FECH4POMoT75?~3i1Xuzr0hRzufF-~ZU!1wMO;_+ho4o?HV&q3cgoPlqi()X=a z(RVkubI4p7K*!KEbPnCa24D-Yi8PxbSC<9}G{@uLs*gpc(D!(5qHhs>kFb4=uC3o+ zYx`am{cio{E?=`*4rkhI<9o0b*bHnZ4JOJ}xF~`0^760Kch*MZTWf^t*BIOE+fuZF z*T@Y&s$xoE0fluHt5p;J!lQKi_~v#w=^VO;4Zs%YTfA1DV#%6_Umcn=XR{~)8mIjRz3;Cl%%9ZazBUq8+I5B9yYqXEG4F{D6!z$@*cfb0 zYk#mwnoqb6HfqtFIhl0{bfY<&sU+j~wQ?U)Tr48JdWn4U)%AMQu}f|C4vQQv7DS?pn+C$Q!SnqsjyjqAUq z#y;Bmn44i+YqvF)g@0uMTh-|kyjd5I$E=|sJ5woZu{CpggZlU5IXv#G2hR6nYyj<5 z^?Qu&KW!|DoS&WOPR@1P`2H7CUUf9bqKxaa?FY{Gxoy(kHo$Hw#S$3gZpIhqduTaTF zRMVX5fOF1a%(LIiC>!WcK41v;8K}kvv)u>Kdw(*?Be55^s;E%(XY6N`-3R%-?KbV0 zAE+uQQ2T(hjj_l~{WoJ~KgBo*VL#E|A6!@{ARo77&gF66!A~}z_yBs(soDWw(0Kzx zGaKz4xoe%{i+(C)fOZkT_Zg>t!l{?Ez}Blft{MC^TjmC9B9VVm&+lWbZvgd;yp%VW z&A!ENHUOK~j0wJ(4SR>^oqt5W_v>h0L>cEtyPpHgAj@n3>x3}RE%89(frmS`lr!rW zotLm!@`@|w_Zj!>`?A>v!h``eCNg!uK-)gP#9p4VezdMH%ltj_%f3#}2FhrStI7wQ z%D{bt-Dof04<(OS&##R2Gyd5JvJEI$045|p==vPB{4?hK09w~SUGj##Q8=SV&kyo5 zem`cb4FD7BGf3Oc5DEMMK-*s4-%I=t#2#Mu`78srflf96Y)G8YJM#m~l?B}a&|KdQ zk|)e}^uzi-);-IBZJ?7402}HvL~x#9knvw%R`lUF`iH)vN7@K4|7{0H^8Ur`VG1}C@uSO#nZwrv2|k?&Eueljv1 z|9ijtfW~-aoTM4w;brVQ^ZhJ0mK$sU7?OCRy@8|rj{k;u^ma*aDSZot?U?PDZNRw= z;M?O8PqZiC)&SuDHX(G1kE#jLIX^D+d$PHV!tUpZ1tW%teM={c$6IE* z8lK&8nK=5LmEw2ztXBf=@yzXdKs$H6^(B!;zu}+GDjO^5t1KAcnXcWItGc`pt+&2@?kw@i9_(@5??q^-*4}KqG^$&ZxDUYBpotwtBxV$TYvxHy|%G0 z{lR;O?-j7eRO#6^b412sU-|&>n5vxoqOVl>u#>;6U;EkMe*8ulz5mxr{No&RJG^ye zTC^cw-gT>E>`Nbjwgbvag_j>+w=m=J4<1vIk)QOH3Lkd!mZ`oCP#=%1@!k7B7Hg6C z$9g5Z{B>3O8|KeW8T--)U_2ldJ~C;{PrmQ9SMZpMjQpgpRQRx)SG@+1#@bsL|IX)A zrR)dh~vjU-@j&)V}Il&-nC^j{@us_vHR|J-Jag1xd5m5pE9&bymZ@& zjP(KF4LmxP&wEFl&(Rq9ZLI0iV$F}g8UOC%AM5&z?852ulTSY6*uH^_OD;HH9Nm>U zYyaf-swJ-NTH37X}kCCYc!j$NV4m|M)z3fq&R&DmIS1(}y*Q zgX`yt4-an%d|LoKfEVzTs$9IlKWxD7b_)7RRr7zoAO8;s{*T|k$MyHgd$f)yRXdmY zr&3#a)s#_U$Gl16#syOyhaca#%(fpvo>b}t&7d7TNPbeizJKI^>-u`@0JZ;p{+?p| zd()P9`datL|6aWFX4mXJRlLajhc?W!jeq2k`TcTziDc`vUuKjK`?(nZsdoT^*#2KP zdA#fPgnfg4v!|Qpjkb+{HUxWKRCBM2qDrlS6~mX-FLk<{hJ5w7Bhwq6C*0hMFH8VpLoC7LHi$h{KNzN>hOv| zVkXJ>m8uFeLzs~&)7G%amK%~ zY`pNdPRjJF{RRR5ewCdQJMbb8qzL#8BV;ld- z@ByXt?QML2=db^7}2x zQ+6ifBa?Zvqhq(yGX66U|FDfr#7QRd4`A$jW2cONZ{+IKAG@6| z6L6CWJh-h_x5^6|{s*9K%fXfm@ZA8MaWBue)Vtz5!9q&sH`xZ6cE8C|j~>QtW2#&lvyNfq&Rwknj{FTK$Y~Gujyc*@OR}_yER!`fQT%pFUZe`QmiN`x#$; zrY&9iNoPHb|Lns*?8}ch^CL~^#9~*}6*&B3jGBWhGAKCjJo9;h$_i0P>5ODPctF0G z-B=+uO+8=iT{>ADUOPj4_o_>jfO|Yc9MV)#TBCB@pv9P`v))3#xu&)>Q=I%9O%k<%5baiF&wFxF|kaXZAQ|n;-GyaqLfN8^;#J<(D z#fOKtxQ2VJFZl4#X0d1GEP=YTYm-JW_7m+SFMJT=pYbp4O4|o20@lVppo&<_*dI$q-PKD!%|5`x`EJHP;~)4B_2@31yLN$Zu&?$3Xp=}E#aDOjmGSSc zJcDST=<|Qi2W@_ddF>T_0nivk+4`Mk#y{i#+FAC$yes5C;i9W`E z_TnGwd5y4U=Q-B(zp-b%cznwO@ttKe#nwy4iLJB8DEE(Fy+FK4adyf}mUi>B^BMmx zwgDLb*@^#H@1Ej=`&&}N<)@EsRWQF~`~`_Md)oE8^7j=JE)?IrdZ9S^NNQ_}-oJ07 z@*UA2y<`1ME8{;q@t^9uAL|5W53e`Hy~Mw~UNWLV{OqR7Q}R3925`@28UOCd(knlY zH8ATYG>JoNrYrmE?^!lQEE-uYiXHZaF_(5Mg?)VYE}x?G!{u6GiEXnh))gZU`tbLy zoaWdEVBerqSwm)!9b|}kMaUGg&DM2BjDLUQf905Z@zLQ;x>z~3cb%AAU1}Q($djy( zoh%O6S7Xnr50Kbb=RL4;s$)7ZZ=o*B%02jo%=Gw!j3H|)P?ow}y?e+AvXZHu~>_wFPrc`YEZ=T zygbIl%4qGrRU3VM*J@K7Xz_94;j2YsctD3btYTmK2KWiB4`_}Qh`&5+j!P{)I7i4T zzmN@Nq%A}5H}*V2_EyUddOF6xKid-j(K6eTy-FLt=Hii-Y__@}-&VP@e4N>(wspJM zPv!$~Mxd<6>J@X2ID1e{lhHk7W3^nQgY1pU%CzTVkLxxfRkrhfM;*f;r}n8dr@btIkX10E%ohDHmOI_zK+X>q2gEF;+!vawS(WUr<# zS=m94WBmIM{}p}v*s@pH_S<{cTEfEB)6B;dv{?D&ZOam6Tfsig?igX>AGAK;mD`uw z=6N%nD{KXSkd2lnv)|Bxm9m4LhVkz|{13|SZQEWyJhaJ@y*g=Y?_M%dDcchE+urSV z(gH&m&ojfMHeTB&F~XwJ{E4yi>qzX%00%dtk~s|bu(?3 zy`JXB?cy1<*vWI{q-NW6;rjwscy@A*8FXN!?4YM%{QD38uqi8ZRa(CgrE@aO?D2b> z=GeyB;tOhQx924tR(-${szb|<+3zQa7g>+dHP$QFcDb1AFe)$8o-_XaiGL?+^Q#NY z*GD|Fb-rypv`oJ!>HNO7FR#Uj6(4Zbj8V4f0x#OSw7+YL`q?h`1DY$;mXoQ!8UOyo z|Jw%Z)RMgur`432+N~4(@0dTy5dUV_m$)(W0jMJxZ+dZ7@ISqFpzU(;jT1?Cre7KV z{>1-}ud_F21$>~NZf37;;@>LvB~8hEfLHi;GOqBW9Scn5D0vF{mGSRS{9~QH-a9YZ zvt5@@FtuB^@NXCU5+_DJz$^S??jo7Y^y08STGE^8SH{0T@xO)6xzMxCWY4gc-ppRz zz`s-MOWO2&fLHi`>E=XxZw*;MhLD)uF9 zS|8vA{!2&}I5#kv&(w>XO|qACX8M)!?@#4AerqOGkCVPgtYkbSc$abCJA9M3w?uUU7z#4;OeCfr37b8Bge$VQjUv=5{ubO69 zrcqr%e$M#!FaB4IuCt8^*z)|Lm4-I#1pk+vKiIH5w`~7XszZ%KEBDFpKYv)2?eb9P z(u-<6=hZElxlvA_@ZXR6W!N{GC83)7p;mC9P4ncIxrQ=wg8%uzzsE919a=ujek=Gl zpbIiE%dd^cKIb7=LupWECO$7COv&?gaMq5`j{nK&aQ;u0;UD()%WvD?7ki5A`23P$ zT|3SO{0}GIAprN2a}(9=0m!SeKbguT3x*G2{0CtC4|B!Y7I5bN8xGFwhJC+t?|Lz@Zg67%t`q!Y zZq93&JDL9jFNyO-8*0S6_ik{6|KHGA;*hb|Jo>TxpuPY7D8qEnv}RnRBin`#08XY1 zZBnq3iTDR^Kig@4o&%*aB{(p7n8gatGx5K17Ub}N;R=@ih z|G~mP^fjesprdc)NSntQ0rKAJ)vx$>vMxgMjP-$&hLmRYyPxqNJp4mvhaH^ZFYVsR z)vx$>!i&uF!0PE)kA22}F!5hS-@W|9!4})^acTQ@ubGDbKiuCUs%Whr>_6KBkN*YJ z2Idc~N~s@U#|LB*{;|go`C*S$%E8{rC5 zCZ?C;<(SX7f0g~SPOb3u>7!dk%f;h5U|-6N+X0M!KjU3ZTQclRd){>M=#(0vN9k8oB?b{c6NMNrle*3`y2mG>~}&{Jgw`4lHsr`;yygINldM7 zU)$?MhM9tIGd>vq{>6VPc8fOpd;6W8htU<7b*oOCcQUdx)M<`C6A7E8qLG}fV zfA8@h>(xu#IR6rH;=6~%*&jZhG<@>-VXX?pEI!*{-(jLdw%jNvp^xq7)}eO*6qmWcN3X^RFuy1L>S4{UX4So4_Gi}l=$$`gO2s}`@{DN_10=MCVc>8{HBBVzSNVvqOAwrYh~`&-$BCvAo~6%zC#~`aPwtz zQpUctsXeQgiV%(CxyAQ1Iz!CPyVj3sr_lVqTk^m@fP2;~b4_12(0G7bw0T_)Fcp;V z{{{vBl_XOuV|^0eW><^}mSbMPCEo{o4{{&itvzd%v3|GY;dgzx#iw35jDPpr6YFUn z&kWOcl*%H2is>j`>wDb+5+2%c0F5m`YZ_ga>|=oKE}WM_{sxl;eS^TrVCmRDAs4mcaD`K0Lfd%pBhAsw`f-W2fu-dTPgJSACQjj-AFc{@us_ z+xOX@KQhDryEL|(3f}ed-n-@!m+-$`V2}MDY2Ez?2d@$z9@?ygKRj?1olUYyiTmPl zch2$Ix4QK^Mtb}>efHiF=W{ehdc&G7r{uuCEhMJjnRZN&T;ZzDX>{C*i9wU*q@S z1^!{9PTz0I@@+c9Xmkn{{Yx3fBf&o zJ8$;P{-;nIIF;{bd)+>G{^n(g@0VM_v)wc=k!+pz%Z&12KNsUaJKO(PPMzqwJ*}HO z-cx&u_wFTrcH`x~YX^WP>|5{>OF`6^Tk_!dzx(h1%KrTY#(#|74R)VnEm1{(@5ep{ z_3h&;AMpH*i)lY}A5XCl90gThZukJkzx()yUT#@9&o%sG@30%Xwo(S#0Z(5&zsuVJ zPi~&;`Fme2kD%&H&4ZJBzvI6#7FnAZ|EKq=6CS%FPrOfW@#>!2Q}zMaLlp1bJFR>d z_vj(E(wQM%oy(hSya4Bv+(Ku0gouW8>Mh9nN<~iPgei%y`gmkb>OFRMOK6Bj7fJdm z1_THH&`CY*2mj#6e#brldxz^n#c9QX+Lo}#=ID1;rmZdT+MO%KB<$&uDU z$_Y~vUyZTY0(a4ydTBKOf3c*mvS2`$*@hF@B2OKi0r0YeeZa3#+o3Vidd|Mny4}bZ z>6t5b%({Tq@m=MaAHaFw+h&dwVXDgwno}tw==!qDdu3rk0{`@`ot`>k-7TR$8XYU~ zUqxpt*yYa;>Cv{_xnQoPF+q&=Vec^V_{>1ET|PzN3<8wpgobqG$pn3w$!Z9- zPbI$UOCpV_Bi7v#nxoOMq^~v<^0mE~$vP9`Ym54ec|)s|@j~GG$hw*0iA{5qfO|Z{ zJ059ji@cx1%tRS`$x{uDQAvC?#N);8qBr%@%FD~YPV}9TGAP?oDd<%)A) z8ln-2|1&i;HD5~|vF?{Z*#E7>f0)i$W_$9dJ+WSbrI!d{N#d#@9zEtha@{GhF&ceJ z(pl2S`}JUK$HB5=)|WGV#q;{K<3ASto;zrDzZCLKJ0<=H(KmEh-_G>Sa$~uvZ9u*D zuRa#L$$jLyQzGUiCH{jx2cVWe-!mS&(gr$={l_9x+(E1RrBM6-9EtyW8n3{(MOVs= z>t^`}-3Bycf1)lNKG%KZx>q9M|8?mDupS=tb6^>;4LGv_tZ|ZfqU&q!A=R6b8e`Er zB)#aju-={No#n=IgAJ6^esYN?T4Q&cH>h>5)W&#ZoTRsw)-13cvmLVyIJbcg>waRf z(e5GDo06JBp?_$IMNUW`5T$RdvHqRwpJkW5vcvZYC64I&$;f#8@4Z2-yQR`N;9f~L z_5!mFXRi&j?w#u%*pWD*>)r06)VtCM|MimYI@%k{HsIU_Saw+|JKA$q7fG!76%8ek z8t)M6ZpkeUZNP>NloDnne(3sJV9H&TdRrQe0c@1?*U;HG z{2t5F_m~ZvXB%m^ks8`VEAi79k6!65THP8I55W3u*DuS0Wnp9kns@&v z!;6dm*?ok1Um~3edX4m9HO1TpFw!?aXJ4SUfof_mOWe>{+E(w8>P-#xWkvr^e0(N( z;WhxmInZ8#rL-JK0 zi;5_nXTtjLtbdkC_R0j9kQl+0&iI|0K7@K+Q#bNw|0(&y_(q85h1dtO4J2%!T6MlJ z;p90&WH--InZ^p5N-`>x}5PDkBW3>ct(_n)c_hYQmP&9qfTdjl_* z_{SAvooovoZGq*HUGl)3m>Ltb$9G}c0Ga-Zx)Fa5OMdIPo@` z3I8Xh55QXIaBeQ+pM79f*g%MEy}H9ZfAnNiEEew?G}g3n8+4is9>MIjVtY4vHfUt zR@b7iYiplwp0LaL-)Dw$-*y>w8ypE&BXXJM{%tD!!2B1R)=s zc^JXDff;54%ujZ)Nf@lL+ z?AuUPbSeKa~-ZTo!RDuK2!!Nj}(d_g6xjS4gV+5ZL2256kGyyN+uXxpA_h)0Gq z-i;+tABmLG9-+5oI{;Ul9fGrvgXsU6=Im>?z*ceQo!W-6<|W(a_>57WJZ4x~**{YM z=z$LMlWhU=tBk4a!&DG-jx{XU-;O=59c(uqeI%%7cqK=wr?K7I_6sET3_+$iPaJ)! zAlL)bm_2?9Hi`3XI^aGQJw^Lo7kP@33@^NG-{5l^xeDx;WIvES`0}eSg$;IU>(hIR z+5kVw)O~zi;BvaPogwlEtsj8wOY`%UwS#`O5vD8i{1j|X5BE5?hr)EiNJj17?*hzs zsuF#uw(|rNXNpRHfW3s+M;)VYjx*je4{v_ZDZXcq`6$?$v^&+6Y%+3VrkvT;34A_! zfOCag&lYe0&ZtTc%32GI!(eYU&mFQaaOyi?JFp?xl4kvm3jdK4utnIUk06p2q+q`! zzKufIPkd`k?FVp=bwopG%{9KGj=mb!VmY-3&X?J~1hxSifvv!1G<)+^m{-R4e+S#k zmOZoDhmdP3JO@S!6EZy09`}p(ESh^ zM>c-9Yv%FjyY{d#*cxok&zQ(o+UR=;|3LGG;~HbpJ7~?tZ}hOw&$M>Uzm07o_G_}E z+hJ29cyuAGD&CzJMz9iBJzfOMPVw}53I$y;h^JM^CL+8*vYyh?Zn=rN*j$sL~ z1Xuzr0hRzufF-~ZUq{5d&_0?gtK)zhY+RO1cR*QQ{v!3fg_!grC7RO(o zHOjBRGl_w=jSn9;%HK8sZ>Zq5ctZu{D(nkG1yr}j8wz-1YrLTV+oDB_J_CvI{b%*# z+r(oipf>RcVIY9S{Dgr3awUBR0@x_y4H!&B>ob^O&wzmh`9kOtnA={yt_C)?$LkTG fs$N$@3F#=sbk=~Xbh_2h-B!T}A`7Ute literal 0 HcmV?d00001 diff --git a/packaging/windows/peerspeak.iss b/packaging/windows/peerspeak.iss new file mode 100644 index 0000000..6fab24c --- /dev/null +++ b/packaging/windows/peerspeak.iss @@ -0,0 +1,63 @@ +; Inno Setup script for PeerSpeak (Windows installer). +; +; PeerSpeak is a single self-contained binary: the GUI icon, notification +; chimes, and avatar presets are all embedded in the .exe (include_bytes!), +; so the only payload here is peerspeak.exe plus an .ico for the shortcuts. +; +; Build (under Wine on Linux, or native Windows): +; wine "C:\Program Files (x86)\Inno Setup 6\ISCC.exe" peerspeak.iss +; Output lands in .\output\peerspeak--setup.exe +; +; The peerspeak.exe is cross-compiled with win-cross-build.sh +; (x86_64-pc-windows-gnu, statically linked -- no extra DLLs needed). + +#define MyAppName "PeerSpeak" +#define MyAppVersion "0.2.0" +#define MyAppPublisher "mollusk" +#define MyAppExeName "peerspeak.exe" + +[Setup] +; A stable AppId keeps upgrades/uninstall tracking consistent across versions. +AppId={{2754D6C1-C8A4-4B13-9824-2D303439739D} +AppName={#MyAppName} +AppVersion={#MyAppVersion} +AppVerName={#MyAppName} {#MyAppVersion} +AppPublisher={#MyAppPublisher} +DefaultDirName={autopf}\{#MyAppName} +DefaultGroupName={#MyAppName} +DisableProgramGroupPage=yes +UninstallDisplayIcon={app}\{#MyAppExeName} +SetupIconFile=peerspeak.ico +Compression=lzma2/max +SolidCompression=yes +WizardStyle=modern +OutputDir=output +OutputBaseFilename=peerspeak-{#MyAppVersion}-setup +; Program Files install + firewall rule both need elevation. +PrivilegesRequired=admin +ArchitecturesAllowed=x64compatible +ArchitecturesInstallIn64BitMode=x64compatible + +[Languages] +Name: "english"; MessagesFile: "compiler:Default.isl" + +[Tasks] +Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked +Name: "firewall"; Description: "Allow PeerSpeak through Windows Firewall (recommended for voice calls)"; GroupDescription: "Network:" + +[Files] +Source: "peerspeak.exe"; DestDir: "{app}"; Flags: ignoreversion +Source: "peerspeak.ico"; DestDir: "{app}"; Flags: ignoreversion + +[Icons] +Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; IconFilename: "{app}\peerspeak.ico" +Name: "{group}\{cm:UninstallProgram,{#MyAppName}}"; Filename: "{uninstallexe}" +Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; IconFilename: "{app}\peerspeak.ico"; Tasks: desktopicon + +[Run] +; iroh uses UDP hole-punching; pre-authorizing avoids a mid-call firewall prompt. +Filename: "{sys}\netsh.exe"; Parameters: "advfirewall firewall add rule name=""PeerSpeak"" dir=in action=allow program=""{app}\{#MyAppExeName}"" enable=yes profile=any"; Flags: runhidden; Tasks: firewall +Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#MyAppName}}"; Flags: nowait postinstall skipifsilent + +[UninstallRun] +Filename: "{sys}\netsh.exe"; Parameters: "advfirewall firewall delete rule name=""PeerSpeak"""; Flags: runhidden; RunOnceId: "DelPeerSpeakFirewall" diff --git a/src/main.rs b/src/main.rs index af0e8fb..9a42670 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,7 @@ +// On Windows, suppress the extra console window for release GUI builds while +// keeping it in debug builds so stderr/panics stay visible during development. +#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] + fn main() { if let Err(e) = peerspeak::app::run_gui() { eprintln!("Error running GUI: {:?}", e); diff --git a/win-cross-build.sh b/win-cross-build.sh new file mode 100755 index 0000000..e063aa5 --- /dev/null +++ b/win-cross-build.sh @@ -0,0 +1,17 @@ +#!/bin/bash +# Cross-compile peerspeak to x86_64-pc-windows-gnu (run inside the peerspeak-win distrobox). +# Produces a statically-linked, self-contained .exe (no extra DLLs) for the +# Windows installer in packaging/windows/. Requires the rust-src component and +# the x86_64-pc-windows-gnu target; invoke with build-std for the static link: +# RUSTC_BOOTSTRAP=1 ./win-cross-build.sh -Z build-std=std,panic_abort +set -euo pipefail +cd "$(dirname "$0")" + +export CARGO_TARGET_X86_64_PC_WINDOWS_GNU_LINKER=x86_64-w64-mingw32-gcc +export CC_x86_64_pc_windows_gnu=x86_64-w64-mingw32-gcc +export CXX_x86_64_pc_windows_gnu=x86_64-w64-mingw32-g++ +export AR_x86_64_pc_windows_gnu=x86_64-w64-mingw32-ar +# Bundled libopus declares cmake_minimum_required < 3.5; cmake 4.x refuses it. +export CMAKE_POLICY_VERSION_MINIMUM=3.5 + +cargo build --release --target x86_64-pc-windows-gnu --bin peerspeak "$@"