use crate::core::backend::GeneratedFile;
use crate::core::config::{Language, ScaffoldCargo, ScaffoldCargoEnvValue};
use crate::scaffold::template_env;
pub(crate) fn rust_toolchain_file(languages: &[Language]) -> GeneratedFile {
let targets = if languages.contains(&Language::Wasm) {
"targets = [\"wasm32-unknown-unknown\"]\n"
} else {
""
};
GeneratedFile {
path: std::path::PathBuf::from("rust-toolchain.toml"),
content: format!(
"[toolchain]\nchannel = \"1.95\"\ncomponents = [\"rust-src\", \"rustfmt\", \"clippy\"]\n{targets}"
),
generated_header: true,
}
}
pub fn render_cargo_config(cargo: &ScaffoldCargo) -> String {
let mut out = String::new();
out.push_str("# This file is auto-generated by alef. DO NOT EDIT.\n");
out.push_str("# Re-generate with: alef scaffold\n");
out.push('\n');
out.push_str("[build]\nincremental = true\n");
if cargo.build_jobs > 0 {
out.push_str(&format!("jobs = {}\n", cargo.build_jobs));
}
if let Some(wrapper) = cargo.rustc_wrapper.as_deref() {
out.push_str(&format!("rustc-wrapper = \"{}\"\n", escape_toml_string(wrapper)));
}
out.push('\n');
out.push_str("[net]\ngit-fetch-with-cli = true\n\n");
out.push_str("[registries.crates-io]\nprotocol = \"sparse\"\n");
let t = &cargo.targets;
if t.macos_dynamic_lookup {
out.push_str(
"\n# Required for PyO3 / ext-php-rs cdylibs: Python and Zend C-API symbols are\n\
# resolved at runtime when the host loads the extension, not at link time.\n\
# macOS ld is strict and rejects unresolved symbols by default.\n\
[target.'cfg(target_os = \"macos\")']\n\
rustflags = [\"-C\", \"link-arg=-Wl,-undefined,dynamic_lookup\"]\n",
);
}
if t.x86_64_pc_windows_msvc {
out.push_str("\n[target.x86_64-pc-windows-msvc]\nlinker = \"rust-lld\"\n");
}
if t.i686_pc_windows_msvc {
out.push_str("\n[target.i686-pc-windows-msvc]\nlinker = \"rust-lld\"\n");
}
if t.aarch64_unknown_linux_gnu {
out.push_str("\n[target.aarch64-unknown-linux-gnu]\nlinker = \"aarch64-linux-gnu-gcc\"\n");
}
if t.x86_64_unknown_linux_musl {
out.push_str("\n[target.x86_64-unknown-linux-musl]\nlinker = \"musl-gcc\"\n");
}
if t.wasm32_unknown_unknown {
out.push_str(
"\n[target.wasm32-unknown-unknown]\n\
rustflags = [\"-C\", \"target-feature=+bulk-memory\", \"--cfg\", \"getrandom_backend=\\\"wasm_js\\\"\", \"-C\", \"link-arg=--allow-multiple-definition\"]\n",
);
}
if !cargo.env.is_empty() {
out.push_str("\n[env]\n");
let mut keys: Vec<&String> = cargo.env.keys().collect();
keys.sort();
for key in keys {
let value = &cargo.env[key];
match value {
ScaffoldCargoEnvValue::Plain(s) => {
out.push_str(&template_env::render(
"cargo_env_plain.jinja",
minijinja::context! { key => key, value => escape_toml_string(s) },
));
}
ScaffoldCargoEnvValue::Structured { value, relative } => {
out.push_str(&template_env::render(
"cargo_env_structured.jinja",
minijinja::context! {
key => key,
value => escape_toml_string(value),
relative => if *relative { "true" } else { "false" },
},
));
}
}
}
}
out
}
fn escape_toml_string(s: &str) -> String {
s.replace('\\', "\\\\").replace('"', "\\\"")
}