mirror of
https://github.com/tinyhumansai/openhuman.git
synced 2026-07-27 21:08:00 +00:00
chore: enhance macOS bundling process for TDLib
- Updated the package-and-publish.yml workflow to utilize Tauri's native bundling for TDLib on macOS, removing the need for post-build scripts. - Modified build.rs to copy TDLib and its dependencies to the libraries/ directory, ensuring they are included in the app bundle. - Updated tauri.conf.json to reference the newly bundled TDLib and its dependencies. - Added entries to .gitignore for the new libraries directory.
This commit is contained in:
@@ -321,35 +321,12 @@ jobs:
|
||||
args: "-c ${{ steps.config-overrides.outputs.json }} ${{ matrix.settings.args }}"
|
||||
includeDebug: ${{ needs.get-version.outputs.should-publish == '' && inputs.forceRelease != 'true' }}
|
||||
includeRelease: ${{ needs.get-version.outputs.should-publish != '' || inputs.forceRelease == 'true' }}
|
||||
# Don't let tauri-action upload for macOS - we need to bundle TDLib first and recreate the DMG
|
||||
# For non-macOS platforms, upload directly via tauri-action
|
||||
releaseId: ${{ matrix.settings.platform != 'macos-latest' && needs.create-release.outputs.releaseId || '' }}
|
||||
# TDLib dylibs are now bundled natively via build.rs + tauri.conf.json macOS.frameworks
|
||||
# No post-build scripts needed - Tauri bundler handles copying and signing
|
||||
releaseId: ${{ needs.create-release.outputs.releaseId }}
|
||||
owner: alphahumanxyz
|
||||
repo: alphahuman
|
||||
|
||||
# # Bundle TDLib dylib into macOS app (fixes "Library not loaded" crash)
|
||||
# - name: Bundle TDLib for macOS
|
||||
# if: matrix.settings.platform == 'macos-latest'
|
||||
# run: |
|
||||
# TARGET="${{ matrix.settings.target }}"
|
||||
# echo "Bundling TDLib for target: $TARGET"
|
||||
# chmod +x ./src-tauri/scripts/bundle-tdlib-macos.sh
|
||||
# ./src-tauri/scripts/bundle-tdlib-macos.sh release "$TARGET"
|
||||
|
||||
# # Re-sign the app after modifying the bundle (required for notarization)
|
||||
# - name: Re-sign macOS app after TDLib bundling
|
||||
# if: matrix.settings.platform == 'macos-latest'
|
||||
# env:
|
||||
# APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE_BASE64 }}
|
||||
# APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
|
||||
# APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
|
||||
# run: bash ./src-tauri/scripts/resign-macos.sh release "${{ matrix.settings.target }}"
|
||||
|
||||
# # Re-create DMG after TDLib bundling (the original DMG was created before bundling)
|
||||
# - name: Recreate DMG with bundled TDLib
|
||||
# if: matrix.settings.platform == 'macos-latest'
|
||||
# run: bash ./src-tauri/scripts/recreate-dmg-macos.sh release "${{ matrix.settings.target }}"
|
||||
|
||||
- name: Get file info
|
||||
id: file-info
|
||||
shell: bash
|
||||
|
||||
@@ -5,3 +5,6 @@
|
||||
# Generated by Tauri
|
||||
# will have schema files for capabilities auto-completion
|
||||
/gen/schemas
|
||||
|
||||
# TDLib and dependencies copied by build.rs for macOS bundling
|
||||
/libraries/
|
||||
|
||||
Generated
+1
-1
@@ -4,7 +4,7 @@ version = 4
|
||||
|
||||
[[package]]
|
||||
name = "AlphaHuman"
|
||||
version = "0.1.0"
|
||||
version = "0.30.0"
|
||||
dependencies = [
|
||||
"aes-gcm",
|
||||
"android_logger",
|
||||
|
||||
@@ -2,6 +2,7 @@ fn main() {
|
||||
// Get the target OS from environment variable (set by Cargo during cross-compilation)
|
||||
let target = std::env::var("TARGET").unwrap_or_default();
|
||||
let is_mobile_target = target.contains("android") || target.contains("ios");
|
||||
let is_macos_target = target.contains("apple") && !target.contains("ios");
|
||||
|
||||
// TDLib build configuration (desktop only)
|
||||
// The tdlib-rs crate with download-tdlib feature handles downloading and linking
|
||||
@@ -12,7 +13,183 @@ fn main() {
|
||||
// Download and link TDLib library
|
||||
// Pass None to use default download location
|
||||
tdlib_rs::build::build(None);
|
||||
|
||||
// On macOS, copy TDLib and its dependencies to libraries/ so that
|
||||
// tauri.conf.json > bundle > macOS > frameworks can bundle them into
|
||||
// the .app's Contents/Frameworks/ directory.
|
||||
if is_macos_target {
|
||||
prepare_macos_libraries();
|
||||
}
|
||||
}
|
||||
|
||||
// Add @executable_path/../Frameworks to rpath so the binary can find
|
||||
// bundled dylibs at runtime (macOS only).
|
||||
if is_macos_target && !is_mobile_target {
|
||||
println!("cargo:rustc-link-arg=-Wl,-rpath,@executable_path/../Frameworks");
|
||||
}
|
||||
|
||||
tauri_build::build()
|
||||
}
|
||||
|
||||
/// Copy TDLib dylib and its non-system dependencies (OpenSSL) to src-tauri/libraries/
|
||||
/// and rewrite their install names to use @rpath so they work inside Contents/Frameworks/.
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
fn prepare_macos_libraries() {
|
||||
use std::fs;
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
let out_dir = std::env::var("OUT_DIR").expect("OUT_DIR not set");
|
||||
let tdlib_lib_dir = PathBuf::from(&out_dir).join("tdlib").join("lib");
|
||||
let manifest_dir =
|
||||
PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR not set"));
|
||||
let dest_dir = manifest_dir.join("libraries");
|
||||
|
||||
// Create libraries/ directory
|
||||
fs::create_dir_all(&dest_dir).expect("Failed to create libraries directory");
|
||||
|
||||
let tdlib_dylib = "libtdjson.1.8.29.dylib";
|
||||
let tdlib_src = tdlib_lib_dir.join(tdlib_dylib);
|
||||
|
||||
if !tdlib_src.exists() {
|
||||
println!(
|
||||
"cargo:warning=TDLib dylib not found at {}, skipping library preparation",
|
||||
tdlib_src.display()
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Copy TDLib dylib
|
||||
let tdlib_dest = dest_dir.join(tdlib_dylib);
|
||||
fs::copy(&tdlib_src, &tdlib_dest).expect("Failed to copy TDLib dylib");
|
||||
make_writable(&tdlib_dest);
|
||||
|
||||
// Fix TDLib's install name
|
||||
run_install_name_tool(&["-id", &format!("@rpath/{tdlib_dylib}"), tdlib_dest.to_str().unwrap()]);
|
||||
|
||||
// Find and bundle non-system dependencies (e.g. OpenSSL from Homebrew)
|
||||
let deps = get_non_system_deps(&tdlib_dest);
|
||||
for dep_path in &deps {
|
||||
let dep_name = Path::new(dep_path)
|
||||
.file_name()
|
||||
.unwrap()
|
||||
.to_str()
|
||||
.unwrap();
|
||||
let dep_dest = dest_dir.join(dep_name);
|
||||
|
||||
if Path::new(dep_path).exists() {
|
||||
fs::copy(dep_path, &dep_dest).unwrap_or_else(|e| panic!("Failed to copy {dep_name}: {e}"));
|
||||
make_writable(&dep_dest);
|
||||
|
||||
// Fix the dependency's install name
|
||||
run_install_name_tool(&[
|
||||
"-id",
|
||||
&format!("@rpath/{dep_name}"),
|
||||
dep_dest.to_str().unwrap(),
|
||||
]);
|
||||
|
||||
// Update TDLib's reference to this dependency
|
||||
run_install_name_tool(&[
|
||||
"-change",
|
||||
dep_path,
|
||||
&format!("@rpath/{dep_name}"),
|
||||
tdlib_dest.to_str().unwrap(),
|
||||
]);
|
||||
|
||||
println!("cargo:warning=Bundled dependency: {dep_name}");
|
||||
} else {
|
||||
println!("cargo:warning=Dependency not found: {dep_path}");
|
||||
}
|
||||
}
|
||||
|
||||
// Fix cross-references between dependencies (e.g. libssl -> libcrypto)
|
||||
let bundled_libs: Vec<PathBuf> = fs::read_dir(&dest_dir)
|
||||
.unwrap()
|
||||
.filter_map(|e| e.ok())
|
||||
.map(|e| e.path())
|
||||
.filter(|p| p.extension().is_some_and(|ext| ext == "dylib"))
|
||||
.collect();
|
||||
|
||||
for lib in &bundled_libs {
|
||||
let lib_deps = get_non_system_deps(lib);
|
||||
for dep_path in &lib_deps {
|
||||
let dep_name = Path::new(dep_path)
|
||||
.file_name()
|
||||
.unwrap()
|
||||
.to_str()
|
||||
.unwrap();
|
||||
// Only fix if the dep is one we bundled
|
||||
if dest_dir.join(dep_name).exists() {
|
||||
run_install_name_tool(&[
|
||||
"-change",
|
||||
dep_path,
|
||||
&format!("@rpath/{dep_name}"),
|
||||
lib.to_str().unwrap(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
println!("cargo:warning=TDLib libraries prepared in libraries/");
|
||||
}
|
||||
|
||||
/// Get non-system dependencies of a dylib using otool
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
fn get_non_system_deps(dylib_path: &std::path::Path) -> Vec<String> {
|
||||
use std::process::Command;
|
||||
|
||||
let output = Command::new("otool")
|
||||
.args(["-L", dylib_path.to_str().unwrap()])
|
||||
.output()
|
||||
.expect("Failed to run otool");
|
||||
|
||||
let stdout = String::from_utf8_lossy(&output.stdout);
|
||||
stdout
|
||||
.lines()
|
||||
.skip(1) // First line is the dylib itself
|
||||
.filter_map(|line| {
|
||||
let path = line.trim().split_whitespace().next()?;
|
||||
// Keep only non-system, non-rpath paths (e.g. Homebrew libs)
|
||||
if path.starts_with("/usr/lib/")
|
||||
|| path.starts_with("/System/")
|
||||
|| path.starts_with("@rpath/")
|
||||
|| path.starts_with("@executable_path/")
|
||||
{
|
||||
None
|
||||
} else if path.starts_with("/opt/homebrew/") || path.starts_with("/usr/local/") {
|
||||
Some(path.to_string())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Make a file writable (Homebrew libs are read-only)
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
fn make_writable(path: &std::path::Path) {
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
let mut perms = std::fs::metadata(path)
|
||||
.expect("Failed to read file metadata")
|
||||
.permissions();
|
||||
perms.set_mode(0o755);
|
||||
std::fs::set_permissions(path, perms).expect("Failed to set file permissions");
|
||||
}
|
||||
|
||||
/// Run install_name_tool with the given arguments
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
fn run_install_name_tool(args: &[&str]) {
|
||||
use std::process::Command;
|
||||
|
||||
let status = Command::new("install_name_tool")
|
||||
.args(args)
|
||||
.status()
|
||||
.expect("Failed to run install_name_tool");
|
||||
|
||||
if !status.success() {
|
||||
println!(
|
||||
"cargo:warning=install_name_tool failed with args: {}",
|
||||
args.join(" ")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,12 @@
|
||||
],
|
||||
"resources": ["../skills/skills"],
|
||||
"macOS": {
|
||||
"minimumSystemVersion": "10.15"
|
||||
"minimumSystemVersion": "10.15",
|
||||
"frameworks": [
|
||||
"./libraries/libtdjson.1.8.29.dylib",
|
||||
"./libraries/libssl.3.dylib",
|
||||
"./libraries/libcrypto.3.dylib"
|
||||
]
|
||||
}
|
||||
},
|
||||
"plugins": {
|
||||
|
||||
Reference in New Issue
Block a user