Files
depot/src/cross.rs
T
SFG545 00ca2ebac6 feat: initial implementation of Depot package manager
- Implement source-based package management with support for archives and Git
- Add multi-system build support (Autotools, CMake, Meson, Rust/Cargo, Custom)
- Implement atomic installation logic using transactions and fakeroot
- Add dependency resolution for build-time and runtime requirements
- Implement package indexing and local repository management
- Add comprehensive configuration system with system/package overrides
- Include Project guidelines (AGENTS.md) and README.md
2026-02-16 11:35:23 -06:00

234 lines
6.6 KiB
Rust
Executable File

//! Cross-compilation support
//!
//! Provides configuration for cross-compiling packages with a target triplet prefix.
use anyhow::{Context, Result};
use std::fs;
use std::io::Write;
use std::path::{Path, PathBuf};
use std::process::Command;
/// Cross-compilation configuration
#[derive(Debug, Clone)]
pub struct CrossConfig {
/// Target triplet prefix (e.g., "x86_64-linux-musl")
pub prefix: String,
/// C compiler
pub cc: String,
/// C++ compiler
pub cxx: String,
/// Archiver
pub ar: String,
/// Ranlib
pub ranlib: String,
/// Strip
pub strip: String,
/// Linker (ld)
pub ld: String,
/// nm
pub nm: String,
/// objcopy
pub objcopy: String,
/// objdump
pub objdump: String,
/// readelf
pub readelf: String,
}
impl CrossConfig {
/// Create a cross-compilation config by discovering tools in PATH
pub fn from_prefix(prefix: &str) -> Result<Self> {
let cc = find_tool(prefix, &["gcc", "clang"], true)?;
let cxx = find_tool(prefix, &["g++", "clang++"], false)
.unwrap_or_else(|_| format!("{}-g++", prefix));
let ar = find_tool(prefix, &["ar", "llvm-ar"], true)?;
let ranlib = find_tool(prefix, &["ranlib", "llvm-ranlib"], false)
.unwrap_or_else(|_| format!("{}-ranlib", prefix));
let strip = find_tool(prefix, &["strip", "llvm-strip"], false)
.unwrap_or_else(|_| format!("{}-strip", prefix));
let ld = find_tool(prefix, &["ld", "ld.lld"], false)
.unwrap_or_else(|_| format!("{}-ld", prefix));
let nm = find_tool(prefix, &["nm", "llvm-nm"], false)
.unwrap_or_else(|_| format!("{}-nm", prefix));
let objcopy = find_tool(prefix, &["objcopy", "llvm-objcopy"], false)
.unwrap_or_else(|_| format!("{}-objcopy", prefix));
let objdump = find_tool(prefix, &["objdump", "llvm-objdump"], false)
.unwrap_or_else(|_| format!("{}-objdump", prefix));
let readelf = find_tool(prefix, &["readelf", "llvm-readelf"], false)
.unwrap_or_else(|_| format!("{}-readelf", prefix));
println!("Cross-compilation tools discovered:");
println!(" CC: {}", cc);
println!(" CXX: {}", cxx);
println!(" AR: {}", ar);
println!(" RANLIB: {}", ranlib);
println!(" STRIP: {}", strip);
Ok(Self {
prefix: prefix.to_string(),
cc,
cxx,
ar,
ranlib,
strip,
ld,
nm,
objcopy,
objdump,
readelf,
})
}
/// Get the host triple for autotools --host flag
pub fn host_triple(&self) -> &str {
&self.prefix
}
/// Get the build machine triple (native compiler)
pub fn build_triple() -> Result<String> {
let output = Command::new("gcc")
.arg("-dumpmachine")
.output()
.or_else(|_| Command::new("cc").arg("-dumpmachine").output())
.context("Failed to determine build machine triple")?;
Ok(String::from_utf8_lossy(&output.stdout).trim().to_string())
}
/// Generate a CMake toolchain file for cross-compilation
pub fn generate_cmake_toolchain(&self, build_dir: &Path) -> Result<PathBuf> {
let toolchain_path = build_dir.join("cross-toolchain.cmake");
let content = format!(
r#"# CMake toolchain file for cross-compilation
# Generated by nyapm for target: {}
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR {})
set(CMAKE_C_COMPILER {})
set(CMAKE_CXX_COMPILER {})
set(CMAKE_AR {} CACHE FILEPATH "Archiver")
set(CMAKE_RANLIB {} CACHE FILEPATH "Ranlib")
set(CMAKE_STRIP {} CACHE FILEPATH "Strip")
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
"#,
self.prefix,
self.target_arch(),
self.cc,
self.cxx,
self.ar,
self.ranlib,
self.strip,
);
fs::create_dir_all(build_dir)?;
let mut file = fs::File::create(&toolchain_path)?;
file.write_all(content.as_bytes())?;
Ok(toolchain_path)
}
/// Generate a Meson cross file for cross-compilation
pub fn generate_meson_cross_file(&self, build_dir: &Path) -> Result<PathBuf> {
let cross_path = build_dir.join("cross-file.ini");
let content = format!(
r#"# Meson cross file for cross-compilation
# Generated by nyapm for target: {}
[binaries]
c = '{}'
cpp = '{}'
ar = '{}'
strip = '{}'
ld = '{}'
nm = '{}'
objcopy = '{}'
objdump = '{}'
readelf = '{}'
[host_machine]
system = 'linux'
cpu_family = '{}'
cpu = '{}'
endian = 'little'
"#,
self.prefix,
self.cc,
self.cxx,
self.ar,
self.strip,
self.ld,
self.nm,
self.objcopy,
self.objdump,
self.readelf,
self.cpu_family(),
self.target_arch(),
);
fs::create_dir_all(build_dir)?;
let mut file = fs::File::create(&cross_path)?;
file.write_all(content.as_bytes())?;
Ok(cross_path)
}
/// Extract target architecture from prefix
fn target_arch(&self) -> &str {
self.prefix.split('-').next().unwrap_or("unknown")
}
/// Get CPU family for Meson
fn cpu_family(&self) -> &str {
let arch = self.target_arch();
match arch {
"x86_64" | "amd64" => "x86_64",
"i686" | "i586" | "i486" | "i386" => "x86",
"aarch64" | "arm64" => "aarch64",
"arm" | "armv7" | "armv7l" => "arm",
"riscv64" => "riscv64",
"riscv32" => "riscv32",
"powerpc64" | "ppc64" => "ppc64",
"powerpc" | "ppc" => "ppc",
"mips64" => "mips64",
"mips" => "mips",
_ => arch,
}
}
}
/// Find a cross-compilation tool in PATH
fn find_tool(prefix: &str, suffixes: &[&str], required: bool) -> Result<String> {
for suffix in suffixes {
let tool_name = format!("{}-{}", prefix, suffix);
if tool_exists(&tool_name) {
return Ok(tool_name);
}
}
if required {
anyhow::bail!(
"Could not find cross tool: {}-{{{}}}",
prefix,
suffixes.join("|")
);
}
Err(anyhow::anyhow!("Tool not found"))
}
/// Check if a tool exists in PATH
fn tool_exists(name: &str) -> bool {
Command::new("which")
.arg(name)
.output()
.map(|o| o.status.success())
.unwrap_or(false)
}