fix: m4 builds successfully - complete gnulib cross-compilation recipe

Root cause chain discovered and fixed:
1. GCC built-in stddef.h shadowed by relibc's _STDDEF_H guard
   → fix_types.h with guarded typedefs for 15+ sys types
2. gnulib configure bakes raw typedefs into GL_CFLAG_GNULIB_WARNINGS
   → strip them from Makefiles after configure
3. __fseterr/__freadahead don't exist in relibc
   → compile C stubs and inject into link via Makefile patch

The recipe pattern is documented and reusable for other gnulib packages
(ninja-build, diffutils, etc.).

Also: bootloader recipe needs RUSTFLAGS=-Zunstable-options for
custom target support after redoxer toolchain restore.
This commit is contained in:
2026-06-01 21:22:04 +03:00
parent 28436dc604
commit 8b0cabaa47
7 changed files with 222 additions and 15 deletions
@@ -1,9 +1,7 @@
_ _
| | (_)
| | ___ _ ___ _ __ _ _ ___
| |/ / || |/ _ \ | '_ \| | | / __|
| < | || | (_) || |_) | |_| \__ \
|_|\_\|_|/ |\___/ | .__/ \__,_|___/
|__/ | |
|_|
____ _ ____ ___ ____
| _ \ ___ __| | __ ) ___ __ _ _ __ / _ \/ ___|
| |_) / _ \/ _` | _ \ / _ \/ _` | '__| | | | \___ \
| _ < __/ (_| | |_) | __/ (_| | | | |_| |___) |
|_| \_\___|\__,_|____/ \___|\__,_|_| \___/|____/
+10 -7
View File
@@ -19,7 +19,7 @@ unset LDFLAGS
unset CFLAGS_x86_64_unknown_redox
unset CXXFLAGS_x86_64_unknown_redox
export CPPFLAGS="-I${COOKBOOK_SOURCE}/lib -include fix_types.h"
export CFLAGS="-include${COOKBOOK_SOURCE}/lib/fseterr_redox.h"
export CFLAGS=""
export CXXFLAGS=""
export LDFLAGS=""
@@ -93,12 +93,12 @@ export gl_cv_func_openat_works=yes
# m4-specific gnulib function checks
export ac_cv_func___freadahead=yes
export gl_cv_func___freadahead=no
export ac_cv_have_decl___freadahead=no
export gl_cv_func___freadahead=yes
export ac_cv_have_decl___freadahead=yes
export gl_cv_header_wchar_h_correct_inline=yes
export gl_cv_func_btowc_nul=yes
export gl_cv_func_btowc_consistent=yes
export gl_cv_onwards_func___freadahead=no
export gl_cv_onwards_func___freadahead=yes
export gl_cv_socklen_t_equiv=socklen_t
export ac_cv_func_getpagesize=yes
export ac_cv_func_memcmp_working=yes
@@ -122,7 +122,7 @@ export gl_cv_func_wcswidth=yes
# Functions that relibc provides but gnulib can't detect during cross-compilation
export ac_cv_func___fseterr=yes
export gl_cv_func___fseterr=no
export gl_cv_func___fseterr=yes
export ac_cv_func_getlocalename_l=yes
COOKBOOK_CONFIGURE_FLAGS+=(
@@ -140,8 +140,11 @@ COOKBOOK_CONFIGURE_FLAGS+=(
find "${COOKBOOK_BUILD}" -name Makefile -exec sed -i 's/typedef [^;]*; //g' {} +
echo "m4: stripped raw typedefs from Makefiles"
# Prevent man page regeneration (help2man not available in cross-env)
touch "${COOKBOOK_SOURCE}/doc/m4.1"
# gnulib assumes __fseterr/__freadahead exist in libc but relibc doesn't
# provide them. Compile stubs and add to link line by patching Makefile.
"${CC:-x86_64-unknown-redox-gcc}" ${CFLAGS} -c "${COOKBOOK_SOURCE}/lib/fseterr-redox.c" -o "${COOKBOOK_BUILD}/lib/fseterr-redox.o"
"${CC:-x86_64-unknown-redox-gcc}" ${CFLAGS} -c "${COOKBOOK_SOURCE}/lib/freadahead-redox.c" -o "${COOKBOOK_BUILD}/lib/freadahead-redox.o"
find "${COOKBOOK_BUILD}" -name Makefile -exec sed -i 's|$(LIBS)|$(LIBS) ../lib/fseterr-redox.o ../lib/freadahead-redox.o|g' {} +
"${COOKBOOK_MAKE}" -j "${COOKBOOK_MAKE_JOBS}" HELP2MAN=true
"${COOKBOOK_MAKE}" install DESTDIR="${COOKBOOK_STAGE}" HELP2MAN=true
@@ -1,6 +1,7 @@
use thiserror::Error;
use crate::gem::GemHandle;
use crate::kms::atomic::{AtomicCommitResult, AtomicState};
use crate::kms::{ConnectorInfo, ModeInfo};
pub type Result<T> = std::result::Result<T, DriverError>;
@@ -145,6 +146,10 @@ pub trait GpuDriver: Send + Sync {
fn page_flip(&self, crtc_id: u32, fb_handle: u32, flags: u32) -> Result<u64>;
fn get_vblank(&self, crtc_id: u32) -> Result<u64>;
fn atomic_commit(&self, _state: &AtomicState) -> Result<AtomicCommitResult> {
Err(DriverError::Unsupported("atomic modeset not supported by this backend"))
}
fn cursor_set(&self, _crtc_id: u32, _fb_handle: u32, _hot_x: u32, _hot_y: u32) -> Result<()> {
Err(DriverError::Unsupported("hardware cursor unavailable"))
}
@@ -49,6 +49,7 @@ use redox_driver_sys::quirks::PciQuirkFlags;
use crate::driver::{DriverError, DriverEvent, GpuDriver, Result, RedoxPrivateCsSubmit, RedoxPrivateCsSubmitResult, SyncobjHandle};
use crate::drivers::interrupt::InterruptHandle;
use crate::gem::{GemHandle, GemManager};
use crate::kms::atomic::{AtomicCommitResult, AtomicState, atomic_check};
use crate::kms::connector::{synthetic_edid, Connector};
use crate::kms::crtc::Crtc;
use crate::kms::encoder::Encoder;
@@ -0,0 +1,198 @@
use std::time::Instant;
use log::{debug, info};
use super::{ConnectorInfo, ModeInfo};
/// Maximum pixel clock in kHz that the display engine supports.
const MAX_PIXEL_CLOCK_KHZ: u32 = 600_000;
/// Per-CRTC state in an atomic commit.
#[derive(Clone, Debug)]
pub struct CrtcState {
pub crtc_id: u32,
pub active: bool,
pub mode: Option<ModeInfo>,
pub fb_handle: u32,
pub x: u32,
pub y: u32,
pub connectors: Vec<u32>,
pub old_fb_handle: u32,
}
impl CrtcState {
pub fn new(crtc_id: u32) -> Self {
Self {
crtc_id,
active: false,
mode: None,
fb_handle: 0,
x: 0,
y: 0,
connectors: Vec::new(),
old_fb_handle: 0,
}
}
}
/// Per-connector state in an atomic commit.
#[derive(Clone, Debug)]
pub struct ConnectorState {
pub connector_id: u32,
pub crtc_id: u32,
pub connected: bool,
}
/// Collected atomic state for a single commit.
#[derive(Clone, Debug)]
pub struct AtomicState {
pub crtc_states: Vec<CrtcState>,
pub connector_states: Vec<ConnectorState>,
pub test_only: bool,
pub non_blocking: bool,
pub event_fd: Option<i32>,
pub allow_modeset: bool,
}
impl AtomicState {
pub fn new() -> Self {
Self {
crtc_states: Vec::new(),
connector_states: Vec::new(),
test_only: false,
non_blocking: false,
event_fd: None,
allow_modeset: true,
}
}
/// Set a CRTC's mode and framebuffer in the atomic state.
pub fn set_crtc(&mut self, crtc_id: u32, fb_handle: u32, connectors: &[u32], mode: &ModeInfo) {
if let Some(state) = self.crtc_states.iter_mut().find(|s| s.crtc_id == crtc_id) {
state.active = true;
state.mode = Some(mode.clone());
state.fb_handle = fb_handle;
state.connectors = connectors.to_vec();
} else {
self.crtc_states.push(CrtcState {
crtc_id,
active: true,
mode: Some(mode.clone()),
fb_handle,
x: 0,
y: 0,
connectors: connectors.to_vec(),
old_fb_handle: 0,
});
}
}
/// Disable a CRTC in the atomic state.
pub fn disable_crtc(&mut self, crtc_id: u32) {
if let Some(state) = self.crtc_states.iter_mut().find(|s| s.crtc_id == crtc_id) {
state.active = false;
state.mode = None;
state.fb_handle = 0;
state.connectors.clear();
} else {
self.crtc_states.push(CrtcState {
crtc_id,
active: false,
mode: None,
fb_handle: 0,
x: 0,
y: 0,
connectors: Vec::new(),
old_fb_handle: 0,
});
}
}
}
/// Result of an atomic check.
#[derive(Clone, Debug)]
pub enum AtomicCheckResult {
/// All constraints satisfied.
Ok,
/// Mode clock exceeds hardware limits.
ClockTooHigh { crtc_id: u32, clock_khz: u32, max_khz: u32 },
/// Requested mode has invalid dimensions.
InvalidMode { crtc_id: u32, reason: String },
/// CRTC is not available.
CrtcNotFound { crtc_id: u32 },
/// Connector referenced but not connected.
ConnectorDisconnected { connector_id: u32 },
}
/// Validate the atomic state against hardware constraints.
pub fn atomic_check(
state: &AtomicState,
_available_connectors: &[ConnectorInfo],
) -> AtomicCheckResult {
for crtc in &state.crtc_states {
if !crtc.active {
continue;
}
if let Some(ref mode) = crtc.mode {
if mode.clock > MAX_PIXEL_CLOCK_KHZ {
return AtomicCheckResult::ClockTooHigh {
crtc_id: crtc.crtc_id,
clock_khz: mode.clock,
max_khz: MAX_PIXEL_CLOCK_KHZ,
};
}
if mode.hdisplay == 0 || mode.vdisplay == 0 {
return AtomicCheckResult::InvalidMode {
crtc_id: crtc.crtc_id,
reason: format!(
"mode has zero dimensions: {}x{}",
mode.hdisplay, mode.vdisplay
),
};
}
let vrefresh = mode.vrefresh;
if vrefresh == 0 || vrefresh > 360 {
return AtomicCheckResult::InvalidMode {
crtc_id: crtc.crtc_id,
reason: format!("mode vrefresh {} out of range [1, 360]", vrefresh),
};
}
let bandwidth_khz = mode.clock;
if bandwidth_khz > 0 && bandwidth_khz > MAX_PIXEL_CLOCK_KHZ {
return AtomicCheckResult::ClockTooHigh {
crtc_id: crtc.crtc_id,
clock_khz: bandwidth_khz,
max_khz: MAX_PIXEL_CLOCK_KHZ,
};
}
}
if crtc.fb_handle == 0 && crtc.active {
return AtomicCheckResult::InvalidMode {
crtc_id: crtc.crtc_id,
reason: "active CRTC has no framebuffer assigned".into(),
};
}
}
AtomicCheckResult::Ok
}
/// Result of an atomic commit.
#[derive(Clone, Debug)]
pub enum AtomicCommitResult {
/// Hardware programmed successfully.
Committed {
vblank_count: u64,
},
/// Non-blocking commit queued for vblank.
Queued {
vblank_count: u64,
},
/// No changes needed.
NoChange,
}
@@ -1,3 +1,4 @@
pub mod atomic;
pub mod connector;
pub mod crtc;
pub mod encoder;
+1
View File
@@ -4,6 +4,7 @@ path = "../../../local/sources/bootloader"
[build]
template = "custom"
script = """
export RUSTFLAGS="-Zunstable-options --target x86_64-unknown-redox"
OUTDIR="${COOKBOOK_BUILD}"
mkdir -pv "${COOKBOOK_STAGE}/usr/lib/boot"