1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
use std::env;
use std::fs;
use std::path::Path;
const COMMANDS: &[&str] = &["ping"];
fn main() {
// Declare cfg flags for Tauri platform detection
// This allows the code to compile during cargo package even when these flags aren't set
println!("cargo::rustc-check-cfg=cfg(desktop)");
println!("cargo::rustc-check-cfg=cfg(mobile)");
// Check if we're running during cargo package
// During packaging, cargo copies source files to target/package/ and runs build.rs
// We detect this by checking if CARGO_MANIFEST_DIR or OUT_DIR contains "target/package"
let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap_or_default();
let out_dir = env::var("OUT_DIR").unwrap_or_default();
let is_packaging =
manifest_dir.contains("target/package") || out_dir.contains("target/package");
// Check if autogenerated files already exist
let autogenerated_commands_dir = Path::new("permissions/autogenerated/commands");
let files_exist = autogenerated_commands_dir.exists()
&& fs::read_dir(autogenerated_commands_dir).is_ok_and(|dir| dir.count() > 0);
// Skip generation if we're packaging and files already exist
// This prevents modifying the source directory during cargo package
// The permissions directory (including autogenerated files) is included in the package
// via the include field in Cargo.toml, so they should already be present
if is_packaging && files_exist {
println!(
"cargo:warning=Skipping permission generation during packaging - files already exist"
);
return;
}
tauri_plugin::Builder::new(COMMANDS)
.android_path("android")
.ios_path("ios")
.build();
// Compile Swift code for macOS ONLY
#[cfg(target_os = "macos")]
{
// Double-check target explicitly to ensure we only run for macOS, not iOS
let target = std::env::var("TARGET").unwrap_or_default();
if target.contains("apple-ios") {
// Explicitly skip for iOS builds
return;
}
use std::path::PathBuf;
use std::process::Command;
let swift_core = PathBuf::from("swift/SecureEnclaveCore.swift");
let swift_ffi = PathBuf::from("swift/secure_element_ffi.swift");
if !swift_core.exists() || !swift_ffi.exists() {
println!("cargo:warning=Swift files not found, skipping macOS build");
return;
}
// Tell Cargo to rerun this build script if Swift files change
println!("cargo:rerun-if-changed={}", swift_core.display());
println!("cargo:rerun-if-changed={}", swift_ffi.display());
let out_dir = std::env::var("OUT_DIR").unwrap();
// Determine target architecture from Cargo's target configuration
let target_arch = std::env::var("CARGO_CFG_TARGET_ARCH").unwrap_or_else(|_| {
// Fallback: try to detect from TARGET triple
if target.starts_with("x86_64") {
"x86_64".to_string()
} else {
"aarch64".to_string()
}
});
// Map Cargo arch names to Apple arch names
let swift_target = match target_arch.as_str() {
"x86_64" => "x86_64-apple-macosx10.15",
"aarch64" | "arm64" => "arm64-apple-macosx11.0",
other => {
println!(
"cargo:warning=Unsupported architecture '{}', defaulting to arm64",
other
);
"arm64-apple-macosx11.0"
}
};
// Get macOS SDK path
let sdk_output = Command::new("xcrun")
.args(["--show-sdk-path", "--sdk", "macosx"])
.output();
let sdk_path = match sdk_output {
Ok(output) => {
let path = String::from_utf8_lossy(&output.stdout).trim().to_string();
if path.is_empty() {
println!("cargo:warning=Failed to get macOS SDK path");
return;
}
path
}
Err(e) => {
println!("cargo:warning=Failed to run xcrun: {}", e);
return;
}
};
// Compile Swift files to object file (swiftc can compile multiple files at once)
let object_file = format!("{}/secure_element.o", out_dir);
let swift_status = Command::new("swiftc")
.args([
"-c",
swift_core.to_str().unwrap(),
swift_ffi.to_str().unwrap(),
"-o",
object_file.as_str(),
"-target",
swift_target,
"-sdk",
sdk_path.as_str(),
"-whole-module-optimization",
])
.output();
match swift_status {
Ok(output) => {
if !output.status.success() {
let stderr = String::from_utf8_lossy(&output.stderr);
println!("cargo:warning=Swift compilation failed: {}", stderr);
return;
}
}
Err(e) => {
println!("cargo:warning=Failed to run swiftc: {}", e);
return;
}
}
// Create static library from object file
let lib_path = format!("{}/libsecure_element.a", out_dir);
let ar_status = Command::new("ar")
.args(["rcs", lib_path.as_str(), object_file.as_str()])
.output();
if let Ok(output) = ar_status {
if output.status.success() {
// Double-check we're building for macOS (not iOS or Android)
let target = std::env::var("TARGET").unwrap_or_default();
if !target.contains("apple-darwin")
|| target.contains("apple-ios")
|| target.contains("android")
{
// Skip linking for non-macOS targets
return;
}
// Get Swift toolchain path dynamically using xcrun
let toolchain_lib_path = Command::new("xcrun")
.args(["--find", "swiftc"])
.output()
.ok()
.and_then(|output| {
if output.status.success() {
let swiftc_path = String::from_utf8_lossy(&output.stdout)
.trim()
.to_string();
// swiftc is at .../Toolchains/XcodeDefault.xctoolchain/usr/bin/swiftc
// We need .../Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/macosx
PathBuf::from(&swiftc_path)
.parent() // usr/bin
.and_then(|p| p.parent()) // usr
.map(|p| p.join("lib/swift/macosx"))
.map(|p| p.to_string_lossy().to_string())
} else {
None
}
})
.unwrap_or_else(|| {
// Fallback to standard Xcode location
"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/macosx".to_string()
});
// Tell cargo to link the library (only for macOS)
println!("cargo:rustc-link-search=native={}", out_dir);
println!("cargo:rustc-link-search=native={}", toolchain_lib_path);
println!("cargo:rustc-link-lib=static=secure_element");
println!("cargo:rustc-link-lib=framework=Security");
println!("cargo:rustc-link-lib=framework=Foundation");
// Link Swift compatibility libraries (macOS only)
println!("cargo:rustc-link-lib=static=swiftCompatibility56");
println!("cargo:rustc-link-lib=static=swiftCompatibilityConcurrency");
}
}
}
}