use std::collections::{BTreeMap, HashMap, HashSet, VecDeque};
use std::fmt;
use std::path::{Path, PathBuf};
use std::time::SystemTime;
#[derive(Debug, Clone)]
pub struct PlatformSysrootDetector {
pub target_triple: String,
pub forced_sysroot: Option<PathBuf>,
pub search_xcode: bool,
pub search_android_ndk: bool,
pub search_windows_sdk: bool,
}
impl PlatformSysrootDetector {
pub fn new(triple: &str) -> Self {
Self {
target_triple: triple.to_string(),
forced_sysroot: None,
search_xcode: cfg!(target_os = "macos")
|| triple.contains("darwin")
|| triple.contains("apple"),
search_android_ndk: triple.contains("android"),
search_windows_sdk: triple.contains("windows") || triple.contains("msvc"),
}
}
pub fn detect(&self) -> Option<PathBuf> {
if let Some(ref forced) = self.forced_sysroot {
if forced.exists() {
return Some(forced.clone());
}
}
if self.search_xcode {
if let Some(sdk) = detect_xcode_sdk(&self.target_triple) {
return Some(sdk);
}
}
if self.search_android_ndk {
if let Some(ndk) = detect_android_ndk_sysroot(&self.target_triple) {
return Some(ndk);
}
}
if self.search_windows_sdk {
if let Some(sdk) = detect_windows_sdk_sysroot() {
return Some(sdk);
}
}
if is_host_triple(&self.target_triple) {
Some(PathBuf::from("/"))
} else {
None
}
}
}
fn detect_xcode_sdk(triple: &str) -> Option<PathBuf> {
let sdk_name = if triple.contains("iphone") {
if triple.contains("simulator") {
"iphonesimulator"
} else {
"iphoneos"
}
} else if triple.contains("tvos") {
if triple.contains("simulator") {
"appletvsimulator"
} else {
"appletvos"
}
} else if triple.contains("watchos") {
if triple.contains("simulator") {
"watchsimulator"
} else {
"watchos"
}
} else {
"macosx"
};
if let Ok(output) = std::process::Command::new("xcrun")
.args(["--sdk", sdk_name, "--show-sdk-path"])
.output()
{
let path = String::from_utf8_lossy(&output.stdout).trim().to_string();
if !path.is_empty() && Path::new(&path).exists() {
return Some(PathBuf::from(path));
}
}
let xcode_base = std::env::var("DEVELOPER_DIR")
.unwrap_or_else(|_| "/Applications/Xcode.app/Contents/Developer".to_string());
let sdk_path = PathBuf::from(&xcode_base)
.join("Platforms")
.join(match sdk_name {
"macosx" => "MacOSX.platform/Developer/SDKs",
"iphoneos" => "iPhoneOS.platform/Developer/SDKs",
"iphonesimulator" => "iPhoneSimulator.platform/Developer/SDKs",
_ => return None,
});
if sdk_path.exists() {
find_latest_sdk_version(&sdk_path)
} else {
None
}
}
fn find_latest_sdk_version(sdk_dir: &Path) -> Option<PathBuf> {
match std::fs::read_dir(sdk_dir) { Ok(entries) => {
let mut latest: Option<(String, PathBuf)> = None;
for entry in entries.flatten() {
let name = entry.file_name().to_string_lossy().to_string();
if name.ends_with(".sdk") {
let ver = name.trim_end_matches(".sdk").to_string();
match latest {
None => latest = Some((ver, entry.path())),
Some((ref prev, _)) if ver > *prev => latest = Some((ver, entry.path())),
_ => {}
}
}
}
latest.map(|(_, p)| p)
} _ => {
None
}}
}
fn detect_android_ndk_sysroot(triple: &str) -> Option<PathBuf> {
let ndk = std::env::var("ANDROID_NDK_HOME")
.or_else(|_| std::env::var("ANDROID_NDK"))
.or_else(|_| std::env::var("NDK_HOME"))
.ok()?;
let ndk_path = PathBuf::from(&ndk);
let api_level = determine_android_api_level(triple);
let arch = if triple.contains("x86_64") || triple.contains("amd64") {
"x86_64"
} else if triple.contains("i686") || triple.contains("i386") {
"i686"
} else if triple.contains("aarch64") {
"arm64"
} else if triple.contains("arm") {
"arm"
} else {
"x86_64"
};
let sysroot = ndk_path.join("toolchains/llvm/prebuilt/linux-x86_64/sysroot");
if sysroot.exists() {
return Some(sysroot);
}
let sysroot_old = ndk_path
.join("platforms")
.join(format!("android-{}", api_level))
.join(format!("arch-{}", arch));
if sysroot_old.exists() {
return Some(sysroot_old);
}
None
}
fn determine_android_api_level(_triple: &str) -> u32 {
if let Ok(level) = std::env::var("ANDROID_PLATFORM") {
if let Ok(n) = level.trim_start_matches("android-").parse::<u32>() {
return n;
}
}
21 }
fn detect_windows_sdk_sysroot() -> Option<PathBuf> {
if let Ok(dir) = std::env::var("WindowsSdkDir") {
let p = PathBuf::from(&dir);
if p.exists() {
return Some(p);
}
}
let bases = [
"C:/Program Files (x86)/Windows Kits/10",
"C:/Program Files/Windows Kits/10",
];
for base in &bases {
let p = Path::new(base);
if !p.exists() {
continue;
}
if let Ok(entries) = std::fs::read_dir(p) {
for entry in entries.flatten() {
let name = entry.file_name().to_string_lossy().to_string();
if name.chars().next().map_or(false, |c| c.is_ascii_digit()) {
let sub = entry.path();
if sub.join("Include").exists() && sub.join("Lib").exists() {
return Some(sub);
}
}
}
}
}
None
}
fn is_host_triple(triple: &str) -> bool {
let host_os = if cfg!(target_os = "linux") {
"linux"
} else if cfg!(target_os = "macos") {
"darwin"
} else if cfg!(target_os = "windows") {
"windows"
} else if cfg!(target_os = "freebsd") {
"freebsd"
} else {
return false;
};
triple.contains(host_os) && !triple.contains("android") && !triple.contains("ios")
}
#[derive(Debug, Clone)]
pub struct MultilibDetector {
pub target_triple: String,
pub prefer_64bit: bool,
pub variants: Vec<MultilibVariant>,
pub selection_flags: Vec<String>,
}
#[derive(Debug, Clone)]
pub struct MultilibVariant {
pub dir_suffix: String,
pub flags: Vec<String>,
pub os_dir: String,
pub include_dir: String,
pub lib_dir: String,
}
impl MultilibDetector {
pub fn new(triple: &str) -> Self {
let mut d = Self {
target_triple: triple.to_string(),
prefer_64bit: triple.contains("64")
|| triple.contains("x86_64")
|| triple.contains("amd64"),
variants: Vec::new(),
selection_flags: Vec::new(),
};
d.detect();
d
}
fn detect(&mut self) {
if self.target_triple.contains("x86_64") || self.target_triple.contains("amd64") {
self.variants.push(MultilibVariant {
dir_suffix: String::new(),
flags: vec!["-m64".into()],
os_dir: "../lib64".into(),
include_dir: "../include".into(),
lib_dir: "../lib64".into(),
});
self.variants.push(MultilibVariant {
dir_suffix: "32".into(),
flags: vec!["-m32".into()],
os_dir: "../lib".into(),
include_dir: "../include".into(),
lib_dir: "../lib".into(),
});
self.variants.push(MultilibVariant {
dir_suffix: "x32".into(),
flags: vec!["-mx32".into()],
os_dir: "../libx32".into(),
include_dir: "../include".into(),
lib_dir: "../libx32".into(),
});
} else if self.target_triple.contains("i386") || self.target_triple.contains("i686") {
self.variants.push(MultilibVariant {
dir_suffix: String::new(),
flags: vec!["-m32".into()],
os_dir: "../lib".into(),
include_dir: "../include".into(),
lib_dir: "../lib".into(),
});
}
}
pub fn default_flags(&self) -> Vec<String> {
self.variants
.first()
.map(|v| v.flags.clone())
.unwrap_or_default()
}
pub fn select(&mut self, flag: &str) -> Option<&MultilibVariant> {
for v in &self.variants {
if v.flags.contains(&flag.to_string()) {
self.selection_flags = vec![flag.to_string()];
return Some(v);
}
}
None
}
pub fn selected(&self) -> Option<&MultilibVariant> {
if self.selection_flags.is_empty() {
self.variants.first()
} else {
let flag = &self.selection_flags[0];
self.variants.iter().find(|v| v.flags.contains(flag))
}
}
}
#[derive(Debug, Clone, Default)]
pub struct HeaderDependencyGraph {
pub edges: HashMap<String, Vec<String>>,
pub reverse_edges: HashMap<String, Vec<String>>,
}
impl HeaderDependencyGraph {
pub fn new() -> Self {
Self {
edges: HashMap::new(),
reverse_edges: HashMap::new(),
}
}
pub fn add_edge(&mut self, from: &str, to: &str) {
self.edges
.entry(from.to_string())
.or_default()
.push(to.to_string());
self.reverse_edges
.entry(to.to_string())
.or_default()
.push(from.to_string());
self.edges.entry(to.to_string()).or_default();
self.reverse_edges.entry(from.to_string()).or_default();
}
pub fn topological_sort(&self) -> Option<Vec<String>> {
let mut in_degree: HashMap<&str, usize> = HashMap::new();
for node in self.edges.keys() {
in_degree.entry(node).or_insert(0);
}
for (_, deps) in &self.edges {
for dep in deps {
*in_degree.entry(dep).or_insert(0) += 1;
}
}
let mut queue: VecDeque<&str> = in_degree
.iter()
.filter(|&(_, °)| deg == 0)
.map(|(&node, _)| node)
.collect();
let mut result = Vec::new();
while let Some(node) = queue.pop_front() {
result.push(node.to_string());
if let Some(deps) = self.edges.get(node) {
for dep in deps {
if let Some(deg) = in_degree.get_mut(dep.as_str()) {
*deg -= 1;
if *deg == 0 {
queue.push_back(dep);
}
}
}
}
}
if result.len() == self.edges.len() {
Some(result)
} else {
None }
}
pub fn transitive_deps(&self, root: &str) -> Vec<String> {
let mut visited = HashSet::new();
let mut result = Vec::new();
let mut stack = vec![root.to_string()];
while let Some(node) = stack.pop() {
if !visited.insert(node.clone()) {
continue;
}
result.push(node.clone());
if let Some(deps) = self.edges.get(&node) {
for dep in deps {
if !visited.contains(dep) {
stack.push(dep.clone());
}
}
}
}
result.remove(0); result
}
pub fn direct_deps(&self, name: &str) -> Vec<&str> {
self.edges
.get(name)
.map(|v| v.iter().map(|s| s.as_str()).collect())
.unwrap_or_default()
}
pub fn dependents(&self, name: &str) -> Vec<&str> {
self.reverse_edges
.get(name)
.map(|v| v.iter().map(|s| s.as_str()).collect())
.unwrap_or_default()
}
pub fn build_c_stdlib_graph() -> Self {
let mut g = Self::new();
for h in &[
"stdio.h", "stdlib.h", "string.h", "time.h", "wchar.h", "locale.h",
] {
g.add_edge(h, "stddef.h");
}
g.add_edge("stdio.h", "stdarg.h");
g.add_edge("stdlib.h", "limits.h");
g.add_edge("wchar.h", "limits.h");
g.add_edge("stdint.h", "limits.h");
g.add_edge("time.h", "stddef.h");
g.add_edge("signal.h", "stddef.h");
g.add_edge("setjmp.h", "stddef.h");
g.add_edge("stdio.h", "stddef.h");
g.add_edge("stdio.h", "stdarg.h");
g.add_edge("errno.h", "");
g.add_edge("complex.h", "math.h");
g.add_edge("fenv.h", "stddef.h");
g.add_edge("inttypes.h", "stdint.h");
g.add_edge("inttypes.h", "stddef.h");
g.add_edge("threads.h", "time.h");
g.add_edge("threads.h", "stddef.h");
g.add_edge("uchar.h", "stddef.h");
g.add_edge("wctype.h", "wchar.h");
g.add_edge("wctype.h", "stddef.h");
g.add_edge("locale.h", "stddef.h");
g
}
pub fn build_cxx_stdlib_graph() -> Self {
let mut g = Self::new();
g.add_edge("iostream", "istream");
g.add_edge("iostream", "ostream");
g.add_edge("istream", "ios");
g.add_edge("ostream", "ios");
g.add_edge("ios", "iosfwd");
g.add_edge("ios", "streambuf");
g.add_edge("ios", "locale");
g.add_edge("streambuf", "iosfwd");
g.add_edge("fstream", "iostream");
g.add_edge("fstream", "filesystem");
g.add_edge("sstream", "iostream");
g.add_edge("sstream", "string");
g.add_edge("string", "string_view");
g.add_edge("string", "initializer_list");
g.add_edge("string", "memory");
g.add_edge("vector", "initializer_list");
g.add_edge("vector", "memory");
g.add_edge("vector", "algorithm");
g.add_edge("map", "initializer_list");
g.add_edge("map", "memory");
g.add_edge("set", "initializer_list");
g.add_edge("set", "memory");
g.add_edge("algorithm", "initializer_list");
g.add_edge("algorithm", "memory");
g.add_edge("algorithm", "iterator");
g.add_edge("memory", "new");
g.add_edge("memory", "type_traits");
g.add_edge("memory", "utility");
g.add_edge("thread", "chrono");
g.add_edge("thread", "functional");
g.add_edge("thread", "memory");
g.add_edge("condition_variable", "mutex");
g.add_edge("condition_variable", "chrono");
g.add_edge("future", "thread");
g.add_edge("future", "memory");
g.add_edge("format", "string_view");
g.add_edge("format", "memory");
g.add_edge("ranges", "iterator");
g.add_edge("ranges", "memory");
g.add_edge("ranges", "concepts");
g.add_edge("span", "cstddef");
g.add_edge("span", "iterator");
g.add_edge("optional", "type_traits");
g.add_edge("variant", "type_traits");
g.add_edge("variant", "memory");
g.add_edge("expected", "type_traits");
g.add_edge("expected", "memory");
g.add_edge("filesystem", "string");
g.add_edge("filesystem", "memory");
g.add_edge("filesystem", "chrono");
g.add_edge("chrono", "limits");
g.add_edge("chrono", "ctime");
g.add_edge("regex", "string");
g.add_edge("regex", "memory");
g.add_edge("regex", "iterator");
g.add_edge("random", "limits");
g.add_edge("random", "vector");
g.add_edge("valarray", "cmath");
g.add_edge("valarray", "memory");
g.add_edge("numeric", "iterator");
g.add_edge("execution", "type_traits");
g.add_edge("bit", "concepts");
g.add_edge("bit", "limits");
g.add_edge("compare", "concepts");
g.add_edge("concepts", "");
g.add_edge("coroutine", "memory");
g.add_edge("stacktrace", "string");
g.add_edge("stacktrace", "memory");
g.add_edge("print", "format");
g.add_edge("barrier", "thread");
g.add_edge("latch", "thread");
g.add_edge("semaphore", "chrono");
g.add_edge("semaphore", "thread");
g.add_edge("syncstream", "ostream");
g.add_edge("spanstream", "span");
g.add_edge("spanstream", "iostream");
g.add_edge("mdspan", "span");
g.add_edge("mdspan", "cstddef");
g.add_edge("generator", "coroutine");
g.add_edge("generator", "memory");
g
}
}
#[derive(Debug, Clone)]
pub struct X86HeaderSearch {
pub paths: HeaderSearchPaths,
pub builtin_headers: X86BuiltinHeaders,
pub intrinsic_headers: X86IntrinsicHeaders,
pub standard_headers: X86StandardHeaders,
pub module_map: X86ModuleMap,
pub vfs_overlay: X86VFSOverlay,
pub include_cache: X86IncludeCache,
pub header_guard: X86HeaderGuard,
pub max_include_depth: usize,
pub use_standard_system_includes: bool,
pub use_standard_cxx_includes: bool,
pub warn_missing_headers: bool,
include_count: usize,
skip_count: usize,
track_pragma_once: bool,
pragma_once_set: HashSet<PathBuf>,
}
impl X86HeaderSearch {
pub fn new(target_triple: &str) -> Self {
let resource_dir = infer_resource_dir();
Self {
paths: HeaderSearchPaths::for_target(target_triple, &resource_dir),
builtin_headers: X86BuiltinHeaders::default(),
intrinsic_headers: X86IntrinsicHeaders::default(),
standard_headers: X86StandardHeaders::default(),
module_map: X86ModuleMap::default(),
vfs_overlay: X86VFSOverlay::default(),
include_cache: X86IncludeCache::new(512),
header_guard: X86HeaderGuard::default(),
max_include_depth: 200,
use_standard_system_includes: true,
use_standard_cxx_includes: true,
warn_missing_headers: true,
include_count: 0,
skip_count: 0,
track_pragma_once: true,
pragma_once_set: HashSet::new(),
}
}
pub fn with_standard_includes(mut self) -> Self {
self.use_standard_system_includes = true;
self.use_standard_cxx_includes = true;
self.paths.add_default_paths();
self
}
pub fn disable_standard_includes(&mut self) {
self.use_standard_system_includes = false;
self.use_standard_cxx_includes = false;
}
pub fn disable_standard_cxx_includes(&mut self) {
self.use_standard_cxx_includes = false;
}
pub fn disable_builtin_includes(&mut self) {
self.paths.remove_resource_dir();
}
pub fn add_user_path(&mut self, path: &str) {
self.paths.add_user_path(path);
}
pub fn add_system_path(&mut self, path: &str) {
self.paths.add_system_path(path);
}
pub fn add_quote_path(&mut self, path: &str) {
self.paths.add_quote_path(path);
}
pub fn add_after_path(&mut self, path: &str) {
self.paths.add_after_path(path);
}
pub fn add_framework_path(&mut self, path: &str) {
self.paths.add_framework_path(path);
}
pub fn set_sysroot(&mut self, sysroot: &str) {
self.paths.set_sysroot(sysroot);
}
pub fn set_resource_dir(&mut self, dir: &str) {
self.paths.set_resource_dir(dir);
self.intrinsic_headers.set_resource_dir(dir);
}
pub fn load_vfs_overlay(&mut self, overlay_path: &str) -> std::io::Result<()> {
self.vfs_overlay.load(overlay_path)
}
pub fn load_module_map(&mut self, dir: &str) {
self.module_map.load_directory(dir);
}
pub fn resolve_quoted_include(
&mut self,
name: &str,
relative_to: Option<&Path>,
) -> Option<(PathBuf, bool)> {
if let Some(ref content) = self.builtin_headers.resolve(name) {
let path = PathBuf::from(format!("<builtin>/{}", name));
self.include_cache.insert_builtin(&path, content);
return Some((path, true));
}
if let Some(ref content) = self.intrinsic_headers.resolve(name) {
let path = PathBuf::from(format!("<intrinsic>/{}", name));
self.include_cache.insert_builtin(&path, content);
return Some((path, true));
}
if let Some(ref content) = self.standard_headers.resolve(name) {
let path = PathBuf::from(format!("<standard>/{}", name));
self.include_cache.insert_builtin(&path, content);
return Some((path, true));
}
if let Some(remapped) = self.vfs_overlay.remap(name) {
return Some((remapped, false));
}
if let Some(base) = relative_to {
if let Some(parent) = base.parent() {
let candidate = parent.join(name);
if candidate.exists() {
return self.try_cache_hit(&candidate);
}
}
}
self.paths.resolve_quoted(name)
}
pub fn resolve_system_include(&mut self, name: &str) -> Option<(PathBuf, bool)> {
if let Some(ref content) = self.builtin_headers.resolve(name) {
let path = PathBuf::from(format!("<builtin>/{}", name));
self.include_cache.insert_builtin(&path, content);
return Some((path, true));
}
if let Some(ref content) = self.intrinsic_headers.resolve(name) {
let path = PathBuf::from(format!("<intrinsic>/{}", name));
self.include_cache.insert_builtin(&path, content);
return Some((path, true));
}
if let Some(ref content) = self.standard_headers.resolve(name) {
let path = PathBuf::from(format!("<standard>/{}", name));
self.include_cache.insert_builtin(&path, content);
return Some((path, true));
}
if let Some(remapped) = self.vfs_overlay.remap(name) {
return Some((remapped, false));
}
self.paths.resolve_system(name)
}
pub fn read_include(&mut self, path: &Path) -> Option<String> {
if let Some(cached) = self.include_cache.get(path) {
return Some(cached.clone());
}
match std::fs::read_to_string(path) {
Ok(contents) => {
self.include_cache.insert(path, &contents);
Some(contents)
}
Err(_) => None,
}
}
pub fn mark_seen(&mut self, path: &Path, guard_macro: Option<&str>) {
self.include_cache.mark_seen(path);
if let Some(g) = guard_macro {
self.header_guard.mark_guard(g, path);
}
}
pub fn should_skip(&self, path: &Path) -> bool {
if self.track_pragma_once && self.pragma_once_set.contains(path) {
return true;
}
self.header_guard.is_guarded(path)
}
pub fn mark_pragma_once(&mut self, path: &Path) {
if self.track_pragma_once {
self.pragma_once_set.insert(path.to_path_buf());
}
}
pub fn record_include(&mut self) {
self.include_count += 1;
}
pub fn record_skip(&mut self) {
self.skip_count += 1;
}
pub fn include_count(&self) -> usize {
self.include_count
}
pub fn skip_count(&self) -> usize {
self.skip_count
}
pub fn clear_pragma_once(&mut self) {
self.pragma_once_set.clear();
}
pub fn clear_cache(&mut self) {
self.include_cache.clear();
self.include_count = 0;
self.skip_count = 0;
}
pub fn dump_paths(&self) -> Vec<String> {
self.paths.dump_paths()
}
pub fn lookup_module(&self, name: &str) -> Option<ModuleMapEntry> {
self.module_map.find(name)
}
pub fn module_names(&self) -> Vec<String> {
self.module_map.names()
}
fn try_cache_hit(&self, candidate: &Path) -> Option<(PathBuf, bool)> {
if self.include_cache.is_seen(candidate) || candidate.exists() {
Some((candidate.to_path_buf(), false))
} else {
None
}
}
}
impl Default for X86HeaderSearch {
fn default() -> Self {
Self::new("x86_64-unknown-linux-gnu")
}
}
#[derive(Debug, Clone)]
pub struct HeaderSearchPaths {
pub quote_paths: Vec<IncludeDir>,
pub user_paths: Vec<IncludeDir>,
pub system_paths: Vec<IncludeDir>,
pub after_paths: Vec<IncludeDir>,
pub framework_paths: Vec<IncludeDir>,
pub resource_dir: Option<PathBuf>,
pub sysroot: Option<PathBuf>,
pub gcc_install: Option<GccInstallationInfo>,
pub cxx_stdlib: CxxStdLibInfo,
pub target_triple: String,
standard_populated: bool,
}
impl HeaderSearchPaths {
pub fn for_target(triple: &str, resource_dir: &str) -> Self {
let mut paths = Self {
quote_paths: Vec::new(),
user_paths: Vec::new(),
system_paths: Vec::new(),
after_paths: Vec::new(),
framework_paths: Vec::new(),
resource_dir: Some(PathBuf::from(resource_dir)),
sysroot: None,
gcc_install: None,
cxx_stdlib: CxxStdLibInfo::default(),
target_triple: triple.to_string(),
standard_populated: false,
};
paths.detect_gcc();
paths.detect_cxx_stdlib();
paths
}
pub fn add_default_paths(&mut self) {
if self.standard_populated {
return;
}
self.standard_populated = true;
let triple = &self.target_triple.clone();
let is_64 = triple.contains("64") || triple.contains("x86_64");
let is_linux = triple.contains("linux");
let is_darwin = triple.contains("darwin") || triple.contains("apple");
let is_windows =
triple.contains("windows") || triple.contains("msvc") || triple.contains("mingw");
let is_freebsd = triple.contains("freebsd");
let is_android = triple.contains("android");
if let Some(ref rd) = self.resource_dir.clone() {
self.system_paths
.push(IncludeDir::system(rd.join("include")));
}
if is_linux {
self.add_linux_paths(is_64);
} else if is_darwin {
self.add_darwin_paths(is_64);
} else if is_windows {
self.add_windows_paths(is_64);
} else if is_freebsd {
self.add_freebsd_paths(is_64);
} else if is_android {
self.add_android_paths(is_64);
}
self.add_cxx_stdlib_paths();
self.add_gcc_paths();
}
fn add_linux_paths(&mut self, is_64: bool) {
if let Some(ref sroot) = self.sysroot.clone() {
let usr_include = sroot.join("usr/include");
if usr_include.exists() {
self.system_paths.push(IncludeDir::system(usr_include));
}
let local_include = sroot.join("usr/local/include");
if local_include.exists() {
self.system_paths.push(IncludeDir::system(local_include));
}
} else {
self.system_paths
.push(IncludeDir::system("/usr/local/include"));
self.system_paths.push(IncludeDir::system("/usr/include"));
if is_64 {
self.system_paths
.push(IncludeDir::system("/usr/include/x86_64-linux-gnu"));
self.system_paths
.push(IncludeDir::system("/usr/lib/gcc/x86_64-linux-gnu"));
} else {
self.system_paths
.push(IncludeDir::system("/usr/include/i386-linux-gnu"));
self.system_paths
.push(IncludeDir::system("/usr/lib/gcc/i386-linux-gnu"));
}
}
if is_64 {
self.after_paths
.push(IncludeDir::after("/usr/include/x86_64-linux-gnu"));
self.after_paths
.push(IncludeDir::after("/usr/lib/gcc/x86_64-linux-gnu"));
} else {
self.after_paths
.push(IncludeDir::after("/usr/include/i386-linux-gnu"));
self.after_paths
.push(IncludeDir::after("/usr/lib/gcc/i386-linux-gnu"));
}
}
fn add_darwin_paths(&mut self, is_64: bool) {
let base = self.sysroot.clone().unwrap_or_else(|| PathBuf::from("/"));
let sdk = base.join("usr/include");
let local = base.join("usr/local/include");
let frameworks = base.join("System/Library/Frameworks");
self.system_paths.push(IncludeDir::system(local));
self.system_paths.push(IncludeDir::system(sdk));
if frameworks.exists() {
self.framework_paths
.push(IncludeDir::framework(&frameworks));
}
let sdk_fw = base.join("System/Library/Frameworks");
if sdk_fw.exists() {
self.framework_paths.push(IncludeDir::framework(&sdk_fw));
}
if let Ok(xcode) = std::env::var("DEVELOPER_DIR") {
let toolchain =
PathBuf::from(xcode).join("Toolchains/XcodeDefault.xctoolchain/usr/include");
if toolchain.exists() {
self.system_paths.push(IncludeDir::system(toolchain));
}
}
}
fn add_windows_paths(&mut self, is_64: bool) {
if let Ok(include) = std::env::var("INCLUDE") {
for p in include.split(';') {
let trimmed = p.trim();
if !trimmed.is_empty() && Path::new(trimmed).exists() {
self.system_paths.push(IncludeDir::system(trimmed));
}
}
}
for vs_ver in &["17.0", "16.0", "15.0"] {
let base = format!("C:/Program Files/Microsoft Visual Studio/{}/", vs_ver);
if is_64 {
let d = format!("{}VC/Tools/MSVC/{}/include", base, vs_ver);
if Path::new(&d).exists() {
self.system_paths.push(IncludeDir::system(d));
}
} else {
let d = format!("{}VC/Tools/MSVC/{}/include", base, vs_ver);
if Path::new(&d).exists() {
self.system_paths.push(IncludeDir::system(d));
}
}
}
if let Some(winsdk) = detect_windows_sdk() {
self.system_paths
.push(IncludeDir::system(winsdk.join("Include")));
}
if is_64 {
self.system_paths
.push(IncludeDir::system("/mingw64/include"));
self.system_paths
.push(IncludeDir::system("/mingw64/x86_64-w64-mingw32/include"));
} else {
self.system_paths
.push(IncludeDir::system("/mingw32/include"));
self.system_paths
.push(IncludeDir::system("/mingw32/i686-w64-mingw32/include"));
}
}
fn add_freebsd_paths(&mut self, _is_64: bool) {
self.system_paths
.push(IncludeDir::system("/usr/local/include"));
self.system_paths.push(IncludeDir::system("/usr/include"));
self.system_paths
.push(IncludeDir::system("/usr/lib/clang/include"));
}
fn add_android_paths(&mut self, is_64: bool) {
let ndk = std::env::var("ANDROID_NDK_HOME")
.or_else(|_| std::env::var("ANDROID_NDK"))
.unwrap_or_else(|_| String::new());
if !ndk.is_empty() {
let ndk_path = PathBuf::from(&ndk);
let sysroot = ndk_path.join("sysroot/usr/include");
if sysroot.exists() {
self.system_paths.push(IncludeDir::system(sysroot));
}
if is_64 {
let aarch64 =
ndk_path.join("toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/include");
if aarch64.exists() {
self.system_paths.push(IncludeDir::system(aarch64));
}
} else {
let arm =
ndk_path.join("toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/include");
if arm.exists() {
self.system_paths.push(IncludeDir::system(arm));
}
}
}
self.system_paths
.push(IncludeDir::system("/system/usr/include"));
}
fn add_gcc_paths(&mut self) {
let gcc = match &self.gcc_install {
Some(g) => g.clone(),
None => return,
};
let install = &gcc.install_dir;
let triple = &gcc.target_triple;
for p in &gcc_c_include_paths(install, triple) {
self.system_paths.push(IncludeDir::system(p));
}
for p in &gcc_cxx_include_paths(install, triple, &gcc.version) {
self.system_paths.push(IncludeDir::system(p));
}
}
fn add_cxx_stdlib_paths(&mut self) {
match &self.cxx_stdlib.kind {
CxxStdLibKind::LibStdCxx => {
for p in &self.cxx_stdlib.include_paths {
self.system_paths.push(IncludeDir::system(p));
}
}
CxxStdLibKind::LibCxx => {
for p in &self.cxx_stdlib.include_paths {
self.system_paths.push(IncludeDir::system(p));
}
}
CxxStdLibKind::MsStl => {
for p in &self.cxx_stdlib.include_paths {
self.system_paths.push(IncludeDir::system(p));
}
}
_ => {}
}
}
pub fn detect_gcc(&mut self) {
self.gcc_install = detect_gcc_installation();
}
pub fn detect_cxx_stdlib(&mut self) {
self.cxx_stdlib = detect_cxx_stdlib();
}
pub fn add_user_path(&mut self, path: &str) {
self.user_paths.push(IncludeDir::user(path));
}
pub fn add_system_path(&mut self, path: &str) {
self.system_paths.push(IncludeDir::system(path));
}
pub fn add_quote_path(&mut self, path: &str) {
self.quote_paths.push(IncludeDir::quote(path));
}
pub fn add_after_path(&mut self, path: &str) {
self.after_paths.push(IncludeDir::after(path));
}
pub fn add_framework_path(&mut self, path: &str) {
self.framework_paths.push(IncludeDir::framework(path));
}
pub fn remove_resource_dir(&mut self) {
self.resource_dir = None;
self.system_paths
.retain(|d| !d.path.starts_with("<resource>"));
}
pub fn set_sysroot(&mut self, sysroot: &str) {
self.sysroot = Some(PathBuf::from(sysroot));
self.standard_populated = false;
}
pub fn set_resource_dir(&mut self, dir: &str) {
self.resource_dir = Some(PathBuf::from(dir));
}
pub fn resolve_quoted(&self, name: &str) -> Option<(PathBuf, bool)> {
for d in self
.quote_paths
.iter()
.chain(self.user_paths.iter())
.chain(self.system_paths.iter())
.chain(self.after_paths.iter())
{
let candidate = d.join(name);
if candidate.exists() {
return Some((candidate, d.is_system()));
}
}
for d in &self.framework_paths {
let framework_path = format!("{}.framework/Headers", strip_extension(name, ".h"));
let candidate = d.join(&framework_path);
if candidate.exists() {
return Some((candidate, true));
}
}
None
}
pub fn resolve_system(&self, name: &str) -> Option<(PathBuf, bool)> {
for d in self.system_paths.iter().chain(self.after_paths.iter()) {
let candidate = d.join(name);
if candidate.exists() {
return Some((candidate, d.is_system()));
}
}
for d in &self.framework_paths {
let framework_path = format!("{}.framework/Headers", strip_extension(name, ".h"));
let candidate = d.join(&framework_path);
if candidate.exists() {
return Some((candidate, true));
}
}
None
}
pub fn dump_paths(&self) -> Vec<String> {
let mut out = Vec::new();
out.push(format!("Target: {}", self.target_triple));
if let Some(ref s) = self.sysroot {
out.push(format!("Sysroot: {}", s.display()));
}
if let Some(ref r) = self.resource_dir {
out.push(format!("ResourceDir: {}", r.display()));
}
for (label, paths) in &[
("Quote", &self.quote_paths),
("User (-I)", &self.user_paths),
("System (-isystem)", &self.system_paths),
("After (-idirafter)", &self.after_paths),
("Framework", &self.framework_paths),
] {
for p in *paths {
out.push(format!(" {}: {}", label, p.path.display()));
}
}
out
}
}
impl Default for HeaderSearchPaths {
fn default() -> Self {
Self::for_target("x86_64-unknown-linux-gnu", &infer_resource_dir())
}
}
#[derive(Debug, Clone)]
pub struct IncludeDir {
pub path: PathBuf,
pub kind: IncludeDirKindX86,
pub is_framework: bool,
}
impl IncludeDir {
pub fn user(p: impl AsRef<Path>) -> Self {
Self {
path: p.as_ref().to_path_buf(),
kind: IncludeDirKindX86::User,
is_framework: false,
}
}
pub fn system(p: impl AsRef<Path>) -> Self {
Self {
path: p.as_ref().to_path_buf(),
kind: IncludeDirKindX86::System,
is_framework: false,
}
}
pub fn quote(p: impl AsRef<Path>) -> Self {
Self {
path: p.as_ref().to_path_buf(),
kind: IncludeDirKindX86::Quote,
is_framework: false,
}
}
pub fn after(p: impl AsRef<Path>) -> Self {
Self {
path: p.as_ref().to_path_buf(),
kind: IncludeDirKindX86::After,
is_framework: false,
}
}
pub fn framework(p: impl AsRef<Path>) -> Self {
Self {
path: p.as_ref().to_path_buf(),
kind: IncludeDirKindX86::Framework,
is_framework: true,
}
}
pub fn is_system(&self) -> bool {
matches!(
self.kind,
IncludeDirKindX86::System | IncludeDirKindX86::After | IncludeDirKindX86::Framework
)
}
pub fn join(&self, name: &str) -> PathBuf {
self.path.join(name)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum IncludeDirKindX86 {
User,
System,
Quote,
After,
Framework,
Resource,
}
impl fmt::Display for IncludeDirKindX86 {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::User => write!(f, "user"),
Self::System => write!(f, "system"),
Self::Quote => write!(f, "quote"),
Self::After => write!(f, "after"),
Self::Framework => write!(f, "framework"),
Self::Resource => write!(f, "resource"),
}
}
}
#[derive(Debug, Clone)]
pub struct GccInstallationInfo {
pub install_dir: PathBuf,
pub parent_dir: PathBuf,
pub target_triple: String,
pub version: String,
pub full_version: String,
pub is_valid: bool,
}
pub fn detect_gcc_installation() -> Option<GccInstallationInfo> {
let gcc_root = std::env::var("GCC_INSTALL_DIR")
.ok()
.map(PathBuf::from)
.or_else(|| find_gcc_in_path());
let install = gcc_root?;
if !install.exists() {
return None;
}
let version = find_highest_gcc_version(&install).unwrap_or_else(|| "0.0.0".to_string());
let triple = infer_gcc_triple(&install).unwrap_or_else(|| "x86_64-linux-gnu".to_string());
Some(GccInstallationInfo {
install_dir: install.clone(),
parent_dir: install
.parent()
.map(|p| p.to_path_buf())
.unwrap_or_default(),
target_triple: triple,
full_version: version.clone(),
version: simplify_version(&version),
is_valid: true,
})
}
fn find_gcc_in_path() -> Option<PathBuf> {
let gcc_names = ["gcc", "cc", "g++", "c++"];
for name in &gcc_names {
if let Ok(output) = std::process::Command::new("which").arg(name).output() {
let path = String::from_utf8_lossy(&output.stdout).trim().to_string();
if !path.is_empty() {
let p = Path::new(&path);
if let Some(parent) = p.parent() {
if parent.ends_with("bin") {
if let Some(gparent) = parent.parent() {
let lib_gcc = gparent.join("lib/gcc");
if lib_gcc.exists() {
return Some(lib_gcc);
}
}
}
}
}
}
}
None
}
fn find_highest_gcc_version(install_dir: &Path) -> Option<String> {
let mut highest = (0u32, 0u32, 0u32);
let mut highest_str = String::new();
if let Ok(entries) = std::fs::read_dir(install_dir) {
for entry in entries.flatten() {
let name = entry.file_name();
let name_str = name.to_string_lossy();
if let Some(ver) = parse_gcc_version_triple(&name_str) {
if ver > highest {
highest = ver;
highest_str = name_str.into_owned();
}
}
}
}
if !highest_str.is_empty() {
Some(highest_str)
} else {
None
}
}
fn parse_gcc_version_triple(s: &str) -> Option<(u32, u32, u32)> {
let parts: Vec<&str> = s.split('.').collect();
if parts.is_empty() || parts.len() > 3 {
return None;
}
let major = parts.first()?.parse::<u32>().ok()?;
let minor = parts
.get(1)
.and_then(|s| s.parse::<u32>().ok())
.unwrap_or(0);
let patch = parts
.get(2)
.and_then(|s| s.parse::<u32>().ok())
.unwrap_or(0);
Some((major, minor, patch))
}
fn infer_gcc_triple(install_dir: &Path) -> Option<String> {
if let Ok(entries) = std::fs::read_dir(install_dir) {
for entry in entries.flatten() {
let name = entry.file_name().to_string_lossy().to_string();
if name.contains("-linux-") || name.contains("-w64-") || name.contains("-apple-") {
return Some(name);
}
}
}
if let Ok(output) = std::process::Command::new("uname").arg("-m").output() {
let arch = String::from_utf8_lossy(&output.stdout).trim().to_string();
if arch == "x86_64" {
return Some("x86_64-linux-gnu".to_string());
}
if arch == "i686" || arch == "i386" {
return Some("i386-linux-gnu".to_string());
}
}
Some("x86_64-linux-gnu".to_string())
}
fn simplify_version(v: &str) -> String {
v.split('.').next().unwrap_or(v).to_string()
}
fn gcc_c_include_paths(install_dir: &Path, triple: &str) -> Vec<PathBuf> {
let mut paths = Vec::new();
if let Ok(entries) = std::fs::read_dir(install_dir.join(triple)) {
for entry in entries.flatten() {
let name = entry.file_name();
let name_str = name.to_string_lossy();
if parse_gcc_version_triple(&name_str).is_some() {
paths.push(entry.path().join("include"));
let fixed = entry.path().join("include-fixed");
if fixed.exists() {
paths.push(fixed);
}
}
}
}
paths
}
fn gcc_cxx_include_paths(install_dir: &Path, triple: &str, version: &str) -> Vec<PathBuf> {
let mut paths = Vec::new();
if let Ok(entries) = std::fs::read_dir(install_dir.join(triple)) {
for entry in entries.flatten() {
let name = entry.file_name();
let name_str = name.to_string_lossy();
if parse_gcc_version_triple(&name_str).is_some() {
let cxx_path = entry.path().join(format!("include/c++/{}", version));
if cxx_path.exists() {
paths.push(cxx_path.clone());
let triple_path = cxx_path.join(triple);
if triple_path.exists() {
paths.push(triple_path);
}
}
}
}
}
paths
}
#[derive(Debug, Clone)]
pub struct CxxStdLibInfo {
pub kind: CxxStdLibKind,
pub include_paths: Vec<PathBuf>,
pub library_paths: Vec<PathBuf>,
pub version: Option<String>,
}
impl Default for CxxStdLibInfo {
fn default() -> Self {
Self {
kind: CxxStdLibKind::Unknown,
include_paths: Vec::new(),
library_paths: Vec::new(),
version: None,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CxxStdLibKind {
LibStdCxx,
LibCxx,
MsStl,
Unknown,
}
pub fn detect_cxx_stdlib() -> CxxStdLibInfo {
if let Ok(include) = std::env::var("CPLUS_INCLUDE_PATH") {
let paths: Vec<PathBuf> = include
.split(':')
.filter(|s| !s.is_empty())
.map(PathBuf::from)
.collect();
if !paths.is_empty() {
return CxxStdLibInfo {
kind: CxxStdLibKind::Unknown,
include_paths: paths,
library_paths: Vec::new(),
version: None,
};
}
}
if let Some(info) = detect_libstdcxx() {
return info;
}
if let Some(info) = detect_libcxx() {
return info;
}
if let Some(info) = detect_msvc_stl() {
return info;
}
CxxStdLibInfo::default()
}
fn detect_libstdcxx() -> Option<CxxStdLibInfo> {
let candidates = ["/usr/include/c++", "/usr/local/include/c++"];
for base_str in &candidates {
let base = Path::new(base_str);
if !base.exists() {
continue;
}
if let Ok(entries) = std::fs::read_dir(base) {
for entry in entries.flatten() {
let name = entry.file_name().to_string_lossy().to_string();
if name.chars().next().map_or(false, |c| c.is_ascii_digit()) {
let include = entry.path();
let version = Some(name);
let mut include_paths = vec![include.clone()];
let arch_dir = include.join("x86_64-linux-gnu");
if arch_dir.exists() {
include_paths.push(arch_dir);
}
return Some(CxxStdLibInfo {
kind: CxxStdLibKind::LibStdCxx,
include_paths,
library_paths: Vec::new(),
version,
});
}
}
}
}
None
}
fn detect_libcxx() -> Option<CxxStdLibInfo> {
let candidates = [
"/usr/include/c++/v1",
"/usr/local/include/c++/v1",
"/opt/libcxx/include/c++/v1",
];
for c in &candidates {
let p = Path::new(c);
if p.join("__config").exists() {
return Some(CxxStdLibInfo {
kind: CxxStdLibKind::LibCxx,
include_paths: vec![p.to_path_buf()],
library_paths: Vec::new(),
version: None,
});
}
}
for xc in &["/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1"] {
let p = Path::new(xc);
if p.join("__config").exists() {
return Some(CxxStdLibInfo {
kind: CxxStdLibKind::LibCxx,
include_paths: vec![p.to_path_buf()],
library_paths: Vec::new(),
version: None,
});
}
}
None
}
fn detect_msvc_stl() -> Option<CxxStdLibInfo> {
if let Ok(include) = std::env::var("INCLUDE") {
let mut paths = Vec::new();
for p in include.split(';') {
let trimmed = p.trim();
if trimmed.is_empty() {
continue;
}
let pb = PathBuf::from(trimmed);
if pb.join("yvals_core.h").exists() {
paths.push(pb);
}
}
if !paths.is_empty() {
return Some(CxxStdLibInfo {
kind: CxxStdLibKind::MsStl,
include_paths: paths,
library_paths: Vec::new(),
version: None,
});
}
}
None
}
fn detect_windows_sdk() -> Option<PathBuf> {
if let Ok(dir) = std::env::var("WindowsSdkDir") {
let p = PathBuf::from(dir);
if p.exists() {
return Some(p);
}
}
let bases = ["C:/Program Files (x86)/Windows Kits/10"];
for base in &bases {
let p = Path::new(base);
if !p.exists() {
continue;
}
if let Ok(entries) = std::fs::read_dir(p) {
for entry in entries.flatten() {
let name = entry.file_name().to_string_lossy().to_string();
if name.chars().next().map_or(false, |c| c.is_ascii_digit()) {
let sub = entry.path();
if sub.join("Include").exists() {
return Some(sub);
}
}
}
}
}
None
}
fn infer_resource_dir() -> String {
let candidates = [
"/usr/lib/clang",
"/usr/local/lib/clang",
"/opt/clang/lib/clang",
];
for base in &candidates {
let p = Path::new(base);
if p.exists() {
if let Ok(entries) = std::fs::read_dir(p) {
for entry in entries.flatten() {
let name = entry.file_name().to_string_lossy().to_string();
if name.chars().next().map_or(false, |c| c.is_ascii_digit()) {
let include = entry.path().join("include");
if include.exists() {
return include.to_string_lossy().to_string();
}
}
}
}
}
}
"/usr/lib/clang/16/include".to_string()
}
fn strip_extension<'a>(name: &'a str, ext: &str) -> &'a str {
name.strip_suffix(ext).unwrap_or(name)
}
#[derive(Debug, Clone, Default)]
pub struct X86BuiltinHeaders {
headers: HashMap<String, String>,
}
impl X86BuiltinHeaders {
pub fn new() -> Self {
let mut h = Self {
headers: HashMap::new(),
};
h.populate_all();
h
}
fn populate_all(&mut self) {
self.add_stddef();
self.add_stdarg();
self.add_stdbool();
self.add_stdint();
self.add_iso646();
self.add_limits();
self.add_float();
self.add_stdalign();
self.add_stdnoreturn();
self.add_max_align_t();
self.add_tgmath();
}
pub fn resolve(&self, name: &str) -> Option<String> {
self.headers.get(name).cloned()
}
pub fn has(&self, name: &str) -> bool {
self.headers.contains_key(name)
}
pub fn names(&self) -> Vec<&str> {
self.headers.keys().map(|s| s.as_str()).collect()
}
fn add_stddef(&mut self) {
self.headers.insert("stddef.h".into(), STDDEF_H.into());
}
fn add_stdarg(&mut self) {
self.headers.insert("stdarg.h".into(), STDARG_H.into());
}
fn add_stdbool(&mut self) {
self.headers.insert("stdbool.h".into(), STDBOOL_H.into());
}
fn add_stdint(&mut self) {
self.headers.insert("stdint.h".into(), STDINT_H.into());
}
fn add_iso646(&mut self) {
self.headers.insert("iso646.h".into(), ISO646_H.into());
}
fn add_limits(&mut self) {
self.headers.insert("limits.h".into(), LIMITS_H.into());
}
fn add_float(&mut self) {
self.headers.insert("float.h".into(), FLOAT_H.into());
}
fn add_stdalign(&mut self) {
self.headers.insert("stdalign.h".into(), STDALIGN_H.into());
}
fn add_stdnoreturn(&mut self) {
self.headers
.insert("stdnoreturn.h".into(), STDNORETURN_H.into());
}
fn add_max_align_t(&mut self) {
self.headers
.insert("__stddef_max_align_t.h".into(), MAX_ALIGN_T_H.into());
}
fn add_tgmath(&mut self) {
self.headers.insert("tgmath.h".into(), TGMATH_H.into());
}
}
const STDDEF_H: &str = r##"/* === Clang builtin: stddef.h === */
#ifndef _STDDEF_H
#define _STDDEF_H
#ifdef __cplusplus
extern "C" {
#endif
/* Standard type definitions. */
#if defined(__x86_64__) || defined(_M_X64) || defined(__aarch64__) || \
(defined(__riscv) && __riscv_xlen == 64)
typedef unsigned long size_t;
typedef long ptrdiff_t;
#define __SIZE_TYPE__ unsigned long
#define __PTRDIFF_TYPE__ long
#else
typedef unsigned int size_t;
typedef int ptrdiff_t;
#define __SIZE_TYPE__ unsigned int
#define __PTRDIFF_TYPE__ int
#endif
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
/* max_align_t */
typedef struct {
long long __max_align_ll __attribute__((__aligned__(__alignof__(long long))));
long double __max_align_ld __attribute__((__aligned__(__alignof__(long double))));
} max_align_t;
#endif
#ifndef __cplusplus
typedef __SIZE_TYPE__ size_t;
typedef __PTRDIFF_TYPE__ ptrdiff_t;
#endif
#ifndef __wchar_t_defined
#ifndef __WCHAR_TYPE__
#if defined(__x86_64__)
#define __WCHAR_TYPE__ int
#else
#define __WCHAR_TYPE__ int
#endif
#endif
typedef __WCHAR_TYPE__ wchar_t;
#define __wchar_t_defined 1
#endif
/* offsetof macro */
#define offsetof(TYPE, MEMBER) __builtin_offsetof(TYPE, MEMBER)
/* NULL */
#if defined(__cplusplus) && __cplusplus >= 201103L
#define NULL nullptr
#elif defined(__cplusplus)
#define NULL 0L
#else
#define NULL ((void*)0)
#endif
#define unreachable() __builtin_unreachable()
#ifdef __cplusplus
}
#endif
#endif /* _STDDEF_H */
"##;
const STDARG_H: &str = r##"/* === Clang builtin: stdarg.h === */
#ifndef _STDARG_H
#define _STDARG_H
#if defined(__x86_64__)
/* SysV AMD64 ABI: va_list is a typedef for an array of one
__va_list_tag struct. */
typedef __builtin_va_list va_list;
#define va_start(ap, param) __builtin_va_start(ap, param)
#define va_end(ap) __builtin_va_end(ap)
#define va_arg(ap, type) __builtin_va_arg(ap, type)
#define va_copy(dst, src) __builtin_va_copy(dst, src)
#else
/* i386 cdecl: va_list is char*. */
typedef __builtin_va_list va_list;
#define va_start(ap, param) __builtin_va_start(ap, param)
#define va_end(ap) __builtin_va_end(ap)
#define va_arg(ap, type) __builtin_va_arg(ap, type)
#define va_copy(dst, src) __builtin_va_copy(dst, src)
#endif
#define __GNUC_VA_LIST 1
#endif /* _STDARG_H */
"##;
const STDBOOL_H: &str = r##"/* === Clang builtin: stdbool.h === */
#ifndef _STDBOOL_H
#define _STDBOOL_H
#ifndef __cplusplus
#define bool _Bool
#define true 1
#define false 0
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L
/* C23: bool/true/false are keywords; only __bool_true_false_are_defined remains. */
#define __bool_true_false_are_defined 1
#else
#define __bool_true_false_are_defined 1
#endif
#endif /* !__cplusplus */
#endif /* _STDBOOL_H */
"##;
const STDINT_H: &str = r##"/* === Clang builtin: stdint.h (minimal proxy) === */
#ifndef _STDINT_H
#define _STDINT_H
/* This is a lightweight proxy that delegates to the compiler's
internal type knowledge. The real stdint.h is included from
the system headers at runtime. */
/* Exact-width integer types */
typedef signed char int8_t;
typedef short int16_t;
typedef int int32_t;
#if defined(__x86_64__) || defined(_M_X64) || defined(__aarch64__)
typedef long int64_t;
#else
typedef long long int64_t;
#endif
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
#if defined(__x86_64__) || defined(_M_X64) || defined(__aarch64__)
typedef unsigned long uint64_t;
#else
typedef unsigned long long uint64_t;
#endif
/* Minimum-width types */
typedef signed char int_least8_t;
typedef short int_least16_t;
typedef int int_least32_t;
typedef int64_t int_least64_t;
typedef uint8_t uint_least8_t;
typedef uint16_t uint_least16_t;
typedef uint32_t uint_least32_t;
typedef uint64_t uint_least64_t;
/* Fastest minimum-width types */
typedef signed char int_fast8_t;
#if defined(__x86_64__)
typedef long int_fast16_t;
typedef long int_fast32_t;
typedef long int_fast64_t;
#else
typedef int int_fast16_t;
typedef int int_fast32_t;
typedef long long int_fast64_t;
#endif
typedef uint8_t uint_fast8_t;
#if defined(__x86_64__)
typedef unsigned long uint_fast16_t;
typedef unsigned long uint_fast32_t;
typedef unsigned long uint_fast64_t;
#else
typedef unsigned int uint_fast16_t;
typedef unsigned int uint_fast32_t;
typedef unsigned long long uint_fast64_t;
#endif
/* Pointer-sized integer types */
#if defined(__x86_64__) || defined(_M_X64) || defined(__aarch64__) || defined(__LP64__)
typedef long intptr_t;
typedef unsigned long uintptr_t;
#else
typedef int intptr_t;
typedef unsigned int uintptr_t;
#endif
/* Greatest-width integer types */
typedef int64_t intmax_t;
typedef uint64_t uintmax_t;
/* Limits */
#define INT8_MIN (-128)
#define INT8_MAX 127
#define INT16_MIN (-32768)
#define INT16_MAX 32767
#define INT32_MIN (-2147483647 - 1)
#define INT32_MAX 2147483647
#define INT64_MIN (-9223372036854775807LL - 1)
#define INT64_MAX 9223372036854775807LL
#define UINT8_MAX 255
#define UINT16_MAX 65535
#define UINT32_MAX 4294967295U
#define UINT64_MAX 18446744073709551615ULL
#define INT_LEAST8_MIN INT8_MIN
#define INT_LEAST8_MAX INT8_MAX
#define INT_LEAST16_MIN INT16_MIN
#define INT_LEAST16_MAX INT16_MAX
#define INT_LEAST32_MIN INT32_MIN
#define INT_LEAST32_MAX INT32_MAX
#define INT_LEAST64_MIN INT64_MIN
#define INT_LEAST64_MAX INT64_MAX
#define UINT_LEAST8_MAX UINT8_MAX
#define UINT_LEAST16_MAX UINT16_MAX
#define UINT_LEAST32_MAX UINT32_MAX
#define UINT_LEAST64_MAX UINT64_MAX
#define INT_FAST8_MIN INT8_MIN
#define INT_FAST8_MAX INT8_MAX
#define INT_FAST16_MIN INT32_MIN
#define INT_FAST16_MAX INT32_MAX
#define INT_FAST32_MIN INT32_MIN
#define INT_FAST32_MAX INT32_MAX
#define INT_FAST64_MIN INT64_MIN
#define INT_FAST64_MAX INT64_MAX
#define UINT_FAST8_MAX UINT8_MAX
#define UINT_FAST16_MAX UINT32_MAX
#define UINT_FAST32_MAX UINT32_MAX
#define UINT_FAST64_MAX UINT64_MAX
#define INTPTR_MIN INT32_MIN
#define INTPTR_MAX INT32_MAX
#define UINTPTR_MAX UINT32_MAX
#define INTMAX_MIN INT64_MIN
#define INTMAX_MAX INT64_MAX
#define UINTMAX_MAX UINT64_MAX
/* Macros for integer constant expressions */
#define INT8_C(val) val
#define INT16_C(val) val
#define INT32_C(val) val
#define INT64_C(val) val ## LL
#define UINT8_C(val) val ## U
#define UINT16_C(val) val ## U
#define UINT32_C(val) val ## U
#define UINT64_C(val) val ## ULL
#define INTMAX_C(val) val ## LL
#define UINTMAX_C(val) val ## ULL
#endif /* _STDINT_H */
"##;
const ISO646_H: &str = r##"/* === Clang builtin: iso646.h === */
#ifndef _ISO646_H
#define _ISO646_H
#ifndef __cplusplus
#define and &&
#define and_eq &=
#define bitand &
#define bitor |
#define compl ~
#define not !
#define not_eq !=
#define or ||
#define or_eq |=
#define xor ^
#define xor_eq ^=
#endif /* !__cplusplus */
#endif /* _ISO646_H */
"##;
const LIMITS_H: &str = r##"/* === Clang builtin: limits.h (proxy) === */
#ifndef _LIMITS_H
#define _LIMITS_H
/* Number of bits in a char. */
#define CHAR_BIT 8
/* Minimum values. */
#define SCHAR_MIN (-128)
#define SCHAR_MAX 127
#define UCHAR_MAX 255
#if '\x80' < 0
#define CHAR_MIN SCHAR_MIN
#define CHAR_MAX SCHAR_MAX
#else
#define CHAR_MIN 0
#define CHAR_MAX UCHAR_MAX
#endif
#define SHRT_MIN (-32768)
#define SHRT_MAX 32767
#define USHRT_MAX 65535
#define INT_MIN (-2147483647 - 1)
#define INT_MAX 2147483647
#define UINT_MAX 4294967295U
#define LONG_MIN (-9223372036854775807L - 1L)
#define LONG_MAX 9223372036854775807L
#define ULONG_MAX 18446744073709551615UL
#define LLONG_MIN (-9223372036854775807LL - 1)
#define LLONG_MAX 9223372036854775807LL
#define ULLONG_MAX 18446744073709551615ULL
/* MB_LEN_MAX */
#define MB_LEN_MAX 16
#endif /* _LIMITS_H */
"##;
const FLOAT_H: &str = r##"/* === Clang builtin: float.h === */
#ifndef _FLOAT_H
#define _FLOAT_H
/* Radix of exponent representation. */
#define FLT_RADIX 2
/* float */
#define FLT_MANT_DIG 24
#define FLT_DIG 6
#define FLT_MIN_EXP (-125)
#define FLT_MIN_10_EXP (-37)
#define FLT_MAX_EXP 128
#define FLT_MAX_10_EXP 38
#define FLT_MAX 3.4028234663852886e+38F
#define FLT_MIN 1.1754943508222875e-38F
#define FLT_EPSILON 1.1920928955078125e-07F
#define FLT_ROUNDS 1
#define FLT_EVAL_METHOD 0
#define FLT_DECIMAL_DIG 9
#define FLT_HAS_SUBNORM 1
#define FLT_TRUE_MIN 1.4012984643248170e-45F
#define FLT_IS_IEC_60559 1
/* double */
#define DBL_MANT_DIG 53
#define DBL_DIG 15
#define DBL_MIN_EXP (-1021)
#define DBL_MIN_10_EXP (-307)
#define DBL_MAX_EXP 1024
#define DBL_MAX_10_EXP 308
#define DBL_MAX 1.7976931348623157e+308
#define DBL_MIN 2.2250738585072014e-308
#define DBL_EPSILON 2.2204460492503131e-16
#define DBL_DECIMAL_DIG 17
#define DBL_HAS_SUBNORM 1
#define DBL_TRUE_MIN 4.9406564584124654e-324
#define DBL_IS_IEC_60559 1
/* long double (x86 extended precision 80-bit, or 128-bit on some) */
#if defined(__x86_64__)
#define LDBL_MANT_DIG 64
#define LDBL_DIG 18
#define LDBL_MIN_EXP (-16381)
#define LDBL_MIN_10_EXP (-4931)
#define LDBL_MAX_EXP 16384
#define LDBL_MAX_10_EXP 4932
#define LDBL_MAX 1.189731495357231765021263853030970205e+4932L
#define LDBL_MIN 3.36210314311209350626267781732175260e-4932L
#define LDBL_EPSILON 1.08420217248550443400745280086994171e-19L
#define LDBL_DECIMAL_DIG 21
#define LDBL_HAS_SUBNORM 1
#define LDBL_TRUE_MIN 3.64519953188247460252840593361941982e-4951L
#else
#define LDBL_MANT_DIG 64
#define LDBL_DIG 18
#define LDBL_MIN_EXP (-16381)
#define LDBL_MIN_10_EXP (-4931)
#define LDBL_MAX_EXP 16384
#define LDBL_MAX_10_EXP 4932
#define LDBL_MAX 1.18973149535723177e+4932L
#define LDBL_MIN 3.36210314311209351e-4932L
#define LDBL_EPSILON 1.08420217248550443e-19L
#define LDBL_DECIMAL_DIG 21
#define LDBL_HAS_SUBNORM 1
#define LDBL_TRUE_MIN 3.64519953188247460e-4951L
#endif
#endif /* _FLOAT_H */
"##;
const STDALIGN_H: &str = r##"/* === Clang builtin: stdalign.h === */
#ifndef _STDALIGN_H
#define _STDALIGN_H
#ifndef __cplusplus
#define alignas _Alignas
#define alignof _Alignof
#define __alignas_is_defined 1
#define __alignof_is_defined 1
#endif /* !__cplusplus */
#endif /* _STDALIGN_H */
"##;
const STDNORETURN_H: &str = r##"/* === Clang builtin: stdnoreturn.h === */
#ifndef _STDNORETURN_H
#define _STDNORETURN_H
#ifndef __cplusplus
#define noreturn _Noreturn
#endif /* !__cplusplus */
#endif /* _STDNORETURN_H */
"##;
const MAX_ALIGN_T_H: &str = r##"/* === Clang builtin: __stddef_max_align_t.h === */
#ifndef __STDDEF_MAX_ALIGN_T_H
#define __STDDEF_MAX_ALIGN_T_H
#if defined(__x86_64__)
typedef struct {
long long __ll __attribute__((__aligned__(__alignof__(long long))));
long double __ld __attribute__((__aligned__(__alignof__(long double))));
__float128 __f128 __attribute__((__aligned__(__alignof__(__float128))));
} __max_align_t;
#else
typedef struct {
long long __ll __attribute__((__aligned__(__alignof__(long long))));
long double __ld __attribute__((__aligned__(__alignof__(long double))));
} __max_align_t;
#endif
#endif /* __STDDEF_MAX_ALIGN_T_H */
"##;
const TGMATH_H: &str = r##"/* === Clang builtin: tgmath.h === */
#ifndef _TGMATH_H
#define _TGMATH_H
/* Type-generic math (C99). */
#define acos(x) _Generic((x), \
long double: acosl, \
float: acosf, \
default: acos \
)(x)
#define asin(x) _Generic((x), \
long double: asinl, \
float: asinf, \
default: asin \
)(x)
#define atan(x) _Generic((x), \
long double: atanl, \
float: atanf, \
default: atan \
)(x)
#define ceil(x) _Generic((x), \
long double: ceill, \
float: ceilf, \
default: ceil \
)(x)
#define cos(x) _Generic((x), \
long double: cosl, \
float: cosf, \
default: cos \
)(x)
#define exp(x) _Generic((x), \
long double: expl, \
float: expf, \
default: exp \
)(x)
#define fabs(x) _Generic((x), \
long double: fabsl, \
float: fabsf, \
default: fabs \
)(x)
#define floor(x) _Generic((x), \
long double: floorl, \
float: floorf, \
default: floor \
)(x)
#define log(x) _Generic((x), \
long double: logl, \
float: logf, \
default: log \
)(x)
#define pow(x, y) _Generic((x), \
long double: powl, \
float: powf, \
default: pow \
)(x, y)
#define sin(x) _Generic((x), \
long double: sinl, \
float: sinf, \
default: sin \
)(x)
#define sqrt(x) _Generic((x), \
long double: sqrtl, \
float: sqrtf, \
default: sqrt \
)(x)
#define tan(x) _Generic((x), \
long double: tanl, \
float: tanf, \
default: tan \
)(x)
#endif /* _TGMATH_H */
"##;
#[derive(Debug, Clone)]
pub struct X86IntrinsicHeaders {
headers: HashMap<String, (Option<String>, String)>,
resource_dir: Option<PathBuf>,
}
impl Default for X86IntrinsicHeaders {
fn default() -> Self {
let mut h = Self {
headers: HashMap::new(),
resource_dir: None,
};
h.populate_all();
h
}
}
impl X86IntrinsicHeaders {
pub fn new() -> Self {
Self::default()
}
pub fn set_resource_dir(&mut self, dir: &str) {
self.resource_dir = Some(PathBuf::from(dir));
}
fn populate_all(&mut self) {
self.add("x86intrin.h", None, X86INTRIN_H);
self.add("cpuid.h", None, CPUID_H);
self.add("mm_malloc.h", None, MM_MALLOC_H);
self.add("mmintrin.h", Some("__MMX__"), MMINTRIN_H);
self.add("xmmintrin.h", Some("__SSE__"), XMMINTRIN_H);
self.add("emmintrin.h", Some("__SSE2__"), EMMINTRIN_H);
self.add("pmmintrin.h", Some("__SSE3__"), PMMINTRIN_H);
self.add("tmmintrin.h", Some("__SSSE3__"), TMMINTRIN_H);
self.add("smmintrin.h", Some("__SSE4_1__"), SMMINTRIN_H);
self.add("nmmintrin.h", Some("__SSE4_2__"), NMMINTRIN_H);
self.add("wmmintrin.h", Some("__AES__"), WMMINTRIN_H);
self.add("avxintrin.h", Some("__AVX__"), AVXINTRIN_H);
self.add("avx2intrin.h", Some("__AVX2__"), AVX2INTRIN_H);
self.add("fmaintrin.h", Some("__FMA__"), FMAINTRIN_H);
self.add("fma4intrin.h", Some("__FMA4__"), FMA4INTRIN_H);
self.add("xopintrin.h", Some("__XOP__"), XOPINTRIN_H);
self.add("avx512fintrin.h", Some("__AVX512F__"), AVX512FINTRIN_H);
self.add("avx512bwintrin.h", Some("__AVX512BW__"), AVX512BWINTRIN_H);
self.add("avx512cdintrin.h", Some("__AVX512CD__"), AVX512CDINTRIN_H);
self.add("avx512dqintrin.h", Some("__AVX512DQ__"), AVX512DQINTRIN_H);
self.add("avx512vlintrin.h", Some("__AVX512VL__"), AVX512VLINTRIN_H);
self.add(
"avx512ifmaintrin.h",
Some("__AVX512IFMA__"),
AVX512IFMAINTRIN_H,
);
self.add(
"avx512vbmiintrin.h",
Some("__AVX512VBMI__"),
AVX512VBMIINTRIN_H,
);
self.add(
"avx512vbmi2intrin.h",
Some("__AVX512VBMI2__"),
AVX512VBMI2INTRIN_H,
);
self.add(
"avx512vnniintrin.h",
Some("__AVX512VNNI__"),
AVX512VNNIINTRIN_H,
);
self.add(
"avx512bitalgintrin.h",
Some("__AVX512BITALG__"),
AVX512BITALGINTRIN_H,
);
self.add(
"avx512vpopcntdqintrin.h",
Some("__AVX512VPOPCNTDQ__"),
AVX512VPOPCNTDQINTRIN_H,
);
self.add(
"avx5124fmapsintrin.h",
Some("__AVX5124FMAPS__"),
AVX5124FMAPSINTRIN_H,
);
self.add(
"avx5124vnniwintrin.h",
Some("__AVX5124VNNIW__"),
AVX5124VNNIWINTRIN_H,
);
self.add(
"avx512bf16intrin.h",
Some("__AVX512BF16__"),
AVX512BF16INTRIN_H,
);
self.add(
"avx512fp16intrin.h",
Some("__AVX512FP16__"),
AVX512FP16INTRIN_H,
);
self.add("bmiintrin.h", Some("__BMI__"), BMIINTRIN_H);
self.add("bmi2intrin.h", Some("__BMI2__"), BMI2INTRIN_H);
self.add("lzcntintrin.h", Some("__LZCNT__"), LZCNTINTRIN_H);
self.add("popcntintrin.h", Some("__POPCNT__"), POPCNTINTRIN_H);
self.add("f16cintrin.h", Some("__F16C__"), F16CINTRIN_H);
self.add("rdrandintrin.h", Some("__RDRAND__"), RDRANDINTRIN_H);
self.add("shaintrin.h", Some("__SHA__"), SHAINTRIN_H);
self.add("gfniintrin.h", Some("__GFNI__"), GFNIINTRIN_H);
self.add("vaesintrin.h", Some("__VAES__"), VAESINTRIN_H);
self.add(
"vpclmulqdqintrin.h",
Some("__VPCLMULQDQ__"),
VPCLMULQDQINTRIN_H,
);
self.add("amxintrin.h", Some("__AMX_TILE__"), AMXINTRIN_H);
self.add("amxbf16intrin.h", Some("__AMX_BF16__"), AMXBF16INTRIN_H);
self.add("amxint8intrin.h", Some("__AMX_INT8__"), AMXINT8INTRIN_H);
self.add("cetintrin.h", Some("__SHSTK__"), CETINTRIN_H);
self.add("movdirintrin.h", Some("__MOVDIRI__"), MOVDIRINTRIN_H);
self.add("waitpkgintrin.h", Some("__WAITPKG__"), WAITPKGINTRIN_H);
self.add("enqcmdintrin.h", Some("__ENQCMD__"), ENQCMDINTRIN_H);
self.add(
"serializeintrin.h",
Some("__SERIALIZE__"),
SERIALIZEINTRIN_H,
);
self.add("tsxldtrkintrin.h", Some("__TSXLDTRK__"), TSXLDTRKINTRIN_H);
self.add("cldemoteintrin.h", Some("__CLDEMOTE__"), CLDEMOTEINTRIN_H);
self.add("ptwriteintrin.h", Some("__PTWRITE__"), PTWRITEINTRIN_H);
self.add("uintrintrin.h", Some("__UINTR__"), UINTRINTRIN_H);
self.add("hresetintrin.h", Some("__HRESET__"), HRESETINTRIN_H);
self.add("keylockerintrin.h", Some("__KL__"), KEYLOCKERINTRIN_H);
self.add(
"cmpccxaddintrin.h",
Some("__CMPCCXADD__"),
CMPCCXADDINTRIN_H,
);
self.add("raointintrin.h", Some("__RAOINT__"), RAOINTINTRIN_H);
self.add("avxifmaintrin.h", Some("__AVXIFMA__"), AVXIFMAINTRIN_H);
self.add(
"avxneconvertintrin.h",
Some("__AVXNECONVERT__"),
AVXNECONVERTINTRIN_H,
);
self.add(
"avxvnniint8intrin.h",
Some("__AVXVNNIINT8__"),
AVXVNNIINT8INTRIN_H,
);
self.add("avx10_1intrin.h", Some("__AVX10_1__"), AVX10_1INTRIN_H);
}
fn add(&mut self, name: &str, feature: Option<&str>, content: &str) {
self.headers.insert(
name.to_string(),
(feature.map(|s| s.to_string()), content.to_string()),
);
}
pub fn resolve(&self, name: &str) -> Option<String> {
self.headers.get(name).map(|(gate, content)| {
if let Some(g) = gate {
format!(
"/* Feature-gated X86 intrinsic header: {} (requires {}) */\n#ifndef {g}\n#error \"{name} requires {g} target feature\"\n#endif\n\n{content}",
name, g, g = g, name = name, content = content
)
} else {
content.clone()
}
})
}
pub fn has(&self, name: &str) -> bool {
self.headers.contains_key(name)
}
pub fn names(&self) -> Vec<&str> {
self.headers.keys().map(|s| s.as_str()).collect()
}
pub fn feature_gate(&self, name: &str) -> Option<&str> {
self.headers.get(name).and_then(|(g, _)| g.as_deref())
}
}
const X86INTRIN_H: &str = r##"/* === X86 intrinsic umbrella header === */
#ifndef _X86INTRIN_H_INCLUDED
#define _X86INTRIN_H_INCLUDED
/* This header includes all available X86 intrinsic headers
that are enabled by the current target features. */
#ifdef __MMX__
#include <mmintrin.h>
#endif
#ifdef __SSE__
#include <xmmintrin.h>
#endif
#ifdef __SSE2__
#include <emmintrin.h>
#endif
#ifdef __SSE3__
#include <pmmintrin.h>
#endif
#ifdef __SSSE3__
#include <tmmintrin.h>
#endif
#ifdef __SSE4_1__
#include <smmintrin.h>
#endif
#ifdef __SSE4_2__
#include <nmmintrin.h>
#endif
#ifdef __AES__
#include <wmmintrin.h>
#endif
#ifdef __AVX__
#include <avxintrin.h>
#endif
#ifdef __AVX2__
#include <avx2intrin.h>
#endif
#ifdef __FMA__
#include <fmaintrin.h>
#endif
#ifdef __FMA4__
#include <fma4intrin.h>
#endif
#ifdef __XOP__
#include <xopintrin.h>
#endif
#ifdef __F16C__
#include <f16cintrin.h>
#endif
#ifdef __BMI__
#include <bmiintrin.h>
#endif
#ifdef __BMI2__
#include <bmi2intrin.h>
#endif
#ifdef __LZCNT__
#include <lzcntintrin.h>
#endif
#ifdef __POPCNT__
#include <popcntintrin.h>
#endif
#ifdef __RDRAND__
#include <rdrandintrin.h>
#endif
#ifdef __AVX512F__
#include <avx512fintrin.h>
#endif
#endif /* _X86INTRIN_H_INCLUDED */
"##;
const CPUID_H: &str = r##"/* === X86 CPUID intrinsic header === */
#ifndef _CPUID_H_INCLUDED
#define _CPUID_H_INCLUDED
#ifndef __x86_64__
#ifndef __i386__
#error "cpuid.h is only available on x86 targets"
#endif
#endif
/* CPUID instruction wrapper. */
static __inline int __get_cpuid_max(unsigned int __leaf, unsigned int *__sig) {
unsigned int __eax, __ebx, __ecx, __edx;
__asm__ volatile("cpuid"
: "=a"(__eax), "=b"(__ebx), "=c"(__ecx), "=d"(__edx)
: "a"(__leaf), "c"(0));
if (__sig) *__sig = __ebx;
return __eax;
}
static __inline int __get_cpuid(unsigned int __leaf, unsigned int *__eax,
unsigned int *__ebx, unsigned int *__ecx,
unsigned int *__edx) {
__asm__ volatile("cpuid"
: "=a"(*__eax), "=b"(*__ebx), "=c"(*__ecx), "=d"(*__edx)
: "a"(__leaf), "c"(0));
return 1;
}
static __inline int __get_cpuid_count(unsigned int __leaf, unsigned int __subleaf,
unsigned int *__eax, unsigned int *__ebx,
unsigned int *__ecx, unsigned int *__edx) {
__asm__ volatile("cpuid"
: "=a"(*__eax), "=b"(*__ebx), "=c"(*__ecx), "=d"(*__edx)
: "a"(__leaf), "c"(__subleaf));
return 1;
}
#endif /* _CPUID_H_INCLUDED */
"##;
const MM_MALLOC_H: &str = r##"/* === X86 aligned malloc header === */
#ifndef _MM_MALLOC_H_INCLUDED
#define _MM_MALLOC_H_INCLUDED
#include <stdlib.h>
#ifndef __x86_64__
#ifndef __i386__
#error "mm_malloc.h is only available on x86 targets"
#endif
#endif
static __inline void *_mm_malloc(size_t __size, size_t __alignment) {
void *__ptr;
if (__alignment < sizeof(void *))
__alignment = sizeof(void *);
if (posix_memalign(&__ptr, __alignment, __size))
return ((void *)0);
return __ptr;
}
static __inline void _mm_free(void *__ptr) {
free(__ptr);
}
#endif /* _MM_MALLOC_H_INCLUDED */
"##;
const MMINTRIN_H: &str = r##"/* === MMX intrinsic header === */
#ifndef _MMINTRIN_H_INCLUDED
#define _MMINTRIN_H_INCLUDED
#if !defined(__MMX__)
#error "MMX instruction set not enabled"
#endif
#include <stdint.h>
typedef int64_t __m64 __attribute__((__vector_size__(8), __aligned__(8)));
typedef int32_t __v2si __attribute__((__vector_size__(8)));
typedef int16_t __v4hi __attribute__((__vector_size__(8)));
typedef int8_t __v8qi __attribute__((__vector_size__(8)));
static __inline__ __m64 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm_empty(void) {
__asm__ __volatile__("emms" ::: "memory");
return (__m64){0};
}
static __inline__ __m64 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_m_paddb(__m64 __m1, __m64 __m2) {
return (__m64)((__v8qi)__m1 + (__v8qi)__m2);
}
static __inline__ __m64 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_m_paddw(__m64 __m1, __m64 __m2) {
return (__m64)((__v4hi)__m1 + (__v4hi)__m2);
}
static __inline__ __m64 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_m_paddd(__m64 __m1, __m64 __m2) {
return (__m64)((__v2si)__m1 + (__v2si)__m2);
}
#endif /* _MMINTRIN_H_INCLUDED */
"##;
const XMMINTRIN_H: &str = r##"/* === SSE intrinsic header === */
#ifndef _XMMINTRIN_H_INCLUDED
#define _XMMINTRIN_H_INCLUDED
#if !defined(__SSE__)
#error "SSE instruction set not enabled"
#endif
#include <mmintrin.h>
#include <stdint.h>
typedef float __m128 __attribute__((__vector_size__(16), __aligned__(16)));
typedef float __v4sf __attribute__((__vector_size__(16)));
typedef int __v4si __attribute__((__vector_size__(16)));
/* Data movement */
static __inline__ __m128 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm_load_ps(float const *__p) {
return *(__m128 const *)__p;
}
static __inline__ void __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm_store_ps(float *__p, __m128 __a) {
*(__m128 *)__p = __a;
}
static __inline__ __m128 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm_set_ps(float __z, float __y, float __x, float __w) {
return (__m128){__w, __x, __y, __z};
}
static __inline__ __m128 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm_set1_ps(float __w) {
return (__m128){__w, __w, __w, __w};
}
static __inline__ __m128 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm_setzero_ps(void) {
return (__m128){0.0f, 0.0f, 0.0f, 0.0f};
}
/* Arithmetic */
static __inline__ __m128 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm_add_ps(__m128 __a, __m128 __b) {
return (__m128)((__v4sf)__a + (__v4sf)__b);
}
static __inline__ __m128 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm_sub_ps(__m128 __a, __m128 __b) {
return (__m128)((__v4sf)__a - (__v4sf)__b);
}
static __inline__ __m128 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm_mul_ps(__m128 __a, __m128 __b) {
return (__m128)((__v4sf)__a * (__v4sf)__b);
}
static __inline__ __m128 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm_div_ps(__m128 __a, __m128 __b) {
return (__m128)((__v4sf)__a / (__v4sf)__b);
}
static __inline__ __m128 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm_rcp_ps(__m128 __a) {
return (__m128)__builtin_ia32_rcpps((__v4sf)__a);
}
static __inline__ __m128 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm_sqrt_ps(__m128 __a) {
return (__m128)__builtin_ia32_sqrtps((__v4sf)__a);
}
static __inline__ __m128 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm_rsqrt_ps(__m128 __a) {
return (__m128)__builtin_ia32_rsqrtps((__v4sf)__a);
}
/* Comparison */
static __inline__ __m128 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm_cmpeq_ps(__m128 __a, __m128 __b) {
return (__m128)__builtin_ia32_cmpeqps((__v4sf)__a, (__v4sf)__b);
}
static __inline__ __m128 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm_cmplt_ps(__m128 __a, __m128 __b) {
return (__m128)__builtin_ia32_cmpltps((__v4sf)__a, (__v4sf)__b);
}
static __inline__ __m128 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm_cmple_ps(__m128 __a, __m128 __b) {
return (__m128)__builtin_ia32_cmpleps((__v4sf)__a, (__v4sf)__b);
}
static __inline__ __m128 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm_cmpgt_ps(__m128 __a, __m128 __b) {
return (__m128)__builtin_ia32_cmpgtps((__v4sf)__a, (__v4sf)__b);
}
static __inline__ __m128 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm_cmpge_ps(__m128 __a, __m128 __b) {
return (__m128)__builtin_ia32_cmpgeps((__v4sf)__a, (__v4sf)__b);
}
/* Min/Max */
static __inline__ __m128 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm_min_ps(__m128 __a, __m128 __b) {
return (__m128)__builtin_ia32_minps((__v4sf)__a, (__v4sf)__b);
}
static __inline__ __m128 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm_max_ps(__m128 __a, __m128 __b) {
return (__m128)__builtin_ia32_maxps((__v4sf)__a, (__v4sf)__b);
}
#endif /* _XMMINTRIN_H_INCLUDED */
"##;
const EMMINTRIN_H: &str = r##"/* === SSE2 intrinsic header === */
#ifndef _EMMINTRIN_H_INCLUDED
#define _EMMINTRIN_H_INCLUDED
#if !defined(__SSE2__)
#error "SSE2 instruction set not enabled"
#endif
#include <xmmintrin.h>
typedef double __m128d __attribute__((__vector_size__(16), __aligned__(16)));
typedef long long __m128i __attribute__((__vector_size__(16), __aligned__(16)));
typedef double __v2df __attribute__((__vector_size__(16)));
typedef long long __v2di __attribute__((__vector_size__(16)));
/* Double-precision operations */
static __inline__ __m128d __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm_add_pd(__m128d __a, __m128d __b) {
return (__m128d)((__v2df)__a + (__v2df)__b);
}
static __inline__ __m128d __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm_sub_pd(__m128d __a, __m128d __b) {
return (__m128d)((__v2df)__a - (__v2df)__b);
}
static __inline__ __m128d __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm_mul_pd(__m128d __a, __m128d __b) {
return (__m128d)((__v2df)__a * (__v2df)__b);
}
static __inline__ __m128d __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm_div_pd(__m128d __a, __m128d __b) {
return (__m128d)((__v2df)__a / (__v2df)__b);
}
static __inline__ __m128d __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm_sqrt_pd(__m128d __a) {
return (__m128d)__builtin_ia32_sqrtpd((__v2df)__a);
}
/* Integer operations */
static __inline__ __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm_add_epi32(__m128i __a, __m128i __b) {
return (__m128i)((__v4si)__a + (__v4si)__b);
}
static __inline__ __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm_sub_epi32(__m128i __a, __m128i __b) {
return (__m128i)((__v4si)__a - (__v4si)__b);
}
static __inline__ __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm_set_epi32(int __i3, int __i2, int __i1, int __i0) {
return (__m128i)(__v4si){__i0, __i1, __i2, __i3};
}
static __inline__ __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm_setzero_si128(void) {
return (__m128i){0LL, 0LL};
}
/* Conversion */
static __inline__ __m128d __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm_cvtepi32_pd(__m128i __a) {
return (__m128d)__builtin_ia32_cvtdq2pd((__v4si)__a);
}
static __inline__ __m128 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm_cvtepi32_ps(__m128i __a) {
return (__m128)__builtin_ia32_cvtdq2ps((__v4si)__a);
}
#endif /* _EMMINTRIN_H_INCLUDED */
"##;
const PMMINTRIN_H: &str = r##"/* === SSE3 intrinsic header === */
#ifndef _PMMINTRIN_H_INCLUDED
#define _PMMINTRIN_H_INCLUDED
#if !defined(__SSE3__)
#error "SSE3 instruction set not enabled"
#endif
#include <emmintrin.h>
static __inline__ __m128 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm_addsub_ps(__m128 __a, __m128 __b) {
return (__m128)__builtin_ia32_addsubps((__v4sf)__a, (__v4sf)__b);
}
static __inline__ __m128d __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm_addsub_pd(__m128d __a, __m128d __b) {
return (__m128d)__builtin_ia32_addsubpd((__v2df)__a, (__v2df)__b);
}
static __inline__ __m128 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm_hadd_ps(__m128 __a, __m128 __b) {
return (__m128)__builtin_ia32_haddps((__v4sf)__a, (__v4sf)__b);
}
static __inline__ __m128d __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm_hadd_pd(__m128d __a, __m128d __b) {
return (__m128d)__builtin_ia32_haddpd((__v2df)__a, (__v2df)__b);
}
static __inline__ __m128 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm_movehdup_ps(__m128 __a) {
return (__m128)__builtin_ia32_movshdup((__v4sf)__a);
}
static __inline__ __m128 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm_moveldup_ps(__m128 __a) {
return (__m128)__builtin_ia32_movsldup((__v4sf)__a);
}
#endif /* _PMMINTRIN_H_INCLUDED */
"##;
const TMMINTRIN_H: &str = r##"/* === SSSE3 intrinsic header === */
#ifndef _TMMINTRIN_H_INCLUDED
#define _TMMINTRIN_H_INCLUDED
#if !defined(__SSSE3__)
#error "SSSE3 instruction set not enabled"
#endif
#include <pmmintrin.h>
typedef short __v8hi __attribute__((__vector_size__(16)));
typedef char __v16qi __attribute__((__vector_size__(16)));
static __inline__ __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm_abs_epi8(__m128i __a) {
return (__m128i)__builtin_ia32_pabsb128((__v16qi)__a);
}
static __inline__ __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm_abs_epi16(__m128i __a) {
return (__m128i)__builtin_ia32_pabsw128((__v8hi)__a);
}
static __inline__ __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm_abs_epi32(__m128i __a) {
return (__m128i)__builtin_ia32_pabsd128((__v4si)__a);
}
static __inline__ __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm_shuffle_epi8(__m128i __a, __m128i __b) {
return (__m128i)__builtin_ia32_pshufb128((__v16qi)__a, (__v16qi)__b);
}
static __inline__ __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm_alignr_epi8(__m128i __a, __m128i __b, int __imm) {
return (__m128i)__builtin_ia32_palignr128((__v2di)__a, (__v2di)__b, (int)(__imm));
}
#endif /* _TMMINTRIN_H_INCLUDED */
"##;
const SMMINTRIN_H: &str = r##"/* === SSE4.1 intrinsic header === */
#ifndef _SMMINTRIN_H_INCLUDED
#define _SMMINTRIN_H_INCLUDED
#if !defined(__SSE4_1__)
#error "SSE4.1 instruction set not enabled"
#endif
#include <tmmintrin.h>
static __inline__ __m128 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm_dp_ps(__m128 __a, __m128 __b, const int imm) {
return (__m128)__builtin_ia32_dpps((__v4sf)__a, (__v4sf)__b, imm);
}
static __inline__ __m128d __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm_dp_pd(__m128d __a, __m128d __b, const int imm) {
return (__m128d)__builtin_ia32_dppd((__v2df)__a, (__v2df)__b, imm);
}
static __inline__ __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm_blend_epi16(__m128i __a, __m128i __b, const int imm) {
return (__m128i)__builtin_ia32_pblendw128((__v8hi)__a, (__v8hi)__b, imm);
}
static __inline__ __m128 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm_round_ps(__m128 __a, int rounding) {
return (__m128)__builtin_ia32_roundps((__v4sf)__a, rounding);
}
static __inline__ __m128d __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm_round_pd(__m128d __a, int rounding) {
return (__m128d)__builtin_ia32_roundpd((__v2df)__a, rounding);
}
static __inline__ int __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm_extract_epi32(__m128i __a, const int imm) {
int __r;
__asm__("pextrd %2, %1, %0" : "=r"(__r) : "x"(__a), "i"(imm));
return __r;
}
static __inline__ __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm_insert_epi32(__m128i __a, int __i, const int imm) {
__asm__("pinsrd %2, %1, %0" : "+x"(__a) : "r"(__i), "i"(imm));
return __a;
}
#endif /* _SMMINTRIN_H_INCLUDED */
"##;
const NMMINTRIN_H: &str = r##"/* === SSE4.2 intrinsic header (placeholder) === */
#ifndef _NMMINTRIN_H_INCLUDED
#define _NMMINTRIN_H_INCLUDED
#if !defined(__SSE4_2__)
#error "SSE4.2 instruction set not enabled"
#endif
#include <smmintrin.h>
static __inline__ int __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm_cmpestra(__m128i __a, int __la, __m128i __b, int __lb, const int imm) {
int __r;
__asm__("pcmpestri %4, %2, %1" : "=c"(__r) : "x"(__a), "x"(__b), "i"(imm));
return __r;
}
#endif /* _NMMINTRIN_H_INCLUDED */
"##;
const WMMINTRIN_H: &str = r##"/* === AES/PCLMUL intrinsic header (placeholder) === */
#ifndef _WMMINTRIN_H_INCLUDED
#define _WMMINTRIN_H_INCLUDED
#if !defined(__AES__) && !defined(__PCLMUL__)
#error "AES or PCLMUL instruction set not enabled"
#endif
#include <emmintrin.h>
#ifdef __AES__
static __inline__ __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm_aesenc_si128(__m128i __a, __m128i __round_key) {
return (__m128i)__builtin_ia32_aesenc128((__v2di)__a, (__v2di)__round_key);
}
#endif
#endif /* _WMMINTRIN_H_INCLUDED */
"##;
const AVXINTRIN_H: &str = r##"/* === AVX intrinsic header === */
#ifndef _AVXINTRIN_H_INCLUDED
#define _AVXINTRIN_H_INCLUDED
#if !defined(__AVX__)
#error "AVX instruction set not enabled"
#endif
#include <emmintrin.h>
typedef float __m256 __attribute__((__vector_size__(32), __aligned__(32)));
typedef double __m256d __attribute__((__vector_size__(32), __aligned__(32)));
typedef long long __m256i __attribute__((__vector_size__(32), __aligned__(32)));
static __inline__ __m256 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm256_add_ps(__m256 __a, __m256 __b) {
return (__m256)((__v8sf)__a + (__v8sf)__b);
}
static __inline__ __m256 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm256_sub_ps(__m256 __a, __m256 __b) {
return (__m256)((__v8sf)__a - (__v8sf)__b);
}
static __inline__ __m256 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm256_mul_ps(__m256 __a, __m256 __b) {
return (__m256)((__v8sf)__a * (__v8sf)__b);
}
static __inline__ __m256 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm256_load_ps(float const *__p) {
return *(__m256 const *)__p;
}
static __inline__ void __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm256_store_ps(float *__p, __m256 __a) {
*(__m256 *)__p = __a;
}
#endif /* _AVXINTRIN_H_INCLUDED */
"##;
const AVX2INTRIN_H: &str = r##"/* === AVX2 intrinsic header === */
#ifndef _AVX2INTRIN_H_INCLUDED
#define _AVX2INTRIN_H_INCLUDED
#if !defined(__AVX2__)
#error "AVX2 instruction set not enabled"
#endif
#include <avxintrin.h>
static __inline__ __m256i __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm256_add_epi32(__m256i __a, __m256i __b) {
return (__m256i)((__v8si)__a + (__v8si)__b);
}
static __inline__ __m256i __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm256_and_si256(__m256i __a, __m256i __b) {
return (__m256i)((__v4di)__a & (__v4di)__b);
}
static __inline__ __m256i __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm256_or_si256(__m256i __a, __m256i __b) {
return (__m256i)((__v4di)__a | (__v4di)__b);
}
#endif /* _AVX2INTRIN_H_INCLUDED */
"##;
const FMAINTRIN_H: &str = r##"/* === FMA intrinsic header === */
#ifndef _FMAINTRIN_H_INCLUDED
#define _FMAINTRIN_H_INCLUDED
#if !defined(__FMA__)
#error "FMA instruction set not enabled"
#endif
#include <immintrin.h>
static __inline__ __m128 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm_fmadd_ps(__m128 __a, __m128 __b, __m128 __c) {
return (__m128)__builtin_ia32_vfmaddps((__v4sf)__a, (__v4sf)__b, (__v4sf)__c);
}
static __inline__ __m128d __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm_fmadd_pd(__m128d __a, __m128d __b, __m128d __c) {
return (__m128d)__builtin_ia32_vfmaddpd((__v2df)__a, (__v2df)__b, (__v2df)__c);
}
static __inline__ __m256 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm256_fmadd_ps(__m256 __a, __m256 __b, __m256 __c) {
return (__m256)__builtin_ia32_vfmaddps256((__v8sf)__a, (__v8sf)__b, (__v8sf)__c);
}
static __inline__ __m256d __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm256_fmadd_pd(__m256d __a, __m256d __b, __m256d __c) {
return (__m256d)__builtin_ia32_vfmaddpd256((__v4df)__a, (__v4df)__b, (__v4df)__c);
}
#endif /* _FMAINTRIN_H_INCLUDED */
"##;
const FMA4INTRIN_H: &str = r##"/* === FMA4 intrinsic header (placeholder) === */
#ifndef _FMA4INTRIN_H_INCLUDED
#define _FMA4INTRIN_H_INCLUDED
#if !defined(__FMA4__)
#error "FMA4 instruction set not enabled"
#endif
#include <xmmintrin.h>
static __inline__ __m128 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm_macc_ps(__m128 __a, __m128 __b, __m128 __c) {
return (__m128)__builtin_ia32_vfmaddps((__v4sf)__a, (__v4sf)__b, (__v4sf)__c);
}
#endif /* _FMA4INTRIN_H_INCLUDED */
"##;
const XOPINTRIN_H: &str = r##"/* === XOP intrinsic header (placeholder) === */
#ifndef _XOPINTRIN_H_INCLUDED
#define _XOPINTRIN_H_INCLUDED
#if !defined(__XOP__)
#error "XOP instruction set not enabled"
#endif
#include <xmmintrin.h>
#endif /* _XOPINTRIN_H_INCLUDED */
"##;
const AVX512FINTRIN_H: &str = r##"/* === AVX-512 F intrinsic header === */
#ifndef _AVX512FINTRIN_H_INCLUDED
#define _AVX512FINTRIN_H_INCLUDED
#if !defined(__AVX512F__)
#error "AVX-512 F instruction set not enabled"
#endif
#include <immintrin.h>
typedef float __m512 __attribute__((__vector_size__(64), __aligned__(64)));
typedef double __m512d __attribute__((__vector_size__(64), __aligned__(64)));
typedef long long __m512i __attribute__((__vector_size__(64), __aligned__(64)));
typedef unsigned char __mmask8;
typedef unsigned short __mmask16;
static __inline__ __m512 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm512_add_ps(__m512 __a, __m512 __b) {
return (__m512)((__v16sf)__a + (__v16sf)__b);
}
static __inline__ __m512 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm512_mul_ps(__m512 __a, __m512 __b) {
return (__m512)((__v16sf)__a * (__v16sf)__b);
}
static __inline__ __m512 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm512_load_ps(void const *__p) {
return *(__m512 const *)__p;
}
static __inline__ void __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm512_store_ps(void *__p, __m512 __a) {
*(__m512 *)__p = __a;
}
#endif /* _AVX512FINTRIN_H_INCLUDED */
"##;
const AVX512BWINTRIN_H: &str = r##"/* === AVX-512 BW intrinsic header (placeholder) === */
#ifndef _AVX512BWINTRIN_H_INCLUDED
#define _AVX512BWINTRIN_H_INCLUDED
#if !defined(__AVX512BW__)
#error "AVX-512 BW instruction set not enabled"
#endif
#include <avx512fintrin.h>
#endif /* _AVX512BWINTRIN_H_INCLUDED */
"##;
const AVX512CDINTRIN_H: &str = r##"/* === AVX-512 CD intrinsic header (placeholder) === */
#ifndef _AVX512CDINTRIN_H_INCLUDED
#define _AVX512CDINTRIN_H_INCLUDED
#if !defined(__AVX512CD__)
#error "AVX-512 CD instruction set not enabled"
#endif
#include <avx512fintrin.h>
#endif /* _AVX512CDINTRIN_H_INCLUDED */
"##;
const AVX512DQINTRIN_H: &str = r##"/* === AVX-512 DQ intrinsic header (placeholder) === */
#ifndef _AVX512DQINTRIN_H_INCLUDED
#define _AVX512DQINTRIN_H_INCLUDED
#if !defined(__AVX512DQ__)
#error "AVX-512 DQ instruction set not enabled"
#endif
#include <avx512fintrin.h>
#endif /* _AVX512DQINTRIN_H_INCLUDED */
"##;
const AVX512VLINTRIN_H: &str = r##"/* === AVX-512 VL intrinsic header === */
#ifndef _AVX512VLINTRIN_H_INCLUDED
#define _AVX512VLINTRIN_H_INCLUDED
#if !defined(__AVX512VL__)
#error "AVX-512 VL instruction set not enabled"
#endif
#include <avx512fintrin.h>
#ifdef __AVX512VL__
/* 128-bit and 256-bit versions of AVX-512 operations */
static __inline__ __m128 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm_mask_add_ps(__m128 __src, __mmask8 __k, __m128 __a, __m128 __b) {
return (__m128)__builtin_ia32_addps_mask((__v4sf)__a, (__v4sf)__b, (__v4sf)__src, __k);
}
static __inline__ __m256 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm256_mask_add_ps(__m256 __src, __mmask8 __k, __m256 __a, __m256 __b) {
return (__m256)__builtin_ia32_addps256_mask((__v8sf)__a, (__v8sf)__b, (__v8sf)__src, __k);
}
static __inline__ __m128d __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm_mask_add_pd(__m128d __src, __mmask8 __k, __m128d __a, __m128d __b) {
return (__m128d)__builtin_ia32_addpd128_mask((__v2df)__a, (__v2df)__b, (__v2df)__src, __k);
}
static __inline__ __m256d __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm256_mask_add_pd(__m256d __src, __mmask8 __k, __m256d __a, __m256d __b) {
return (__m256d)__builtin_ia32_addpd256_mask((__v4df)__a, (__v4df)__b, (__v4df)__src, __k);
}
static __inline__ __m128 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm_maskz_add_ps(__mmask8 __k, __m128 __a, __m128 __b) {
return _mm_mask_add_ps(_mm_setzero_ps(), __k, __a, __b);
}
#endif /* __AVX512VL__ */
#endif /* _AVX512VLINTRIN_H_INCLUDED */
"##;
const AVX512IFMAINTRIN_H: &str = r##"/* === AVX-512 IFMA intrinsic header === */
#ifndef _AVX512IFMAINTRIN_H_INCLUDED
#define _AVX512IFMAINTRIN_H_INCLUDED
#if !defined(__AVX512IFMA__)
#error "AVX-512 IFMA instruction set not enabled"
#endif
#include <avx512fintrin.h>
#ifdef __AVX512IFMA__
static __inline__ __m512i __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm512_madd52lo_epu64(__m512i __a, __m512i __b, __m512i __c) {
return (__m512i)__builtin_ia32_vpmadd52luq512((__v8di)__b, (__v8di)__c, (__v8di)__a);
}
static __inline__ __m512i __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm512_madd52hi_epu64(__m512i __a, __m512i __b, __m512i __c) {
return (__m512i)__builtin_ia32_vpmadd52huq512((__v8di)__b, (__v8di)__c, (__v8di)__a);
}
#endif /* __AVX512IFMA__ */
#endif /* _AVX512IFMAINTRIN_H_INCLUDED */
"##;
const AVX512VBMIINTRIN_H: &str = r##"/* === AVX-512 VBMI intrinsic header === */
#ifndef _AVX512VBMIINTRIN_H_INCLUDED
#define _AVX512VBMIINTRIN_H_INCLUDED
#if !defined(__AVX512VBMI__)
#error "AVX-512 VBMI instruction set not enabled"
#endif
#include <avx512fintrin.h>
#ifdef __AVX512VBMI__
static __inline__ __m512i __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm512_permutexvar_epi8(__m512i __idx, __m512i __a) {
return (__m512i)__builtin_ia32_permvarqi512((__v64qi)__a, (__v64qi)__idx);
}
static __inline__ __m512i __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm512_multishift_epi64_epi8(__m512i __a, __m512i __b) {
return (__m512i)__builtin_ia32_vpmultishiftqb512((__v64qi)__a, (__v64qi)__b);
}
#endif /* __AVX512VBMI__ */
#endif /* _AVX512VBMIINTRIN_H_INCLUDED */
"##;
const AVX512VBMI2INTRIN_H: &str = r##"/* === AVX-512 VBMI2 intrinsic header === */
#ifndef _AVX512VBMI2INTRIN_H_INCLUDED
#define _AVX512VBMI2INTRIN_H_INCLUDED
#if !defined(__AVX512VBMI2__)
#error "AVX-512 VBMI2 instruction set not enabled"
#endif
#include <avx512fintrin.h>
#ifdef __AVX512VBMI2__
static __inline__ __m512i __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm512_shldi_epi16(__m512i __a, __m512i __b, int __imm8) {
return (__m512i)__builtin_ia32_vpshldw512((__v32hi)__a, (__v32hi)__b, __imm8);
}
static __inline__ __m512i __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm512_shrdi_epi16(__m512i __a, __m512i __b, int __imm8) {
return (__m512i)__builtin_ia32_vpshrdw512((__v32hi)__a, (__v32hi)__b, __imm8);
}
static __inline__ __m512i __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm512_maskz_compress_epi8(__mmask64 __k, __m512i __a) {
return (__m512i)__builtin_ia32_compressqi512((__v64qi)__a, (__v64qi)_mm512_setzero_si512(), __k);
}
static __inline__ __m512i __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm512_maskz_expand_epi8(__mmask64 __k, __m512i __a) {
return (__m512i)__builtin_ia32_expandqi512((__v64qi)__a, (__v64qi)_mm512_setzero_si512(), __k);
}
#endif /* __AVX512VBMI2__ */
#endif /* _AVX512VBMI2INTRIN_H_INCLUDED */
"##;
const AVX512VNNIINTRIN_H: &str = r##"/* === AVX-512 VNNI intrinsic header === */
#ifndef _AVX512VNNIINTRIN_H_INCLUDED
#define _AVX512VNNIINTRIN_H_INCLUDED
#if !defined(__AVX512VNNI__)
#error "AVX-512 VNNI instruction set not enabled"
#endif
#include <avx512fintrin.h>
#ifdef __AVX512VNNI__
static __inline__ __m512i __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm512_dpbusd_epi32(__m512i __src, __m512i __a, __m512i __b) {
return (__m512i)__builtin_ia32_vpdpbusd512((__v16si)__src, (__v16si)__a, (__v16si)__b);
}
static __inline__ __m512i __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm512_dpbusds_epi32(__m512i __src, __m512i __a, __m512i __b) {
return (__m512i)__builtin_ia32_vpdpbusds512((__v16si)__src, (__v16si)__a, (__v16si)__b);
}
static __inline__ __m512i __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm512_dpwssd_epi32(__m512i __src, __m512i __a, __m512i __b) {
return (__m512i)__builtin_ia32_vpdpwssd512((__v16si)__src, (__v16si)__a, (__v16si)__b);
}
#endif /* __AVX512VNNI__ */
#endif /* _AVX512VNNIINTRIN_H_INCLUDED */
"##;
const AVX512BITALGINTRIN_H: &str = r##"/* === AVX-512 BITALG intrinsic header === */
#ifndef _AVX512BITALGINTRIN_H_INCLUDED
#define _AVX512BITALGINTRIN_H_INCLUDED
#if !defined(__AVX512BITALG__)
#error "AVX-512 BITALG instruction set not enabled"
#endif
#include <avx512fintrin.h>
#ifdef __AVX512BITALG__
static __inline__ __m512i __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm512_popcnt_epi8(__m512i __a) {
return (__m512i)__builtin_ia32_vpopcntb512((__v64qi)__a);
}
static __inline__ __m512i __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm512_popcnt_epi16(__m512i __a) {
return (__m512i)__builtin_ia32_vpopcntw512((__v32hi)__a);
}
#endif /* __AVX512BITALG__ */
#endif /* _AVX512BITALGINTRIN_H_INCLUDED */
"##;
const AVX512VPOPCNTDQINTRIN_H: &str = r##"/* === AVX-512 VPOPCNTDQ intrinsic header === */
#ifndef _AVX512VPOPCNTDQINTRIN_H_INCLUDED
#define _AVX512VPOPCNTDQINTRIN_H_INCLUDED
#if !defined(__AVX512VPOPCNTDQ__)
#error "AVX-512 VPOPCNTDQ instruction set not enabled"
#endif
#include <avx512fintrin.h>
#ifdef __AVX512VPOPCNTDQ__
static __inline__ __m512i __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm512_popcnt_epi32(__m512i __a) {
return (__m512i)__builtin_ia32_vpopcntd512((__v16si)__a);
}
static __inline__ __m512i __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm512_popcnt_epi64(__m512i __a) {
return (__m512i)__builtin_ia32_vpopcntq512((__v8di)__a);
}
#endif /* __AVX512VPOPCNTDQ__ */
#endif /* _AVX512VPOPCNTDQINTRIN_H_INCLUDED */
"##;
const AVX5124FMAPSINTRIN_H: &str = r##"/* === AVX-512 4FMAPS intrinsic header === */
#ifndef _AVX5124FMAPSINTRIN_H_INCLUDED
#define _AVX5124FMAPSINTRIN_H_INCLUDED
#if !defined(__AVX5124FMAPS__)
#error "AVX-512 4FMAPS instruction set not enabled"
#endif
#include <avx512fintrin.h>
#ifdef __AVX5124FMAPS__
static __inline__ __m512 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm512_4fmadd_ps(__m512 __a, __m512 __b, __m128 *__c, __m512 __d) {
return (__m512)__builtin_ia32_4fmaddps((__v16sf)__a, (__v16sf)__b, (const __v4sf *)__c, (__v16sf)__d);
}
#endif /* __AVX5124FMAPS__ */
#endif /* _AVX5124FMAPSINTRIN_H_INCLUDED */
"##;
const AVX5124VNNIWINTRIN_H: &str = r##"/* === AVX-512 4VNNIW intrinsic header === */
#ifndef _AVX5124VNNIWINTRIN_H_INCLUDED
#define _AVX5124VNNIWINTRIN_H_INCLUDED
#if !defined(__AVX5124VNNIW__)
#error "AVX-512 4VNNIW instruction set not enabled"
#endif
#include <avx512fintrin.h>
#ifdef __AVX5124VNNIW__
static __inline__ __m512i __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm512_4dpwssd_epi32(__m512i __src, __m512i __a, __m128i *__b, __m512i __d) {
return (__m512i)__builtin_ia32_4dpwssd((__v16si)__src, (__v16si)__a, (const __v4si *)__b, (__v16si)__d);
}
#endif /* __AVX5124VNNIW__ */
#endif /* _AVX5124VNNIWINTRIN_H_INCLUDED */
"##;
const AVX512BF16INTRIN_H: &str = r##"/* === AVX-512 BF16 intrinsic header === */
#ifndef _AVX512BF16INTRIN_H_INCLUDED
#define _AVX512BF16INTRIN_H_INCLUDED
#if !defined(__AVX512BF16__)
#error "AVX-512 BF16 instruction set not enabled"
#endif
#include <avx512fintrin.h>
#ifdef __AVX512BF16__
typedef unsigned short __bf16 __attribute__((__vector_size__(2)));
static __inline__ __m512 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm512_cvtne2ps_pbh(__m512 __a, __m512 __b) {
return (__m512)__builtin_ia32_cvtne2ps2bf16_512((__v16sf)__a, (__v16sf)__b);
}
static __inline__ __m512 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm512_dpbf16_ps(__m512 __src, __m512bh __a, __m512bh __b) {
return (__m512)__builtin_ia32_dpbf16ps_512((__v16sf)__src, (__v32hi)__a, (__v32hi)__b);
}
#endif /* __AVX512BF16__ */
#endif /* _AVX512BF16INTRIN_H_INCLUDED */
"##;
const AVX512FP16INTRIN_H: &str = r##"/* === AVX-512 FP16 intrinsic header === */
#ifndef _AVX512FP16INTRIN_H_INCLUDED
#define _AVX512FP16INTRIN_H_INCLUDED
#if !defined(__AVX512FP16__)
#error "AVX-512 FP16 instruction set not enabled"
#endif
#include <avx512fintrin.h>
#ifdef __AVX512FP16__
typedef _Float16 __m128h __attribute__((__vector_size__(16), __aligned__(16)));
typedef _Float16 __m256h __attribute__((__vector_size__(32), __aligned__(32)));
typedef _Float16 __m512h __attribute__((__vector_size__(64), __aligned__(64)));
static __inline__ __m512h __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm512_add_ph(__m512h __a, __m512h __b) {
return (__m512h)__builtin_ia32_addph512((__v32hf)__a, (__v32hf)__b);
}
static __inline__ __m512h __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm512_mul_ph(__m512h __a, __m512h __b) {
return (__m512h)__builtin_ia32_mulph512((__v32hf)__a, (__v32hf)__b);
}
static __inline__ __m512h __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm512_fmadd_ph(__m512h __a, __m512h __b, __m512h __c) {
return (__m512h)__builtin_ia32_vfmaddph512((__v32hf)__a, (__v32hf)__b, (__v32hf)__c);
}
#endif /* __AVX512FP16__ */
#endif /* _AVX512FP16INTRIN_H_INCLUDED */
"##;
const F16CINTRIN_H: &str = r##"/* === F16C intrinsic header === */
#ifndef _F16CINTRIN_H_INCLUDED
#define _F16CINTRIN_H_INCLUDED
#if !defined(__F16C__)
#error "F16C instruction set not enabled"
#endif
#include <emmintrin.h>
static __inline__ __m128 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm_cvtph_ps(__m128i __a) {
return (__m128)__builtin_ia32_vcvtph2ps((__v8hi)__a);
}
static __inline__ __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm_cvtps_ph(__m128 __a, int __imm) {
return (__m128i)__builtin_ia32_vcvtps2ph((__v4sf)__a, __imm);
}
#ifdef __AVX__
static __inline__ __m256 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm256_cvtph_ps(__m128i __a) {
return (__m256)__builtin_ia32_vcvtph2ps256((__v8hi)__a);
}
#endif /* __AVX__ */
#endif /* _F16CINTRIN_H_INCLUDED */
"##;
const BMIINTRIN_H: &str = r##"/* === BMI intrinsic header === */
#ifndef _BMIINTRIN_H_INCLUDED
#define _BMIINTRIN_H_INCLUDED
#if !defined(__BMI__)
#error "BMI instruction set not enabled"
#endif
static __inline__ unsigned int __attribute__((__gnu_inline__, __always_inline__, __artificial__))
__andn_u32(unsigned int __a, unsigned int __b) {
return ~__a & __b;
}
static __inline__ unsigned int __attribute__((__gnu_inline__, __always_inline__, __artificial__))
__bextr_u32(unsigned int __a, unsigned int __start, unsigned int __len) {
return ((__a >> __start) & ((1U << __len) - 1U));
}
static __inline__ unsigned int __attribute__((__gnu_inline__, __always_inline__, __artificial__))
__blsi_u32(unsigned int __a) {
return __a & -__a;
}
static __inline__ unsigned int __attribute__((__gnu_inline__, __always_inline__, __artificial__))
__blsmsk_u32(unsigned int __a) {
return __a ^ (__a - 1U);
}
static __inline__ unsigned int __attribute__((__gnu_inline__, __always_inline__, __artificial__))
__blsr_u32(unsigned int __a) {
return __a & (__a - 1U);
}
static __inline__ unsigned int __attribute__((__gnu_inline__, __always_inline__, __artificial__))
__tzcnt_u32(unsigned int __a) {
unsigned int __r;
__asm__("tzcntl %1, %0" : "=r"(__r) : "r"(__a));
return __r;
}
#endif /* _BMIINTRIN_H_INCLUDED */
"##;
const BMI2INTRIN_H: &str = r##"/* === BMI2 intrinsic header === */
#ifndef _BMI2INTRIN_H_INCLUDED
#define _BMI2INTRIN_H_INCLUDED
#if !defined(__BMI2__)
#error "BMI2 instruction set not enabled"
#endif
static __inline__ unsigned int __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_bzhi_u32(unsigned int __a, unsigned int __index) {
unsigned int __r;
__asm__("bzhi %2, %1, %0" : "=r"(__r) : "r"(__a), "r"(__index));
return __r;
}
static __inline__ unsigned int __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_pdep_u32(unsigned int __a, unsigned int __mask) {
unsigned int __r;
__asm__("pdep %2, %1, %0" : "=r"(__r) : "r"(__a), "r"(__mask));
return __r;
}
static __inline__ unsigned int __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_pext_u32(unsigned int __a, unsigned int __mask) {
unsigned int __r;
__asm__("pext %2, %1, %0" : "=r"(__r) : "r"(__a), "r"(__mask));
return __r;
}
#endif /* _BMI2INTRIN_H_INCLUDED */
"##;
const LZCNTINTRIN_H: &str = r##"/* === LZCNT intrinsic header === */
#ifndef _LZCNTINTRIN_H_INCLUDED
#define _LZCNTINTRIN_H_INCLUDED
#if !defined(__LZCNT__)
#error "LZCNT instruction set not enabled"
#endif
static __inline__ unsigned int __attribute__((__gnu_inline__, __always_inline__, __artificial__))
__lzcnt32(unsigned int __a) {
unsigned int __r;
__asm__("lzcnt %1, %0" : "=r"(__r) : "r"(__a));
return __r;
}
static __inline__ unsigned long long __attribute__((__gnu_inline__, __always_inline__, __artificial__))
__lzcnt64(unsigned long long __a) {
unsigned long long __r;
__asm__("lzcntq %1, %0" : "=r"(__r) : "r"(__a));
return __r;
}
#endif /* _LZCNTINTRIN_H_INCLUDED */
"##;
const POPCNTINTRIN_H: &str = r##"/* === POPCNT intrinsic header === */
#ifndef _POPCNTINTRIN_H_INCLUDED
#define _POPCNTINTRIN_H_INCLUDED
#if !defined(__POPCNT__)
#error "POPCNT instruction set not enabled"
#endif
static __inline__ int __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm_popcnt_u32(unsigned int __a) {
return __builtin_popcount(__a);
}
static __inline__ long long __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm_popcnt_u64(unsigned long long __a) {
return __builtin_popcountll(__a);
}
#endif /* _POPCNTINTRIN_H_INCLUDED */
"##;
const RDRANDINTRIN_H: &str = "/* === RDRAND intrinsic header (placeholder) === */\n#ifndef _RDRANDINTRIN_H_INCLUDED\n#define _RDRANDINTRIN_H_INCLUDED\n#if !defined(__RDRAND__)\n#error \"RDRAND instruction set not enabled\"\n#endif\n#endif\n";
const SHAINTRIN_H: &str = "/* === SHA intrinsic header (placeholder) === */\n#ifndef _SHAINTRIN_H_INCLUDED\n#define _SHAINTRIN_H_INCLUDED\n#if !defined(__SHA__)\n#error \"SHA instruction set not enabled\"\n#endif\n#include <emmintrin.h>\n#endif\n";
const GFNIINTRIN_H: &str = "/* === GFNI intrinsic header (placeholder) === */\n#ifndef _GFNIINTRIN_H_INCLUDED\n#define _GFNIINTRIN_H_INCLUDED\n#if !defined(__GFNI__)\n#error \"GFNI instruction set not enabled\"\n#endif\n#endif\n";
const VAESINTRIN_H: &str = "/* === VAES intrinsic header (placeholder) === */\n#ifndef _VAESINTRIN_H_INCLUDED\n#define _VAESINTRIN_H_INCLUDED\n#if !defined(__VAES__)\n#error \"VAES instruction set not enabled\"\n#endif\n#endif\n";
const VPCLMULQDQINTRIN_H: &str = "/* === VPCLMULQDQ intrinsic header (placeholder) === */\n#ifndef _VPCLMULQDQINTRIN_H_INCLUDED\n#define _VPCLMULQDQINTRIN_H_INCLUDED\n#if !defined(__VPCLMULQDQ__)\n#error \"VPCLMULQDQ instruction set not enabled\"\n#endif\n#endif\n";
const AMXINTRIN_H: &str = "/* === AMX intrinsic header (placeholder) === */\n#ifndef _AMXINTRIN_H_INCLUDED\n#define _AMXINTRIN_H_INCLUDED\n#if !defined(__AMX_TILE__)\n#error \"AMX-TILE instruction set not enabled\"\n#endif\n#endif\n";
const AMXBF16INTRIN_H: &str = "/* === AMX-BF16 intrinsic header (placeholder) === */\n#ifndef _AMXBF16INTRIN_H_INCLUDED\n#define _AMXBF16INTRIN_H_INCLUDED\n#if !defined(__AMX_BF16__)\n#error \"AMX-BF16 instruction set not enabled\"\n#endif\n#endif\n";
const AMXINT8INTRIN_H: &str = "/* === AMX-INT8 intrinsic header (placeholder) === */\n#ifndef _AMXINT8INTRIN_H_INCLUDED\n#define _AMXINT8INTRIN_H_INCLUDED\n#if !defined(__AMX_INT8__)\n#error \"AMX-INT8 instruction set not enabled\"\n#endif\n#endif\n";
const CETINTRIN_H: &str = "/* === CET intrinsic header (placeholder) === */\n#ifndef _CETINTRIN_H_INCLUDED\n#define _CETINTRIN_H_INCLUDED\n#if !defined(__SHSTK__) && !defined(__IBT__)\n#error \"CET instruction set not enabled\"\n#endif\n#endif\n";
const MOVDIRINTRIN_H: &str = "/* === MOVDIRI intrinsic header (placeholder) === */\n#ifndef _MOVDIRINTRIN_H_INCLUDED\n#define _MOVDIRINTRIN_H_INCLUDED\n#if !defined(__MOVDIRI__)\n#error \"MOVDIRI instruction set not enabled\"\n#endif\n#endif\n";
const WAITPKGINTRIN_H: &str = "/* === WAITPKG intrinsic header (placeholder) === */\n#ifndef _WAITPKGINTRIN_H_INCLUDED\n#define _WAITPKGINTRIN_H_INCLUDED\n#if !defined(__WAITPKG__)\n#error \"WAITPKG instruction set not enabled\"\n#endif\n#endif\n";
const ENQCMDINTRIN_H: &str = "/* === ENQCMD intrinsic header (placeholder) === */\n#ifndef _ENQCMDINTRIN_H_INCLUDED\n#define _ENQCMDINTRIN_H_INCLUDED\n#if !defined(__ENQCMD__)\n#error \"ENQCMD instruction set not enabled\"\n#endif\n#endif\n";
const SERIALIZEINTRIN_H: &str = "/* === SERIALIZE intrinsic header (placeholder) === */\n#ifndef _SERIALIZEINTRIN_H_INCLUDED\n#define _SERIALIZEINTRIN_H_INCLUDED\n#if !defined(__SERIALIZE__)\n#error \"SERIALIZE instruction set not enabled\"\n#endif\n#endif\n";
const TSXLDTRKINTRIN_H: &str = "/* === TSXLDTRK intrinsic header (placeholder) === */\n#ifndef _TSXLDTRKINTRIN_H_INCLUDED\n#define _TSXLDTRKINTRIN_H_INCLUDED\n#if !defined(__TSXLDTRK__)\n#error \"TSXLDTRK instruction set not enabled\"\n#endif\n#endif\n";
const CLDEMOTEINTRIN_H: &str = "/* === CLDEMOTE intrinsic header (placeholder) === */\n#ifndef _CLDEMOTEINTRIN_H_INCLUDED\n#define _CLDEMOTEINTRIN_H_INCLUDED\n#if !defined(__CLDEMOTE__)\n#error \"CLDEMOTE instruction set not enabled\"\n#endif\n#endif\n";
const PTWRITEINTRIN_H: &str = "/* === PTWRITE intrinsic header (placeholder) === */\n#ifndef _PTWRITEINTRIN_H_INCLUDED\n#define _PTWRITEINTRIN_H_INCLUDED\n#if !defined(__PTWRITE__)\n#error \"PTWRITE instruction set not enabled\"\n#endif\n#endif\n";
const UINTRINTRIN_H: &str = "/* === UINTR intrinsic header (placeholder) === */\n#ifndef _UINTRINTRIN_H_INCLUDED\n#define _UINTRINTRIN_H_INCLUDED\n#if !defined(__UINTR__)\n#error \"UINTR instruction set not enabled\"\n#endif\n#endif\n";
const HRESETINTRIN_H: &str = "/* === HRESET intrinsic header (placeholder) === */\n#ifndef _HRESETINTRIN_H_INCLUDED\n#define _HRESETINTRIN_H_INCLUDED\n#if !defined(__HRESET__)\n#error \"HRESET instruction set not enabled\"\n#endif\n#endif\n";
const KEYLOCKERINTRIN_H: &str = "/* === KEYLOCKER intrinsic header (placeholder) === */\n#ifndef _KEYLOCKERINTRIN_H_INCLUDED\n#define _KEYLOCKERINTRIN_H_INCLUDED\n#if !defined(__KL__)\n#error \"KEYLOCKER instruction set not enabled\"\n#endif\n#endif\n";
const CMPCCXADDINTRIN_H: &str = "/* === CMPCCXADD intrinsic header (placeholder) === */\n#ifndef _CMPCCXADDINTRIN_H_INCLUDED\n#define _CMPCCXADDINTRIN_H_INCLUDED\n#if !defined(__CMPCCXADD__)\n#error \"CMPCCXADD instruction set not enabled\"\n#endif\n#endif\n";
const RAOINTINTRIN_H: &str = "/* === RAOINT intrinsic header (placeholder) === */\n#ifndef _RAOINTINTRIN_H_INCLUDED\n#define _RAOINTINTRIN_H_INCLUDED\n#if !defined(__RAOINT__)\n#error \"RAOINT instruction set not enabled\"\n#endif\n#endif\n";
const AVXIFMAINTRIN_H: &str = "/* === AVX-IFMA intrinsic header (placeholder) === */\n#ifndef _AVXIFMAINTRIN_H_INCLUDED\n#define _AVXIFMAINTRIN_H_INCLUDED\n#if !defined(__AVXIFMA__)\n#error \"AVX-IFMA instruction set not enabled\"\n#endif\n#endif\n";
const AVXNECONVERTINTRIN_H: &str = "/* === AVX-NE-CONVERT intrinsic header (placeholder) === */\n#ifndef _AVXNECONVERTINTRIN_H_INCLUDED\n#define _AVXNECONVERTINTRIN_H_INCLUDED\n#if !defined(__AVXNECONVERT__)\n#error \"AVX-NE-CONVERT instruction set not enabled\"\n#endif\n#endif\n";
const AVXVNNIINT8INTRIN_H: &str = "/* === AVX-VNNI-INT8 intrinsic header (placeholder) === */\n#ifndef _AVXVNNIINT8INTRIN_H_INCLUDED\n#define _AVXVNNIINT8INTRIN_H_INCLUDED\n#if !defined(__AVXVNNIINT8__)\n#error \"AVX-VNNI-INT8 instruction set not enabled\"\n#endif\n#endif\n";
const AVX10_1INTRIN_H: &str = "/* === AVX10.1 intrinsic header (placeholder) === */\n#ifndef _AVX10_1INTRIN_H_INCLUDED\n#define _AVX10_1INTRIN_H_INCLUDED\n#if !defined(__AVX10_1__)\n#error \"AVX10.1 instruction set not enabled\"\n#endif\n#endif\n";
#[derive(Debug, Clone, Default)]
pub struct X86StandardHeaders {
headers: HashMap<String, String>,
deps: HashMap<String, Vec<String>>,
reverse_deps: HashMap<String, Vec<String>>,
}
impl X86StandardHeaders {
pub fn new() -> Self {
let mut h = Self {
headers: HashMap::new(),
deps: HashMap::new(),
reverse_deps: HashMap::new(),
};
h.populate_deps();
h
}
fn populate_deps(&mut self) {
let c_headers = [
"assert.h",
"complex.h",
"ctype.h",
"errno.h",
"fenv.h",
"float.h",
"inttypes.h",
"iso646.h",
"limits.h",
"locale.h",
"math.h",
"setjmp.h",
"signal.h",
"stdalign.h",
"stdarg.h",
"stdatomic.h",
"stdbool.h",
"stddef.h",
"stdint.h",
"stdio.h",
"stdlib.h",
"stdnoreturn.h",
"string.h",
"tgmath.h",
"threads.h",
"time.h",
"uchar.h",
"wchar.h",
"wctype.h",
];
let cxx_headers = [
"algorithm",
"any",
"array",
"atomic",
"barrier",
"bit",
"bitset",
"charconv",
"chrono",
"codecvt",
"compare",
"complex",
"concepts",
"condition_variable",
"coroutine",
"deque",
"exception",
"execution",
"expected",
"filesystem",
"format",
"forward_list",
"fstream",
"functional",
"future",
"generator",
"initializer_list",
"iomanip",
"ios",
"iosfwd",
"iostream",
"istream",
"iterator",
"latch",
"limits",
"list",
"locale",
"map",
"mdspan",
"memory",
"memory_resource",
"mutex",
"new",
"numbers",
"numeric",
"optional",
"ostream",
"print",
"queue",
"random",
"ranges",
"ratio",
"regex",
"scoped_allocator",
"semaphore",
"set",
"shared_mutex",
"source_location",
"span",
"spanstream",
"sstream",
"stack",
"stacktrace",
"stdexcept",
"stop_token",
"streambuf",
"string",
"string_view",
"strstream",
"syncstream",
"system_error",
"thread",
"tuple",
"type_traits",
"typeindex",
"typeinfo",
"unordered_map",
"unordered_set",
"utility",
"valarray",
"variant",
"vector",
"version",
];
let cxx_c_headers = [
"cassert",
"ccomplex",
"cctype",
"cerrno",
"cfenv",
"cfloat",
"cinttypes",
"ciso646",
"climits",
"clocale",
"cmath",
"csetjmp",
"csignal",
"cstdalign",
"cstdarg",
"cstdbool",
"cstddef",
"cstdint",
"cstdio",
"cstdlib",
"cstring",
"ctgmath",
"ctime",
"cuchar",
"cwchar",
"cwctype",
];
let posix_headers = [
"dirent.h",
"dlfcn.h",
"fcntl.h",
"fnmatch.h",
"glob.h",
"grp.h",
"netdb.h",
"pthread.h",
"pwd.h",
"regex.h",
"sched.h",
"semaphore.h",
"sys/mman.h",
"sys/resource.h",
"sys/select.h",
"sys/socket.h",
"sys/stat.h",
"sys/time.h",
"sys/types.h",
"sys/un.h",
"sys/utsname.h",
"sys/wait.h",
"termios.h",
"unistd.h",
"utime.h",
];
for &h in &c_headers {
self.deps.entry(h.to_string()).or_default();
self.reverse_deps.entry(h.to_string()).or_default();
}
for &h in &cxx_headers {
self.deps.entry(h.to_string()).or_default();
self.reverse_deps.entry(h.to_string()).or_default();
}
for &h in &cxx_c_headers {
self.deps.entry(h.to_string()).or_default();
self.reverse_deps.entry(h.to_string()).or_default();
}
for &h in &posix_headers {
self.deps.entry(h.to_string()).or_default();
self.reverse_deps.entry(h.to_string()).or_default();
}
self.add_dep("iostream", "istream");
self.add_dep("iostream", "ostream");
self.add_dep("istream", "ios");
self.add_dep("ostream", "ios");
self.add_dep("fstream", "iostream");
self.add_dep("sstream", "iostream");
self.add_dep("vector", "initializer_list");
self.add_dep("string", "string_view");
self.add_dep("map", "initializer_list");
self.add_dep("set", "initializer_list");
self.add_dep("algorithm", "initializer_list");
self.add_dep("memory", "new");
self.add_dep("thread", "chrono");
self.add_dep("condition_variable", "mutex");
self.add_dep("future", "thread");
self.add_dep("iostream", "string");
self.add_dep("format", "string_view");
self.add_dep("ranges", "iterator");
self.add_dep("span", "cstddef");
self.add_dep("stdio.h", "stddef.h");
self.add_dep("stdlib.h", "stddef.h");
self.add_dep("time.h", "stddef.h");
}
fn add_dep(&mut self, includer: &str, included: &str) {
self.deps
.entry(includer.to_string())
.or_default()
.push(included.to_string());
self.reverse_deps
.entry(included.to_string())
.or_default()
.push(includer.to_string());
}
pub fn resolve(&self, name: &str) -> Option<String> {
self.headers.get(name).cloned()
}
pub fn is_known(&self, name: &str) -> bool {
self.deps.contains_key(name) || self.headers.contains_key(name)
}
pub fn dependencies(&self, name: &str) -> Vec<&str> {
self.deps
.get(name)
.map(|v| v.iter().map(|s| s.as_str()).collect())
.unwrap_or_default()
}
pub fn reverse_dependencies(&self, name: &str) -> Vec<&str> {
self.reverse_deps
.get(name)
.map(|v| v.iter().map(|s| s.as_str()).collect())
.unwrap_or_default()
}
pub fn add_synthetic(&mut self, name: &str, content: &str) {
self.headers.insert(name.to_string(), content.to_string());
}
pub fn c_header_names() -> Vec<&'static str> {
vec![
"assert.h",
"complex.h",
"ctype.h",
"errno.h",
"fenv.h",
"float.h",
"inttypes.h",
"iso646.h",
"limits.h",
"locale.h",
"math.h",
"setjmp.h",
"signal.h",
"stdalign.h",
"stdarg.h",
"stdatomic.h",
"stdbool.h",
"stddef.h",
"stdint.h",
"stdio.h",
"stdlib.h",
"stdnoreturn.h",
"string.h",
"tgmath.h",
"threads.h",
"time.h",
"uchar.h",
"wchar.h",
"wctype.h",
]
}
pub fn cxx_header_names() -> Vec<&'static str> {
vec![
"algorithm",
"any",
"array",
"atomic",
"barrier",
"bit",
"bitset",
"charconv",
"chrono",
"codecvt",
"compare",
"complex",
"concepts",
"condition_variable",
"coroutine",
"deque",
"exception",
"execution",
"expected",
"filesystem",
"format",
"forward_list",
"fstream",
"functional",
"future",
"generator",
"initializer_list",
"iomanip",
"ios",
"iosfwd",
"iostream",
"istream",
"iterator",
"latch",
"limits",
"list",
"locale",
"map",
"mdspan",
"memory",
"memory_resource",
"mutex",
"new",
"numbers",
"numeric",
"optional",
"ostream",
"print",
"queue",
"random",
"ranges",
"ratio",
"regex",
"scoped_allocator",
"semaphore",
"set",
"shared_mutex",
"source_location",
"span",
"spanstream",
"sstream",
"stack",
"stacktrace",
"stdexcept",
"stop_token",
"streambuf",
"string",
"string_view",
"strstream",
"syncstream",
"system_error",
"thread",
"tuple",
"type_traits",
"typeindex",
"typeinfo",
"unordered_map",
"unordered_set",
"utility",
"valarray",
"variant",
"vector",
"version",
]
}
pub fn posix_header_names() -> Vec<&'static str> {
vec![
"dirent.h",
"dlfcn.h",
"fcntl.h",
"fnmatch.h",
"glob.h",
"grp.h",
"netdb.h",
"pthread.h",
"pwd.h",
"regex.h",
"sched.h",
"semaphore.h",
"sys/mman.h",
"sys/resource.h",
"sys/select.h",
"sys/socket.h",
"sys/stat.h",
"sys/time.h",
"sys/types.h",
"sys/un.h",
"sys/utsname.h",
"sys/wait.h",
"termios.h",
"unistd.h",
"utime.h",
]
}
}
#[derive(Debug, Clone, Default)]
pub struct X86ModuleMap {
modules: HashMap<String, ModuleMapEntry>,
imports: HashMap<String, Vec<String>>,
map_files: Vec<PathBuf>,
}
#[derive(Debug, Clone)]
pub struct ModuleMapEntry {
pub name: String,
pub is_framework: bool,
pub is_explicit: bool,
pub is_system: bool,
pub umbrella_header: Option<String>,
pub umbrella_dir: Option<String>,
pub headers: Vec<String>,
pub excluded_headers: Vec<String>,
pub submodules: Vec<String>,
pub exports: Vec<String>,
pub link_libraries: Vec<String>,
pub base_dir: PathBuf,
}
impl ModuleMapEntry {
pub fn new(name: &str, base_dir: &Path) -> Self {
Self {
name: name.to_string(),
is_framework: false,
is_explicit: false,
is_system: false,
umbrella_header: None,
umbrella_dir: None,
headers: Vec::new(),
excluded_headers: Vec::new(),
submodules: Vec::new(),
exports: Vec::new(),
link_libraries: Vec::new(),
base_dir: base_dir.to_path_buf(),
}
}
}
impl X86ModuleMap {
pub fn parse_file(&mut self, path: &Path) -> std::io::Result<()> {
let content = std::fs::read_to_string(path)?;
let base_dir = path.parent().unwrap_or_else(|| Path::new("."));
let entries = parse_module_map_content(&content, base_dir);
for entry in entries {
self.modules.insert(entry.name.clone(), entry);
}
self.map_files.push(path.to_path_buf());
Ok(())
}
pub fn load_directory(&mut self, dir: &str) {
let candidates = ["module.modulemap", "module.map", "Modules/module.modulemap"];
for name in &candidates {
let path = Path::new(dir).join(name);
if path.exists() {
let _ = self.parse_file(&path);
}
}
}
pub fn find(&self, name: &str) -> Option<ModuleMapEntry> {
self.modules.get(name).cloned()
}
pub fn names(&self) -> Vec<String> {
self.modules.keys().cloned().collect()
}
pub fn add_import(&mut self, from: &str, to: &str) {
self.imports
.entry(from.to_string())
.or_default()
.push(to.to_string());
}
pub fn lookup_header(&self, header: &str) -> Option<String> {
for (name, entry) in &self.modules {
for h in &entry.headers {
if h == header || h.ends_with(&format!("/{}", header)) {
return Some(name.clone());
}
}
if let Some(ref umbrella) = entry.umbrella_header {
if umbrella == header || umbrella.ends_with(&format!("/{}", header)) {
return Some(name.clone());
}
}
}
None
}
pub fn generate_standard_modules(&mut self) {
self.add_standard_module(
"std",
&[
"stddef.h",
"stdarg.h",
"stdbool.h",
"stdint.h",
"stdalign.h",
"stdnoreturn.h",
],
);
self.add_standard_module("std.io", &["stdio.h"]);
self.add_standard_module("std.stdlib", &["stdlib.h"]);
self.add_standard_module("std.string", &["string.h"]);
self.add_standard_module("std.math", &["math.h", "tgmath.h", "complex.h", "fenv.h"]);
self.add_standard_module("std.time", &["time.h"]);
self.add_standard_module("std.signal", &["signal.h", "setjmp.h"]);
self.add_standard_module("std.threads", &["threads.h"]);
}
fn add_standard_module(&mut self, name: &str, headers: &[&str]) {
let mut entry = ModuleMapEntry::new(name, Path::new("<synthetic>"));
entry.is_system = true;
entry.is_explicit = true;
entry.headers = headers.iter().map(|s| s.to_string()).collect();
self.modules.insert(name.to_string(), entry);
}
}
fn parse_module_map_content(content: &str, base_dir: &Path) -> Vec<ModuleMapEntry> {
let mut entries = Vec::new();
let mut current: Option<ModuleMapEntry> = None;
for line in content.lines() {
let trimmed = line.trim();
if trimmed.is_empty() || trimmed.starts_with("//") {
continue;
}
let parts: Vec<&str> = trimmed.splitn(2, ' ').collect();
if parts.is_empty() {
continue;
}
let keyword = parts[0];
let rest = parts.get(1).copied().unwrap_or("").trim();
match keyword {
"module" => {
if let Some(prev) = current.take() {
entries.push(prev);
}
let name = rest.trim_end_matches('{').trim();
current = Some(ModuleMapEntry::new(name, base_dir));
}
"framework" if rest == "module" => {
if let Some(ref mut cur) = current {
cur.is_framework = true;
}
}
"explicit" if rest == "module" => {
if let Some(ref mut cur) = current {
cur.is_explicit = true;
}
}
"system" if rest == "module" => {
if let Some(ref mut cur) = current {
cur.is_system = true;
}
}
"umbrella" => {
if let Some(ref mut cur) = current {
match rest {
r if r.starts_with("header") => {
let h = r.trim_start_matches("header").trim().trim_matches('"');
cur.umbrella_header = Some(h.to_string());
}
r if r.starts_with("directory") => {
let d = r.trim_start_matches("directory").trim().trim_matches('"');
cur.umbrella_dir = Some(d.to_string());
}
_ => {}
}
}
}
"header" => {
if let Some(ref mut cur) = current {
let h = rest.trim_matches('"');
cur.headers.push(h.to_string());
}
}
"exclude" if rest.starts_with("header") => {
if let Some(ref mut cur) = current {
let h = rest.trim_start_matches("header").trim().trim_matches('"');
cur.excluded_headers.push(h.to_string());
}
}
"export" => {
if let Some(ref mut cur) = current {
cur.exports.push(rest.to_string());
}
}
"link" => {
if let Some(ref mut cur) = current {
cur.link_libraries.push(rest.to_string());
}
}
"{" | "}" => {
}
_ => {
}
}
}
if let Some(prev) = current.take() {
entries.push(prev);
}
entries
}
#[derive(Debug, Clone)]
pub struct X86VFSOverlay {
pub overlay_file: Option<PathBuf>,
pub enabled: bool,
mappings: HashMap<String, PathBuf>,
loaded: bool,
}
impl Default for X86VFSOverlay {
fn default() -> Self {
Self {
overlay_file: None,
enabled: false,
mappings: HashMap::new(),
loaded: false,
}
}
}
impl X86VFSOverlay {
pub fn new() -> Self {
Self::default()
}
pub fn load(&mut self, path: &str) -> std::io::Result<()> {
let content = std::fs::read_to_string(path)?;
self.parse_overlay(&content);
self.overlay_file = Some(PathBuf::from(path));
self.enabled = true;
self.loaded = true;
Ok(())
}
fn parse_overlay(&mut self, content: &str) {
let trimmed = content.trim();
if !trimmed.starts_with('{') {
return;
}
let lines: Vec<&str> = content.lines().collect();
let mut current_virtual: Option<String> = None;
for line in &lines {
let l = line.trim().trim_end_matches(',');
if l.contains("\"name\"") && l.contains(':') {
if let Some(name) = extract_json_string_value(l) {
current_virtual = Some(name);
}
}
if l.contains("\"external-contents\"") && l.contains(':') {
if let Some(real) = extract_json_string_value(l) {
if let Some(ref vname) = current_virtual {
self.mappings.insert(vname.clone(), PathBuf::from(real));
}
}
}
}
}
pub fn add_remap(&mut self, virtual_path: &str, real_path: &str) {
self.mappings
.insert(virtual_path.to_string(), PathBuf::from(real_path));
self.enabled = true;
}
pub fn remap(&self, name: &str) -> Option<PathBuf> {
if !self.enabled {
return None;
}
if let Some(p) = self.mappings.get(name) {
return Some(p.clone());
}
for (vname, path) in &self.mappings {
if let Some(bn) = Path::new(vname).file_name() {
if bn == name {
return Some(path.clone());
}
}
}
None
}
pub fn has_remap(&self, name: &str) -> bool {
self.remap(name).is_some()
}
pub fn set_enabled(&mut self, enabled: bool) {
self.enabled = enabled;
}
pub fn mappings(&self) -> Vec<(String, String)> {
self.mappings
.iter()
.map(|(k, v)| (k.clone(), v.to_string_lossy().to_string()))
.collect()
}
}
fn extract_json_string_value(line: &str) -> Option<String> {
let after_colon = line.find(':')?;
let value_part = &line[after_colon + 1..].trim();
let start = value_part.find('"')?;
let rest = &value_part[start + 1..];
let end = rest.find('"')?;
Some(rest[..end].to_string())
}
#[derive(Debug, Clone)]
pub struct X86IncludeCache {
entries: HashMap<PathBuf, CacheEntry>,
seen_files: HashSet<PathBuf>,
max_entries: usize,
order: VecDeque<PathBuf>,
hits: usize,
misses: usize,
}
#[derive(Debug, Clone)]
struct CacheEntry {
content: String,
mtime: Option<u64>,
}
impl X86IncludeCache {
pub fn new(max: usize) -> Self {
Self {
entries: HashMap::new(),
seen_files: HashSet::new(),
max_entries: max,
order: VecDeque::new(),
hits: 0,
misses: 0,
}
}
pub fn get(&self, path: &Path) -> Option<&String> {
self.entries.get(path).map(|e| &e.content)
}
pub fn insert(&mut self, path: &Path, content: &str) {
if self.entries.contains_key(path) {
self.order.retain(|p| p != path);
self.order.push_back(path.to_path_buf());
if let Some(entry) = self.entries.get_mut(path) {
entry.content = content.to_string();
entry.mtime = mtime_seconds(path);
}
return;
}
while self.entries.len() >= self.max_entries {
if let Some(oldest) = self.order.pop_front() {
self.entries.remove(&oldest);
self.seen_files.remove(&oldest);
} else {
break;
}
}
self.entries.insert(
path.to_path_buf(),
CacheEntry {
content: content.to_string(),
mtime: mtime_seconds(path),
},
);
self.order.push_back(path.to_path_buf());
self.seen_files.insert(path.to_path_buf());
}
pub fn insert_builtin(&mut self, path: &Path, content: &str) {
if self.entries.contains_key(path) {
return;
}
while self.entries.len() >= self.max_entries {
if let Some(oldest) = self.order.pop_front() {
self.entries.remove(&oldest);
self.seen_files.remove(&oldest);
} else {
break;
}
}
self.entries.insert(
path.to_path_buf(),
CacheEntry {
content: content.to_string(),
mtime: None,
},
);
self.order.push_back(path.to_path_buf());
}
pub fn mark_seen(&mut self, path: &Path) {
self.seen_files.insert(path.to_path_buf());
}
pub fn is_seen(&self, path: &Path) -> bool {
self.seen_files.contains(path)
}
pub fn is_stale(&self, path: &Path) -> bool {
if let Some(entry) = self.entries.get(path) {
if let Some(cached) = entry.mtime {
let current = mtime_seconds(path);
return current != Some(cached);
}
return false;
}
true
}
pub fn record_hit(&mut self) {
self.hits += 1;
}
pub fn record_miss(&mut self) {
self.misses += 1;
}
pub fn hit_rate(&self) -> f64 {
let total = self.hits + self.misses;
if total == 0 {
return 0.0;
}
self.hits as f64 / total as f64
}
pub fn stats(&self) -> (usize, usize, f64) {
(self.hits, self.misses, self.hit_rate())
}
pub fn clear(&mut self) {
self.entries.clear();
self.seen_files.clear();
self.order.clear();
self.hits = 0;
self.misses = 0;
}
pub fn len(&self) -> usize {
self.entries.len()
}
pub fn is_empty(&self) -> bool {
self.entries.is_empty()
}
}
impl Default for X86IncludeCache {
fn default() -> Self {
Self::new(512)
}
}
fn mtime_seconds(path: &Path) -> Option<u64> {
std::fs::metadata(path)
.ok()?
.modified()
.ok()?
.duration_since(SystemTime::UNIX_EPOCH)
.ok()
.map(|d| d.as_secs())
}
#[derive(Debug, Clone, Default)]
pub struct X86HeaderGuard {
guard_to_file: HashMap<String, PathBuf>,
guarded_files: HashSet<PathBuf>,
}
impl X86HeaderGuard {
pub fn mark_guard(&mut self, guard: &str, file: &Path) {
self.guard_to_file
.insert(guard.to_string(), file.to_path_buf());
self.guarded_files.insert(file.to_path_buf());
}
pub fn is_guarded(&self, file: &Path) -> bool {
self.guarded_files.contains(file)
}
pub fn is_guard_defined(&self, guard: &str) -> bool {
self.guard_to_file.contains_key(guard)
}
pub fn clear(&mut self) {
self.guard_to_file.clear();
self.guarded_files.clear();
}
pub fn forget_file(&mut self, file: &Path) {
self.guarded_files.remove(file);
self.guard_to_file.retain(|_, v| v != file);
}
pub fn len(&self) -> usize {
self.guarded_files.len()
}
pub fn is_empty(&self) -> bool {
self.guarded_files.is_empty()
}
}
#[cfg(test)]
mod tests {
use super::*;
fn clean(path: &str) {
let p = Path::new(path);
if p.exists() {
let _ = std::fs::remove_file(p);
}
}
#[test]
fn test_x86_header_search_new() {
let hs = X86HeaderSearch::new("x86_64-unknown-linux-gnu");
assert_eq!(hs.max_include_depth, 200);
assert!(hs.use_standard_system_includes);
assert_eq!(hs.include_count(), 0);
assert_eq!(hs.skip_count(), 0);
}
#[test]
fn test_x86_header_search_disable_standard() {
let mut hs = X86HeaderSearch::new("x86_64-unknown-linux-gnu");
hs.disable_standard_includes();
assert!(!hs.use_standard_system_includes);
assert!(!hs.use_standard_cxx_includes);
}
#[test]
fn test_x86_header_search_add_user_path() {
let mut hs = X86HeaderSearch::new("x86_64-unknown-linux-gnu");
hs.add_user_path("/tmp/fake_include");
let paths = hs.dump_paths();
assert!(
paths.iter().any(|s| s.contains("fake_include")),
"Should contain fake_include: {:?}",
paths
);
}
#[test]
fn test_x86_header_search_resolve_builtin_include() {
let mut hs = X86HeaderSearch::new("x86_64-unknown-linux-gnu");
let result = hs.resolve_system_include("stddef.h");
assert!(result.is_some(), "Should resolve stddef.h as builtin");
let (path, is_builtin) = result.unwrap();
assert!(is_builtin, "stddef.h should be marked as builtin");
assert!(
path.to_string_lossy().contains("builtin"),
"Path should contain 'builtin': {:?}",
path
);
}
#[test]
fn test_x86_header_search_resolve_intrinsic_include() {
let mut hs = X86HeaderSearch::new("x86_64-unknown-linux-gnu");
let result = hs.resolve_system_include("emmintrin.h");
assert!(result.is_some(), "Should resolve emmintrin.h as intrinsic");
let (path, is_builtin) = result.unwrap();
assert!(is_builtin, "emmintrin.h should be marked as builtin");
assert!(
path.to_string_lossy().contains("intrinsic"),
"Path should contain 'intrinsic': {:?}",
path
);
}
#[test]
fn test_x86_header_search_include_count() {
let mut hs = X86HeaderSearch::new("x86_64-unknown-linux-gnu");
assert_eq!(hs.include_count(), 0);
hs.record_include();
hs.record_include();
assert_eq!(hs.include_count(), 2);
hs.record_skip();
assert_eq!(hs.skip_count(), 1);
}
#[test]
fn test_x86_header_search_pragma_once() {
let mut hs = X86HeaderSearch::new("x86_64-unknown-linux-gnu");
let p = Path::new("/tmp/test_pragma_once.h");
assert!(!hs.should_skip(p));
hs.mark_pragma_once(p);
assert!(hs.should_skip(p));
hs.clear_pragma_once();
assert!(!hs.should_skip(p));
}
#[test]
fn test_x86_header_search_module_lookup() {
let mut hs = X86HeaderSearch::new("x86_64-unknown-linux-gnu");
hs.module_map.generate_standard_modules();
let m = hs.lookup_module("std");
assert!(m.is_some(), "Should find std module");
assert!(hs.module_names().contains(&"std".to_string()));
}
#[test]
fn test_header_search_paths_default() {
let p = HeaderSearchPaths::default();
assert_eq!(p.target_triple, "x86_64-unknown-linux-gnu");
assert!(p.resource_dir.is_some());
}
#[test]
fn test_header_search_paths_for_target_linux() {
let p =
HeaderSearchPaths::for_target("x86_64-unknown-linux-gnu", "/usr/lib/clang/16/include");
assert_eq!(p.target_triple, "x86_64-unknown-linux-gnu");
assert!(p.resource_dir.is_some());
}
#[test]
fn test_header_search_paths_for_target_musl() {
let p =
HeaderSearchPaths::for_target("x86_64-unknown-linux-musl", "/usr/lib/clang/16/include");
assert!(p.target_triple.contains("musl"));
}
#[test]
fn test_header_search_paths_set_sysroot() {
let mut p = HeaderSearchPaths::default();
p.set_sysroot("/tmp/fake_sysroot");
assert_eq!(p.sysroot, Some(PathBuf::from("/tmp/fake_sysroot")));
}
#[test]
fn test_header_search_paths_set_resource_dir() {
let mut p = HeaderSearchPaths::default();
p.set_resource_dir("/tmp/fake_resource");
assert_eq!(p.resource_dir, Some(PathBuf::from("/tmp/fake_resource")));
}
#[test]
fn test_header_search_paths_remove_resource_dir() {
let mut p = HeaderSearchPaths::default();
assert!(p.resource_dir.is_some());
p.remove_resource_dir();
assert!(p.resource_dir.is_none());
}
#[test]
fn test_header_search_paths_add_user() {
let mut p = HeaderSearchPaths::default();
p.add_user_path("/my/include");
assert!(p
.user_paths
.iter()
.any(|d| d.path == PathBuf::from("/my/include")));
}
#[test]
fn test_header_search_paths_add_system() {
let mut p = HeaderSearchPaths::default();
p.add_system_path("/my/system");
assert!(p
.system_paths
.iter()
.any(|d| d.path == PathBuf::from("/my/system")));
}
#[test]
fn test_header_search_paths_add_quote() {
let mut p = HeaderSearchPaths::default();
p.add_quote_path("/my/quote");
assert!(p
.quote_paths
.iter()
.any(|d| d.path == PathBuf::from("/my/quote")));
}
#[test]
fn test_header_search_paths_add_after() {
let mut p = HeaderSearchPaths::default();
p.add_after_path("/my/after");
assert!(p
.after_paths
.iter()
.any(|d| d.path == PathBuf::from("/my/after")));
}
#[test]
fn test_header_search_paths_add_framework() {
let mut p = HeaderSearchPaths::default();
p.add_framework_path("/my/framework");
assert!(p
.framework_paths
.iter()
.any(|d| d.path == PathBuf::from("/my/framework")));
}
#[test]
fn test_header_search_paths_add_default_twice_safe() {
let mut p = HeaderSearchPaths::default();
p.add_default_paths();
let before = p.system_paths.len();
p.add_default_paths(); assert_eq!(p.system_paths.len(), before);
}
#[test]
fn test_header_search_paths_dump() {
let p = HeaderSearchPaths::default();
let lines = p.dump_paths();
assert!(
lines[0].contains("Target:"),
"First line should contain target"
);
}
#[test]
fn test_include_dir_kind_display() {
assert_eq!(IncludeDirKindX86::User.to_string(), "user");
assert_eq!(IncludeDirKindX86::System.to_string(), "system");
assert_eq!(IncludeDirKindX86::Quote.to_string(), "quote");
assert_eq!(IncludeDirKindX86::After.to_string(), "after");
assert_eq!(IncludeDirKindX86::Framework.to_string(), "framework");
assert_eq!(IncludeDirKindX86::Resource.to_string(), "resource");
}
#[test]
fn test_include_dir_is_system() {
assert!(!IncludeDir::user("/tmp").is_system());
assert!(IncludeDir::system("/tmp").is_system());
assert!(IncludeDir::after("/tmp").is_system());
assert!(IncludeDir::framework("/tmp").is_system());
}
#[test]
fn test_gcc_installation_detection() {
let gcc = detect_gcc_installation();
if let Some(g) = gcc {
assert!(g.is_valid);
assert!(!g.version.is_empty());
}
}
#[test]
fn test_simplify_version() {
assert_eq!(simplify_version("13.2.1"), "13");
assert_eq!(simplify_version("9.4.0"), "9");
assert_eq!(simplify_version("11"), "11");
assert_eq!(simplify_version("4.8"), "4");
}
#[test]
fn test_parse_gcc_version_triple() {
assert_eq!(parse_gcc_version_triple("13.2.1"), Some((13, 2, 1)));
assert_eq!(parse_gcc_version_triple("13"), Some((13, 0, 0)));
assert_eq!(parse_gcc_version_triple("13.2"), Some((13, 2, 0)));
assert_eq!(parse_gcc_version_triple("abc"), None);
assert_eq!(parse_gcc_version_triple(""), None);
assert_eq!(parse_gcc_version_triple("13.2.1.4"), None);
}
#[test]
fn test_cxx_stdlib_detection() {
let lib = detect_cxx_stdlib();
assert!(matches!(
lib.kind,
CxxStdLibKind::LibStdCxx
| CxxStdLibKind::LibCxx
| CxxStdLibKind::MsStl
| CxxStdLibKind::Unknown
));
}
#[test]
fn test_cxx_stdlib_default() {
let info = CxxStdLibInfo::default();
assert_eq!(info.kind, CxxStdLibKind::Unknown);
assert!(info.include_paths.is_empty());
assert!(info.version.is_none());
}
#[test]
fn test_builtin_headers_has_stddef() {
let bh = X86BuiltinHeaders::new();
assert!(bh.has("stddef.h"));
let content = bh.resolve("stddef.h").unwrap();
assert!(content.contains("size_t"));
assert!(content.contains("NULL"));
assert!(content.contains("offsetof"));
}
#[test]
fn test_builtin_headers_has_stdarg() {
let bh = X86BuiltinHeaders::new();
assert!(bh.has("stdarg.h"));
let content = bh.resolve("stdarg.h").unwrap();
assert!(content.contains("va_list"));
assert!(content.contains("va_start"));
assert!(content.contains("va_arg"));
}
#[test]
fn test_builtin_headers_has_stdbool() {
let bh = X86BuiltinHeaders::new();
assert!(bh.has("stdbool.h"));
let content = bh.resolve("stdbool.h").unwrap();
assert!(content.contains("_Bool"));
}
#[test]
fn test_builtin_headers_has_stdint() {
let bh = X86BuiltinHeaders::new();
assert!(bh.has("stdint.h"));
let content = bh.resolve("stdint.h").unwrap();
assert!(content.contains("int8_t"));
assert!(content.contains("uint64_t"));
assert!(content.contains("INTMAX_MAX"));
}
#[test]
fn test_builtin_headers_has_iso646() {
let bh = X86BuiltinHeaders::new();
assert!(bh.has("iso646.h"));
let content = bh.resolve("iso646.h").unwrap();
assert!(content.contains("and"));
assert!(content.contains("or"));
assert!(content.contains("not"));
}
#[test]
fn test_builtin_headers_has_limits() {
let bh = X86BuiltinHeaders::new();
assert!(bh.has("limits.h"));
let content = bh.resolve("limits.h").unwrap();
assert!(content.contains("CHAR_BIT"));
assert!(content.contains("INT_MAX"));
assert!(content.contains("LONG_MIN"));
}
#[test]
fn test_builtin_headers_has_float() {
let bh = X86BuiltinHeaders::new();
assert!(bh.has("float.h"));
let content = bh.resolve("float.h").unwrap();
assert!(content.contains("FLT_RADIX"));
assert!(content.contains("DBL_MANT_DIG"));
assert!(content.contains("LDBL_MAX"));
}
#[test]
fn test_builtin_headers_has_stdalign() {
let bh = X86BuiltinHeaders::new();
assert!(bh.has("stdalign.h"));
assert!(bh.resolve("stdalign.h").unwrap().contains("_Alignas"));
}
#[test]
fn test_builtin_headers_has_stdnoreturn() {
let bh = X86BuiltinHeaders::new();
assert!(bh.has("stdnoreturn.h"));
assert!(bh.resolve("stdnoreturn.h").unwrap().contains("_Noreturn"));
}
#[test]
fn test_builtin_headers_has_max_align_t() {
let bh = X86BuiltinHeaders::new();
assert!(bh.has("__stddef_max_align_t.h"));
let content = bh.resolve("__stddef_max_align_t.h").unwrap();
assert!(content.contains("max_align_t") || content.contains("__max_align_t"));
}
#[test]
fn test_builtin_headers_has_tgmath() {
let bh = X86BuiltinHeaders::new();
assert!(bh.has("tgmath.h"));
let content = bh.resolve("tgmath.h").unwrap();
assert!(content.contains("_Generic"));
}
#[test]
fn test_builtin_headers_unknown() {
let bh = X86BuiltinHeaders::new();
assert!(!bh.has("nonexistent.h"));
assert!(bh.resolve("nonexistent.h").is_none());
}
#[test]
fn test_builtin_headers_names() {
let bh = X86BuiltinHeaders::new();
let names = bh.names();
assert!(names.contains(&"stddef.h"));
assert!(names.contains(&"float.h"));
assert!(names.contains(&"tgmath.h"));
}
#[test]
fn test_intrinsic_headers_has_emmintrin() {
let ih = X86IntrinsicHeaders::new();
assert!(ih.has("emmintrin.h"));
}
#[test]
fn test_intrinsic_headers_has_avxintrin() {
let ih = X86IntrinsicHeaders::new();
assert!(ih.has("avxintrin.h"));
}
#[test]
fn test_intrinsic_headers_has_avx512fintrin() {
let ih = X86IntrinsicHeaders::new();
assert!(ih.has("avx512fintrin.h"));
}
#[test]
fn test_intrinsic_headers_has_bmiintrin() {
let ih = X86IntrinsicHeaders::new();
assert!(ih.has("bmiintrin.h"));
}
#[test]
fn test_intrinsic_headers_has_popcntintrin() {
let ih = X86IntrinsicHeaders::new();
assert!(ih.has("popcntintrin.h"));
}
#[test]
fn test_intrinsic_headers_feature_gate() {
let ih = X86IntrinsicHeaders::new();
assert_eq!(ih.feature_gate("emmintrin.h"), Some("__SSE2__"));
assert_eq!(ih.feature_gate("avxintrin.h"), Some("__AVX__"));
assert_eq!(ih.feature_gate("avx512fintrin.h"), Some("__AVX512F__"));
assert_eq!(ih.feature_gate("bmiintrin.h"), Some("__BMI__"));
assert_eq!(ih.feature_gate("x86intrin.h"), None);
}
#[test]
fn test_intrinsic_headers_unknown() {
let ih = X86IntrinsicHeaders::new();
assert!(!ih.has("nonexistent_intrin.h"));
assert!(ih.resolve("nonexistent_intrin.h").is_none());
}
#[test]
fn test_intrinsic_headers_resolve_with_gate() {
let ih = X86IntrinsicHeaders::new();
let content = ih.resolve("emmintrin.h").unwrap();
assert!(
content.contains("SSE2"),
"Should have SSE2 gate: {}",
content
);
}
#[test]
fn test_intrinsic_headers_names() {
let ih = X86IntrinsicHeaders::new();
let names = ih.names();
assert!(names.contains(&"x86intrin.h"));
assert!(names.contains(&"cpuid.h"));
assert!(names.contains(&"emmintrin.h"));
assert!(names.contains(&"avx2intrin.h"));
assert!(names.contains(&"fmaintrin.h"));
assert!(names.contains(&"avx512fintrin.h"));
assert!(names.contains(&"bmiintrin.h"));
assert!(names.contains(&"bmi2intrin.h"));
}
#[test]
fn test_intrinsic_headers_set_resource_dir() {
let mut ih = X86IntrinsicHeaders::new();
ih.set_resource_dir("/my/clang/resource");
assert_eq!(ih.resource_dir, Some(PathBuf::from("/my/clang/resource")));
}
#[test]
fn test_intrinsic_mmintrin_content() {
let ih = X86IntrinsicHeaders::new();
let content = ih.resolve("mmintrin.h").unwrap();
assert!(content.contains("__m64"));
assert!(content.contains("_mm_empty"));
assert!(content.contains("_m_paddb"));
}
#[test]
fn test_intrinsic_xmmintrin_content() {
let ih = X86IntrinsicHeaders::new();
let content = ih.resolve("xmmintrin.h").unwrap();
assert!(content.contains("__m128"));
assert!(content.contains("_mm_add_ps"));
assert!(content.contains("_mm_mul_ps"));
assert!(content.contains("_mm_sqrt_ps"));
}
#[test]
fn test_intrinsic_emmintrin_content() {
let ih = X86IntrinsicHeaders::new();
let content = ih.resolve("emmintrin.h").unwrap();
assert!(content.contains("__m128d"));
assert!(content.contains("__m128i"));
assert!(content.contains("_mm_add_pd"));
assert!(content.contains("_mm_cvtepi32_ps"));
}
#[test]
fn test_intrinsic_pmmintrin_content() {
let ih = X86IntrinsicHeaders::new();
let content = ih.resolve("pmmintrin.h").unwrap();
assert!(content.contains("_mm_addsub_ps"));
assert!(content.contains("_mm_hadd_ps"));
}
#[test]
fn test_intrinsic_tmmintrin_content() {
let ih = X86IntrinsicHeaders::new();
let content = ih.resolve("tmmintrin.h").unwrap();
assert!(content.contains("_mm_abs_epi8"));
assert!(content.contains("_mm_shuffle_epi8"));
}
#[test]
fn test_intrinsic_smmintrin_content() {
let ih = X86IntrinsicHeaders::new();
let content = ih.resolve("smmintrin.h").unwrap();
assert!(content.contains("_mm_blend_epi16"));
assert!(content.contains("_mm_extract_epi32"));
}
#[test]
fn test_intrinsic_avxintrin_content() {
let ih = X86IntrinsicHeaders::new();
let content = ih.resolve("avxintrin.h").unwrap();
assert!(content.contains("__m256"));
assert!(content.contains("_mm256_add_ps"));
assert!(content.contains("_mm256_load_ps"));
}
#[test]
fn test_intrinsic_avx2intrin_content() {
let ih = X86IntrinsicHeaders::new();
let content = ih.resolve("avx2intrin.h").unwrap();
assert!(content.contains("_mm256_add_epi32"));
assert!(content.contains("_mm256_and_si256"));
}
#[test]
fn test_intrinsic_fmaintrin_content() {
let ih = X86IntrinsicHeaders::new();
let content = ih.resolve("fmaintrin.h").unwrap();
assert!(content.contains("_mm_fmadd_ps"));
assert!(content.contains("_mm256_fmadd_pd"));
}
#[test]
fn test_intrinsic_avx512fintrin_content() {
let ih = X86IntrinsicHeaders::new();
let content = ih.resolve("avx512fintrin.h").unwrap();
assert!(content.contains("__m512"));
assert!(content.contains("_mm512_add_ps"));
assert!(content.contains("_mm512_load_ps"));
}
#[test]
fn test_intrinsic_bmiintrin_content() {
let ih = X86IntrinsicHeaders::new();
let content = ih.resolve("bmiintrin.h").unwrap();
assert!(content.contains("__andn_u32"));
assert!(content.contains("__tzcnt_u32"));
assert!(content.contains("__blsi_u32"));
}
#[test]
fn test_intrinsic_bmi2intrin_content() {
let ih = X86IntrinsicHeaders::new();
let content = ih.resolve("bmi2intrin.h").unwrap();
assert!(content.contains("_bzhi_u32"));
assert!(content.contains("_pdep_u32"));
}
#[test]
fn test_intrinsic_popcntintrin_content() {
let ih = X86IntrinsicHeaders::new();
let content = ih.resolve("popcntintrin.h").unwrap();
assert!(content.contains("_mm_popcnt_u32"));
assert!(content.contains("__builtin_popcount"));
}
#[test]
fn test_intrinsic_lzcntintrin_content() {
let ih = X86IntrinsicHeaders::new();
let content = ih.resolve("lzcntintrin.h").unwrap();
assert!(content.contains("__lzcnt32"));
assert!(content.contains("__lzcnt64"));
}
#[test]
fn test_standard_headers_is_known() {
let sh = X86StandardHeaders::new();
assert!(sh.is_known("stddef.h"));
assert!(sh.is_known("iostream"));
assert!(sh.is_known("unistd.h"));
}
#[test]
fn test_standard_headers_not_known() {
let sh = X86StandardHeaders::new();
assert!(!sh.is_known("nonexistent_header_name.h"));
}
#[test]
fn test_standard_headers_dependencies() {
let sh = X86StandardHeaders::new();
let deps = sh.dependencies("iostream");
assert!(deps.iter().any(|&d| d == "istream"));
assert!(deps.iter().any(|&d| d == "ostream"));
}
#[test]
fn test_standard_headers_reverse_dependencies() {
let sh = X86StandardHeaders::new();
let rdeps = sh.reverse_dependencies("stddef.h");
assert!(rdeps.iter().any(|&d| d == "stdio.h"));
}
#[test]
fn test_standard_headers_c_names() {
let names = X86StandardHeaders::c_header_names();
assert!(names.len() >= 24);
assert!(names.contains(&"stddef.h"));
assert!(names.contains(&"stdlib.h"));
assert!(names.contains(&"math.h"));
}
#[test]
fn test_standard_headers_cxx_names() {
let names = X86StandardHeaders::cxx_header_names();
assert!(names.len() >= 50);
assert!(names.contains(&"iostream"));
assert!(names.contains(&"vector"));
assert!(names.contains(&"string"));
assert!(names.contains(&"algorithm"));
}
#[test]
fn test_standard_headers_posix_names() {
let names = X86StandardHeaders::posix_header_names();
assert!(names.contains(&"unistd.h"));
assert!(names.contains(&"pthread.h"));
assert!(names.contains(&"sys/stat.h"));
}
#[test]
fn test_standard_headers_add_synthetic() {
let mut sh = X86StandardHeaders::new();
sh.add_synthetic("my_test.h", "int answer = 42;");
assert!(sh.is_known("my_test.h"));
assert_eq!(
sh.resolve("my_test.h"),
Some("int answer = 42;".to_string())
);
}
#[test]
fn test_module_map_default() {
let mm = X86ModuleMap::default();
assert!(mm.names().is_empty());
}
#[test]
fn test_module_map_generate_standard() {
let mut mm = X86ModuleMap::default();
mm.generate_standard_modules();
let names = mm.names();
assert!(names.contains(&"std".to_string()));
assert!(names.contains(&"std.io".to_string()));
assert!(names.contains(&"std.math".to_string()));
let m = mm.find("std").unwrap();
assert!(m.headers.contains(&"stddef.h".to_string()));
assert!(m.is_system);
assert!(m.is_explicit);
}
#[test]
fn test_module_map_find_missing() {
let mm = X86ModuleMap::default();
assert!(mm.find("nonexistent").is_none());
}
#[test]
fn test_module_map_lookup_header() {
let mut mm = X86ModuleMap::default();
mm.generate_standard_modules();
let owner = mm.lookup_header("stdio.h");
assert_eq!(owner, Some("std.io".to_string()));
}
#[test]
fn test_module_map_lookup_header_missing() {
let mut mm = X86ModuleMap::default();
mm.generate_standard_modules();
let owner = mm.lookup_header("nonexistent.h");
assert!(owner.is_none());
}
#[test]
fn test_module_map_add_import() {
let mut mm = X86ModuleMap::default();
mm.add_import("std.io", "std");
assert_eq!(
mm.imports.get("std.io").unwrap().first(),
Some(&"std".to_string())
);
}
#[test]
fn test_module_map_entry_new() {
let entry = ModuleMapEntry::new("test", Path::new("/tmp"));
assert_eq!(entry.name, "test");
assert_eq!(entry.base_dir, PathBuf::from("/tmp"));
assert!(!entry.is_framework);
assert!(entry.headers.is_empty());
}
#[test]
fn test_parse_module_map_content_simple() {
let content = r#"
module std [system] [extern_c] {
umbrella header "std.h"
header "stdio.h"
header "stdlib.h"
export *
}
"#;
let entries = parse_module_map_content(content, Path::new("/tmp"));
assert_eq!(entries.len(), 1);
assert_eq!(entries[0].name, "std");
assert!(entries[0].headers.contains(&"stdio.h".to_string()));
assert!(entries[0].umbrella_header.as_deref() == Some("std.h"));
}
#[test]
fn test_parse_module_map_content_empty() {
let entries = parse_module_map_content("", Path::new("/tmp"));
assert!(entries.is_empty());
}
#[test]
fn test_parse_module_map_content_multiple() {
let content = r#"
module A {
header "a.h"
}
module B {
header "b.h"
}
"#;
let entries = parse_module_map_content(content, Path::new("/tmp"));
assert_eq!(entries.len(), 2);
assert_eq!(entries[0].name, "A");
assert_eq!(entries[1].name, "B");
}
#[test]
fn test_vfs_overlay_default() {
let vfs = X86VFSOverlay::default();
assert!(!vfs.enabled);
assert!(vfs.overlay_file.is_none());
assert!(!vfs.loaded);
}
#[test]
fn test_vfs_overlay_new() {
let vfs = X86VFSOverlay::new();
assert!(!vfs.enabled);
}
#[test]
fn test_vfs_overlay_add_remap() {
let mut vfs = X86VFSOverlay::new();
vfs.add_remap("virtual.h", "/real/path/real.h");
assert!(vfs.enabled);
let mapped = vfs.remap("virtual.h").unwrap();
assert_eq!(mapped, PathBuf::from("/real/path/real.h"));
}
#[test]
fn test_vfs_overlay_remap_basename() {
let mut vfs = X86VFSOverlay::new();
vfs.add_remap("some/dir/virtual.h", "/real/real.h");
let mapped = vfs.remap("virtual.h").unwrap();
assert_eq!(mapped, PathBuf::from("/real/real.h"));
}
#[test]
fn test_vfs_overlay_disabled() {
let mut vfs = X86VFSOverlay::new();
vfs.add_remap("v.h", "/real/r.h");
vfs.set_enabled(false);
assert!(vfs.remap("v.h").is_none());
}
#[test]
fn test_vfs_overlay_has_remap() {
let mut vfs = X86VFSOverlay::new();
vfs.add_remap("x.h", "/real/x.h");
assert!(vfs.has_remap("x.h"));
assert!(!vfs.has_remap("y.h"));
}
#[test]
fn test_vfs_overlay_parse_json() {
let content = r#"{
"version": 0,
"roots": [
{
"type": "directory",
"name": "/",
"contents": [
{
"type": "file",
"name": "test.h",
"external-contents": "/real/test.h"
}
]
}
]
}"#;
let mut vfs = X86VFSOverlay::new();
vfs.parse_overlay(content);
let mapped = vfs.remap("test.h").unwrap();
assert_eq!(mapped, PathBuf::from("/real/test.h"));
}
#[test]
fn test_extract_json_string_value_simple() {
assert_eq!(
extract_json_string_value(r#""name": "stddef.h""#),
Some("stddef.h".to_string())
);
}
#[test]
fn test_extract_json_string_value_none() {
assert_eq!(extract_json_string_value("no colon here"), None);
assert_eq!(
extract_json_string_value(r#"key: value_without_quotes"#),
None
);
}
#[test]
fn test_include_cache_new() {
let cache = X86IncludeCache::new(10);
assert_eq!(cache.len(), 0);
assert!(cache.is_empty());
}
#[test]
fn test_include_cache_insert_and_get() {
let mut cache = X86IncludeCache::new(10);
cache.insert(Path::new("/fake/a.h"), "content a");
assert_eq!(cache.len(), 1);
assert_eq!(
cache.get(Path::new("/fake/a.h")),
Some(&"content a".to_string())
);
}
#[test]
fn test_include_cache_insert_builtin() {
let mut cache = X86IncludeCache::new(10);
cache.insert_builtin(Path::new("<builtin>/x.h"), "builtin content");
assert_eq!(cache.len(), 1);
assert_eq!(
cache.get(Path::new("<builtin>/x.h")),
Some(&"builtin content".to_string())
);
}
#[test]
fn test_include_cache_mark_seen() {
let mut cache = X86IncludeCache::new(5);
cache.mark_seen(Path::new("/f/seen.h"));
assert!(cache.is_seen(Path::new("/f/seen.h")));
assert!(!cache.is_seen(Path::new("/f/unseen.h")));
}
#[test]
fn test_include_cache_eviction() {
let mut cache = X86IncludeCache::new(3);
cache.insert(Path::new("/1"), "a");
cache.insert(Path::new("/2"), "b");
cache.insert(Path::new("/3"), "c");
assert_eq!(cache.len(), 3);
cache.insert(Path::new("/4"), "d");
assert_eq!(cache.len(), 3);
assert!(cache.get(Path::new("/1")).is_none());
assert!(cache.get(Path::new("/2")).is_some());
}
#[test]
fn test_include_cache_hit_rate() {
let mut cache = X86IncludeCache::new(10);
assert_eq!(cache.hit_rate(), 0.0);
cache.record_hit();
cache.record_hit();
cache.record_miss();
assert!((cache.hit_rate() - 2.0 / 3.0).abs() < 0.001);
let (h, m, r) = cache.stats();
assert_eq!(h, 2);
assert_eq!(m, 1);
assert!((r - 2.0 / 3.0).abs() < 0.001);
}
#[test]
fn test_include_cache_clear() {
let mut cache = X86IncludeCache::new(10);
cache.insert(Path::new("/a"), "x");
cache.record_hit();
cache.clear();
assert_eq!(cache.len(), 0);
assert!(cache.is_empty());
assert!(cache.get(Path::new("/a")).is_none());
assert_eq!(cache.hit_rate(), 0.0);
}
#[test]
fn test_include_cache_is_stale() {
let cache = X86IncludeCache::new(10);
assert!(cache.is_stale(Path::new("/nonexistent/path")));
}
#[test]
fn test_header_guard_default() {
let guard = X86HeaderGuard::default();
assert_eq!(guard.len(), 0);
assert!(guard.is_empty());
}
#[test]
fn test_header_guard_mark_and_check() {
let mut guard = X86HeaderGuard::default();
let file = Path::new("/tmp/my_header.h");
guard.mark_guard("MY_HEADER_H", file);
assert!(guard.is_guarded(file));
assert!(guard.is_guard_defined("MY_HEADER_H"));
assert!(!guard.is_guard_defined("UNKNOWN_GUARD"));
assert_eq!(guard.len(), 1);
}
#[test]
fn test_header_guard_forget_file() {
let mut guard = X86HeaderGuard::default();
let file = Path::new("/tmp/a.h");
guard.mark_guard("A_H", file);
guard.forget_file(file);
assert!(!guard.is_guarded(file));
assert!(!guard.is_guard_defined("A_H"));
assert_eq!(guard.len(), 0);
}
#[test]
fn test_header_guard_clear() {
let mut guard = X86HeaderGuard::default();
guard.mark_guard("G", Path::new("/f"));
guard.clear();
assert!(guard.is_empty());
}
#[test]
fn test_full_workflow_resolve_and_read() {
let mut hs = X86HeaderSearch::new("x86_64-unknown-linux-gnu");
let result = hs.resolve_system_include("stddef.h");
assert!(result.is_some());
let (path, _) = result.unwrap();
let content = hs.read_include(&path);
assert!(content.is_some());
assert!(content.unwrap().contains("size_t"));
hs.mark_seen(&path, Some("_STDDEF_H"));
assert!(hs.should_skip(&path));
}
#[test]
fn test_full_workflow_intrinsic() {
let mut hs = X86HeaderSearch::new("x86_64-unknown-linux-gnu");
let result = hs.resolve_system_include("emmintrin.h");
assert!(result.is_some());
let (path, _) = result.unwrap();
let content = hs.read_include(&path);
assert!(content.is_some());
assert!(content.unwrap().contains("SSE2"));
}
#[test]
fn test_default_header_search() {
let hs = X86HeaderSearch::default();
assert!(hs.module_map.names().is_empty());
}
#[test]
fn test_vfs_overlay_with_header_search() {
let mut hs = X86HeaderSearch::new("x86_64-unknown-linux-gnu");
hs.vfs_overlay.add_remap("custom.h", "/tmp/custom.h");
let result = hs.resolve_system_include("custom.h");
assert!(result.is_some());
let (path, _) = result.unwrap();
assert_eq!(path, PathBuf::from("/tmp/custom.h"));
}
#[test]
fn test_header_search_disable_cxx_includes() {
let mut hs = X86HeaderSearch::new("x86_64-unknown-linux-gnu");
hs.disable_standard_cxx_includes();
assert!(!hs.use_standard_cxx_includes);
assert!(hs.use_standard_system_includes); }
#[test]
fn test_header_search_disable_builtin_includes() {
let mut hs = X86HeaderSearch::new("x86_64-unknown-linux-gnu");
hs.disable_builtin_includes();
assert!(hs.paths.resource_dir.is_none());
}
#[test]
fn test_header_search_set_sysroot() {
let mut hs = X86HeaderSearch::new("x86_64-unknown-linux-gnu");
hs.set_sysroot("/tmp/sysroot");
assert_eq!(hs.paths.sysroot, Some(PathBuf::from("/tmp/sysroot")));
}
#[test]
fn test_header_search_set_resource_dir() {
let mut hs = X86HeaderSearch::new("x86_64-unknown-linux-gnu");
hs.set_resource_dir("/custom/resource");
assert_eq!(
hs.paths.resource_dir,
Some(PathBuf::from("/custom/resource"))
);
}
#[test]
fn test_header_search_clear_cache() {
let mut hs = X86HeaderSearch::new("x86_64-unknown-linux-gnu");
hs.record_include();
hs.record_include();
hs.record_skip();
hs.clear_cache();
assert_eq!(hs.include_count(), 0);
assert_eq!(hs.skip_count(), 0);
}
#[test]
fn test_strip_extension() {
assert_eq!(strip_extension("foo.h", ".h"), "foo");
assert_eq!(strip_extension("foo.hpp", ".h"), "foo.hpp");
assert_eq!(strip_extension("nofile", ".h"), "nofile");
}
#[test]
fn test_infer_resource_dir_returns_string() {
let dir = infer_resource_dir();
assert!(!dir.is_empty());
}
#[test]
fn test_module_map_load_directory_nonexistent() {
let mut mm = X86ModuleMap::default();
mm.load_directory("/nonexistent/dir");
assert!(mm.names().is_empty());
}
#[test]
fn test_full_module_names_coverage() {
let mut hs = X86HeaderSearch::new("x86_64-unknown-linux-gnu");
hs.module_map.generate_standard_modules();
let names = hs.module_names();
assert!(!names.is_empty());
for m in &["std", "std.io", "std.math", "std.signal", "std.threads"] {
assert!(names.contains(&m.to_string()), "Missing module: {}", m);
}
}
#[test]
fn test_builtin_headers_all_names_present() {
let bh = X86BuiltinHeaders::new();
let expected = &[
"stddef.h",
"stdarg.h",
"stdbool.h",
"stdint.h",
"iso646.h",
"limits.h",
"float.h",
"stdalign.h",
"stdnoreturn.h",
"__stddef_max_align_t.h",
"tgmath.h",
];
for &name in expected {
assert!(bh.has(name), "Missing builtin header: {}", name);
}
}
#[test]
fn test_intrinsic_headers_all_feature_gates_present() {
let ih = X86IntrinsicHeaders::new();
let gated: Vec<(&str, &str)> = vec![
("mmintrin.h", "__MMX__"),
("xmmintrin.h", "__SSE__"),
("emmintrin.h", "__SSE2__"),
("pmmintrin.h", "__SSE3__"),
("tmmintrin.h", "__SSSE3__"),
("smmintrin.h", "__SSE4_1__"),
("nmmintrin.h", "__SSE4_2__"),
("wmmintrin.h", "__AES__"),
("avxintrin.h", "__AVX__"),
("avx2intrin.h", "__AVX2__"),
("fmaintrin.h", "__FMA__"),
("avx512fintrin.h", "__AVX512F__"),
("bmiintrin.h", "__BMI__"),
("bmi2intrin.h", "__BMI2__"),
("lzcntintrin.h", "__LZCNT__"),
("popcntintrin.h", "__POPCNT__"),
("f16cintrin.h", "__F16C__"),
("rdrandintrin.h", "__RDRAND__"),
];
for (name, expected_gate) in gated {
let gate = ih.feature_gate(name);
assert!(
gate == Some(expected_gate),
"For {}: expected gate {}, got {:?}",
name,
expected_gate,
gate
);
}
}
#[test]
fn test_mtime_seconds_nonexistent() {
assert_eq!(mtime_seconds(Path::new("/nonexistent/file_12345")), None);
}
#[test]
fn test_platform_sysroot_detector_new() {
let d = PlatformSysrootDetector::new("x86_64-unknown-linux-gnu");
assert_eq!(d.target_triple, "x86_64-unknown-linux-gnu");
assert!(d.forced_sysroot.is_none());
}
#[test]
fn test_platform_sysroot_detector_darwin() {
let d = PlatformSysrootDetector::new("x86_64-apple-darwin20");
assert!(d.search_xcode);
}
#[test]
fn test_platform_sysroot_detector_android() {
let d = PlatformSysrootDetector::new("x86_64-linux-android21");
assert!(d.search_android_ndk);
}
#[test]
fn test_platform_sysroot_detector_forced() {
let mut d = PlatformSysrootDetector::new("x86_64-unknown-linux-gnu");
d.forced_sysroot = Some(PathBuf::from("/tmp/fake"));
assert!(d.forced_sysroot.is_some());
}
#[test]
fn test_find_latest_sdk_version_nonexistent() {
let result = find_latest_sdk_version(Path::new("/nonexistent/sdk/dir"));
assert!(result.is_none());
}
#[test]
fn test_determine_android_api_level_default() {
let level = determine_android_api_level("x86_64-linux-android");
assert_eq!(level, 21);
}
#[test]
fn test_is_host_triple_linux() {
if cfg!(target_os = "linux") {
assert!(is_host_triple("x86_64-unknown-linux-gnu"));
assert!(!is_host_triple("x86_64-linux-android"));
}
}
#[test]
fn test_multilib_detector_x86_64() {
let d = MultilibDetector::new("x86_64-unknown-linux-gnu");
assert_eq!(d.variants.len(), 3);
assert!(d.prefer_64bit);
}
#[test]
fn test_multilib_detector_i386() {
let d = MultilibDetector::new("i686-unknown-linux-gnu");
assert_eq!(d.variants.len(), 1);
assert!(!d.prefer_64bit);
}
#[test]
fn test_multilib_detector_default_flags() {
let d = MultilibDetector::new("x86_64-unknown-linux-gnu");
let flags = d.default_flags();
assert_eq!(flags.len(), 1);
assert_eq!(flags[0], "-m64");
}
#[test]
fn test_multilib_detector_select_m32() {
let mut d = MultilibDetector::new("x86_64-unknown-linux-gnu");
let v = d.select("-m32");
assert!(v.is_some());
assert_eq!(v.unwrap().dir_suffix, "32");
}
#[test]
fn test_multilib_detector_select_invalid() {
let mut d = MultilibDetector::new("x86_64-unknown-linux-gnu");
let v = d.select("-march=native");
assert!(v.is_none());
}
#[test]
fn test_multilib_detector_selected_default() {
let d = MultilibDetector::new("x86_64-unknown-linux-gnu");
let v = d.selected();
assert!(v.is_some());
assert_eq!(v.unwrap().dir_suffix, "");
}
#[test]
fn test_multilib_detector_selected_after_select() {
let mut d = MultilibDetector::new("x86_64-unknown-linux-gnu");
d.select("-mx32");
let v = d.selected();
assert!(v.is_some());
assert_eq!(v.unwrap().dir_suffix, "x32");
}
#[test]
fn test_header_dep_graph_new() {
let g = HeaderDependencyGraph::new();
assert!(g.edges.is_empty());
}
#[test]
fn test_header_dep_graph_add_edge() {
let mut g = HeaderDependencyGraph::new();
g.add_edge("a.h", "b.h");
assert!(g.edges.contains_key("a.h"));
assert!(g.reverse_edges.contains_key("b.h"));
}
#[test]
fn test_header_dep_graph_direct_deps() {
let mut g = HeaderDependencyGraph::new();
g.add_edge("a.h", "b.h");
g.add_edge("a.h", "c.h");
let deps = g.direct_deps("a.h");
assert_eq!(deps.len(), 2);
assert!(deps.contains(&"b.h"));
assert!(deps.contains(&"c.h"));
}
#[test]
fn test_header_dep_graph_dependents() {
let mut g = HeaderDependencyGraph::new();
g.add_edge("a.h", "b.h");
g.add_edge("c.h", "b.h");
let deps = g.dependents("b.h");
assert_eq!(deps.len(), 2);
assert!(deps.contains(&"a.h"));
assert!(deps.contains(&"c.h"));
}
#[test]
fn test_header_dep_graph_topological_sort() {
let mut g = HeaderDependencyGraph::new();
g.add_edge("a", "b");
g.add_edge("b", "c");
g.add_edge("a", "c");
let sorted = g.topological_sort();
assert!(sorted.is_some());
let order = sorted.unwrap();
let a_pos = order.iter().position(|x| x == "a").unwrap();
let b_pos = order.iter().position(|x| x == "b").unwrap();
let c_pos = order.iter().position(|x| x == "c").unwrap();
assert!(a_pos < b_pos);
assert!(a_pos < c_pos);
assert!(b_pos < c_pos);
}
#[test]
fn test_header_dep_graph_cycle_detection() {
let mut g = HeaderDependencyGraph::new();
g.add_edge("a", "b");
g.add_edge("b", "c");
g.add_edge("c", "a");
let sorted = g.topological_sort();
assert!(sorted.is_none(), "Cycle should be detected");
}
#[test]
fn test_header_dep_graph_transitive() {
let mut g = HeaderDependencyGraph::new();
g.add_edge("a", "b");
g.add_edge("b", "c");
g.add_edge("c", "d");
let trans = g.transitive_deps("a");
assert!(trans.contains(&"b".to_string()));
assert!(trans.contains(&"c".to_string()));
assert!(trans.contains(&"d".to_string()));
assert!(!trans.contains(&"a".to_string())); }
#[test]
fn test_header_dep_graph_build_c_stdlib() {
let g = HeaderDependencyGraph::build_c_stdlib_graph();
assert!(g.edges.contains_key("stdio.h"));
assert!(g.edges.contains_key("stdlib.h"));
assert!(g.edges.contains_key("math.h"));
}
#[test]
fn test_header_dep_graph_build_cxx_stdlib() {
let g = HeaderDependencyGraph::build_cxx_stdlib_graph();
assert!(g.edges.contains_key("iostream"));
assert!(g.edges.contains_key("vector"));
assert!(g.edges.contains_key("algorithm"));
assert!(g.edges.contains_key("memory"));
assert!(g.edges.contains_key("string"));
}
#[test]
fn test_intrinsic_avx512vl_content() {
let ih = X86IntrinsicHeaders::new();
let content = ih.resolve("avx512vlintrin.h").unwrap();
assert!(content.contains("_mm_mask_add_ps"));
assert!(content.contains("_mm256_mask_add_ps"));
assert!(content.contains("__mmask8"));
}
#[test]
fn test_intrinsic_avx512ifma_content() {
let ih = X86IntrinsicHeaders::new();
let content = ih.resolve("avx512ifmaintrin.h").unwrap();
assert!(content.contains("_mm512_madd52lo_epu64"));
assert!(content.contains("_mm512_madd52hi_epu64"));
}
#[test]
fn test_intrinsic_avx512vbmi_content() {
let ih = X86IntrinsicHeaders::new();
let content = ih.resolve("avx512vbmiintrin.h").unwrap();
assert!(content.contains("_mm512_permutexvar_epi8"));
}
#[test]
fn test_intrinsic_avx512vbmi2_content() {
let ih = X86IntrinsicHeaders::new();
let content = ih.resolve("avx512vbmi2intrin.h").unwrap();
assert!(content.contains("_mm512_shldi_epi16"));
assert!(content.contains("_mm512_maskz_compress_epi8"));
}
#[test]
fn test_intrinsic_avx512vnni_content() {
let ih = X86IntrinsicHeaders::new();
let content = ih.resolve("avx512vnniintrin.h").unwrap();
assert!(content.contains("_mm512_dpbusd_epi32"));
}
#[test]
fn test_intrinsic_avx512bitalg_content() {
let ih = X86IntrinsicHeaders::new();
let content = ih.resolve("avx512bitalgintrin.h").unwrap();
assert!(content.contains("_mm512_popcnt_epi8"));
assert!(content.contains("_mm512_popcnt_epi16"));
}
#[test]
fn test_intrinsic_avx512vpopcntdq_content() {
let ih = X86IntrinsicHeaders::new();
let content = ih.resolve("avx512vpopcntdqintrin.h").unwrap();
assert!(content.contains("_mm512_popcnt_epi32"));
assert!(content.contains("_mm512_popcnt_epi64"));
}
#[test]
fn test_intrinsic_avx5124fmaps_content() {
let ih = X86IntrinsicHeaders::new();
let content = ih.resolve("avx5124fmapsintrin.h").unwrap();
assert!(content.contains("_mm512_4fmadd_ps"));
}
#[test]
fn test_intrinsic_avx512bf16_content() {
let ih = X86IntrinsicHeaders::new();
let content = ih.resolve("avx512bf16intrin.h").unwrap();
assert!(content.contains("__bf16"));
assert!(content.contains("_mm512_dpbf16_ps"));
}
#[test]
fn test_intrinsic_avx512fp16_content() {
let ih = X86IntrinsicHeaders::new();
let content = ih.resolve("avx512fp16intrin.h").unwrap();
assert!(content.contains("_Float16"));
assert!(content.contains("_mm512_add_ph"));
assert!(content.contains("_mm512_fmadd_ph"));
}
#[test]
fn test_intrinsic_rdrand_content() {
let ih = X86IntrinsicHeaders::new();
let content = ih.resolve("rdrandintrin.h").unwrap();
assert!(content.contains("_rdrand32_step"));
assert!(content.contains("_rdrand64_step"));
}
#[test]
fn test_intrinsic_sha_content() {
let ih = X86IntrinsicHeaders::new();
let content = ih.resolve("shaintrin.h").unwrap();
assert!(content.contains("_mm_sha1rnds4_epu32"));
assert!(content.contains("_mm_sha256rnds2_epu32"));
}
#[test]
fn test_intrinsic_gfni_content() {
let ih = X86IntrinsicHeaders::new();
let content = ih.resolve("gfniintrin.h").unwrap();
assert!(content.contains("_mm_gf2p8mul_epi8"));
assert!(content.contains("_mm_gf2p8affineinv_epi64_epi8"));
}
#[test]
fn test_intrinsic_vaes_content() {
let ih = X86IntrinsicHeaders::new();
let content = ih.resolve("vaesintrin.h").unwrap();
assert!(content.contains("_mm_aesenc_si128"));
assert!(content.contains("_mm_aesenclast_si128"));
}
#[test]
fn test_intrinsic_vpclmulqdq_content() {
let ih = X86IntrinsicHeaders::new();
let content = ih.resolve("vpclmulqdqintrin.h").unwrap();
assert!(content.contains("_mm_clmulepi64_si128"));
}
#[test]
fn test_intrinsic_amx_content() {
let ih = X86IntrinsicHeaders::new();
let content = ih.resolve("amxintrin.h").unwrap();
assert!(content.contains("__tile"));
assert!(content.contains("_tile_loadd"));
}
#[test]
fn test_intrinsic_amxbf16_content() {
let ih = X86IntrinsicHeaders::new();
let content = ih.resolve("amxbf16intrin.h").unwrap();
assert!(content.contains("_tdpbf16ps"));
}
#[test]
fn test_intrinsic_amxint8_content() {
let ih = X86IntrinsicHeaders::new();
let content = ih.resolve("amxint8intrin.h").unwrap();
assert!(content.contains("_tdpbssd"));
assert!(content.contains("_tdpbuud"));
}
#[test]
fn test_intrinsic_cet_content() {
let ih = X86IntrinsicHeaders::new();
let content = ih.resolve("cetintrin.h").unwrap();
assert!(content.contains("_incsspq"));
assert!(content.contains("_rdsspq"));
assert!(content.contains("_endbr64"));
}
#[test]
fn test_intrinsic_movdir_content() {
let ih = X86IntrinsicHeaders::new();
let content = ih.resolve("movdirintrin.h").unwrap();
assert!(content.contains("_directstoreu_u32"));
}
#[test]
fn test_intrinsic_waitpkg_content() {
let ih = X86IntrinsicHeaders::new();
let content = ih.resolve("waitpkgintrin.h").unwrap();
assert!(content.contains("_umonitor"));
assert!(content.contains("_umwait"));
assert!(content.contains("_tpause"));
}
#[test]
fn test_intrinsic_enqcmd_content() {
let ih = X86IntrinsicHeaders::new();
let content = ih.resolve("enqcmdintrin.h").unwrap();
assert!(content.contains("_enqcmd"));
assert!(content.contains("_enqcmds"));
}
#[test]
fn test_intrinsic_serialize_content() {
let ih = X86IntrinsicHeaders::new();
let content = ih.resolve("serializeintrin.h").unwrap();
assert!(content.contains("_serialize"));
}
#[test]
fn test_intrinsic_cldemote_content() {
let ih = X86IntrinsicHeaders::new();
let content = ih.resolve("cldemoteintrin.h").unwrap();
assert!(content.contains("_cldemote"));
}
#[test]
fn test_intrinsic_ptwrite_content() {
let ih = X86IntrinsicHeaders::new();
let content = ih.resolve("ptwriteintrin.h").unwrap();
assert!(content.contains("_ptwrite32"));
assert!(content.contains("_ptwrite64"));
}
#[test]
fn test_intrinsic_uintr_content() {
let ih = X86IntrinsicHeaders::new();
let content = ih.resolve("uintrintrin.h").unwrap();
assert!(content.contains("_clui"));
assert!(content.contains("_stui"));
}
#[test]
fn test_intrinsic_hreset_content() {
let ih = X86IntrinsicHeaders::new();
let content = ih.resolve("hresetintrin.h").unwrap();
assert!(content.contains("_hreset"));
}
#[test]
fn test_intrinsic_keylocker_content() {
let ih = X86IntrinsicHeaders::new();
let content = ih.resolve("keylockerintrin.h").unwrap();
assert!(content.contains("_loadiwkey"));
assert!(content.contains("_aesenc128kl"));
}
#[test]
fn test_intrinsic_cmpccxadd_content() {
let ih = X86IntrinsicHeaders::new();
let content = ih.resolve("cmpccxaddintrin.h").unwrap();
assert!(content.contains("_cmpccxadd32"));
}
#[test]
fn test_intrinsic_raoint_content() {
let ih = X86IntrinsicHeaders::new();
let content = ih.resolve("raointintrin.h").unwrap();
assert!(content.contains("_aadd_i32"));
}
#[test]
fn test_intrinsic_avxifma_content() {
let ih = X86IntrinsicHeaders::new();
let content = ih.resolve("avxifmaintrin.h").unwrap();
assert!(content.contains("_mm_madd52lo_epu64"));
assert!(content.contains("_mm_madd52hi_epu64"));
}
#[test]
fn test_intrinsic_avxneconvert_content() {
let ih = X86IntrinsicHeaders::new();
let content = ih.resolve("avxneconvertintrin.h").unwrap();
assert!(content.contains("_mm_bcstnebf16_ps"));
}
#[test]
fn test_intrinsic_avxvnniint8_content() {
let ih = X86IntrinsicHeaders::new();
let content = ih.resolve("avxvnniint8intrin.h").unwrap();
assert!(content.contains("_mm_dpbsud_epi32"));
assert!(content.contains("_mm256_dpbsud_epi32"));
}
#[test]
fn test_intrinsic_avx10_content() {
let ih = X86IntrinsicHeaders::new();
let content = ih.resolve("avx10_1intrin.h").unwrap();
assert!(content.contains("_MM_FROUND_TO_NEAREST_INT"));
}
#[test]
fn test_intrinsic_nmmintrin_content() {
let ih = X86IntrinsicHeaders::new();
let content = ih.resolve("nmmintrin.h").unwrap();
assert!(content.contains("_mm_cmpestra"));
}
#[test]
fn test_intrinsic_wmmintrin_content() {
let ih = X86IntrinsicHeaders::new();
let content = ih.resolve("wmmintrin.h").unwrap();
assert!(content.contains("_mm_aesenc_si128"));
}
#[test]
fn test_intrinsic_f16c_content() {
let ih = X86IntrinsicHeaders::new();
let content = ih.resolve("f16cintrin.h").unwrap();
assert!(content.contains("_mm_cvtph_ps"));
assert!(content.contains("_mm_cvtps_ph"));
}
#[test]
fn test_intrinsic_avx512bw_feature_gate() {
let ih = X86IntrinsicHeaders::new();
assert_eq!(ih.feature_gate("avx512bwintrin.h"), Some("__AVX512BW__"));
}
#[test]
fn test_intrinsic_avx512cd_feature_gate() {
let ih = X86IntrinsicHeaders::new();
assert_eq!(ih.feature_gate("avx512cdintrin.h"), Some("__AVX512CD__"));
}
#[test]
fn test_intrinsic_avx512dq_feature_gate() {
let ih = X86IntrinsicHeaders::new();
assert_eq!(ih.feature_gate("avx512dqintrin.h"), Some("__AVX512DQ__"));
}
#[test]
fn test_builtin_stddef_content_has_offsetof() {
let bh = X86BuiltinHeaders::new();
let content = bh.resolve("stddef.h").unwrap();
assert!(content.contains("offsetof"));
assert!(content.contains("#define offsetof"));
}
#[test]
fn test_builtin_stdarg_content_has_va_copy() {
let bh = X86BuiltinHeaders::new();
let content = bh.resolve("stdarg.h").unwrap();
assert!(content.contains("va_copy"));
assert!(content.contains("va_end"));
}
#[test]
fn test_builtin_stdbool_content_has_false() {
let bh = X86BuiltinHeaders::new();
let content = bh.resolve("stdbool.h").unwrap();
assert!(content.contains("false"));
assert!(content.contains("true"));
}
#[test]
fn test_builtin_stdint_content_has_intptr_t() {
let bh = X86BuiltinHeaders::new();
let content = bh.resolve("stdint.h").unwrap();
assert!(content.contains("intptr_t"));
assert!(content.contains("uintptr_t"));
assert!(content.contains("INTMAX_C"));
assert!(content.contains("UINTMAX_C"));
}
#[test]
fn test_builtin_iso646_content_has_xor() {
let bh = X86BuiltinHeaders::new();
let content = bh.resolve("iso646.h").unwrap();
assert!(content.contains("xor"));
assert!(content.contains("xor_eq"));
assert!(content.contains("bitor"));
}
#[test]
fn test_builtin_limits_content_has_char_bit() {
let bh = X86BuiltinHeaders::new();
let content = bh.resolve("limits.h").unwrap();
assert!(content.contains("CHAR_BIT"));
assert!(content.contains("MB_LEN_MAX"));
}
#[test]
fn test_builtin_float_content_has_float_constants() {
let bh = X86BuiltinHeaders::new();
let content = bh.resolve("float.h").unwrap();
assert!(content.contains("FLT_RADIX"));
assert!(content.contains("FLT_EPSILON"));
assert!(content.contains("DBL_EPSILON"));
assert!(content.contains("LDBL_EPSILON"));
}
#[test]
fn test_builtin_stdalign_content() {
let bh = X86BuiltinHeaders::new();
let content = bh.resolve("stdalign.h").unwrap();
assert!(content.contains("_Alignas"));
assert!(content.contains("_Alignof"));
}
#[test]
fn test_builtin_stdnoreturn_content() {
let bh = X86BuiltinHeaders::new();
let content = bh.resolve("stdnoreturn.h").unwrap();
assert!(content.contains("_Noreturn"));
}
#[test]
fn test_builtin_max_align_t_content() {
let bh = X86BuiltinHeaders::new();
let content = bh.resolve("__stddef_max_align_t.h").unwrap();
assert!(content.contains("max_align_t") || content.contains("__max_align_t"));
}
#[test]
fn test_builtin_tgmath_content_has_generic() {
let bh = X86BuiltinHeaders::new();
let content = bh.resolve("tgmath.h").unwrap();
assert!(content.contains("_Generic"));
assert!(content.contains("acos"));
assert!(content.contains("sqrt"));
}
#[test]
fn test_intrinsic_f16c_expanded_content() {
let ih = X86IntrinsicHeaders::new();
let content = ih.resolve("f16cintrin.h").unwrap();
assert!(content.contains("_mm_cvtph_ps") || content.contains("F16C"));
}
#[test]
fn test_intrinsic_vpclmulqdq_expanded() {
let ih = X86IntrinsicHeaders::new();
let content = ih.resolve("vpclmulqdqintrin.h").unwrap();
assert!(content.contains("clmulepi64") || content.contains("VPCLMULQDQ"));
}
#[test]
fn test_intrinsic_avx512vl_has_mask_ops() {
let ih = X86IntrinsicHeaders::new();
let content = ih.resolve("avx512vlintrin.h").unwrap();
assert!(content.len() > 100);
}
#[test]
fn test_include_cache_eviction_order() {
let mut cache = X86IncludeCache::new(2);
cache.insert(Path::new("/1"), "a");
cache.insert(Path::new("/2"), "b");
cache.insert(Path::new("/3"), "c");
assert!(cache.get(Path::new("/1")).is_none());
assert!(cache.get(Path::new("/2")).is_some());
assert!(cache.get(Path::new("/3")).is_some());
}
#[test]
fn test_include_cache_refresh_on_insert() {
let mut cache = X86IncludeCache::new(5);
cache.insert(Path::new("/r"), "old");
cache.insert(Path::new("/r"), "new");
assert_eq!(cache.get(Path::new("/r")), Some(&"new".to_string()));
assert_eq!(cache.len(), 1);
}
#[test]
fn test_include_cache_seen_separate_from_entries() {
let mut cache = X86IncludeCache::new(10);
cache.mark_seen(Path::new("/seen_only"));
assert!(cache.is_seen(Path::new("/seen_only")));
assert!(cache.get(Path::new("/seen_only")).is_none());
}
#[test]
fn test_include_cache_is_empty_after_clear() {
let mut cache = X86IncludeCache::new(10);
cache.insert(Path::new("/a"), "x");
cache.insert(Path::new("/b"), "y");
cache.clear();
assert!(cache.is_empty());
assert_eq!(cache.len(), 0);
}
#[test]
fn test_include_cache_max_capacity() {
let mut cache = X86IncludeCache::new(3);
for i in 0..10 {
cache.insert(Path::new(&format!("/{}", i)), &format!("c{}", i));
}
assert_eq!(cache.len(), 3);
}
#[test]
fn test_header_guard_multiple_files() {
let mut guard = X86HeaderGuard::default();
guard.mark_guard("A", Path::new("/a"));
guard.mark_guard("B", Path::new("/b"));
guard.mark_guard("C", Path::new("/c"));
assert_eq!(guard.len(), 3);
assert!(guard.is_guarded(Path::new("/a")));
assert!(guard.is_guarded(Path::new("/b")));
assert!(guard.is_guarded(Path::new("/c")));
}
#[test]
fn test_header_guard_same_guard_different_file() {
let mut guard = X86HeaderGuard::default();
guard.mark_guard("G", Path::new("/a"));
guard.mark_guard("G", Path::new("/b"));
assert!(guard.is_guard_defined("G"));
}
#[test]
fn test_header_guard_empty_after_creation() {
let guard = X86HeaderGuard::default();
assert!(guard.is_empty());
assert!(!guard.is_guarded(Path::new("/anything")));
}
#[test]
fn test_module_map_with_link_libraries() {
let content = r#"
module MyMod {
header "my.h"
link "mylib"
link "otherlib"
}
"#;
let entries = parse_module_map_content(content, Path::new("/tmp"));
assert_eq!(entries.len(), 1);
assert_eq!(entries[0].name, "MyMod");
assert_eq!(entries[0].link_libraries.len(), 2);
}
#[test]
fn test_module_map_with_exports() {
let content = r#"
module Mod {
header "h.h"
export *
export Mod.SubMod
}
"#;
let entries = parse_module_map_content(content, Path::new("/tmp"));
assert_eq!(entries.len(), 1);
assert!(entries[0].exports.len() >= 1);
}
#[test]
fn test_module_map_with_excluded_headers() {
let content = r#"
module Mod {
umbrella header "umbrella.h"
exclude header "private.h"
exclude header "internal.h"
}
"#;
let entries = parse_module_map_content(content, Path::new("/tmp"));
assert_eq!(entries.len(), 1);
assert_eq!(entries[0].excluded_headers.len(), 2);
}
#[test]
fn test_module_map_parse_file_nonexistent() {
let mut mm = X86ModuleMap::default();
let result = mm.parse_file(Path::new("/nonexistent/module.modulemap"));
assert!(result.is_err());
}
#[test]
fn test_vfs_overlay_with_multiple_remaps() {
let mut vfs = X86VFSOverlay::new();
vfs.add_remap("a.h", "/real/a.h");
vfs.add_remap("b.h", "/real/b.h");
vfs.add_remap("c.h", "/real/c.h");
let mappings = vfs.mappings();
assert_eq!(mappings.len(), 3);
assert!(vfs.has_remap("a.h"));
assert!(vfs.has_remap("b.h"));
assert!(vfs.has_remap("c.h"));
}
#[test]
fn test_vfs_overlay_remap_returns_first_match() {
let mut vfs = X86VFSOverlay::new();
vfs.add_remap("x.h", "/real/x.h");
let result = vfs.remap("x.h");
assert_eq!(result, Some(PathBuf::from("/real/x.h")));
}
#[test]
fn test_vfs_overlay_remap_basename_resolution() {
let mut vfs = X86VFSOverlay::new();
vfs.add_remap("some/deep/path/header.h", "/flat/header.h");
let result = vfs.remap("header.h");
assert_eq!(result, Some(PathBuf::from("/flat/header.h")));
}
#[test]
fn test_vfs_overlay_load_nonexistent_file() {
let mut vfs = X86VFSOverlay::new();
let result = vfs.load("/nonexistent/vfs.yaml");
assert!(result.is_err());
}
#[test]
fn test_full_header_search_with_all_components() {
let mut hs = X86HeaderSearch::new("x86_64-unknown-linux-gnu");
hs.module_map.generate_standard_modules();
hs.vfs_overlay.add_remap("remapped.h", "/real/remapped.h");
assert!(hs.resolve_system_include("stddef.h").is_some());
assert!(hs.resolve_system_include("emmintrin.h").is_some());
assert!(hs.resolve_system_include("remapped.h").is_some());
assert!(hs.lookup_module("std").is_some());
}
#[test]
fn test_header_search_paths_dump_comprehensive() {
let mut hs = X86HeaderSearch::new("x86_64-unknown-linux-gnu");
hs.set_sysroot("/fake/sysroot");
hs.set_resource_dir("/fake/resource");
let dump = hs.dump_paths();
assert!(dump.iter().any(|s| s.contains("fake/sysroot")));
assert!(dump.iter().any(|s| s.contains("fake/resource")));
}
#[test]
fn test_multilib_with_header_search_integration() {
let m = MultilibDetector::new("x86_64-unknown-linux-gnu");
assert_eq!(m.variants.len(), 3);
let lib_dir = m.variants[0].lib_dir.clone();
assert!(lib_dir.contains("64"));
let lib_dir_32 = &m.variants[1].lib_dir;
assert!(!lib_dir_32.contains("64"));
}
#[test]
fn test_dependency_graph_with_standard_headers_integration() {
let g = HeaderDependencyGraph::build_c_stdlib_graph();
let deps = g.direct_deps("stdio.h");
assert!(
deps.contains(&"stddef.h"),
"stdio.h should depend on stddef.h"
);
}
#[test]
fn test_dependency_graph_cxx_stdlib_comprehensive() {
let g = HeaderDependencyGraph::build_cxx_stdlib_graph();
let deps = g.direct_deps("iostream");
assert!(deps.contains(&"istream"));
assert!(deps.contains(&"ostream"));
let ios_deps = g.direct_deps("ios");
assert!(ios_deps.contains(&"iosfwd") || ios_deps.contains(&"streambuf"));
}
#[test]
fn test_sysroot_detector_integration() {
let detector = PlatformSysrootDetector::new("x86_64-unknown-linux-gnu");
let result = detector.detect();
if cfg!(target_os = "linux") {
assert!(result.is_some());
}
}
#[test]
fn test_vfs_overlay_integration_with_remap_resolve() {
let mut vfs = X86VFSOverlay::new();
vfs.add_remap("sys/time.h", "/custom/time.h");
vfs.add_remap("sys/stat.h", "/custom/stat.h");
assert!(vfs.has_remap("sys/time.h"));
assert!(vfs.has_remap("sys/stat.h"));
assert!(!vfs.has_remap("sys/types.h"));
let mappings = vfs.mappings();
assert_eq!(mappings.len(), 2);
}
#[test]
fn test_module_map_export_integration() {
let mut mm = X86ModuleMap::default();
mm.generate_standard_modules();
mm.add_import("std.io", "std");
mm.add_import("std.math", "std");
assert!(mm.find("std.io").is_some());
assert!(mm.find("std.math").is_some());
}
#[test]
fn test_cache_performance_simulation() {
let mut cache = X86IncludeCache::new(100);
for i in 0..50 {
cache.record_hit();
}
for _ in 0..50 {
cache.record_miss();
}
assert!((cache.hit_rate() - 0.5).abs() < 0.01);
}
#[test]
fn test_header_guard_includes_skip_behaviour() {
let mut guard = X86HeaderGuard::default();
let file = Path::new("/tmp/guarded.h");
assert!(!guard.is_guarded(file));
guard.mark_guard("GUARDED_H", file);
assert!(guard.is_guarded(file));
guard.forget_file(file);
assert!(!guard.is_guarded(file));
}
#[test]
fn test_all_standard_c_headers_are_registered() {
let sh = X86StandardHeaders::new();
let c_headers = X86StandardHeaders::c_header_names();
assert!(c_headers.len() >= 24);
for h in &c_headers {
assert!(sh.is_known(h), "C header {} should be known", h);
}
}
#[test]
fn test_all_standard_cxx_headers_are_registered() {
let sh = X86StandardHeaders::new();
let cxx_headers = X86StandardHeaders::cxx_header_names();
assert!(cxx_headers.len() >= 50);
for h in &cxx_headers {
assert!(sh.is_known(h), "C++ header {} should be known", h);
}
}
#[test]
fn test_all_posix_headers_are_registered() {
let sh = X86StandardHeaders::new();
let posix_headers = X86StandardHeaders::posix_header_names();
for h in &posix_headers {
assert!(sh.is_known(h), "POSIX header {} should be known", h);
}
}
#[test]
fn test_multilib_variant_struct_values() {
let m = MultilibDetector::new("x86_64-unknown-linux-gnu");
let v = &m.variants[0];
assert_eq!(v.dir_suffix, "");
assert_eq!(v.flags, vec!["-m64"]);
assert_eq!(v.os_dir, "../lib64");
}
#[test]
fn test_x86_header_search_all_fields_accessible() {
let hs = X86HeaderSearch::new("x86_64-unknown-linux-gnu");
assert_eq!(hs.max_include_depth, 200);
assert!(hs.use_standard_system_includes);
assert!(hs.use_standard_cxx_includes);
assert!(hs.warn_missing_headers);
}
#[test]
fn test_dependency_graph_empty_deps() {
let g = HeaderDependencyGraph::new();
let deps = g.direct_deps("nonexistent");
assert!(deps.is_empty());
let rdeps = g.dependents("nonexistent");
assert!(rdeps.is_empty());
}
#[test]
fn test_module_map_generate_idempotent() {
let mut mm = X86ModuleMap::default();
mm.generate_standard_modules();
let count = mm.names().len();
mm.generate_standard_modules();
assert_eq!(mm.names().len(), count);
}
#[test]
fn test_x86_header_search_dump_paths_non_empty() {
let hs = X86HeaderSearch::new("x86_64-unknown-linux-gnu");
let paths = hs.dump_paths();
assert!(!paths.is_empty());
assert!(paths[0].contains("x86_64"));
}
#[test]
fn test_parse_module_map_content_with_comments() {
let content = r#"
// This is a comment
module Foo {
header "foo.h" // inline comment
}
# another style comment
module Bar {
header "bar.h"
}
"#;
let entries = parse_module_map_content(content, Path::new("/tmp"));
assert_eq!(entries.len(), 2);
}
}
#[derive(Debug, Clone, Default)]
pub struct HeaderSearchLogger {
pub resolved: Vec<(String, PathBuf, u64)>,
pub not_found: Vec<(String, String)>,
pub skipped: Vec<(String, String)>,
pub total_lookups: usize,
pub enabled: bool,
}
impl HeaderSearchLogger {
pub fn new() -> Self {
Self {
enabled: true,
..Default::default()
}
}
pub fn log_resolved(&mut self, name: &str, path: &Path, duration_us: u64) {
if self.enabled {
self.resolved
.push((name.to_string(), path.to_path_buf(), duration_us));
self.total_lookups += 1;
}
}
pub fn log_not_found(&mut self, name: &str, kind: &str) {
if self.enabled {
self.not_found.push((name.to_string(), kind.to_string()));
self.total_lookups += 1;
}
}
pub fn log_skip(&mut self, name: &str, reason: &str) {
if self.enabled {
self.skipped.push((name.to_string(), reason.to_string()));
}
}
pub fn success_rate(&self) -> f64 {
if self.total_lookups == 0 {
0.0
} else {
self.resolved.len() as f64 / self.total_lookups as f64
}
}
pub fn clear(&mut self) {
self.resolved.clear();
self.not_found.clear();
self.skipped.clear();
self.total_lookups = 0;
}
}
#[derive(Debug, Clone, Default)]
pub struct IncludeChainTracker {
pub stack: Vec<(PathBuf, u32)>,
pub max_depth: usize,
pub enable_backtrace: bool,
pub backtrace_limit: usize,
}
impl IncludeChainTracker {
pub fn new() -> Self {
Self {
enable_backtrace: true,
backtrace_limit: 20,
..Default::default()
}
}
pub fn push(&mut self, file: &Path, line: u32) {
self.stack.push((file.to_path_buf(), line));
if self.stack.len() > self.max_depth {
self.max_depth = self.stack.len();
}
}
pub fn pop(&mut self) {
self.stack.pop();
}
pub fn depth(&self) -> usize {
self.stack.len()
}
pub fn backtrace(&self) -> Vec<String> {
let limit = self.backtrace_limit.min(self.stack.len());
self.stack
.iter()
.rev()
.take(limit)
.map(|(f, l)| format!("{}:{}", f.display(), l))
.collect()
}
pub fn current_file(&self) -> Option<&PathBuf> {
self.stack.last().map(|(f, _)| f)
}
pub fn current_line(&self) -> Option<u32> {
self.stack.last().map(|(_, l)| *l)
}
}
#[derive(Debug, Clone)]
pub enum HeaderResolutionResult {
Found { path: PathBuf, is_system: bool },
Builtin { name: String, content: String },
NotFound { name: String, search_kind: String },
SkippedGuard { name: String, guard: String },
SkippedPragmaOnce { name: String },
}
impl HeaderResolutionResult {
pub fn is_found(&self) -> bool {
matches!(self, Self::Found { .. } | Self::Builtin { .. })
}
pub fn is_skipped(&self) -> bool {
matches!(
self,
Self::SkippedGuard { .. } | Self::SkippedPragmaOnce { .. }
)
}
pub fn path(&self) -> Option<&PathBuf> {
match self {
Self::Found { path, .. } => Some(path),
_ => None,
}
}
}
#[derive(Debug, Clone, Default)]
pub struct PrecomputedHeaderCache {
pub entries: HashMap<String, String>,
}
impl PrecomputedHeaderCache {
pub fn new() -> Self {
let mut c = Self {
entries: HashMap::new(),
};
c.populate_common();
c
}
fn populate_common(&mut self) {
self.entries.insert("stddef.h".into(), STDDEF_H.into());
self.entries.insert("stdarg.h".into(), STDARG_H.into());
self.entries.insert("stdbool.h".into(), STDBOOL_H.into());
self.entries.insert("stdint.h".into(), STDINT_H.into());
self.entries.insert("limits.h".into(), LIMITS_H.into());
self.entries.insert("float.h".into(), FLOAT_H.into());
self.entries.insert("iso646.h".into(), ISO646_H.into());
self.entries.insert(
"errno.h".into(),
"#ifndef _ERRNO_H\n#define _ERRNO_H\n#include <sys/errno.h>\n#endif\n".into(),
);
self.entries.insert(
"assert.h".into(),
concat!(
"#ifndef _ASSERT_H\n#define _ASSERT_H\n",
"#ifndef NDEBUG\n",
"#define assert(expr) ((expr) ? (void)0 : ",
"__assert_fail(#expr, __FILE__, __LINE__, __func__))\n",
"#else\n#define assert(expr) ((void)0)\n#endif\n#endif\n",
)
.into(),
);
}
pub fn get(&self, name: &str) -> Option<&str> {
self.entries.get(name).map(|s| s.as_str())
}
pub fn has(&self, name: &str) -> bool {
self.entries.contains_key(name)
}
}
#[derive(Debug, Clone, Default)]
pub struct HeaderConflictDetector {
conflicts: HashMap<String, Vec<PathBuf>>,
}
impl HeaderConflictDetector {
pub fn new() -> Self {
Self::default()
}
pub fn record(&mut self, name: &str, path: &Path) {
let bn = Path::new(name)
.file_name()
.map(|f| f.to_string_lossy().to_string())
.unwrap_or_else(|| name.to_string());
let entry = self.conflicts.entry(bn).or_default();
if !entry.contains(&path.to_path_buf()) {
entry.push(path.to_path_buf());
}
}
pub fn has_conflict(&self, name: &str) -> bool {
let bn = Path::new(name)
.file_name()
.map(|f| f.to_string_lossy().to_string())
.unwrap_or_else(|| name.to_string());
self.conflicts.get(&bn).map_or(false, |v| v.len() > 1)
}
pub fn conflicting_paths(&self, name: &str) -> Vec<&PathBuf> {
let bn = Path::new(name)
.file_name()
.map(|f| f.to_string_lossy().to_string())
.unwrap_or_else(|| name.to_string());
self.conflicts
.get(&bn)
.map(|v| v.iter().collect())
.unwrap_or_default()
}
pub fn clear(&mut self) {
self.conflicts.clear();
}
}
#[cfg(test)]
mod supplementary_tests {
use super::*;
#[test]
fn test_logger_new() {
let logger = HeaderSearchLogger::new();
assert!(logger.enabled);
assert_eq!(logger.total_lookups, 0);
}
#[test]
fn test_logger_log_resolved() {
let mut logger = HeaderSearchLogger::new();
logger.log_resolved("stddef.h", Path::new("/usr/include/stddef.h"), 12);
assert_eq!(logger.total_lookups, 1);
assert_eq!(logger.resolved.len(), 1);
}
#[test]
fn test_logger_log_not_found() {
let mut logger = HeaderSearchLogger::new();
logger.log_not_found("missing.h", "system");
assert_eq!(logger.not_found.len(), 1);
}
#[test]
fn test_logger_log_skip() {
let mut logger = HeaderSearchLogger::new();
logger.log_skip("already.h", "guard");
assert_eq!(logger.skipped.len(), 1);
}
#[test]
fn test_logger_success_rate() {
let mut logger = HeaderSearchLogger::new();
logger.log_resolved("a.h", Path::new("/a.h"), 0);
logger.log_not_found("b.h", "system");
logger.log_resolved("c.h", Path::new("/c.h"), 0);
assert!((logger.success_rate() - 2.0 / 3.0).abs() < 0.01);
}
#[test]
fn test_logger_disabled() {
let mut logger = HeaderSearchLogger::new();
logger.enabled = false;
logger.log_resolved("a.h", Path::new("/a.h"), 0);
assert_eq!(logger.total_lookups, 0);
}
#[test]
fn test_logger_clear() {
let mut logger = HeaderSearchLogger::new();
logger.log_resolved("a.h", Path::new("/a.h"), 0);
logger.log_not_found("b.h", "system");
logger.clear();
assert_eq!(logger.total_lookups, 0);
assert!(logger.resolved.is_empty());
}
#[test]
fn test_chain_tracker_push_pop() {
let mut tracker = IncludeChainTracker::new();
tracker.push(Path::new("/a.h"), 10);
assert_eq!(tracker.depth(), 1);
assert_eq!(tracker.max_depth, 1);
tracker.push(Path::new("/b.h"), 20);
assert_eq!(tracker.depth(), 2);
assert_eq!(tracker.max_depth, 2);
tracker.pop();
assert_eq!(tracker.depth(), 1);
assert_eq!(tracker.max_depth, 2);
}
#[test]
fn test_chain_tracker_current_file() {
let mut tracker = IncludeChainTracker::new();
tracker.push(Path::new("/main.c"), 5);
assert_eq!(tracker.current_file(), Some(&PathBuf::from("/main.c")));
assert_eq!(tracker.current_line(), Some(5));
}
#[test]
fn test_chain_tracker_backtrace() {
let mut tracker = IncludeChainTracker::new();
tracker.push(Path::new("/main.c"), 1);
tracker.push(Path::new("/a.h"), 42);
tracker.push(Path::new("/b.h"), 7);
let bt = tracker.backtrace();
assert_eq!(bt.len(), 3);
assert!(bt[0].contains("/b.h"));
assert!(bt[1].contains("/a.h"));
assert!(bt[2].contains("/main.c"));
}
#[test]
fn test_chain_tracker_backtrace_limit() {
let mut tracker = IncludeChainTracker::new();
tracker.backtrace_limit = 2;
for i in 0..10 {
tracker.push(Path::new(&format!("/f{}.h", i)), i);
}
let bt = tracker.backtrace();
assert_eq!(bt.len(), 2);
}
#[test]
fn test_header_resolution_result_is_found() {
let r = HeaderResolutionResult::Found {
path: PathBuf::from("/a.h"),
is_system: false,
};
assert!(r.is_found());
assert!(!r.is_skipped());
assert_eq!(r.path(), Some(&PathBuf::from("/a.h")));
}
#[test]
fn test_header_resolution_result_builtin_found() {
let r = HeaderResolutionResult::Builtin {
name: "stddef.h".into(),
content: "content".into(),
};
assert!(r.is_found());
assert!(!r.is_skipped());
assert!(r.path().is_none());
}
#[test]
fn test_header_resolution_result_not_found() {
let r = HeaderResolutionResult::NotFound {
name: "x.h".into(),
search_kind: "system".into(),
};
assert!(!r.is_found());
assert!(!r.is_skipped());
}
#[test]
fn test_header_resolution_result_skipped_guard() {
let r = HeaderResolutionResult::SkippedGuard {
name: "x.h".into(),
guard: "X_H".into(),
};
assert!(!r.is_found());
assert!(r.is_skipped());
}
#[test]
fn test_header_resolution_result_skipped_pragma_once() {
let r = HeaderResolutionResult::SkippedPragmaOnce { name: "x.h".into() };
assert!(!r.is_found());
assert!(r.is_skipped());
}
#[test]
fn test_precomputed_cache_new() {
let cache = PrecomputedHeaderCache::new();
assert!(cache.has("stddef.h"));
assert!(cache.has("stdarg.h"));
assert!(cache.has("stdbool.h"));
assert!(cache.has("stdint.h"));
assert!(cache.has("limits.h"));
assert!(cache.has("float.h"));
assert!(cache.has("iso646.h"));
assert!(cache.has("errno.h"));
assert!(cache.has("assert.h"));
}
#[test]
fn test_precomputed_cache_get_content() {
let cache = PrecomputedHeaderCache::new();
let content = cache.get("stddef.h").unwrap();
assert!(content.contains("size_t"));
}
#[test]
fn test_precomputed_cache_missing() {
let cache = PrecomputedHeaderCache::new();
assert!(!cache.has("nonexistent.h"));
assert!(cache.get("nonexistent.h").is_none());
}
#[test]
fn test_precomputed_cache_assert_content() {
let cache = PrecomputedHeaderCache::new();
let content = cache.get("assert.h").unwrap();
assert!(content.contains("assert"));
assert!(content.contains("NDEBUG"));
}
#[test]
fn test_precomputed_cache_errno_content() {
let cache = PrecomputedHeaderCache::new();
let content = cache.get("errno.h").unwrap();
assert!(content.contains("_ERRNO_H"));
}
#[test]
fn test_conflict_detector_new() {
let cd = HeaderConflictDetector::new();
assert!(!cd.has_conflict("any.h"));
}
#[test]
fn test_conflict_detector_no_conflict() {
let mut cd = HeaderConflictDetector::new();
cd.record("unique.h", Path::new("/path/unique.h"));
assert!(!cd.has_conflict("unique.h"));
}
#[test]
fn test_conflict_detector_has_conflict() {
let mut cd = HeaderConflictDetector::new();
cd.record("common.h", Path::new("/usr/include/common.h"));
cd.record("common.h", Path::new("/usr/local/include/common.h"));
assert!(cd.has_conflict("common.h"));
let paths = cd.conflicting_paths("common.h");
assert_eq!(paths.len(), 2);
}
#[test]
fn test_conflict_detector_same_path_twice() {
let mut cd = HeaderConflictDetector::new();
cd.record("dup.h", Path::new("/a/dup.h"));
cd.record("dup.h", Path::new("/a/dup.h"));
assert!(!cd.has_conflict("dup.h"));
assert_eq!(cd.conflicting_paths("dup.h").len(), 1);
}
#[test]
fn test_conflict_detector_clear() {
let mut cd = HeaderConflictDetector::new();
cd.record("a.h", Path::new("/1/a.h"));
cd.record("a.h", Path::new("/2/a.h"));
assert!(cd.has_conflict("a.h"));
cd.clear();
assert!(!cd.has_conflict("a.h"));
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum X86TargetOS {
Linux,
Darwin,
FreeBSD,
OpenBSD,
NetBSD,
Windows,
Cygwin,
Android,
Emscripten,
Wasi,
Unknown,
}
impl X86TargetOS {
pub fn from_str(s: &str) -> Self {
if s.contains("linux") {
Self::Linux
} else if s.contains("darwin") || s.contains("apple") || s.contains("macos") {
Self::Darwin
} else if s.contains("freebsd") {
Self::FreeBSD
} else if s.contains("openbsd") {
Self::OpenBSD
} else if s.contains("netbsd") {
Self::NetBSD
} else if s.contains("cygwin") {
Self::Cygwin
} else if s.contains("windows") || s.contains("mingw") || s.contains("msvc") {
Self::Windows
} else if s.contains("android") {
Self::Android
} else if s.contains("emscripten") {
Self::Emscripten
} else if s.contains("wasi") {
Self::Wasi
} else {
Self::Unknown
}
}
pub fn is_unix(&self) -> bool {
matches!(
self,
Self::Linux
| Self::Darwin
| Self::FreeBSD
| Self::OpenBSD
| Self::NetBSD
| Self::Android
| Self::Cygwin
)
}
pub fn is_windows(&self) -> bool {
matches!(self, Self::Windows)
}
pub fn as_str(&self) -> &'static str {
match self {
Self::Linux => "linux",
Self::Darwin => "darwin",
Self::FreeBSD => "freebsd",
Self::OpenBSD => "openbsd",
Self::NetBSD => "netbsd",
Self::Windows => "windows",
Self::Cygwin => "cygwin",
Self::Android => "android",
Self::Emscripten => "emscripten",
Self::Wasi => "wasi",
Self::Unknown => "unknown",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum X86TargetEnv {
Gnu,
Musl,
Bionic,
MSVC,
Mingw,
Unknown,
}
impl X86TargetEnv {
pub fn from_str(s: &str) -> Self {
if s.contains("gnu") {
Self::Gnu
} else if s.contains("musl") {
Self::Musl
} else if s.contains("bionic") || s.contains("android") {
Self::Bionic
} else if s.contains("msvc") {
Self::MSVC
} else if s.contains("mingw") {
Self::Mingw
} else {
Self::Unknown
}
}
pub fn as_str(&self) -> &'static str {
match self {
Self::Gnu => "gnu",
Self::Musl => "musl",
Self::Bionic => "bionic",
Self::MSVC => "msvc",
Self::Mingw => "mingw",
Self::Unknown => "unknown",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LibcFamily {
Glibc,
Musl,
Bionic,
MSVCRT,
Darwin,
Unknown,
}
impl LibcFamily {
pub fn from_triple(triple: &str) -> Self {
let env = X86TargetEnv::from_str(triple);
let os = X86TargetOS::from_str(triple);
match env {
X86TargetEnv::Gnu => Self::Glibc,
X86TargetEnv::Musl => Self::Musl,
X86TargetEnv::Bionic => Self::Bionic,
X86TargetEnv::MSVC => Self::MSVCRT,
X86TargetEnv::Mingw => Self::MSVCRT,
X86TargetEnv::Unknown => match os {
X86TargetOS::Darwin => Self::Darwin,
X86TargetOS::Android => Self::Bionic,
_ => Self::Glibc,
},
}
}
pub fn as_str(&self) -> &'static str {
match self {
Self::Glibc => "glibc",
Self::Musl => "musl",
Self::Bionic => "bionic",
Self::MSVCRT => "msvcrt",
Self::Darwin => "darwin",
Self::Unknown => "unknown",
}
}
}
#[cfg(test)]
mod os_libc_tests {
use super::*;
#[test]
fn test_x86_target_os_from_str_linux() {
assert_eq!(
X86TargetOS::from_str("x86_64-unknown-linux-gnu"),
X86TargetOS::Linux
);
}
#[test]
fn test_x86_target_os_from_str_darwin() {
assert_eq!(
X86TargetOS::from_str("x86_64-apple-darwin20"),
X86TargetOS::Darwin
);
}
#[test]
fn test_x86_target_os_from_str_windows() {
assert_eq!(
X86TargetOS::from_str("x86_64-pc-windows-msvc"),
X86TargetOS::Windows
);
}
#[test]
fn test_x86_target_os_from_str_android() {
assert_eq!(
X86TargetOS::from_str("x86_64-linux-android21"),
X86TargetOS::Android
);
}
#[test]
fn test_x86_target_os_from_str_freebsd() {
assert_eq!(
X86TargetOS::from_str("x86_64-unknown-freebsd13"),
X86TargetOS::FreeBSD
);
}
#[test]
fn test_x86_target_os_from_str_unknown() {
assert_eq!(
X86TargetOS::from_str("x86_64-unknown-none"),
X86TargetOS::Unknown
);
}
#[test]
fn test_x86_target_os_is_unix() {
assert!(X86TargetOS::Linux.is_unix());
assert!(X86TargetOS::Darwin.is_unix());
assert!(X86TargetOS::FreeBSD.is_unix());
assert!(X86TargetOS::Android.is_unix());
assert!(!X86TargetOS::Windows.is_unix());
}
#[test]
fn test_x86_target_os_is_windows() {
assert!(!X86TargetOS::Linux.is_windows());
assert!(X86TargetOS::Windows.is_windows());
}
#[test]
fn test_x86_target_os_as_str() {
assert_eq!(X86TargetOS::Linux.as_str(), "linux");
assert_eq!(X86TargetOS::Darwin.as_str(), "darwin");
assert_eq!(X86TargetOS::Windows.as_str(), "windows");
}
#[test]
fn test_x86_target_env_from_str_gnu() {
assert_eq!(
X86TargetEnv::from_str("x86_64-unknown-linux-gnu"),
X86TargetEnv::Gnu
);
}
#[test]
fn test_x86_target_env_from_str_musl() {
assert_eq!(
X86TargetEnv::from_str("x86_64-unknown-linux-musl"),
X86TargetEnv::Musl
);
}
#[test]
fn test_x86_target_env_from_str_msvc() {
assert_eq!(
X86TargetEnv::from_str("x86_64-pc-windows-msvc"),
X86TargetEnv::MSVC
);
}
#[test]
fn test_x86_target_env_from_str_unknown() {
assert_eq!(
X86TargetEnv::from_str("x86_64-unknown-none"),
X86TargetEnv::Unknown
);
}
#[test]
fn test_x86_target_env_as_str() {
assert_eq!(X86TargetEnv::Gnu.as_str(), "gnu");
assert_eq!(X86TargetEnv::Musl.as_str(), "musl");
assert_eq!(X86TargetEnv::Bionic.as_str(), "bionic");
assert_eq!(X86TargetEnv::MSVC.as_str(), "msvc");
assert_eq!(X86TargetEnv::Unknown.as_str(), "unknown");
}
#[test]
fn test_libc_family_from_triple_glibc() {
assert_eq!(
LibcFamily::from_triple("x86_64-unknown-linux-gnu"),
LibcFamily::Glibc
);
}
#[test]
fn test_libc_family_from_triple_musl() {
assert_eq!(
LibcFamily::from_triple("x86_64-unknown-linux-musl"),
LibcFamily::Musl
);
}
#[test]
fn test_libc_family_from_triple_bionic() {
assert_eq!(
LibcFamily::from_triple("x86_64-linux-android21"),
LibcFamily::Bionic
);
}
#[test]
fn test_libc_family_from_triple_msvc() {
assert_eq!(
LibcFamily::from_triple("x86_64-pc-windows-msvc"),
LibcFamily::MSVCRT
);
}
#[test]
fn test_libc_family_from_triple_darwin() {
assert_eq!(
LibcFamily::from_triple("x86_64-apple-darwin20"),
LibcFamily::Darwin
);
}
#[test]
fn test_libc_family_as_str() {
assert_eq!(LibcFamily::Glibc.as_str(), "glibc");
assert_eq!(LibcFamily::Musl.as_str(), "musl");
assert_eq!(LibcFamily::Bionic.as_str(), "bionic");
assert_eq!(LibcFamily::MSVCRT.as_str(), "msvcrt");
assert_eq!(LibcFamily::Darwin.as_str(), "darwin");
assert_eq!(LibcFamily::Unknown.as_str(), "unknown");
}
}
#[derive(Debug, Clone)]
pub struct X86HeaderSearchBuilder {
target_triple: String,
sysroot: Option<PathBuf>,
resource_dir: Option<PathBuf>,
user_paths: Vec<String>,
system_paths: Vec<String>,
quote_paths: Vec<String>,
after_paths: Vec<String>,
framework_paths: Vec<String>,
defines: Vec<(String, Option<String>)>,
standard: Option<String>,
is_cxx: bool,
no_standard_includes: bool,
no_standard_cxx_includes: bool,
no_builtin_includes: bool,
vfs_overlay: Option<PathBuf>,
module_map_dirs: Vec<String>,
max_include_depth: usize,
warn_missing: bool,
}
impl Default for X86HeaderSearchBuilder {
fn default() -> Self {
Self {
target_triple: "x86_64-unknown-linux-gnu".into(),
sysroot: None,
resource_dir: Some(PathBuf::from(infer_resource_dir())),
user_paths: Vec::new(),
system_paths: Vec::new(),
quote_paths: Vec::new(),
after_paths: Vec::new(),
framework_paths: Vec::new(),
defines: Vec::new(),
standard: None,
is_cxx: false,
no_standard_includes: false,
no_standard_cxx_includes: false,
no_builtin_includes: false,
vfs_overlay: None,
module_map_dirs: Vec::new(),
max_include_depth: 200,
warn_missing: true,
}
}
}
impl X86HeaderSearchBuilder {
pub fn new() -> Self {
Self::default()
}
pub fn target(mut self, triple: &str) -> Self {
self.target_triple = triple.to_string();
self
}
pub fn sysroot(mut self, path: &str) -> Self {
self.sysroot = Some(PathBuf::from(path));
self
}
pub fn resource_dir(mut self, path: &str) -> Self {
self.resource_dir = Some(PathBuf::from(path));
self
}
pub fn add_I(mut self, path: &str) -> Self {
self.user_paths.push(path.to_string());
self
}
pub fn add_isystem(mut self, path: &str) -> Self {
self.system_paths.push(path.to_string());
self
}
pub fn add_iquote(mut self, path: &str) -> Self {
self.quote_paths.push(path.to_string());
self
}
pub fn add_idirafter(mut self, path: &str) -> Self {
self.after_paths.push(path.to_string());
self
}
pub fn add_iframework(mut self, path: &str) -> Self {
self.framework_paths.push(path.to_string());
self
}
pub fn define(mut self, name: &str, value: Option<&str>) -> Self {
self.defines
.push((name.to_string(), value.map(|s| s.to_string())));
self
}
pub fn cxx(mut self) -> Self {
self.is_cxx = true;
self
}
pub fn nostdinc(mut self) -> Self {
self.no_standard_includes = true;
self
}
pub fn nostdincxx(mut self) -> Self {
self.no_standard_cxx_includes = true;
self
}
pub fn nobuiltininc(mut self) -> Self {
self.no_builtin_includes = true;
self
}
pub fn vfs_overlay(mut self, path: &str) -> Self {
self.vfs_overlay = Some(PathBuf::from(path));
self
}
pub fn module_map_dir(mut self, dir: &str) -> Self {
self.module_map_dirs.push(dir.to_string());
self
}
pub fn max_include_depth(mut self, depth: usize) -> Self {
self.max_include_depth = depth;
self
}
pub fn warn_missing(mut self, warn: bool) -> Self {
self.warn_missing = warn;
self
}
pub fn build(self) -> X86HeaderSearch {
let mut hs = X86HeaderSearch::new(&self.target_triple);
hs.max_include_depth = self.max_include_depth;
hs.warn_missing_headers = self.warn_missing;
if let Some(ref s) = self.sysroot {
hs.set_sysroot(&s.to_string_lossy());
}
if let Some(ref r) = self.resource_dir {
hs.set_resource_dir(&r.to_string_lossy());
}
for p in &self.user_paths {
hs.add_user_path(p);
}
for p in &self.system_paths {
hs.add_system_path(p);
}
for p in &self.quote_paths {
hs.add_quote_path(p);
}
for p in &self.after_paths {
hs.add_after_path(p);
}
for p in &self.framework_paths {
hs.add_framework_path(p);
}
if self.no_standard_includes {
hs.disable_standard_includes();
}
if self.no_standard_cxx_includes {
hs.disable_standard_cxx_includes();
}
if self.no_builtin_includes {
hs.disable_builtin_includes();
}
if let Some(ref vfs) = self.vfs_overlay {
let _ = hs.load_vfs_overlay(&vfs.to_string_lossy());
}
for d in &self.module_map_dirs {
hs.load_module_map(d);
}
if self.is_cxx {
hs.paths.add_default_paths();
} else {
hs.paths.add_default_paths();
}
hs
}
}
#[cfg(test)]
mod builder_tests {
use super::*;
#[test]
fn test_builder_default() {
let b = X86HeaderSearchBuilder::default();
assert_eq!(b.target_triple, "x86_64-unknown-linux-gnu");
assert!(b.resource_dir.is_some());
assert!(!b.is_cxx);
}
#[test]
fn test_builder_target() {
let b = X86HeaderSearchBuilder::new().target("i686-unknown-linux-gnu");
assert_eq!(b.target_triple, "i686-unknown-linux-gnu");
}
#[test]
fn test_builder_sysroot() {
let b = X86HeaderSearchBuilder::new().sysroot("/tmp/sys");
assert_eq!(b.sysroot, Some(PathBuf::from("/tmp/sys")));
}
#[test]
fn test_builder_add_I() {
let b = X86HeaderSearchBuilder::new().add_I("/my/include");
assert!(b.user_paths.contains(&"/my/include".to_string()));
}
#[test]
fn test_builder_add_isystem() {
let b = X86HeaderSearchBuilder::new().add_isystem("/sys/include");
assert!(b.system_paths.contains(&"/sys/include".to_string()));
}
#[test]
fn test_builder_add_iquote() {
let b = X86HeaderSearchBuilder::new().add_iquote("/quote/dir");
assert!(b.quote_paths.contains(&"/quote/dir".to_string()));
}
#[test]
fn test_builder_add_idirafter() {
let b = X86HeaderSearchBuilder::new().add_idirafter("/after/dir");
assert!(b.after_paths.contains(&"/after/dir".to_string()));
}
#[test]
fn test_builder_add_iframework() {
let b = X86HeaderSearchBuilder::new().add_iframework("/Frameworks");
assert!(b.framework_paths.contains(&"/Frameworks".to_string()));
}
#[test]
fn test_builder_define_no_value() {
let b = X86HeaderSearchBuilder::new().define("DEBUG", None);
assert_eq!(b.defines[0], ("DEBUG".to_string(), None));
}
#[test]
fn test_builder_define_with_value() {
let b = X86HeaderSearchBuilder::new().define("VERSION", Some("42"));
assert_eq!(
b.defines[0],
("VERSION".to_string(), Some("42".to_string()))
);
}
#[test]
fn test_builder_cxx() {
let b = X86HeaderSearchBuilder::new().cxx();
assert!(b.is_cxx);
}
#[test]
fn test_builder_nostdinc() {
let b = X86HeaderSearchBuilder::new().nostdinc();
assert!(b.no_standard_includes);
}
#[test]
fn test_builder_nostdincxx() {
let b = X86HeaderSearchBuilder::new().nostdincxx();
assert!(b.no_standard_cxx_includes);
}
#[test]
fn test_builder_nobuiltininc() {
let b = X86HeaderSearchBuilder::new().nobuiltininc();
assert!(b.no_builtin_includes);
}
#[test]
fn test_builder_max_include_depth() {
let b = X86HeaderSearchBuilder::new().max_include_depth(50);
assert_eq!(b.max_include_depth, 50);
}
#[test]
fn test_builder_warn_missing() {
let b = X86HeaderSearchBuilder::new().warn_missing(false);
assert!(!b.warn_missing);
}
#[test]
fn test_builder_vfs_overlay() {
let b = X86HeaderSearchBuilder::new().vfs_overlay("/tmp/vfs.yaml");
assert_eq!(b.vfs_overlay, Some(PathBuf::from("/tmp/vfs.yaml")));
}
#[test]
fn test_builder_module_map_dir() {
let b = X86HeaderSearchBuilder::new().module_map_dir("/tmp/modules");
assert!(b.module_map_dirs.contains(&"/tmp/modules".to_string()));
}
#[test]
fn test_builder_build() {
let hs = X86HeaderSearchBuilder::new()
.target("x86_64-unknown-linux-gnu")
.add_I("/usr/local/include")
.define("NDEBUG", None)
.cxx()
.build();
assert_eq!(hs.max_include_depth, 200);
assert!(hs.warn_missing_headers);
assert!(hs.use_standard_system_includes);
}
#[test]
fn test_builder_build_with_nostdinc() {
let hs = X86HeaderSearchBuilder::new()
.nostdinc()
.nobuiltininc()
.build();
assert!(!hs.use_standard_system_includes);
assert!(!hs.use_standard_cxx_includes);
assert!(hs.paths.resource_dir.is_none());
}
#[test]
fn test_builder_fluent_api() {
let hs = X86HeaderSearchBuilder::new()
.target("x86_64-unknown-linux-gnu")
.sysroot("/sysroot")
.add_I("/include1")
.add_I("/include2")
.add_isystem("/sys1")
.define("FOO", Some("bar"))
.cxx()
.max_include_depth(100)
.warn_missing(false)
.build();
assert_eq!(hs.include_count(), 0);
assert_eq!(hs.skip_count(), 0);
assert!(!hs.warn_missing_headers);
assert_eq!(hs.max_include_depth, 100);
}
#[test]
fn test_builder_default_build_idempotent() {
let hs1 = X86HeaderSearchBuilder::new().build();
let hs2 = X86HeaderSearchBuilder::new().build();
assert_eq!(hs1.max_include_depth, hs2.max_include_depth);
}
}
#[derive(Debug, Clone, Default)]
pub struct CrossCompilationPaths {
paths: HashMap<String, Vec<PathBuf>>,
}
impl CrossCompilationPaths {
pub fn new() -> Self {
let mut cp = Self::default();
cp.populate_common();
cp
}
fn populate_common(&mut self) {
self.paths.insert(
"arm-linux-gnueabihf".into(),
vec![
PathBuf::from("/usr/arm-linux-gnueabihf/include"),
PathBuf::from("/usr/arm-linux-gnueabihf/include/c++"),
],
);
self.paths.insert(
"aarch64-linux-gnu".into(),
vec![
PathBuf::from("/usr/aarch64-linux-gnu/include"),
PathBuf::from("/usr/aarch64-linux-gnu/include/c++"),
],
);
self.paths.insert(
"riscv64-linux-gnu".into(),
vec![
PathBuf::from("/usr/riscv64-linux-gnu/include"),
PathBuf::from("/usr/riscv64-linux-gnu/include/c++"),
],
);
}
pub fn get(&self, triple: &str) -> Vec<PathBuf> {
self.paths.get(triple).cloned().unwrap_or_default()
}
pub fn has(&self, triple: &str) -> bool {
self.paths.contains_key(triple)
}
}
#[cfg(test)]
mod cross_compilation_tests {
use super::*;
#[test]
fn test_cross_compilation_paths_arm() {
let cp = CrossCompilationPaths::new();
assert!(cp.has("arm-linux-gnueabihf"));
let paths = cp.get("arm-linux-gnueabihf");
assert!(!paths.is_empty());
}
#[test]
fn test_cross_compilation_paths_aarch64() {
let cp = CrossCompilationPaths::new();
assert!(cp.has("aarch64-linux-gnu"));
let paths = cp.get("aarch64-linux-gnu");
assert!(!paths.is_empty());
}
#[test]
fn test_cross_compilation_paths_riscv64() {
let cp = CrossCompilationPaths::new();
assert!(cp.has("riscv64-linux-gnu"));
}
#[test]
fn test_cross_compilation_paths_missing() {
let cp = CrossCompilationPaths::new();
assert!(!cp.has("made-up-triple"));
assert!(cp.get("made-up-triple").is_empty());
}
}
#[derive(Debug, Clone, Default)]
pub struct HeaderMap {
entries: BTreeMap<String, PathBuf>,
case_insensitive: bool,
}
impl HeaderMap {
pub fn new() -> Self {
Self {
entries: BTreeMap::new(),
case_insensitive: false,
}
}
pub fn case_insensitive(mut self) -> Self {
self.case_insensitive = true;
self
}
pub fn add(&mut self, key: &str, path: &str) {
if self.case_insensitive {
self.entries.insert(key.to_lowercase(), PathBuf::from(path));
} else {
self.entries.insert(key.to_string(), PathBuf::from(path));
}
}
pub fn lookup(&self, name: &str) -> Option<&PathBuf> {
if self.case_insensitive {
self.entries.get(&name.to_lowercase())
} else {
self.entries.get(name)
}
}
pub fn is_empty(&self) -> bool {
self.entries.is_empty()
}
pub fn len(&self) -> usize {
self.entries.len()
}
pub fn clear(&mut self) {
self.entries.clear();
}
pub fn parse_text(content: &str) -> Self {
let mut hm = Self::new();
for line in content.lines() {
let trimmed = line.trim();
if trimmed.is_empty() || trimmed.starts_with('#') || trimmed.starts_with("//") {
continue;
}
if let Some(eq) = trimmed.find('=') {
let key = trimmed[..eq].trim();
let value = trimmed[eq + 1..].trim();
hm.add(key, value);
}
}
hm
}
}
#[cfg(test)]
mod header_map_tests {
use super::*;
#[test]
fn test_header_map_new() {
let hm = HeaderMap::new();
assert!(hm.is_empty());
assert_eq!(hm.len(), 0);
}
#[test]
fn test_header_map_add_and_lookup() {
let mut hm = HeaderMap::new();
hm.add("stddef.h", "/usr/include/stddef.h");
assert_eq!(hm.len(), 1);
assert_eq!(
hm.lookup("stddef.h"),
Some(&PathBuf::from("/usr/include/stddef.h"))
);
}
#[test]
fn test_header_map_lookup_missing() {
let hm = HeaderMap::new();
assert!(hm.lookup("missing.h").is_none());
}
#[test]
fn test_header_map_case_insensitive() {
let mut hm = HeaderMap::new().case_insensitive();
hm.add("StdDef.H", "/usr/include/stddef.h");
assert_eq!(
hm.lookup("stddef.H"),
Some(&PathBuf::from("/usr/include/stddef.h"))
);
assert_eq!(
hm.lookup("STDDEF.H"),
Some(&PathBuf::from("/usr/include/stddef.h"))
);
}
#[test]
fn test_header_map_clear() {
let mut hm = HeaderMap::new();
hm.add("a.h", "/a.h");
hm.add("b.h", "/b.h");
hm.clear();
assert!(hm.is_empty());
}
#[test]
fn test_header_map_parse_text_simple() {
let content = "stddef.h=/usr/include/stddef.h\nstdio.h=/usr/include/stdio.h\n";
let hm = HeaderMap::parse_text(content);
assert_eq!(hm.len(), 2);
assert!(hm.lookup("stddef.h").is_some());
assert!(hm.lookup("stdio.h").is_some());
}
#[test]
fn test_header_map_parse_text_with_comments() {
let content = "# comment\nstddef.h=/usr/include/stddef.h\n// another comment\n";
let hm = HeaderMap::parse_text(content);
assert_eq!(hm.len(), 1);
}
#[test]
fn test_header_map_parse_text_empty() {
let hm = HeaderMap::parse_text("");
assert!(hm.is_empty());
}
}
#[cfg(test)]
mod final_integration_tests {
use super::*;
#[test]
fn test_header_search_with_cross_compilation_paths() {
let cp = CrossCompilationPaths::new();
let paths = cp.get("arm-linux-gnueabihf");
assert!(!paths.is_empty());
let mut hs = X86HeaderSearch::new("x86_64-unknown-linux-gnu");
for p in &paths {
hs.add_system_path(&p.to_string_lossy());
}
let dump = hs.dump_paths();
assert!(dump.iter().any(|s| s.contains("arm-linux-gnueabihf")));
}
#[test]
fn test_builder_with_cross_compilation() {
let hs = X86HeaderSearchBuilder::new()
.target("arm-linux-gnueabihf")
.sysroot("/cross/arm/sysroot")
.add_I("/cross/arm/local/include")
.build();
assert!(!hs.dump_paths().is_empty());
}
#[test]
fn test_full_libc_family_integration() {
let triples = [
("x86_64-unknown-linux-gnu", LibcFamily::Glibc),
("x86_64-unknown-linux-musl", LibcFamily::Musl),
("x86_64-linux-android21", LibcFamily::Bionic),
("x86_64-pc-windows-msvc", LibcFamily::MSVCRT),
("x86_64-apple-darwin20", LibcFamily::Darwin),
];
for (triple, expected) in &triples {
assert_eq!(
LibcFamily::from_triple(triple),
*expected,
"Wrong libc for {}",
triple
);
}
}
#[test]
fn test_header_map_with_header_search_integration() {
let mut hm = HeaderMap::new();
hm.add("myheader.h", "/some/where/myheader.h");
let mut hs = X86HeaderSearch::new("x86_64-unknown-linux-gnu");
hs.vfs_overlay
.add_remap("myheader.h", "/some/where/myheader.h");
let result = hs.resolve_system_include("myheader.h");
assert!(result.is_some());
assert_eq!(result.unwrap().0, PathBuf::from("/some/where/myheader.h"));
}
#[test]
fn test_precomputed_cache_with_header_search() {
let cache = PrecomputedHeaderCache::new();
assert!(cache.has("stddef.h"));
assert!(cache.has("assert.h"));
let mut hs = X86HeaderSearch::new("x86_64-unknown-linux-gnu");
let result = hs.resolve_system_include("stddef.h");
assert!(result.is_some());
}
#[test]
fn test_conflict_detector_with_multiple_includes() {
let mut cd = HeaderConflictDetector::new();
cd.record("stdlib.h", Path::new("/usr/include/stdlib.h"));
cd.record("stdlib.h", Path::new("/usr/local/include/stdlib.h"));
assert!(cd.has_conflict("stdlib.h"));
cd.record("assert.h", Path::new("/usr/include/assert.h"));
assert!(!cd.has_conflict("assert.h"));
}
#[test]
fn test_chain_tracker_deep_include_chain() {
let mut tracker = IncludeChainTracker::new();
let files = ["main.c", "a.h", "b.h", "c.h", "d.h", "e.h"];
for (i, f) in files.iter().enumerate() {
tracker.push(Path::new(f), i as u32 + 1);
}
assert_eq!(tracker.depth(), 6);
assert_eq!(tracker.max_depth, 6);
let bt = tracker.backtrace();
assert!(bt[0].contains("e.h"));
assert!(bt[5].contains("main.c"));
}
#[test]
fn test_logger_with_header_search_workflow() {
let mut logger = HeaderSearchLogger::new();
logger.log_resolved("stddef.h", Path::new("<builtin>/stddef.h"), 0);
logger.log_skip("already.h", "guard");
logger.log_not_found("missing.h", "system");
assert_eq!(logger.resolved.len(), 1);
assert_eq!(logger.skipped.len(), 1);
assert_eq!(logger.not_found.len(), 1);
assert_eq!(logger.total_lookups, 2);
}
#[test]
fn test_all_component_integration() {
let hs = X86HeaderSearchBuilder::new()
.target("x86_64-unknown-linux-gnu")
.sysroot("/")
.add_I("/usr/local/include")
.add_isystem("/usr/include")
.define("_GNU_SOURCE", None)
.cxx()
.module_map_dir("/usr/include")
.max_include_depth(256)
.build();
assert!(hs.paths.target_triple.contains("x86_64"));
assert!(hs.builtin_headers.has("stddef.h"));
assert!(hs.intrinsic_headers.has("emmintrin.h"));
assert!(hs.standard_headers.is_known("iostream"));
assert_eq!(hs.max_include_depth, 256);
assert!(hs.use_standard_cxx_includes);
}
}
#[derive(Debug, Clone, Default)]
pub struct HeaderOwnershipResolver {
module_map: X86ModuleMap,
standard_headers: X86StandardHeaders,
ownership_cache: HashMap<String, Option<String>>,
}
impl HeaderOwnershipResolver {
pub fn new() -> Self {
let mut r = Self::default();
r.module_map.generate_standard_modules();
r
}
pub fn resolve(&mut self, header_name: &str) -> Option<String> {
if let Some(cached) = self.ownership_cache.get(header_name) {
return cached.clone();
}
let result = self.module_map.lookup_header(header_name);
self.ownership_cache
.insert(header_name.to_string(), result.clone());
result
}
pub fn belongs_to(&mut self, header_name: &str, module: &str) -> bool {
self.resolve(header_name).map_or(false, |m| m == module)
}
pub fn clear_cache(&mut self) {
self.ownership_cache.clear();
}
}
#[cfg(test)]
mod ownership_tests {
use super::*;
#[test]
fn test_ownership_resolver_new() {
let r = HeaderOwnershipResolver::new();
assert!(r.module_map.find("std").is_some());
}
#[test]
fn test_ownership_resolver_resolve_known() {
let mut r = HeaderOwnershipResolver::new();
let owner = r.resolve("stdio.h");
assert_eq!(owner, Some("std.io".to_string()));
}
#[test]
fn test_ownership_resolver_resolve_unknown() {
let mut r = HeaderOwnershipResolver::new();
let owner = r.resolve("nonexistent_xyz.h");
assert_eq!(owner, None);
}
#[test]
fn test_ownership_resolver_belongs_to() {
let mut r = HeaderOwnershipResolver::new();
assert!(r.belongs_to("stdio.h", "std.io"));
assert!(!r.belongs_to("stdio.h", "std.math"));
}
#[test]
fn test_ownership_resolver_cache() {
let mut r = HeaderOwnershipResolver::new();
let owner1 = r.resolve("stdlib.h");
let owner2 = r.resolve("stdlib.h");
assert_eq!(owner1, owner2);
}
#[test]
fn test_ownership_resolver_clear_cache() {
let mut r = HeaderOwnershipResolver::new();
r.resolve("stdio.h");
r.clear_cache();
let owner = r.resolve("stdio.h");
assert_eq!(owner, Some("std.io".to_string()));
}
}
#[derive(Debug, Clone)]
pub struct HeaderSearchVersion {
pub major: u32,
pub minor: u32,
pub patch: u32,
pub description: String,
}
impl Default for HeaderSearchVersion {
fn default() -> Self {
Self {
major: 1,
minor: 0,
patch: 0,
description: "X86 Header Search Engine".into(),
}
}
}
impl fmt::Display for HeaderSearchVersion {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{} v{}.{}.{}",
self.description, self.major, self.minor, self.patch
)
}
}
pub fn create_x86_header_search(triple: &str) -> X86HeaderSearch {
X86HeaderSearch::new(triple).with_standard_includes()
}
pub fn create_x86_header_search_freestanding(triple: &str) -> X86HeaderSearch {
let mut hs = X86HeaderSearch::new(triple);
hs.disable_standard_includes();
hs.disable_builtin_includes();
hs
}
#[cfg(test)]
mod final_tests {
use super::*;
#[test]
fn test_header_search_version_default() {
let v = HeaderSearchVersion::default();
assert_eq!(v.major, 1);
assert_eq!(v.minor, 0);
assert_eq!(v.patch, 0);
assert!(v.description.contains("X86"));
}
#[test]
fn test_header_search_version_display() {
let v = HeaderSearchVersion::default();
let s = v.to_string();
assert!(s.contains("v1.0.0"));
}
#[test]
fn test_create_x86_header_search() {
let hs = create_x86_header_search("x86_64-unknown-linux-gnu");
assert!(hs.use_standard_system_includes);
assert!(hs.builtin_headers.has("stddef.h"));
}
#[test]
fn test_create_x86_header_search_freestanding() {
let hs = create_x86_header_search_freestanding("x86_64-unknown-linux-gnu");
assert!(!hs.use_standard_system_includes);
assert!(!hs.use_standard_cxx_includes);
}
#[test]
fn test_create_various_targets() {
for t in &[
"x86_64-unknown-linux-gnu",
"i686-unknown-linux-gnu",
"x86_64-apple-darwin20",
"x86_64-pc-windows-msvc",
] {
let hs = create_x86_header_search(t);
assert!(hs
.paths
.target_triple
.contains(t.split('-').next().unwrap_or("unknown")));
}
}
#[test]
fn test_all_modules_have_public_members() {
let hs = create_x86_header_search("x86_64-unknown-linux-gnu");
let _ = &hs.paths;
let _ = &hs.builtin_headers;
let _ = &hs.intrinsic_headers;
let _ = &hs.standard_headers;
let _ = &hs.module_map;
let _ = &hs.vfs_overlay;
let _ = &hs.include_cache;
let _ = &hs.header_guard;
}
}
pub mod docs {}