mirror of
https://github.com/tauri-apps/tauri.git
synced 2026-01-31 00:35:19 +01:00
use separate helper for macOS to optimize bundle size
This commit is contained in:
19
cef-helper/Cargo.toml
Normal file
19
cef-helper/Cargo.toml
Normal file
@@ -0,0 +1,19 @@
|
||||
[package]
|
||||
name = "tauri-cef-helper"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
license = "Apache-2.0 OR MIT"
|
||||
publish = false
|
||||
|
||||
[dependencies]
|
||||
cef = { version = "142.2.1", default-features = false }
|
||||
|
||||
[features]
|
||||
default = ["sandbox"]
|
||||
# Mirrors `tauri-runtime-cef` default feature to enable CEF sandbox support on macOS.
|
||||
sandbox = ["cef/sandbox"]
|
||||
|
||||
# Ensure this crate is NOT treated as part of the repo workspace.
|
||||
[workspace]
|
||||
|
||||
|
||||
27
cef-helper/src/main.rs
Normal file
27
cef-helper/src/main.rs
Normal file
@@ -0,0 +1,27 @@
|
||||
use cef::{args::Args, *};
|
||||
|
||||
fn main() {
|
||||
let args = Args::new();
|
||||
|
||||
#[cfg(all(target_os = "macos", feature = "sandbox"))]
|
||||
let _sandbox = {
|
||||
let mut sandbox = cef::sandbox::Sandbox::new();
|
||||
sandbox.initialize(args.as_main_args());
|
||||
sandbox
|
||||
};
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
let _loader = {
|
||||
let loader = library_loader::LibraryLoader::new(&std::env::current_exe().unwrap(), true);
|
||||
assert!(loader.load());
|
||||
loader
|
||||
};
|
||||
|
||||
execute_process(
|
||||
Some(args.as_main_args()),
|
||||
None::<&mut App>,
|
||||
std::ptr::null_mut(),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
109
crates/tauri-bundler/build.rs
Normal file
109
crates/tauri-bundler/build.rs
Normal file
@@ -0,0 +1,109 @@
|
||||
// Copyright 2019-2025 Tauri Programme within The Commons Conservancy
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
use std::{
|
||||
env, fs,
|
||||
path::{Path, PathBuf},
|
||||
process::Command,
|
||||
};
|
||||
|
||||
fn main() {
|
||||
let target = env::var("TARGET").unwrap_or_default();
|
||||
let host = env::var("HOST").unwrap_or_default();
|
||||
|
||||
// Only build/embed the CEF helper when compiling `tauri-bundler` for macOS.
|
||||
if !target.contains("apple-darwin") {
|
||||
return;
|
||||
}
|
||||
|
||||
// We need `lipo` and a functioning macOS toolchain to produce a universal Mach-O.
|
||||
if !host.contains("apple-darwin") {
|
||||
panic!(
|
||||
"Building tauri-bundler for macOS requires a macOS host to build/embed the CEF helper binary"
|
||||
);
|
||||
}
|
||||
|
||||
let out_dir = PathBuf::from(env::var("OUT_DIR").expect("OUT_DIR not set"));
|
||||
let bundler_manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
|
||||
|
||||
let helper_root = bundler_manifest_dir
|
||||
.parent() // crates/
|
||||
.and_then(|p| p.parent()) // repo root
|
||||
.map(|p| p.join("cef-helper"))
|
||||
.expect("failed to compute cef-helper path");
|
||||
|
||||
let helper_manifest = helper_root.join("Cargo.toml");
|
||||
let helper_main = helper_root.join("src").join("main.rs");
|
||||
|
||||
// Rebuild if the helper crate changes.
|
||||
println!("cargo:rerun-if-changed={}", helper_manifest.display());
|
||||
println!("cargo:rerun-if-changed={}", helper_main.display());
|
||||
|
||||
// Copy the helper crate sources into OUT_DIR so any generated files (Cargo.lock, target dir)
|
||||
// stay out of the repo checkout.
|
||||
let helper_src_dir = out_dir.join("cef-helper-src");
|
||||
let helper_src_manifest = helper_src_dir.join("Cargo.toml");
|
||||
let helper_src_main = helper_src_dir.join("src").join("main.rs");
|
||||
fs::create_dir_all(helper_src_main.parent().unwrap())
|
||||
.expect("failed to create cef-helper-src directory");
|
||||
fs::copy(&helper_manifest, &helper_src_manifest).expect("failed to copy cef-helper Cargo.toml");
|
||||
fs::copy(&helper_main, &helper_src_main).expect("failed to copy cef-helper main.rs");
|
||||
|
||||
let cargo = env::var("CARGO").unwrap_or_else(|_| "cargo".into());
|
||||
|
||||
let helper_target_dir = out_dir.join("cef-helper-target");
|
||||
let aarch64 = build_helper(
|
||||
&cargo,
|
||||
&helper_src_manifest,
|
||||
&helper_target_dir,
|
||||
"aarch64-apple-darwin",
|
||||
"tauri-cef-helper",
|
||||
);
|
||||
let x86_64 = build_helper(
|
||||
&cargo,
|
||||
&helper_src_manifest,
|
||||
&helper_target_dir,
|
||||
"x86_64-apple-darwin",
|
||||
"tauri-cef-helper",
|
||||
);
|
||||
|
||||
// Generate a small rust shim that exposes the embedded helper bytes.
|
||||
let shim_path = out_dir.join("cef_helpers.rs");
|
||||
let shim = format!(
|
||||
"pub const CEF_HELPER_AARCH64: &[u8] = include_bytes!(r#\"{}\"#);\n\
|
||||
pub const CEF_HELPER_X86_64: &[u8] = include_bytes!(r#\"{}\"#);\n",
|
||||
aarch64.display(),
|
||||
x86_64.display()
|
||||
);
|
||||
fs::write(&shim_path, shim).expect("failed to write cef_helpers.rs");
|
||||
}
|
||||
|
||||
fn build_helper(
|
||||
cargo: &str,
|
||||
manifest_path: &Path,
|
||||
target_dir: &Path,
|
||||
target: &str,
|
||||
bin_name: &str,
|
||||
) -> PathBuf {
|
||||
let mut cmd = Command::new(cargo);
|
||||
cmd
|
||||
.arg("build")
|
||||
.arg("--release")
|
||||
.arg("--manifest-path")
|
||||
.arg(manifest_path)
|
||||
.arg("--bin")
|
||||
.arg(bin_name)
|
||||
.arg("--target")
|
||||
.arg(target)
|
||||
.env("CARGO_TARGET_DIR", target_dir);
|
||||
|
||||
let status = cmd
|
||||
.status()
|
||||
.expect("failed to spawn cargo build for CEF helper");
|
||||
if !status.success() {
|
||||
panic!("failed to build CEF helper for target {target}");
|
||||
}
|
||||
|
||||
target_dir.join(target).join("release").join(bin_name)
|
||||
}
|
||||
@@ -52,6 +52,23 @@ const NESTED_CODE_FOLDER: [&str; 6] = [
|
||||
|
||||
const CEF_FRAMEWORK: &str = "Chromium Embedded Framework.framework";
|
||||
|
||||
mod embedded_cef_helper {
|
||||
// Generated by `crates/tauri-bundler/build.rs` when compiling on macOS.
|
||||
include!(concat!(env!("OUT_DIR"), "/cef_helpers.rs"));
|
||||
}
|
||||
|
||||
fn lipo_create_universal(output: &Path, aarch64: &Path, x86_64: &Path) -> crate::Result<()> {
|
||||
Command::new("lipo")
|
||||
.arg("-create")
|
||||
.arg("-output")
|
||||
.arg(output)
|
||||
.arg(aarch64)
|
||||
.arg(x86_64)
|
||||
.output_ok()
|
||||
.with_context(|| "failed to create universal CEF helper binary using lipo")?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Bundles the project.
|
||||
/// Returns a vector of PathBuf that shows where the .app was created.
|
||||
pub fn bundle_project(settings: &Settings) -> crate::Result<Vec<PathBuf>> {
|
||||
@@ -650,6 +667,8 @@ fn create_cef_helpers(
|
||||
frameworks_dir.to_path_buf(),
|
||||
)?;
|
||||
|
||||
let arch = settings.binary_arch();
|
||||
|
||||
// Create helper .app bundles
|
||||
let helpers = vec![
|
||||
format!("{} Helper (GPU)", exec_name),
|
||||
@@ -659,7 +678,33 @@ fn create_cef_helpers(
|
||||
format!("{} Helper", exec_name),
|
||||
];
|
||||
|
||||
let main_binary_path = bundle_directory.join("MacOS").join(exec_name);
|
||||
// If building an universal app bundle, create a universal helper binary once (outside the loop),
|
||||
// then copy it into each helper .app.
|
||||
let universal_helper: Option<(tempfile::TempDir, PathBuf)> =
|
||||
if arch == crate::bundle::settings::Arch::Universal {
|
||||
let tmp = tempfile::tempdir().map_err(|e| {
|
||||
crate::Error::GenericError(format!(
|
||||
"failed to create temp dir for CEF helper lipo: {e}"
|
||||
))
|
||||
})?;
|
||||
let aarch64 = tmp.path().join("tauri-cef-helper.aarch64");
|
||||
let x86_64 = tmp.path().join("tauri-cef-helper.x86_64");
|
||||
let universal = tmp.path().join("tauri-cef-helper.universal");
|
||||
|
||||
fs::write(&aarch64, embedded_cef_helper::CEF_HELPER_AARCH64).fs_context(
|
||||
"failed to write embedded CEF helper (aarch64)",
|
||||
aarch64.clone(),
|
||||
)?;
|
||||
fs::write(&x86_64, embedded_cef_helper::CEF_HELPER_X86_64).fs_context(
|
||||
"failed to write embedded CEF helper (x86_64)",
|
||||
x86_64.clone(),
|
||||
)?;
|
||||
|
||||
lipo_create_universal(&universal, &aarch64, &x86_64)?;
|
||||
Some((tmp, universal))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
for helper_name in helpers {
|
||||
let helper_app = frameworks_dir.join(format!("{helper_name}.app"));
|
||||
@@ -709,10 +754,31 @@ fn create_cef_helpers(
|
||||
|
||||
let helper_exec = helper_macos.join(&helper_name);
|
||||
|
||||
std::fs::copy(&main_binary_path, &helper_exec).fs_context(
|
||||
"failed to copy main binary to CEF helper",
|
||||
helper_exec.clone(),
|
||||
)?;
|
||||
match arch {
|
||||
crate::bundle::settings::Arch::AArch64 => {
|
||||
fs::write(&helper_exec, embedded_cef_helper::CEF_HELPER_AARCH64).fs_context(
|
||||
"failed to write embedded CEF helper executable",
|
||||
helper_exec.clone(),
|
||||
)?;
|
||||
}
|
||||
crate::bundle::settings::Arch::X86_64 => {
|
||||
fs::write(&helper_exec, embedded_cef_helper::CEF_HELPER_X86_64).fs_context(
|
||||
"failed to write embedded CEF helper executable",
|
||||
helper_exec.clone(),
|
||||
)?;
|
||||
}
|
||||
crate::bundle::settings::Arch::Universal => {
|
||||
let (_temp_dir, universal_path) = universal_helper
|
||||
.as_ref()
|
||||
.expect("universal helper binary was not generated");
|
||||
fs_utils::copy_file(universal_path, &helper_exec)?;
|
||||
}
|
||||
other => {
|
||||
return Err(GenericError(format!(
|
||||
"CEF helper embedding is only supported for aarch64, x86_64, and universal on macOS (got {other:?})"
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user