fix: embed C compiler path at build time for self-contained binary
build.rs captures the absolute path to cc/gcc/clang during compilation and bakes it into the binary. On Nix systems this embeds the full /nix/store path so `lux compile` works without cc on PATH. Lookup order: $CC env var > embedded build-time path > PATH search. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
38
build.rs
Normal file
38
build.rs
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// Capture the absolute C compiler path at build time so the binary is self-contained.
|
||||||
|
// This is critical for Nix builds where cc/gcc live in /nix/store paths.
|
||||||
|
let cc_path = std::env::var("CC").ok()
|
||||||
|
.filter(|s| !s.is_empty())
|
||||||
|
.and_then(|s| resolve_absolute(&s))
|
||||||
|
.or_else(|| find_in_path("cc"))
|
||||||
|
.or_else(|| find_in_path("gcc"))
|
||||||
|
.or_else(|| find_in_path("clang"))
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
|
println!("cargo:rustc-env=LUX_CC_PATH={}", cc_path);
|
||||||
|
println!("cargo:rerun-if-env-changed=CC");
|
||||||
|
println!("cargo:rerun-if-env-changed=PATH");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Resolve a command name to its absolute path by searching PATH.
|
||||||
|
fn find_in_path(cmd: &str) -> Option<String> {
|
||||||
|
let path_var = std::env::var("PATH").ok()?;
|
||||||
|
for dir in path_var.split(':') {
|
||||||
|
let candidate = PathBuf::from(dir).join(cmd);
|
||||||
|
if candidate.is_file() {
|
||||||
|
return Some(candidate.to_string_lossy().into_owned());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
/// If the path is already absolute and exists, return it. Otherwise search PATH.
|
||||||
|
fn resolve_absolute(cmd: &str) -> Option<String> {
|
||||||
|
let p = PathBuf::from(cmd);
|
||||||
|
if p.is_absolute() && p.is_file() {
|
||||||
|
return Some(cmd.to_string());
|
||||||
|
}
|
||||||
|
find_in_path(cmd)
|
||||||
|
}
|
||||||
34
src/main.rs
34
src/main.rs
@@ -726,6 +726,36 @@ fn collect_lux_files_nonrecursive(dir: &str, pattern: Option<&str>, files: &mut
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Find a C compiler. Priority: $CC env var, build-time embedded path, PATH search.
|
||||||
|
fn find_c_compiler() -> String {
|
||||||
|
// 1. Explicit env var
|
||||||
|
if let Ok(cc) = std::env::var("CC") {
|
||||||
|
if !cc.is_empty() {
|
||||||
|
return cc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 2. Path captured at build time (e.g. absolute nix store path)
|
||||||
|
let built_in = env!("LUX_CC_PATH");
|
||||||
|
if !built_in.is_empty() && std::path::Path::new(built_in).exists() {
|
||||||
|
return built_in.to_string();
|
||||||
|
}
|
||||||
|
// 3. Search PATH
|
||||||
|
for name in &["cc", "gcc", "clang"] {
|
||||||
|
if let Ok(output) = std::process::Command::new("which").arg(name).output() {
|
||||||
|
if output.status.success() {
|
||||||
|
if let Ok(p) = String::from_utf8(output.stdout) {
|
||||||
|
let p = p.trim();
|
||||||
|
if !p.is_empty() {
|
||||||
|
return p.to_string();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 4. Last resort
|
||||||
|
"cc".to_string()
|
||||||
|
}
|
||||||
|
|
||||||
fn compile_to_c(path: &str, output_path: Option<&str>, run_after: bool, emit_c: bool) {
|
fn compile_to_c(path: &str, output_path: Option<&str>, run_after: bool, emit_c: bool) {
|
||||||
use codegen::c_backend::CBackend;
|
use codegen::c_backend::CBackend;
|
||||||
use modules::ModuleLoader;
|
use modules::ModuleLoader;
|
||||||
@@ -817,8 +847,8 @@ fn compile_to_c(path: &str, output_path: Option<&str>, run_after: bool, emit_c:
|
|||||||
std::process::exit(1);
|
std::process::exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find C compiler
|
// Find C compiler: $CC env var > embedded build-time path > PATH search
|
||||||
let cc = std::env::var("CC").unwrap_or_else(|_| "cc".to_string());
|
let cc = find_c_compiler();
|
||||||
|
|
||||||
let compile_result = Command::new(&cc)
|
let compile_result = Command::new(&cc)
|
||||||
.args(["-O2", "-o"])
|
.args(["-O2", "-o"])
|
||||||
|
|||||||
Reference in New Issue
Block a user