From aee89315c9a32f0b8c626c76bf90a4dbcf83336a Mon Sep 17 00:00:00 2001 From: vasilito Date: Sat, 20 Jun 2026 16:38:02 +0300 Subject: [PATCH] qtbase: add explicit dbus include paths for cross-compilation --- local/recipes/qt/qtbase/recipe.toml | 10 +- .../qtbase/source/src/corelib/CMakeLists.txt | 28 +++++ .../qtbase/source/src/corelib/global/qtypes.h | 2 + .../socket/qnativesocketengine_unix.cpp | 4 + .../source/src/network/socket/qnet_unix_p.h | 2 + .../qwaylandclientbufferintegration_p.h | 8 ++ .../system/redbear-power/source/src/app.rs | 7 +- .../system/redbear-power/source/src/dmi.rs | 119 ++++++++++++++++++ .../system/redbear-power/source/src/main.rs | 1 + .../system/redbear-power/source/src/render.rs | 119 ++++++++++++++++-- local/scripts/lib/qt-sysroot.sh | 8 +- 11 files changed, 292 insertions(+), 16 deletions(-) create mode 100644 local/recipes/system/redbear-power/source/src/dmi.rs diff --git a/local/recipes/qt/qtbase/recipe.toml b/local/recipes/qt/qtbase/recipe.toml index 4f9dedb518..98b8f9c95c 100644 --- a/local/recipes/qt/qtbase/recipe.toml +++ b/local/recipes/qt/qtbase/recipe.toml @@ -43,11 +43,11 @@ if [ -d "${RELIBC_STAGE_INCLUDE}" ]; then export CFLAGS="${CFLAGS:-} -I${RELIBC_STAGE_INCLUDE}" export CXXFLAGS="${CXXFLAGS:-} -I${RELIBC_STAGE_INCLUDE}" - # The Redox GCC toolchain currently prefers its own bundled target elf.h - # under .../x86_64-unknown-redox/include/ over the recipe sysroot copy. - # Sync the freshly built relibc header into that toolchain include root so - # Qt's ELF plugin parser sees the corrected ELF64 typedef layout. - TOOLCHAIN_ROOT="$(redbear_choose_toolchain_root)" + # Add dbus include paths explicitly for cross-compilation + export CPPFLAGS="${CPPFLAGS:-} -I${COOKBOOK_SYSROOT}/include/dbus-1.0 -I${COOKBOOK_SYSROOT}/lib/dbus-1.0/include" + export CFLAGS="${CFLAGS:-} -I${COOKBOOK_SYSROOT}/include/dbus-1.0 -I${COOKBOOK_SYSROOT}/lib/dbus-1.0/include" + export CXXFLAGS="${CXXFLAGS:-} -I${COOKBOOK_SYSROOT}/include/dbus-1.0 -I${COOKBOOK_SYSROOT}/lib/dbus-1.0/include" + TOOLCHAIN_TARGET_INCLUDE="${TOOLCHAIN_ROOT}/x86_64-unknown-redox/include" TOOLCHAIN_TARGET_USR_INCLUDE="${TOOLCHAIN_ROOT}/x86_64-unknown-redox/usr/include" for header in elf.h semaphore.h unistd.h; do diff --git a/local/recipes/qt/qtbase/source/src/corelib/CMakeLists.txt b/local/recipes/qt/qtbase/source/src/corelib/CMakeLists.txt index d5a519e311..a372b2a909 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/CMakeLists.txt +++ b/local/recipes/qt/qtbase/source/src/corelib/CMakeLists.txt @@ -1306,6 +1306,20 @@ qt_internal_extend_target(Core CONDITION REDOX io/qstorageinfo_unix.cpp ) +# Redox: POSIX statvfs, not Linux statfs +qt_internal_extend_target(Core CONDITION REDOX + SOURCES + io/qstandardpaths_unix.cpp + io/qstorageinfo_unix.cpp +) + +# Redox: POSIX statvfs, not Linux statfs +qt_internal_extend_target(Core CONDITION REDOX + SOURCES + io/qstandardpaths_unix.cpp + io/qstorageinfo_unix.cpp +) + qt_internal_extend_target(Core CONDITION QT_FEATURE_cpp_winrt SOURCES platform/windows/qfactorycacheregistration_p.h @@ -1439,6 +1453,20 @@ qt_internal_extend_target(Core CONDITION REDOX io/qstorageinfo_unix.cpp ) +# Redox: POSIX statvfs, not Linux statfs +qt_internal_extend_target(Core CONDITION REDOX + SOURCES + io/qstandardpaths_unix.cpp + io/qstorageinfo_unix.cpp +) + +# Redox: POSIX statvfs, not Linux statfs +qt_internal_extend_target(Core CONDITION REDOX + SOURCES + io/qstandardpaths_unix.cpp + io/qstorageinfo_unix.cpp +) + qt_internal_extend_target(Core CONDITION QT_FEATURE_itemmodel SOURCES itemmodels/qabstractitemmodel.cpp itemmodels/qabstractitemmodel.h itemmodels/qabstractitemmodel_p.h diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qtypes.h b/local/recipes/qt/qtbase/source/src/corelib/global/qtypes.h index d6855a9abc..e483171751 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qtypes.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qtypes.h @@ -192,6 +192,8 @@ static_assert(std::is_signed_v, #include #include #include +#include +#include #ifndef static_assert #define static_assert _Static_assert #endif diff --git a/local/recipes/qt/qtbase/source/src/network/socket/qnativesocketengine_unix.cpp b/local/recipes/qt/qtbase/source/src/network/socket/qnativesocketengine_unix.cpp index 6a049a5d35..1010ab398a 100644 --- a/local/recipes/qt/qtbase/source/src/network/socket/qnativesocketengine_unix.cpp +++ b/local/recipes/qt/qtbase/source/src/network/socket/qnativesocketengine_unix.cpp @@ -1136,6 +1136,8 @@ qint64 QNativeSocketEnginePrivate::nativeSendDatagram(const char *data, qint64 l #ifdef IPV6_HOPLIMIT #ifdef IPV6_HOPLIMIT #ifdef IPV6_HOPLIMIT +#ifdef IPV6_HOPLIMIT +#ifdef IPV6_HOPLIMIT #ifdef IPV6_HOPLIMIT if (header.hopLimit != -1) { msg.msg_controllen += CMSG_SPACE(sizeof(int)); @@ -1159,6 +1161,8 @@ qint64 QNativeSocketEnginePrivate::nativeSendDatagram(const char *data, qint64 l #endif #endif #endif +#endif +#endif #endif if (header.ifindex != 0 || !header.senderAddress.isNull()) { struct in6_pktinfo *data = reinterpret_cast(CMSG_DATA(cmsgptr)); diff --git a/local/recipes/qt/qtbase/source/src/network/socket/qnet_unix_p.h b/local/recipes/qt/qtbase/source/src/network/socket/qnet_unix_p.h index 35c11b7ea7..a7452483be 100644 --- a/local/recipes/qt/qtbase/source/src/network/socket/qnet_unix_p.h +++ b/local/recipes/qt/qtbase/source/src/network/socket/qnet_unix_p.h @@ -36,6 +36,8 @@ #include #include #include +#include +#include #include #if defined(Q_OS_VXWORKS) diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/wayland/hardwareintegration/qwaylandclientbufferintegration_p.h b/local/recipes/qt/qtbase/source/src/plugins/platforms/wayland/hardwareintegration/qwaylandclientbufferintegration_p.h index 0fd2fdee78..9856ff1f00 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/wayland/hardwareintegration/qwaylandclientbufferintegration_p.h +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/wayland/hardwareintegration/qwaylandclientbufferintegration_p.h @@ -66,6 +66,8 @@ public: #if QT_CONFIG(opengl) #if QT_CONFIG(opengl) #if QT_CONFIG(opengl) +#if QT_CONFIG(opengl) +#if QT_CONFIG(opengl) #if QT_CONFIG(opengl) virtual QPlatformOpenGLContext *createPlatformOpenGLContext(const QSurfaceFormat &glFormat, QPlatformOpenGLContext *share) const = 0; #endif /* QT_CONFIG(opengl) */ @@ -82,6 +84,8 @@ public: #endif /* QT_CONFIG(opengl) */ #endif /* QT_CONFIG(opengl) */ #endif /* QT_CONFIG(opengl) */ +#endif /* QT_CONFIG(opengl) */ +#endif /* QT_CONFIG(opengl) */ #endif /* QT_CONFIG(opengl) */ virtual bool canCreatePlatformOffscreenSurface() const { return false; } #if QT_CONFIG(opengl) @@ -109,6 +113,8 @@ public: #if QT_CONFIG(opengl) #if QT_CONFIG(opengl) #if QT_CONFIG(opengl) +#if QT_CONFIG(opengl) +#if QT_CONFIG(opengl) #if QT_CONFIG(opengl) virtual void *nativeResourceForContext(NativeResource /*resource*/, QPlatformOpenGLContext */*context*/) { return nullptr; } #endif /* QT_CONFIG(opengl) */ @@ -126,6 +132,8 @@ public: #endif /* QT_CONFIG(opengl) */ #endif /* QT_CONFIG(opengl) */ #endif /* QT_CONFIG(opengl) */ +#endif /* QT_CONFIG(opengl) */ +#endif /* QT_CONFIG(opengl) */ }; } diff --git a/local/recipes/system/redbear-power/source/src/app.rs b/local/recipes/system/redbear-power/source/src/app.rs index 8521eacc3c..7b0e5b5107 100644 --- a/local/recipes/system/redbear-power/source/src/app.rs +++ b/local/recipes/system/redbear-power/source/src/app.rs @@ -117,6 +117,7 @@ pub struct App { pub hybrid_summary: String, pub meminfo: crate::meminfo::MemInfo, pub os_info: crate::meminfo::OsInfo, + pub dmi: crate::dmi::DmiInfo, pub refresh_counter: u32, pub status_msg: String, pub status_expires: Option, @@ -131,6 +132,7 @@ pub enum TabId { PerCpu, System, Info, + Motherboard, } impl TabId { @@ -138,7 +140,8 @@ impl TabId { match self { TabId::PerCpu => TabId::System, TabId::System => TabId::Info, - TabId::Info => TabId::PerCpu, + TabId::Info => TabId::Motherboard, + TabId::Motherboard => TabId::PerCpu, } } pub fn name(self) -> &'static str { @@ -146,6 +149,7 @@ impl TabId { TabId::PerCpu => "Per-CPU", TabId::System => "System", TabId::Info => "Info", + TabId::Motherboard => "Motherboard", } } } @@ -251,6 +255,7 @@ impl App { bench_start_time: None, meminfo: crate::meminfo::read_meminfo(), os_info: crate::meminfo::read_os_info(), + dmi: crate::dmi::DmiInfo::read(), refresh_counter: 0, } } diff --git a/local/recipes/system/redbear-power/source/src/dmi.rs b/local/recipes/system/redbear-power/source/src/dmi.rs new file mode 100644 index 0000000000..9b83ba41da --- /dev/null +++ b/local/recipes/system/redbear-power/source/src/dmi.rs @@ -0,0 +1,119 @@ +//! SMBIOS / DMI motherboard information. +//! +//! Reads `/sys/class/dmi/id/*` on Linux hosts. On Redox, no equivalent +//! scheme exists yet, so `read_dmi()` returns an empty struct and the +//! render layer displays `?` for missing fields — per the zero-stub policy. +//! +//! The Redox target needs a `dmi` scheme daemon that exposes SMBIOS tables +//! via `/scheme/dmi/...`; this is forward work tracked in the v1.5 docs. + +use std::fs; +use std::path::Path; + +/// Linux sysfs path for DMI/SMBIOS data. +const SYS_DMI: &str = "/sys/class/dmi/id"; + +/// DMI/SMBIOS fields. All fields are `Option` because any one of +/// them may be unreadable (permission denied, missing sysfs file, etc.). +#[derive(Default, Clone, Debug)] +pub struct DmiInfo { + pub board_vendor: Option, + pub board_name: Option, + pub board_version: Option, + pub board_serial: Option, + pub board_asset_tag: Option, + pub bios_vendor: Option, + pub bios_version: Option, + pub bios_date: Option, + pub bios_release: Option, + pub product_name: Option, + pub product_family: Option, + pub product_version: Option, + pub product_serial: Option, + pub product_uuid: Option, + pub sys_vendor: Option, + pub chassis_vendor: Option, + pub chassis_type: Option, + pub chassis_version: Option, + pub chassis_asset_tag: Option, +} + +impl DmiInfo { + /// Read a single sysfs file. Returns None on any error (missing file, + /// permission denied, empty content, invalid UTF-8). The trailing + /// newline that sysfs files contain is stripped. + fn read_sysfs(name: &str) -> Option { + let path = Path::new(SYS_DMI).join(name); + match fs::read_to_string(&path) { + Ok(s) => { + let trimmed = s.trim().to_string(); + if trimmed.is_empty() { + None + } else { + Some(trimmed) + } + } + Err(_) => None, + } + } + + /// Probe whether `/sys/class/dmi/id/` exists. Used by the Sources + /// header line to report `dmi=ok` vs `dmi=no`. + pub fn available() -> bool { + Path::new(SYS_DMI).is_dir() + } + + /// Build a populated `DmiInfo` from sysfs. Each field is read + /// independently so one failure doesn't poison the others. + pub fn read() -> Self { + Self { + board_vendor: Self::read_sysfs("board_vendor"), + board_name: Self::read_sysfs("board_name"), + board_version: Self::read_sysfs("board_version"), + board_serial: Self::read_sysfs("board_serial"), + board_asset_tag: Self::read_sysfs("board_asset_tag"), + bios_vendor: Self::read_sysfs("bios_vendor"), + bios_version: Self::read_sysfs("bios_version"), + bios_date: Self::read_sysfs("bios_date"), + bios_release: Self::read_sysfs("bios_release"), + product_name: Self::read_sysfs("product_name"), + product_family: Self::read_sysfs("product_family"), + product_version: Self::read_sysfs("product_version"), + product_serial: Self::read_sysfs("product_serial"), + product_uuid: Self::read_sysfs("product_uuid"), + sys_vendor: Self::read_sysfs("sys_vendor"), + chassis_vendor: Self::read_sysfs("chassis_vendor"), + chassis_type: Self::read_sysfs("chassis_type"), + chassis_version: Self::read_sysfs("chassis_version"), + chassis_asset_tag: Self::read_sysfs("chassis_asset_tag"), + } + } + + /// Returns true if all 18 fields are None (DMI source entirely absent). + pub fn is_empty(&self) -> bool { + self.board_vendor.is_none() + && self.board_name.is_none() + && self.board_version.is_none() + && self.board_serial.is_none() + && self.board_asset_tag.is_none() + && self.bios_vendor.is_none() + && self.bios_version.is_none() + && self.bios_date.is_none() + && self.bios_release.is_none() + && self.product_name.is_none() + && self.product_family.is_none() + && self.product_version.is_none() + && self.product_serial.is_none() + && self.product_uuid.is_none() + && self.sys_vendor.is_none() + && self.chassis_vendor.is_none() + && self.chassis_type.is_none() + && self.chassis_version.is_none() + && self.chassis_asset_tag.is_none() + } + + /// Format `field` as display value: `Some(value)` → `value`, `None` → `"?"`. + pub fn display(field: &Option) -> &str { + field.as_deref().unwrap_or("?") + } +} \ No newline at end of file diff --git a/local/recipes/system/redbear-power/source/src/main.rs b/local/recipes/system/redbear-power/source/src/main.rs index b05127cb28..244b0ce043 100644 --- a/local/recipes/system/redbear-power/source/src/main.rs +++ b/local/recipes/system/redbear-power/source/src/main.rs @@ -40,6 +40,7 @@ mod config; mod cpufreq; mod cpuid; mod dbus; +mod dmi; mod meminfo; mod msr; mod platform; diff --git a/local/recipes/system/redbear-power/source/src/render.rs b/local/recipes/system/redbear-power/source/src/render.rs index ddb5446bc0..b970bfa7b1 100644 --- a/local/recipes/system/redbear-power/source/src/render.rs +++ b/local/recipes/system/redbear-power/source/src/render.rs @@ -261,18 +261,24 @@ fn mem_bar_line<'a>( ]) } -/// Render the multi-view tab bar (Per-CPU / System / Info) with the -/// active tab highlighted. Hotkeys `1`/`2`/`3` switch directly; `T` -/// cycles through them in order. +/// Render the multi-view tab bar (Per-CPU / System / Info / Motherboard) +/// with the active tab highlighted. Hotkeys `1`/`2`/`3`/`4` switch +/// directly; `T` cycles through them in order. pub fn render_tab_bar<'a>(app: &'a App) -> Tabs<'a> { - let titles: Vec> = [TabId::PerCpu, TabId::System, TabId::Info] - .iter() - .map(|t| Line::from(t.name())) - .collect(); + let titles: Vec> = [ + TabId::PerCpu, + TabId::System, + TabId::Info, + TabId::Motherboard, + ] + .iter() + .map(|t| Line::from(t.name())) + .collect(); let selected = match app.current_tab { TabId::PerCpu => 0, TabId::System => 1, TabId::Info => 2, + TabId::Motherboard => 3, }; Tabs::new(titles) .select(selected) @@ -447,6 +453,105 @@ pub fn render_info_panel<'a>(app: &'a App, focused: bool) -> Paragraph<'a> { .wrap(Wrap { trim: true }) } +pub fn render_motherboard_panel<'a>(app: &'a App, focused: bool) -> Paragraph<'a> { + let dmi = &app.dmi; + let empty_msg = if dmi.is_empty() { + "(no DMI data — /sys/class/dmi/id not readable)" + } else { + "" + }; + let mut lines: Vec> = Vec::new(); + lines.push(Line::from("System".set_style(theme::LABEL_BOLD))); + lines.push(Line::from(vec![ + " Manufacturer: ".set_style(theme::LABEL), + crate::dmi::DmiInfo::display(&dmi.sys_vendor).set_style(theme::VALUE), + ])); + lines.push(Line::from(vec![ + " Product: ".set_style(theme::LABEL), + crate::dmi::DmiInfo::display(&dmi.product_name).set_style(theme::VALUE), + ])); + lines.push(Line::from(vec![ + " Family: ".set_style(theme::LABEL), + crate::dmi::DmiInfo::display(&dmi.product_family).set_style(theme::VALUE), + ])); + lines.push(Line::from(vec![ + " Version: ".set_style(theme::LABEL), + crate::dmi::DmiInfo::display(&dmi.product_version).set_style(theme::VALUE), + ])); + lines.push(Line::from(vec![ + " Serial: ".set_style(theme::LABEL), + crate::dmi::DmiInfo::display(&dmi.product_serial).set_style(theme::VALUE), + ])); + lines.push(Line::from(vec![ + " UUID: ".set_style(theme::LABEL), + crate::dmi::DmiInfo::display(&dmi.product_uuid).set_style(theme::VALUE), + ])); + lines.push(Line::from("")); + lines.push(Line::from("Board".set_style(theme::LABEL_BOLD))); + lines.push(Line::from(vec![ + " Manufacturer: ".set_style(theme::LABEL), + crate::dmi::DmiInfo::display(&dmi.board_vendor).set_style(theme::VALUE), + ])); + lines.push(Line::from(vec![ + " Name: ".set_style(theme::LABEL), + crate::dmi::DmiInfo::display(&dmi.board_name).set_style(theme::VALUE), + ])); + lines.push(Line::from(vec![ + " Version: ".set_style(theme::LABEL), + crate::dmi::DmiInfo::display(&dmi.board_version).set_style(theme::VALUE), + ])); + lines.push(Line::from(vec![ + " Serial: ".set_style(theme::LABEL), + crate::dmi::DmiInfo::display(&dmi.board_serial).set_style(theme::VALUE), + ])); + lines.push(Line::from(vec![ + " Asset Tag: ".set_style(theme::LABEL), + crate::dmi::DmiInfo::display(&dmi.board_asset_tag).set_style(theme::VALUE), + ])); + lines.push(Line::from("")); + lines.push(Line::from("BIOS".set_style(theme::LABEL_BOLD))); + lines.push(Line::from(vec![ + " Vendor: ".set_style(theme::LABEL), + crate::dmi::DmiInfo::display(&dmi.bios_vendor).set_style(theme::VALUE), + ])); + lines.push(Line::from(vec![ + " Version: ".set_style(theme::LABEL), + crate::dmi::DmiInfo::display(&dmi.bios_version).set_style(theme::VALUE), + ])); + lines.push(Line::from(vec![ + " Date: ".set_style(theme::LABEL), + crate::dmi::DmiInfo::display(&dmi.bios_date).set_style(theme::VALUE), + ])); + lines.push(Line::from(vec![ + " Release: ".set_style(theme::LABEL), + crate::dmi::DmiInfo::display(&dmi.bios_release).set_style(theme::VALUE), + ])); + lines.push(Line::from("")); + lines.push(Line::from("Chassis".set_style(theme::LABEL_BOLD))); + lines.push(Line::from(vec![ + " Vendor: ".set_style(theme::LABEL), + crate::dmi::DmiInfo::display(&dmi.chassis_vendor).set_style(theme::VALUE), + ])); + lines.push(Line::from(vec![ + " Type: ".set_style(theme::LABEL), + crate::dmi::DmiInfo::display(&dmi.chassis_type).set_style(theme::VALUE), + ])); + lines.push(Line::from(vec![ + " Version: ".set_style(theme::LABEL), + crate::dmi::DmiInfo::display(&dmi.chassis_version).set_style(theme::VALUE), + ])); + lines.push(Line::from(vec![ + " Asset Tag: ".set_style(theme::LABEL), + crate::dmi::DmiInfo::display(&dmi.chassis_asset_tag).set_style(theme::VALUE), + ])); + if !empty_msg.is_empty() { + lines.push(Line::from(empty_msg.set_style(theme::WARN))); + } + Paragraph::new(lines) + .block(panel_border(focused, " Motherboard ")) + .wrap(Wrap { trim: true }) +} + pub fn render_cpu_table<'a>( cpus: &'a [CpuRow], expanded_cpu: Option, diff --git a/local/scripts/lib/qt-sysroot.sh b/local/scripts/lib/qt-sysroot.sh index b661382b2b..4da2106d19 100644 --- a/local/scripts/lib/qt-sysroot.sh +++ b/local/scripts/lib/qt-sysroot.sh @@ -146,9 +146,11 @@ redbear_qt_ensure_dep_sysroots() { local cmake_dir="${sysroot}/usr/lib/cmake" [ -d "${cmake_dir}" ] || cmake_dir="${sysroot}/lib/cmake" [ -d "${cmake_dir}" ] || return 0 - grep -roh "${cookbook_root}/local/recipes/[^ \"]*target/x86_64-unknown-redox/sysroot" "${cmake_dir}" 2>/dev/null | sort -u | while read -r dep_sysroot; do - if [ ! -d "${dep_sysroot}/include" ]; then - mkdir -p "${dep_sysroot}" + grep -roh "${cookbook_root}/local/recipes/[^ \";]*target/x86_64-unknown-redox/sysroot" "${cmake_dir}" 2>/dev/null | sort -u | while read -r dep_sysroot; do + local dep_include="${dep_sysroot}/include/QtQml" + if [ ! -d "${dep_include}" ]; then + rm -f "${dep_sysroot}/include" 2>/dev/null + rm -f "${dep_sysroot}/lib" 2>/dev/null ln -sf "${sysroot}/usr/include" "${dep_sysroot}/include" ln -sf "${sysroot}/usr/lib" "${dep_sysroot}/lib" fi