00ca2ebac6
- 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
234 lines
6.6 KiB
Rust
Executable File
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)
|
|
}
|