autozig_engine/
zig_compiler.rs1use std::{
4 path::Path,
5 process::Command,
6};
7
8use anyhow::{
9 Context,
10 Result,
11};
12
13pub struct ZigCompiler {
15 zig_path: String,
16}
17
18impl ZigCompiler {
19 pub fn new() -> Self {
21 let zig_path = std::env::var("ZIG_PATH").unwrap_or_else(|_| "zig".to_string());
23 Self { zig_path }
24 }
25
26 pub fn check_version(&self) -> Result<String> {
28 let output = Command::new(&self.zig_path)
29 .arg("version")
30 .output()
31 .context("Failed to execute zig version command")?;
32
33 if !output.status.success() {
34 anyhow::bail!("Zig compiler not found or failed to run");
35 }
36
37 let version = String::from_utf8_lossy(&output.stdout).trim().to_string();
38 Ok(version)
39 }
40
41 pub fn compile_with_target(
48 &self,
49 source: &Path,
50 output_lib: &Path,
51 target: &str,
52 ) -> Result<()> {
53 println!("cargo:warning=Compiling Zig code: {} for target: {}", source.display(), target);
54
55 let status = Command::new(&self.zig_path)
61 .arg("build-lib")
62 .arg(source)
63 .arg("-static")
64 .arg(format!("-femit-bin={}", output_lib.display()))
65 .arg("-target")
66 .arg(target)
67 .arg("-fPIC")
69 .arg("-lc")
71 .arg("-O")
73 .arg("ReleaseFast")
74 .status()
75 .context("Failed to execute zig build-lib")?;
76
77 if !status.success() {
78 anyhow::bail!("Zig compilation failed");
79 }
80
81 println!("cargo:warning=Zig compilation successful");
82 println!("cargo:warning=Library: {}", output_lib.display());
83
84 Ok(())
85 }
86
87 pub fn compile(&self, source: &Path, output_lib: &Path) -> Result<()> {
89 self.compile_with_target(source, output_lib, "native")
90 }
91
92 pub fn compile_tests(&self, source: &Path, output_exe: &Path, target: &str) -> Result<()> {
99 println!("cargo:warning=Compiling Zig tests: {} for target: {}", source.display(), target);
100
101 let status = Command::new(&self.zig_path)
103 .arg("test")
104 .arg(source)
105 .arg(format!("-femit-bin={}", output_exe.display()))
106 .arg("-target")
107 .arg(target)
108 .arg("-O")
110 .arg("ReleaseFast")
111 .status()
112 .context("Failed to execute zig test")?;
113
114 if !status.success() {
115 anyhow::bail!("Zig test compilation failed");
116 }
117
118 println!("cargo:warning=Zig test compilation successful");
119 println!("cargo:warning=Test executable: {}", output_exe.display());
120
121 Ok(())
122 }
123
124 pub fn run_test_executable(&self, test_exe: &Path) -> Result<String> {
129 let output = Command::new(test_exe)
130 .output()
131 .context(format!("Failed to execute test: {}", test_exe.display()))?;
132
133 let stdout = String::from_utf8_lossy(&output.stdout).to_string();
134 let stderr = String::from_utf8_lossy(&output.stderr).to_string();
135
136 if !output.status.success() {
137 anyhow::bail!("Zig tests failed:\nStdout: {}\nStderr: {}", stdout, stderr);
138 }
139
140 Ok(format!("Stdout: {}\nStderr: {}", stdout, stderr))
141 }
142}
143
144impl Default for ZigCompiler {
145 fn default() -> Self {
146 Self::new()
147 }
148}
149
150#[cfg(test)]
151mod tests {
152 use super::*;
153
154 #[test]
155 fn test_compiler_creation() {
156 let compiler = ZigCompiler::new();
157 assert!(!compiler.zig_path.is_empty());
158 }
159
160 #[test]
161 #[ignore] fn test_check_version() {
163 let compiler = ZigCompiler::new();
164 let version = compiler.check_version();
165 if version.is_ok() {
166 println!("Zig version: {}", version.unwrap());
167 }
168 }
169}