feat(desktop): build macOS as a universal binary (#1603)

This commit is contained in:
Hampus authored and GitHub committed 2026-08-15 01:25:35 +02:00
1 parent 3588090f22
commit 6e4c055ebd
5 files changed
+83 -68

No files matched your search

+44 -48
View File
@@ -32,6 +32,7 @@ const PUBLIC_DL_BASE: &str = "https://api.fluxer.app/dl";
const PNPM_VERSION: &str = "10.29.3";
const RUST_TOOLCHAIN: &str = "1.93.0";
const DEFAULT_DESKTOP_VARIANT: &str = "default";
pub(crate) const MACOS_UNIVERSAL_ARCH: &str = "universal";
const WINDOWS_GAME_CAPTURE_DESKTOP_VARIANT: &str = "windows-game-capture";
#[derive(Debug, Args, Clone)]
@@ -53,10 +54,6 @@ pub struct BuildDesktopArgs {
#[arg(long)]
skip_macos: Option<String>,
#[arg(long)]
skip_macos_x64: Option<String>,
#[arg(long)]
skip_macos_arm64: Option<String>,
#[arg(long)]
skip_linux: Option<String>,
#[arg(long)]
skip_linux_x64: Option<String>,
@@ -136,17 +133,10 @@ const PLATFORMS: &[Platform] = &[
},
Platform {
platform: "macos",
arch: "x64",
arch: MACOS_UNIVERSAL_ARCH,
desktop_variant: DEFAULT_DESKTOP_VARIANT,
os: "fluxer-desktop-macos-arm64",
electron_arch: "x64",
},
Platform {
platform: "macos",
arch: "arm64",
desktop_variant: DEFAULT_DESKTOP_VARIANT,
os: "fluxer-desktop-macos-arm64",
electron_arch: "arm64",
electron_arch: MACOS_UNIVERSAL_ARCH,
},
Platform {
platform: "linux",
@@ -381,8 +371,7 @@ fn skip_target_set(args: &BuildDesktopArgs) -> Result<BTreeSet<String>> {
"windows-x64",
"windows-arm64",
"macos",
"macos-x64",
"macos-arm64",
"macos-universal",
"linux",
"linux-x64",
"linux-arm64",
@@ -424,11 +413,7 @@ fn skip_platform(
|| (platform.arch == "arm64"
&& flag(&args.skip_windows_arm64, "SKIP_WINDOWS_ARM64"))
}
"macos" => {
flag(&args.skip_macos, "SKIP_MACOS")
|| (platform.arch == "x64" && flag(&args.skip_macos_x64, "SKIP_MACOS_X64"))
|| (platform.arch == "arm64" && flag(&args.skip_macos_arm64, "SKIP_MACOS_ARM64"))
}
"macos" => flag(&args.skip_macos, "SKIP_MACOS"),
"linux" => {
flag(&args.skip_linux, "SKIP_LINUX")
|| (platform.arch == "x64" && flag(&args.skip_linux_x64, "SKIP_LINUX_X64"))
@@ -2618,7 +2603,7 @@ fn is_unix_upload_artifact(name: &str) -> bool {
fn normalise_updater_yaml_step() -> Result<()> {
if env::var("PLATFORM").unwrap_or_default() == "macos"
&& env::var("ARCH").unwrap_or_default() == "arm64"
&& env::var("ARCH").unwrap_or_default() == MACOS_UNIVERSAL_ARCH
{
let source = Path::new("upload_staging/latest-mac.yml");
let target = Path::new("upload_staging/latest-mac-arm64.yml");
@@ -2768,30 +2753,32 @@ fn build_payload_step() -> Result<()> {
continue;
}
};
let mut dest = payload_root
.join(&channel)
.join(platform)
.join(&identity.arch);
if let Some(segment) = desktop_variant_path_segment(&identity.desktop_variant) {
dest = dest.join(segment);
for published_arch in published_arches(platform, &identity.arch) {
let mut dest = payload_root
.join(&channel)
.join(platform)
.join(published_arch);
if let Some(segment) = desktop_variant_path_segment(&identity.desktop_variant) {
dest = dest.join(segment);
}
fs::create_dir_all(&dest)?;
copy_dir_contents(&dir, &dest)?;
let manifest = build_desktop_manifest(
&dest,
&PayloadManifestInput {
channel: channel.clone(),
platform: platform.to_string(),
arch: published_arch.to_string(),
desktop_variant: identity.desktop_variant.clone(),
version: version.clone(),
pub_date: pub_date.clone(),
},
)?;
if platform == "darwin" {
write_macos_releases(&dest, &s3_prefix, &channel, &manifest)?;
}
write_json_pretty(&dest.join("manifest.json"), &manifest)?;
}
fs::create_dir_all(&dest)?;
copy_dir_contents(&dir, &dest)?;
let manifest = build_desktop_manifest(
&dest,
&PayloadManifestInput {
channel: channel.clone(),
platform: platform.to_string(),
arch: identity.arch.clone(),
desktop_variant: identity.desktop_variant.clone(),
version: version.clone(),
pub_date: pub_date.clone(),
},
)?;
if platform == "darwin" {
write_macos_releases(&dest, &s3_prefix, &channel, &manifest)?;
}
write_json_pretty(&dest.join("manifest.json"), &manifest)?;
}
println!("Payload tree:");
@@ -3003,6 +2990,17 @@ fn manifest_file_entry(kind: &str, file: &Path) -> Result<DesktopManifestFile> {
}
}
fn published_arches(platform: &str, arch: &str) -> Vec<&'static str> {
if platform == "darwin" && arch == MACOS_UNIVERSAL_ARCH {
return vec!["x64", "arm64"];
}
match arch {
"x64" => vec!["x64"],
"arm64" => vec!["arm64"],
other => panic!("Unsupported desktop arch: {other}"),
}
}
fn write_macos_releases(
dest: &Path,
s3_prefix: &str,
@@ -3332,8 +3330,6 @@ mod tests {
skip_windows_x64: Some("false".to_string()),
skip_windows_arm64: Some("false".to_string()),
skip_macos: Some("false".to_string()),
skip_macos_x64: Some("false".to_string()),
skip_macos_arm64: Some("false".to_string()),
skip_linux: Some("false".to_string()),
skip_linux_x64: Some("false".to_string()),
skip_linux_arm64: Some("false".to_string()),
@@ -3414,7 +3410,7 @@ mod tests {
fn matrix_selects_one_row_per_platform_arch_by_default() {
let selected = selected_platforms(&matrix_args()).unwrap();
assert_eq!(selected.len(), 6);
assert_eq!(selected.len(), 5);
assert_eq!(
selected
.iter()
@@ -3462,7 +3458,7 @@ mod tests {
.iter()
.all(|platform| platform.platform != "windows")
);
assert_eq!(selected.len(), 4);
assert_eq!(selected.len(), 3);
}
#[test]
+21 -9
View File
@@ -3,6 +3,7 @@
use crate::common::{
CommandSpec, command_succeeds, output_text, remove_file_if_exists, run_command,
};
use crate::desktop::MACOS_UNIVERSAL_ARCH;
use anyhow::{Context, Result, anyhow, bail, ensure};
use clap::Args;
use sha2::{Digest, Sha256};
@@ -358,9 +359,23 @@ fn ensure_pkg_config(requirement: &PkgConfigRequirement) -> Result<()> {
fn build_rust_node_addon(addon_root: &Path, addon: &DesktopNativeAddon) -> Result<BuiltNodeAddon> {
let platform = current_platform();
let arch = electron_arch();
let tag = platform_tag(&platform, &arch)?;
let target = rust_target_for_platform(&platform, &arch)?;
let target_root = cargo_target_root_for_build(addon_root, &platform)?;
if platform == "darwin" && arch == MACOS_UNIVERSAL_ARCH {
let arm64 = build_rust_node_addon_for_arch(addon_root, addon, &platform, "arm64")?;
build_rust_node_addon_for_arch(addon_root, addon, &platform, "x64")?;
return Ok(arm64);
}
build_rust_node_addon_for_arch(addon_root, addon, &platform, &arch)
}
fn build_rust_node_addon_for_arch(
addon_root: &Path,
addon: &DesktopNativeAddon,
platform: &str,
arch: &str,
) -> Result<BuiltNodeAddon> {
let tag = platform_tag(platform, arch)?;
let target = rust_target_for_platform(platform, arch)?;
let target_root = cargo_target_root_for_build(addon_root, platform)?;
let mut args = vec![
OsString::from("build"),
OsString::from("--release"),
@@ -396,10 +411,7 @@ fn build_rust_node_addon(addon_root: &Path, addon: &DesktopNativeAddon) -> Resul
let source = target_root
.join(&target)
.join("release")
.join(cargo_dynamic_library_file_name(
addon.crate_name,
&platform,
)?);
.join(cargo_dynamic_library_file_name(addon.crate_name, platform)?);
let out_file = addon_root.join(format!("{}.{}.node", addon.node_file_stem, tag));
ensure!(
source.exists(),
@@ -418,8 +430,8 @@ fn build_rust_node_addon(addon_root: &Path, addon: &DesktopNativeAddon) -> Resul
"expected {} to exist after copy",
out_file.display()
);
sign_macos_node_addon(&out_file, &platform)?;
assert_no_redistributable_runtime_imports(&out_file, &platform)?;
sign_macos_node_addon(&out_file, platform)?;
assert_no_redistributable_runtime_imports(&out_file, platform)?;
Ok(BuiltNodeAddon {
out_file,
source,