first commit
This commit is contained in:
@@ -0,0 +1 @@
|
|||||||
|
scripts/uxplay.log
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
# iOS/iPadOS Screen Mirroring to Windows (AirPlay via WSL)
|
||||||
|
|
||||||
|
This project sets up UxPlay (open-source AirPlay receiver) inside WSL2 and launches it as a window using WSLg.
|
||||||
|
Your iPhone/iPad can mirror to that window.
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
- Windows 11 with WSL.
|
||||||
|
- iPhone/iPad and PC on the same Wi-Fi.
|
||||||
|
|
||||||
|
## One-time setup
|
||||||
|
1. Open PowerShell in this folder and run:
|
||||||
|
scripts\setup-wsl-airplay.ps1
|
||||||
|
2. If the script asks you to restart WSL, run:
|
||||||
|
wsl --shutdown
|
||||||
|
Then rerun the setup script.
|
||||||
|
|
||||||
|
## Start mirroring
|
||||||
|
scripts\start-airplay.ps1
|
||||||
|
|
||||||
|
On the iPhone/iPad: Control Center -> Screen Mirroring -> select the server name.
|
||||||
|
|
||||||
|
## Tips
|
||||||
|
- If the device does not see the receiver, verify WSL mirrored networking was enabled and allow UDP 5353 in Windows Firewall.
|
||||||
|
|
||||||
|
- If it appears but fails to connect, open UDP/TCP 35000-35002 in Windows Firewall (this is the default port range).
|
||||||
|
|
||||||
|
- Default is low latency with hardware decoding.
|
||||||
|
|
||||||
|
- If audio crackles or drifts, try:
|
||||||
|
scripts\start-airplay.ps1 -UseVsync
|
||||||
|
scripts\start-airplay.ps1 -UseVsync -SoftwareDecode
|
||||||
|
|
||||||
|
## Opening the ports locally
|
||||||
|
|
||||||
|
Run in an elevated PowerShell:
|
||||||
|
|
||||||
|
New-NetFirewallRule -DisplayName "WSL AirPlay TCP" -Direction Inbound -Action Allow -Protocol TCP -LocalPort 35000-35002
|
||||||
|
New-NetFirewallRule -DisplayName "WSL AirPlay UDP" -Direction Inbound -Action Allow -Protocol UDP -LocalPort 35000-35002
|
||||||
|
New-NetFirewallRule -DisplayName "WSL AirPlay mDNS" -Direction Inbound -Action Allow -Protocol UDP -LocalPort 5353
|
||||||
|
|
||||||
|
## What gets installed in WSL
|
||||||
|
- UxPlay
|
||||||
|
- Avahi (mDNS/DNS-SD)
|
||||||
|
- GStreamer plugins for audio/video
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
$DefaultName = "winniepc"
|
||||||
@@ -0,0 +1,201 @@
|
|||||||
|
param(
|
||||||
|
[string]$Distro = "Ubuntu"
|
||||||
|
)
|
||||||
|
|
||||||
|
$ErrorActionPreference = "Stop"
|
||||||
|
|
||||||
|
function Write-Info {
|
||||||
|
param([string]$Message)
|
||||||
|
Write-Host $Message
|
||||||
|
}
|
||||||
|
|
||||||
|
function Ensure-WslInstalled {
|
||||||
|
if (-not (Get-Command wsl.exe -ErrorAction SilentlyContinue)) {
|
||||||
|
Write-Warning "WSL is not installed. Install it with: wsl --install -d $Distro"
|
||||||
|
throw "WSL is required."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Ensure-WslDistro {
|
||||||
|
$distros = @()
|
||||||
|
try {
|
||||||
|
$distros = wsl -l -q 2>$null
|
||||||
|
} catch {
|
||||||
|
$distros = @()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-not $distros -or ($distros -notcontains $Distro)) {
|
||||||
|
Write-Warning "WSL distro '$Distro' is not installed. Install it with: wsl --install -d $Distro"
|
||||||
|
throw "WSL distro not found."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Ensure-WslConfig {
|
||||||
|
$configPath = Join-Path $env:USERPROFILE ".wslconfig"
|
||||||
|
$lines = [System.Collections.Generic.List[string]]::new()
|
||||||
|
|
||||||
|
if (Test-Path $configPath) {
|
||||||
|
$content = Get-Content -Path $configPath -ErrorAction SilentlyContinue
|
||||||
|
foreach ($line in $content) {
|
||||||
|
$null = $lines.Add([string]$line)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$wsl2Index = $lines.FindIndex({ param($l) $l -match '^\s*\[wsl2\]\s*$' })
|
||||||
|
|
||||||
|
if ($wsl2Index -lt 0) {
|
||||||
|
if ($lines.Count -gt 0 -and $lines[$lines.Count - 1] -ne "") {
|
||||||
|
$lines.Add("")
|
||||||
|
}
|
||||||
|
$lines.Add("[wsl2]")
|
||||||
|
$lines.Add("networkingMode=mirrored")
|
||||||
|
$lines.Add("guiApplications=true")
|
||||||
|
} else {
|
||||||
|
$blockEnd = $lines.Count
|
||||||
|
for ($i = $wsl2Index + 1; $i -lt $lines.Count; $i++) {
|
||||||
|
if ($lines[$i] -match '^\s*\[.+\]\s*$') {
|
||||||
|
$blockEnd = $i
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$netIndex = -1
|
||||||
|
$guiIndex = -1
|
||||||
|
for ($i = $wsl2Index + 1; $i -lt $blockEnd; $i++) {
|
||||||
|
if ($lines[$i] -match '^\s*networkingMode=') { $netIndex = $i }
|
||||||
|
if ($lines[$i] -match '^\s*guiApplications=') { $guiIndex = $i }
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($netIndex -ge 0) {
|
||||||
|
$lines[$netIndex] = "networkingMode=mirrored"
|
||||||
|
} else {
|
||||||
|
$lines.Insert($blockEnd, "networkingMode=mirrored")
|
||||||
|
$blockEnd++
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($guiIndex -ge 0) {
|
||||||
|
$lines[$guiIndex] = "guiApplications=true"
|
||||||
|
} else {
|
||||||
|
$lines.Insert($blockEnd, "guiApplications=true")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Set-Content -Path $configPath -Value $lines -Encoding ASCII
|
||||||
|
}
|
||||||
|
|
||||||
|
function New-StartMenuShortcut {
|
||||||
|
param(
|
||||||
|
[string]$ShortcutName,
|
||||||
|
[string]$ScriptPath,
|
||||||
|
[string]$WorkingDirectory
|
||||||
|
)
|
||||||
|
|
||||||
|
$startMenuDir = Join-Path $env:APPDATA "Microsoft\Windows\Start Menu\Programs"
|
||||||
|
$shortcutPath = Join-Path $startMenuDir "$ShortcutName.lnk"
|
||||||
|
$iconPath = Join-Path $env:SystemRoot "System32\imageres.dll"
|
||||||
|
|
||||||
|
$shell = New-Object -ComObject WScript.Shell
|
||||||
|
$shortcut = $shell.CreateShortcut($shortcutPath)
|
||||||
|
$shortcut.TargetPath = (Get-Command powershell.exe).Source
|
||||||
|
$shortcut.Arguments = "-NoProfile -ExecutionPolicy Bypass -File `"$ScriptPath`""
|
||||||
|
$shortcut.WorkingDirectory = $WorkingDirectory
|
||||||
|
$shortcut.IconLocation = "$iconPath,15"
|
||||||
|
$shortcut.WindowStyle = 1
|
||||||
|
$shortcut.Save()
|
||||||
|
}
|
||||||
|
|
||||||
|
function Test-IsAdmin {
|
||||||
|
$current = [Security.Principal.WindowsIdentity]::GetCurrent()
|
||||||
|
$principal = New-Object Security.Principal.WindowsPrincipal($current)
|
||||||
|
return $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
|
||||||
|
}
|
||||||
|
|
||||||
|
function Add-FirewallRules {
|
||||||
|
$rulePrefix = "ScreenShare AirPlay"
|
||||||
|
New-NetFirewallRule -DisplayName "$rulePrefix TCP" -Direction Inbound -Action Allow -Protocol TCP -LocalPort 35000-35002 | Out-Null
|
||||||
|
New-NetFirewallRule -DisplayName "$rulePrefix UDP" -Direction Inbound -Action Allow -Protocol UDP -LocalPort 35000-35002 | Out-Null
|
||||||
|
New-NetFirewallRule -DisplayName "$rulePrefix mDNS" -Direction Inbound -Action Allow -Protocol UDP -LocalPort 5353 | Out-Null
|
||||||
|
}
|
||||||
|
|
||||||
|
function Write-Config {
|
||||||
|
param(
|
||||||
|
[string]$ConfigPath,
|
||||||
|
[string]$DefaultName
|
||||||
|
)
|
||||||
|
|
||||||
|
$lines = @()
|
||||||
|
if (-not [string]::IsNullOrWhiteSpace($DefaultName)) {
|
||||||
|
$safeName = $DefaultName.Replace('"', '`"')
|
||||||
|
$lines += "`$DefaultName = `"$safeName`""
|
||||||
|
}
|
||||||
|
|
||||||
|
Set-Content -Path $ConfigPath -Value $lines -Encoding ASCII
|
||||||
|
}
|
||||||
|
|
||||||
|
Ensure-WslInstalled
|
||||||
|
Ensure-WslDistro
|
||||||
|
|
||||||
|
Write-Info "Updating .wslconfig to enable mirrored networking and GUI apps..."
|
||||||
|
Ensure-WslConfig
|
||||||
|
|
||||||
|
$repoRoot = Resolve-Path (Join-Path $PSScriptRoot "..")
|
||||||
|
$wslScriptWindows = Resolve-Path (Join-Path $repoRoot "wsl\setup-uxplay.sh")
|
||||||
|
$wslScriptWindowsPath = $wslScriptWindows.Path
|
||||||
|
$wslScriptWindowsForWsl = $wslScriptWindowsPath -replace "\\", "/"
|
||||||
|
|
||||||
|
$wslScriptLinux = (wsl -d $Distro -- wslpath -a "$wslScriptWindowsForWsl" 2>$null)
|
||||||
|
if (-not $wslScriptLinux) {
|
||||||
|
throw "Failed to resolve WSL path for setup script: $wslScriptWindowsPath"
|
||||||
|
}
|
||||||
|
$wslScriptLinux = $wslScriptLinux.Trim()
|
||||||
|
|
||||||
|
Write-Info "Running WSL setup script..."
|
||||||
|
$bashCmd = "chmod +x '$wslScriptLinux'; '$wslScriptLinux'"
|
||||||
|
& wsl -d $Distro -- bash -lc $bashCmd
|
||||||
|
|
||||||
|
Write-Info "Restarting WSL to apply systemd and networking changes..."
|
||||||
|
& wsl --shutdown
|
||||||
|
|
||||||
|
Write-Info "Attempting to enable Avahi after restart (may prompt for sudo password)..."
|
||||||
|
$enableCmd = "if command -v systemctl >/dev/null 2>&1; then sudo systemctl enable --now avahi-daemon; else echo 'systemctl not available'; fi"
|
||||||
|
& wsl -d $Distro -- bash -lc $enableCmd
|
||||||
|
|
||||||
|
$startScriptPath = Resolve-Path (Join-Path $repoRoot "scripts\start-airplay.ps1")
|
||||||
|
$startShortcutName = "ScreenShare"
|
||||||
|
$prompt = "Create Start Menu shortcut for $startShortcutName? (Y/N) [Y]"
|
||||||
|
$response = Read-Host $prompt
|
||||||
|
if ([string]::IsNullOrWhiteSpace($response) -or $response -match '^[Yy]') {
|
||||||
|
New-StartMenuShortcut -ShortcutName $startShortcutName -ScriptPath $startScriptPath.Path -WorkingDirectory $repoRoot.Path
|
||||||
|
Write-Info "Start Menu shortcut created: $startShortcutName"
|
||||||
|
} else {
|
||||||
|
Write-Info "Skipped Start Menu shortcut."
|
||||||
|
}
|
||||||
|
|
||||||
|
$firewallPrompt = "Add Windows Firewall rules for ports 35000-35002 and 5353? (Y/N) [Y]"
|
||||||
|
$firewallResponse = Read-Host $firewallPrompt
|
||||||
|
if ([string]::IsNullOrWhiteSpace($firewallResponse) -or $firewallResponse -match '^[Yy]') {
|
||||||
|
if (Test-IsAdmin) {
|
||||||
|
Add-FirewallRules
|
||||||
|
Write-Info "Firewall rules added."
|
||||||
|
} else {
|
||||||
|
Write-Info "Skipping firewall rules (requires an elevated PowerShell)."
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Write-Info "Skipped firewall rules."
|
||||||
|
}
|
||||||
|
|
||||||
|
$configPath = Join-Path $repoRoot "scripts\config.ps1"
|
||||||
|
$namePrompt = "Set default AirPlay name? (Y/N) [Y]"
|
||||||
|
$nameResponse = Read-Host $namePrompt
|
||||||
|
if ([string]::IsNullOrWhiteSpace($nameResponse) -or $nameResponse -match '^[Yy]') {
|
||||||
|
$defaultName = Read-Host "Default name (blank keeps ScreenShare)"
|
||||||
|
if ([string]::IsNullOrWhiteSpace($defaultName)) {
|
||||||
|
$defaultName = "ScreenShare"
|
||||||
|
}
|
||||||
|
Write-Config -ConfigPath $configPath -DefaultName $defaultName
|
||||||
|
Write-Info "Default name set to: $defaultName"
|
||||||
|
} else {
|
||||||
|
Write-Info "Skipped default name configuration."
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Info "Setup complete. You can now run scripts\\start-airplay.ps1"
|
||||||
@@ -0,0 +1,161 @@
|
|||||||
|
param(
|
||||||
|
[string]$Distro = "Ubuntu",
|
||||||
|
[string]$Name = "ScreenShare",
|
||||||
|
[switch]$NoHostSuffix,
|
||||||
|
[switch]$LowLatency,
|
||||||
|
[switch]$UseVsync,
|
||||||
|
[switch]$HardwareDecode,
|
||||||
|
[switch]$SoftwareDecode,
|
||||||
|
[string]$VideoSink = "gtksink",
|
||||||
|
[switch]$AutoVideo,
|
||||||
|
[int]$PortBase = 35000,
|
||||||
|
[switch]$Quiet,
|
||||||
|
[string]$LogPath = ""
|
||||||
|
)
|
||||||
|
|
||||||
|
$ErrorActionPreference = "Stop"
|
||||||
|
|
||||||
|
$configPath = Join-Path $PSScriptRoot "config.ps1"
|
||||||
|
if (Test-Path $configPath) {
|
||||||
|
try {
|
||||||
|
. $configPath
|
||||||
|
} catch {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-not $PSBoundParameters.ContainsKey("Name") -and $DefaultName) {
|
||||||
|
$Name = $DefaultName
|
||||||
|
}
|
||||||
|
|
||||||
|
if ([string]::IsNullOrWhiteSpace($Name)) {
|
||||||
|
$Name = "ScreenShare"
|
||||||
|
}
|
||||||
|
|
||||||
|
function Reset-OutputCursor {
|
||||||
|
try {
|
||||||
|
if ([Console]::CursorLeft -ne 0) {
|
||||||
|
[Console]::WriteLine("")
|
||||||
|
}
|
||||||
|
[Console]::CursorLeft = 0
|
||||||
|
} catch {
|
||||||
|
try {
|
||||||
|
$pos = $Host.UI.RawUI.CursorPosition
|
||||||
|
if ($pos.X -ne 0) {
|
||||||
|
Write-Host ""
|
||||||
|
}
|
||||||
|
$Host.UI.RawUI.CursorPosition = New-Object Management.Automation.Host.Coordinates 0 $Host.UI.RawUI.CursorPosition.Y
|
||||||
|
} catch {
|
||||||
|
Write-Host ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if ($Host.UI.RawUI.CursorPosition.X -ne 0) {
|
||||||
|
Write-Host ""
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-not (Get-Command wsl.exe -ErrorAction SilentlyContinue)) {
|
||||||
|
throw "WSL is not installed. Run scripts\\setup-wsl-airplay.ps1 first."
|
||||||
|
}
|
||||||
|
|
||||||
|
$distros = @()
|
||||||
|
try {
|
||||||
|
$distros = wsl -l -q 2>$null
|
||||||
|
} catch {
|
||||||
|
$distros = @()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-not $distros -or ($distros -notcontains $Distro)) {
|
||||||
|
throw "WSL distro '$Distro' not found. Run scripts\\setup-wsl-airplay.ps1 first."
|
||||||
|
}
|
||||||
|
|
||||||
|
$uxplayPath = (wsl -d $Distro -- bash -lc "command -v uxplay" 2>$null).Trim()
|
||||||
|
if (-not $uxplayPath) {
|
||||||
|
throw "UxPlay is not installed in WSL. Run scripts\\setup-wsl-airplay.ps1 first."
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($PortBase -ne 0) {
|
||||||
|
if ($PortBase -lt 1024 -or $PortBase -gt 65533) {
|
||||||
|
throw "PortBase must be between 1024 and 65533."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$escapedName = $Name -replace '"', '\\"'
|
||||||
|
$cmd = "uxplay -n `"$escapedName`""
|
||||||
|
|
||||||
|
if ($NoHostSuffix) {
|
||||||
|
$cmd += " -nh"
|
||||||
|
}
|
||||||
|
|
||||||
|
$useLowLatency = $true
|
||||||
|
if ($UseVsync) {
|
||||||
|
$useLowLatency = $false
|
||||||
|
}
|
||||||
|
if ($LowLatency) {
|
||||||
|
$useLowLatency = $true
|
||||||
|
}
|
||||||
|
|
||||||
|
$useHardwareDecode = $true
|
||||||
|
if ($SoftwareDecode) {
|
||||||
|
$useHardwareDecode = $false
|
||||||
|
}
|
||||||
|
if ($HardwareDecode) {
|
||||||
|
$useHardwareDecode = $true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-not $useHardwareDecode) {
|
||||||
|
$cmd += " -avdec"
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($useLowLatency) {
|
||||||
|
$cmd += " -vsync no"
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-not $AutoVideo -and $VideoSink) {
|
||||||
|
$cmd += " -vs $VideoSink"
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($PortBase -ne 0) {
|
||||||
|
$cmd += " -p $PortBase"
|
||||||
|
}
|
||||||
|
|
||||||
|
Reset-OutputCursor
|
||||||
|
[Console]::WriteLine("Starting ScreenShare. Logs follow below.")
|
||||||
|
|
||||||
|
$redirectLogs = $Quiet
|
||||||
|
if ($redirectLogs -and [string]::IsNullOrWhiteSpace($LogPath)) {
|
||||||
|
$LogPath = Join-Path $PSScriptRoot "screenshare.log"
|
||||||
|
}
|
||||||
|
|
||||||
|
$nativePrefSet = $false
|
||||||
|
$nativePrefValue = $null
|
||||||
|
if (Get-Variable -Name PSNativeCommandUseErrorActionPreference -ErrorAction SilentlyContinue) {
|
||||||
|
$nativePrefSet = $true
|
||||||
|
$nativePrefValue = $PSNativeCommandUseErrorActionPreference
|
||||||
|
$PSNativeCommandUseErrorActionPreference = $false
|
||||||
|
}
|
||||||
|
|
||||||
|
$savedErrorActionPreference = $ErrorActionPreference
|
||||||
|
if ($redirectLogs) {
|
||||||
|
$ErrorActionPreference = "SilentlyContinue"
|
||||||
|
} else {
|
||||||
|
$ErrorActionPreference = "Continue"
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if ($redirectLogs) {
|
||||||
|
& wsl -d $Distro -- bash -lc $cmd 1>$LogPath 2>&1
|
||||||
|
Reset-OutputCursor
|
||||||
|
[Console]::WriteLine("ScreenShare logs written to: $LogPath")
|
||||||
|
} else {
|
||||||
|
& wsl -d $Distro -- bash -lc $cmd
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
$ErrorActionPreference = $savedErrorActionPreference
|
||||||
|
if ($nativePrefSet) {
|
||||||
|
$PSNativeCommandUseErrorActionPreference = $nativePrefValue
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
echo "==> Configuring WSL for systemd (required for Avahi)"
|
||||||
|
if [ ! -f /etc/wsl.conf ]; then
|
||||||
|
printf "[boot]\nsystemd=true\n" | sudo tee /etc/wsl.conf >/dev/null
|
||||||
|
else
|
||||||
|
if ! grep -q '^\[boot\]' /etc/wsl.conf; then
|
||||||
|
printf "\n[boot]\nsystemd=true\n" | sudo tee -a /etc/wsl.conf >/dev/null
|
||||||
|
elif ! grep -q '^systemd=' /etc/wsl.conf; then
|
||||||
|
sudo sed -i '/^\[boot\]$/a systemd=true' /etc/wsl.conf
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "==> Installing dependencies"
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y \
|
||||||
|
build-essential \
|
||||||
|
cmake \
|
||||||
|
pkg-config \
|
||||||
|
git \
|
||||||
|
libssl-dev \
|
||||||
|
libplist-dev \
|
||||||
|
libavahi-compat-libdnssd-dev \
|
||||||
|
avahi-daemon \
|
||||||
|
avahi-utils \
|
||||||
|
gstreamer1.0-tools \
|
||||||
|
gstreamer1.0-plugins-base \
|
||||||
|
gstreamer1.0-plugins-good \
|
||||||
|
gstreamer1.0-plugins-bad \
|
||||||
|
gstreamer1.0-plugins-ugly \
|
||||||
|
gstreamer1.0-libav \
|
||||||
|
gstreamer1.0-gtk3
|
||||||
|
|
||||||
|
echo "==> Installing UxPlay"
|
||||||
|
if apt-cache show uxplay >/dev/null 2>&1; then
|
||||||
|
sudo apt-get install -y uxplay
|
||||||
|
else
|
||||||
|
workdir="$HOME/uxplay-src"
|
||||||
|
if [ ! -d "$workdir/.git" ]; then
|
||||||
|
rm -rf "$workdir"
|
||||||
|
git clone https://github.com/FDH2/UxPlay "$workdir"
|
||||||
|
else
|
||||||
|
git -C "$workdir" pull --ff-only
|
||||||
|
fi
|
||||||
|
|
||||||
|
cmake -S "$workdir" -B "$workdir/build"
|
||||||
|
cmake --build "$workdir/build" -j
|
||||||
|
sudo cmake --install "$workdir/build"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if command -v systemctl >/dev/null 2>&1 && ps -p 1 -o comm= | grep -q systemd; then
|
||||||
|
echo "==> Enabling Avahi"
|
||||||
|
sudo systemctl enable --now avahi-daemon
|
||||||
|
else
|
||||||
|
echo "NOTE: systemd is not active yet. After WSL restart, run:"
|
||||||
|
echo " sudo systemctl enable --now avahi-daemon"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "==> Done"
|
||||||
Reference in New Issue
Block a user