Fastfetch Hardware Detection Architecture: Modular Design and OS Abstraction
TLDR: Fastfetch implements a layered hardware detection system where OS-specific implementations are abstracted behind uniform public APIs, allowing portable detection of CPU, GPU, memory, and disk information across Linux, Windows, and macOS.
According to the fastfetch-cli/fastfetch source code, the hardware detection system is organized under src/detection/ using a three-tier architecture: OS-specific collectors, platform-agnostic dispatchers, and high-level result consumers. This design separates data acquisition from presentation, enabling consistent hardware reporting across all supported platforms.
Core Architecture Principles
The architecture follows three fundamental principles that govern all detection modules from CPU to physical disk enumeration.
Separate Result Types
Every hardware component defines a dedicated result struct that holds collected data. For example, src/detection/cpu/cpu.h defines FFCPUResult containing fields for name, vendor, frequencyMax, and temperature. Similarly, src/detection/gpu/gpu.h declares FFGPUResult with vendor information, device names, and memory specifications. These structs act as the strict contract between detection logic and consuming modules, ensuring type safety across the codebase.
Per-OS Implementations
Detection logic resides in files following the pattern <component>_<os>.c. At compile time, the build system selects the appropriate implementation for the target platform. For CPU detection, the repository contains src/detection/cpu/cpu_linux.c (procfs/sysfs parsing), src/detection/cpu/cpu_windows.c (registry/WMI queries), and src/detection/cpu/cpu_apple.m (sysctl/IOKit). Each file implements a private ffDetect<Component>Impl function that populates the result struct using native system APIs.
Uniform Public API
Every detection module exposes a single entry point: ffDetect<Thing>(const FF<Thing>Options*, FF<Thing>Result*). This function returns const char* containing an error message or NULL on success. The dispatcher lives in the platform-agnostic source file (e.g., src/detection/cpu/cpu.c), which forwards calls to the OS-specific implementation and performs generic post-processing such as stripping vendor prefixes or normalizing frequency units.
Detection Flow and Data Pipeline
The hardware detection process follows a strict five-stage pipeline:
- Module Entry Point – A Fastfetch module (e.g.,
src/modules/cpu/cpu.c) initializes an empty result struct and invokes the public API. - Dispatcher – The platform-agnostic file (
src/detection/cpu/cpu.c) receives the call and forwards it toffDetectCPUImpl. - OS-Specific Collection – The implementation file gathers raw data using native APIs such as procfs on Linux, Windows registry queries, or macOS IOKit.
- Post-Processing – The dispatcher performs generic cleanup, such as normalizing CPU vendor strings or converting memory units.
- Result Consumption – The calling module formats the populated struct for terminal output or JSON serialization.
+----------------------+ +------------------------+
| src/modules/cpu.c | ---> | src/detection/cpu.c |
+----------------------+ +------------------------+
|
+--------------------------+--------------------------+
| | |
+---------------------+ +---------------------+ +---------------------+
| cpu_linux.c | | cpu_windows.c | | cpu_apple.m |
+---------------------+ +---------------------+ +---------------------+
Multi-Backend Detection Strategies
Some components support multiple detection backends to handle varying hardware configurations. The ffDetectGPU function in src/detection/gpu/gpu.c implements a fallback chain: PCI → Vulkan → OpenCL → OpenGL.
The detection function receives an options struct containing a detectionMethod enum. When FF_GPU_DETECTION_METHOD_AUTO is specified, Fastfetch attempts methods in order of preference, falling back to the next if a method fails or is disabled at compile time. This logic is contained entirely within the component's main detection file, while OS-specific files in src/detection/gpu/gpu_linux.c and src/detection/gpu/gpu_windows.c handle the low-level API interactions for each respective method.
Extending the Architecture
Adding new hardware support requires four steps without modifying existing display logic:
- Define the contract – Create
src/detection/foobar/foobar.hwith theFFFooBarResultstruct andffDetectFooBarfunction declaration. - Implement OS collectors – Add
foobar_linux.c,foobar_windows.c, andfoobar_apple.cimplementing the privateffDetectFooBarImplfunction. - Add dispatcher – Create
foobar.cwith the publicffDetectFooBarfunction that routes calls to OS implementations and performs data cleaning. - Create module – Add
src/modules/foobar/foobar.cto call the detection API and handle output formatting.
The existing ffPrint and ffGenerateJsonResult patterns automatically integrate the new module into JSON generation and CLI output without additional glue code.
Implementation Examples
Detecting CPU Information
The following example demonstrates how to call the CPU detection API from a standalone program:
#include "detection/cpu/cpu.h"
int main(void) {
FFCPUResult cpu = {
.temperature = FF_CPU_TEMP_UNSET,
.frequencyMax = 0,
.frequencyBase = 0,
.name = ffStrbufCreate(),
.vendor = ffStrbufCreate(),
};
const char *err = ffDetectCPU(&(FFCPUOptions){}, &cpu);
if (err) {
fprintf(stderr, "CPU detection failed: %s\n", err);
return 1;
}
printf("CPU: %s (%s) @ %u MHz\n",
cpu.name.chars,
cpu.vendor.chars,
cpu.frequencyMax ? cpu.frequencyMax : cpu.frequencyBase);
ffStrbufDestroy(&cpu.name);
ffStrbufDestroy(&cpu.vendor);
return 0;
}
Configuring GPU Detection Methods
To explicitly control the GPU detection backend, populate the options struct before calling ffDetectGPU:
#include "detection/gpu/gpu.h"
int main(void) {
FFlist gpus;
ffListInit(&gpus);
FFGPUOptions opt = {
.detectionMethod = FF_GPU_DETECTION_METHOD_AUTO,
.temp = true,
};
const char *err = ffDetectGPU(&opt, &gpus);
if (err) {
puts(err);
return 1;
}
for (uint32_t i = 0; i < gpus.length; ++i) {
FFGPUResult *gpu = (FFGPUResult*)ffListGet(&gpus, i);
printf("%s: %s %s\n", gpu->vendor.chars, gpu->name.chars, gpu->memoryType.chars);
}
ffListDestroy(&gpus);
return 0;
}
Summary
- Fastfetch organizes hardware detection into separate result structs, per-OS implementations, and uniform public APIs located under
src/detection/. - The architecture follows a five-stage pipeline: module entry → dispatcher → OS-specific collection → post-processing → result consumption.
- Multi-backend components like GPU detection use fallback chains (PCI → Vulkan → OpenCL → OpenGL) controlled by the
detectionMethodoption insrc/detection/gpu/gpu.c. - Extensibility requires only adding new files in
src/detection/andsrc/modules/without modifying core logic, thanks to the genericffPrintandffGenerateJsonResultpatterns. - All OS-specific code is isolated in files like
cpu_linux.c,gpu_windows.c, andmemory_apple.c, enabling clean cross-platform support through compile-time selection.
Frequently Asked Questions
How does fastfetch handle cross-platform compatibility?
Fastfetch achieves cross-platform compatibility by isolating OS-specific code into separate implementation files (e.g., cpu_linux.c, cpu_windows.c, cpu_apple.m). A platform-agnostic dispatcher in the main component file (e.g., src/detection/cpu/cpu.c) forwards calls to the appropriate OS-specific ffDetect<Component>Impl function at compile time. This ensures that Linux procfs queries, Windows registry access, and macOS IOKit calls never mix in the same compilation unit, preventing platform-specific code from leaking into the generic logic.
What is the fallback order for GPU detection in fastfetch?
According to the src/detection/gpu/gpu.c implementation, fastfetch attempts GPU detection in the following order: PCI (direct hardware enumeration) → Vulkan (graphics API) → OpenCL (compute API) → OpenGL (legacy graphics API). The FF_GPU_DETECTION_METHOD_AUTO enum value triggers this chain automatically, skipping any methods disabled at compile time or unsupported by the hardware. Users can force a specific method by setting the detectionMethod field in the options struct passed to ffDetectGPU.
How can I add support for a new hardware component to fastfetch?
To add a new detector, create a header file in src/detection/foobar/ defining FFFooBarResult and ffDetectFooBar, then implement ffDetectFooBarImpl in OS-specific files (foobar_linux.c, foobar_windows.c, etc.). Add a dispatcher in foobar.c to route calls and clean data, and finally create a module in src/modules/foobar/ to format the output. The existing architecture automatically integrates the new component into JSON generation and CLI output without additional glue code, as all modules follow the standardized ffDetect<Thing> pattern.
Where are the OS-specific detection implementations located?
OS-specific implementations follow the naming convention src/detection/<component>/<component>_<os>.c. For example, Linux CPU detection resides in src/detection/cpu/cpu_linux.c, Windows GPU detection in src/detection/gpu/gpu_windows.c, and macOS memory detection in src/detection/memory/memory_apple.c. These files contain the low-level system calls using native APIs like procfs, sysctl, or Windows Management Instrumentation (WMI), while the corresponding src/detection/<component>/<component>.c files handle the generic dispatching logic.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →