Add slack-desktop for aarch64 on a native Electron runtime
Slack only publishes an x86_64 Linux build, so the AUR recipe produces an aarch64 package full of x86_64 binaries that cannot start. Run Slack's application code on the AArch64 build of the Electron release it ships with, replace the three native addons Slack requires at boot with JavaScript equivalents, and drop the x86_64 addons it can do without.
This commit is contained in:
1 parent
049d7671e1
commit
418a48bef6
7 files changed
+278
No files matched your search
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"source": "local",
|
||||
"upstream": {
|
||||
"watch": {
|
||||
"json": "https://slack.com/api/desktop.latestRelease?arch=x64&variant=deb",
|
||||
"path": "version"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
# Maintainer: Ryan Hughes <ryan@omarchy.org>
|
||||
|
||||
pkgname=slack-desktop
|
||||
pkgver=4.52.171
|
||||
pkgrel=1
|
||||
# Slack publishes Linux builds for x86_64 only. Its application code runs
|
||||
# unchanged on the AArch64 build of the Electron release it ships with; see
|
||||
# README.md for the native modules that are replaced or dropped.
|
||||
_electronver=44.4.5
|
||||
pkgdesc='Slack Desktop for Linux on a native AArch64 Electron runtime'
|
||||
arch=('aarch64')
|
||||
url='https://slack.com/downloads'
|
||||
license=('custom')
|
||||
depends=(
|
||||
'alsa-lib'
|
||||
'at-spi2-core'
|
||||
'cairo'
|
||||
'dbus'
|
||||
'expat'
|
||||
'fontconfig'
|
||||
'gcc-libs'
|
||||
'glib2'
|
||||
'glibc'
|
||||
'gtk3'
|
||||
'libcups'
|
||||
'libnotify'
|
||||
'libsecret'
|
||||
'libx11'
|
||||
'libxcb'
|
||||
'libxcomposite'
|
||||
'libxdamage'
|
||||
'libxext'
|
||||
'libxfixes'
|
||||
'libxkbcommon'
|
||||
'libxrandr'
|
||||
'mesa'
|
||||
'nspr'
|
||||
'nss'
|
||||
'pango'
|
||||
'systemd-libs'
|
||||
'xdg-utils'
|
||||
)
|
||||
optdepends=(
|
||||
'libappindicator-gtk3: Systray indicator support'
|
||||
'org.freedesktop.secrets: Keyring password store support'
|
||||
)
|
||||
makedepends=('asar')
|
||||
options=('!debug' '!strip')
|
||||
source=(
|
||||
"slack-desktop-${pkgver}-amd64.deb::https://downloads.slack-edge.com/desktop-releases/linux/x64/${pkgver}/slack-desktop-${pkgver}-amd64.deb"
|
||||
"electron-v${_electronver}-linux-arm64.zip::https://github.com/electron/electron/releases/download/v${_electronver}/electron-v${_electronver}-linux-arm64.zip"
|
||||
'slack.desktop'
|
||||
'slack-desktop-utils.js'
|
||||
'file-handler-info.js'
|
||||
'electron-native-auth.js'
|
||||
)
|
||||
noextract=(
|
||||
"slack-desktop-${pkgver}-amd64.deb"
|
||||
"electron-v${_electronver}-linux-arm64.zip"
|
||||
)
|
||||
sha256sums=('c6199816e6d842289869a9e84a05042af6e0de68959df7a15e7273873b86dc36'
|
||||
'3bf0acab49c4ea3c9283cdb86bf3dd7204bd52a6fba6c8ae51101bdba2adae0e'
|
||||
'e438e78265f3e566990300946afb4ea5d09bcd8c426738ab8f486ae9ddb86c0f'
|
||||
'6de40409af5a04605c3287cb3c661132eb55a4f636f7cd9bbfd456f4adf41971'
|
||||
'a2a8fd45daa4f493ad4487da9f01477233feecfef360ed366bfb0a58f804890a'
|
||||
'9cd53c84fdc407c83f2ca6e9485916296f3712b2742dcc0acf22fda5195ead50')
|
||||
|
||||
# x86_64 addons in Slack's app that can never load on AArch64. The three that
|
||||
# Slack requires on Linux are replaced by the JavaScript files above; the rest
|
||||
# are Windows/macOS helpers or degrade on failure (native-keymap). Any other
|
||||
# foreign binary fails the build so a new native module gets reviewed.
|
||||
_x86_addons=(
|
||||
'@tinyspeck/slack-desktop-utils/lib/binding/napi-v8/slackdesktoputils.node'
|
||||
'file-handler-info/build/Release/file_handler_info.node'
|
||||
'electron-native-auth/build/Release/electron_native_auth.node'
|
||||
'@tinyspeck/native-keymap/build/Release/keymapping.node'
|
||||
'cf-prefs/build/Release/cf-prefs.node'
|
||||
'macos-notification-state/build/Release/notificationstate.node'
|
||||
'registry-js/build/Release/registry.node'
|
||||
'windows-focus-assist/build/Release/focusassist.node'
|
||||
)
|
||||
|
||||
prepare() {
|
||||
rm -rf slack electron app
|
||||
mkdir slack electron
|
||||
bsdtar -O -xf "slack-desktop-${pkgver}-amd64.deb" 'data.tar.*' | bsdtar -C slack -xf -
|
||||
bsdtar -C electron -xf "electron-v${_electronver}-linux-arm64.zip"
|
||||
|
||||
local slack_electron
|
||||
slack_electron=$(<slack/usr/lib/slack/version)
|
||||
if [[ $slack_electron != "$_electronver" ]]; then
|
||||
error "Slack $pkgver ships Electron $slack_electron, but _electronver is $_electronver."
|
||||
plain "Set _electronver=$slack_electron and update its checksum."
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Electron loads resources/app ahead of app.asar, so the extracted tree can
|
||||
# carry the replacement modules without repacking the archive.
|
||||
asar extract slack/usr/lib/slack/resources/app.asar app
|
||||
}
|
||||
|
||||
package() {
|
||||
local lib="$pkgdir/usr/lib/slack"
|
||||
local app="$lib/resources/app"
|
||||
|
||||
install -d "$lib"
|
||||
cp -a --no-preserve=ownership electron/. "$lib/"
|
||||
mv "$lib/electron" "$lib/slack"
|
||||
rm -f "$lib/resources/default_app.asar" "$lib/LICENSE"
|
||||
find slack/usr/lib/slack/resources -maxdepth 1 -type f ! -name app.asar \
|
||||
-exec cp --no-preserve=ownership -t "$lib/resources" {} +
|
||||
cp -a --no-preserve=ownership app "$app"
|
||||
|
||||
local shim target
|
||||
for shim in \
|
||||
'slack-desktop-utils.js:@tinyspeck/slack-desktop-utils/lib/index.js' \
|
||||
'file-handler-info.js:file-handler-info/index.js' \
|
||||
'electron-native-auth.js:electron-native-auth/index.js'; do
|
||||
target="$app/node_modules/${shim#*:}"
|
||||
if [[ ! -f $target ]]; then
|
||||
error "Slack $pkgver no longer ships ${shim#*:}; review the replacement modules."
|
||||
return 1
|
||||
fi
|
||||
install -m644 "$srcdir/${shim%%:*}" "$target"
|
||||
done
|
||||
|
||||
local addon
|
||||
for addon in "${_x86_addons[@]}"; do
|
||||
rm -f "$app/node_modules/$addon"
|
||||
done
|
||||
|
||||
local file machine
|
||||
while IFS= read -r -d '' file; do
|
||||
machine=$(readelf -h "$file" 2>/dev/null |
|
||||
sed -n 's/^[[:space:]]*Machine:[[:space:]]*//p')
|
||||
case "$machine" in
|
||||
'' | AArch64) ;;
|
||||
*) error "Unexpected ${machine} binary: ${file#"$pkgdir"}"; return 1 ;;
|
||||
esac
|
||||
done < <(find "$lib" -type f -print0)
|
||||
|
||||
find "$lib" -type d -exec chmod 755 {} +
|
||||
find "$lib" -type f -exec chmod 644 {} +
|
||||
# Chromium sandboxes through unprivileged user namespaces, which Arch-family
|
||||
# kernels allow; a setuid-root helper is not needed.
|
||||
chmod 755 "$lib/slack" "$lib/chrome_crashpad_handler" "$lib/chrome-sandbox"
|
||||
|
||||
install -d "$pkgdir/usr/bin"
|
||||
ln -s /usr/lib/slack/slack "$pkgdir/usr/bin/slack"
|
||||
install -Dm644 slack.desktop "$pkgdir/usr/share/applications/slack.desktop"
|
||||
install -Dm644 slack/usr/share/pixmaps/slack.png \
|
||||
"$pkgdir/usr/share/icons/hicolor/512x512/apps/slack.png"
|
||||
|
||||
local licenses="$pkgdir/usr/share/licenses/$pkgname"
|
||||
install -Dm644 slack/usr/lib/slack/LICENSE "$licenses/LICENSE"
|
||||
install -Dm644 slack/usr/share/doc/slack-desktop/OPEN_SOURCE_LICENSE_ATTRIBUTIONS \
|
||||
"$licenses/OPEN_SOURCE_LICENSE_ATTRIBUTIONS"
|
||||
install -Dm644 electron/LICENSE "$licenses/LICENSE.electron.txt"
|
||||
install -Dm644 electron/LICENSES.chromium.html "$licenses/LICENSES.chromium.html"
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
# Slack on ARM
|
||||
|
||||
Slack publishes Linux builds for x86_64 only, and the AUR `slack-desktop` recipe repackages that `.deb`. This package runs the same application code on the AArch64 build of the Electron release Slack ships with, so `yay -S slack-desktop` on an ARM Omarchy install resolves to a working package.
|
||||
|
||||
## Electron version
|
||||
|
||||
`_electronver` must equal the Electron version inside Slack's `.deb` (`usr/lib/slack/version`). `prepare()` refuses to build when they differ and prints the version to set. A Slack release that moves to a new Electron therefore fails its sync PR build until `_electronver` and the Electron checksum are updated; the upstream watch only tracks Slack's version.
|
||||
|
||||
## Native modules
|
||||
|
||||
Slack's app carries eight x86_64 Node addons. None can load on AArch64, so they are removed, and the build fails on any other foreign binary so a new native module is reviewed before it ships.
|
||||
|
||||
Three are required while Slack boots on Linux and are replaced by JavaScript:
|
||||
|
||||
- `file-handler-info` and `electron-native-auth` are MIT-licensed and their Linux builds compile no-op implementations (`impl_none.cc`, `addon_none.cc`). The replacements return the same results.
|
||||
- `@tinyspeck/slack-desktop-utils` is closed source. Its replacement throws `Method not implemented` from every native call, which is the error Slack's own wrapper uses for methods a platform lacks. Slack catches it, so these Linux features are unavailable: double-press and combo global shortcuts, the huddle screen-share border overlay, audio device detail lookups, clipboard set-and-paste, and haptics.
|
||||
|
||||
`@tinyspeck/native-keymap` already catches a missing addon and returns defaults, so keyboard layout detection reports `unknown`. The other four addons are Windows/macOS helpers that Slack does not use on Linux.
|
||||
|
||||
## Validation
|
||||
|
||||
Installed and used on an aarch64 Omarchy machine (N1x). Features listed above as unavailable were not expected to work and were not checked.
|
||||
@@ -0,0 +1,14 @@
|
||||
// Linux builds of electron-native-auth (github.com/clavin/electron-native-auth)
|
||||
// compile src/addon_none.cc: native auth sessions are unavailable and
|
||||
// constructing a request throws. This is the same facade in JavaScript.
|
||||
class AuthRequest {
|
||||
static isAvailable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
constructor() {
|
||||
throw new Error('this function is not implemented for this platform');
|
||||
}
|
||||
}
|
||||
|
||||
exports.AuthRequest = AuthRequest;
|
||||
@@ -0,0 +1,9 @@
|
||||
// Linux builds of file-handler-info (github.com/clavin/node-file-handler-info)
|
||||
// compile src/impl_none.cc, which finds no handler. This is the same result
|
||||
// without an architecture-specific addon.
|
||||
exports.getHandlerInfo = (filePath) => {
|
||||
if (typeof filePath !== 'string') {
|
||||
throw new TypeError('Expected 1st argument to be string');
|
||||
}
|
||||
return { handlerPath: null, friendlyName: null };
|
||||
};
|
||||
@@ -0,0 +1,53 @@
|
||||
// Stand-in for Slack's closed-source native helpers, which ship no aarch64
|
||||
// build. Slack's main bundle requires this module while booting, so a missing
|
||||
// addon stops the window from ever opening. Every native call throws the same
|
||||
// error the vendor wrapper uses for methods a platform lacks, and Slack's call
|
||||
// sites already catch it and fall back.
|
||||
const unavailable = () => {
|
||||
throw new Error('Method not implemented');
|
||||
};
|
||||
|
||||
const namespace = new Proxy(
|
||||
{},
|
||||
{
|
||||
get: (_, key) =>
|
||||
typeof key === 'symbol' || key === 'then' ? undefined : unavailable,
|
||||
},
|
||||
);
|
||||
|
||||
const constants = {
|
||||
AppRestartFlags: { NoCrash: 1, NoHang: 2, NoPatch: 4, NoReboot: 8 },
|
||||
WindowsNotifierState: {
|
||||
NotificationPlatformUnavailable: -2,
|
||||
Error: -1,
|
||||
Enabled: 0,
|
||||
DisabledForApplication: 1,
|
||||
DisabledForUser: 2,
|
||||
DisabledByGroupPolicy: 3,
|
||||
DisabledByManifest: 4,
|
||||
},
|
||||
StartupTaskState: {
|
||||
Error: -1,
|
||||
Disabled: 0,
|
||||
DisabledByUser: 1,
|
||||
Enabled: 2,
|
||||
DisabledByPolicy: 3,
|
||||
EnabledByPolicy: 4,
|
||||
},
|
||||
ActivationType: { Error: -1, StartupTask: 1020 },
|
||||
};
|
||||
|
||||
module.exports = new Proxy(constants, {
|
||||
get: (target, key) => {
|
||||
if (key in target) return target[key];
|
||||
if (
|
||||
typeof key === 'symbol' ||
|
||||
key === '__esModule' ||
|
||||
key === 'default' ||
|
||||
key === 'then'
|
||||
) {
|
||||
return undefined;
|
||||
}
|
||||
return namespace;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,11 @@
|
||||
[Desktop Entry]
|
||||
Name=Slack
|
||||
StartupWMClass=Slack
|
||||
Comment=Slack Desktop
|
||||
GenericName=Slack Client for Linux
|
||||
Exec=/usr/bin/slack %U
|
||||
Icon=slack
|
||||
Type=Application
|
||||
StartupNotify=true
|
||||
Categories=GNOME;GTK;Network;InstantMessaging;
|
||||
MimeType=x-scheme-handler/slack;
|
||||
Reference in new issue
Block a user