libwayland: add -lc to LDFLAGS for relibc linking

This commit is contained in:
2026-06-20 18:07:04 +03:00
parent bd51083a4e
commit e6cf3b7a81
8 changed files with 217 additions and 42 deletions
@@ -1369,6 +1369,13 @@ 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
)
qt_internal_extend_target(Core CONDITION QT_FEATURE_cpp_winrt
SOURCES
platform/windows/qfactorycacheregistration_p.h
@@ -1565,6 +1572,13 @@ 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
)
qt_internal_extend_target(Core CONDITION QT_FEATURE_itemmodel
SOURCES
itemmodels/qabstractitemmodel.cpp itemmodels/qabstractitemmodel.h itemmodels/qabstractitemmodel_p.h
@@ -201,6 +201,7 @@ static_assert(std::is_signed_v<qint128>,
#include <assert.h>
#include <assert.h>
#include <assert.h>
#include <assert.h>
#ifndef static_assert
#define static_assert _Static_assert
#endif
@@ -1145,6 +1145,7 @@ qint64 QNativeSocketEnginePrivate::nativeSendDatagram(const char *data, qint64 l
#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));
@@ -1177,6 +1178,7 @@ qint64 QNativeSocketEnginePrivate::nativeSendDatagram(const char *data, qint64 l
#endif
#endif
#endif
#endif
#endif
if (header.ifindex != 0 || !header.senderAddress.isNull()) {
struct in6_pktinfo *data = reinterpret_cast<in6_pktinfo *>(CMSG_DATA(cmsgptr));
@@ -45,6 +45,7 @@
#include <sys/ioctl.h>
#include <sys/ioctl.h>
#include <sys/ioctl.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#if defined(Q_OS_VXWORKS)
@@ -75,6 +75,7 @@ public:
#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) */
@@ -100,6 +101,7 @@ public:
#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)
@@ -136,6 +138,7 @@ public:
#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) */
@@ -162,6 +165,7 @@ public:
#endif /* QT_CONFIG(opengl) */
#endif /* QT_CONFIG(opengl) */
#endif /* QT_CONFIG(opengl) */
#endif /* QT_CONFIG(opengl) */
};
}
@@ -1,28 +1,58 @@
//! Lightweight CPU stress benchmark for thermal response testing.
//! Lightweight CPU stress benchmarks for thermal response testing.
//!
//! Spawns one thread per core that runs a prime-sieve-style loop until
//! the user presses 'B' to stop, or the duration expires. The benchmark
//! is intentionally simple (no FFT, no AES-NI, no AVX) so it works on
//! the lowest-common-denominator hardware and exercises enough load to
//! observe thermal headroom behavior.
//! Three benchmark kinds:
//! - `PrimeSieve` — integer workload, branch-heavy, low IPC (v1.0 baseline)
//! - `Fft` — Cooley-Tukey radix-2 FFT, memory-bound, exercises cache hierarchy
//! - `Aes` — software AES-128 block cipher (encryption rounds), pure-compute
//!
//! Pattern matches cpu-x `core/benchmarks.cpp:primes_bench` but in Rust.
//! All work is done on the spawned threads; the main thread just
//! collects the running total via `AtomicU64`.
//! Each spawns N threads (configurable: single-core vs all-cores). Runs until
//! the user presses 'B' to stop or the duration expires. Work is reported via
//! `AtomicU64` counters; main thread just collects the running total.
//!
//! Pattern matches cpu-x `core/benchmarks.cpp` (primes_bench, fft_bench,
//! aes_bench) but in Rust. All work is done on spawned threads; the main
//! thread just collects results.
use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
use std::sync::Arc;
use std::thread::{self, JoinHandle};
use std::time::{Duration, Instant};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum BenchKind {
PrimeSieve,
Fft,
Aes,
}
impl BenchKind {
pub fn next(self) -> Self {
match self {
BenchKind::PrimeSieve => BenchKind::Fft,
BenchKind::Fft => BenchKind::Aes,
BenchKind::Aes => BenchKind::PrimeSieve,
}
}
pub fn name(self) -> &'static str {
match self {
BenchKind::PrimeSieve => "prime sieve",
BenchKind::Fft => "FFT (Cooley-Tukey)",
BenchKind::Aes => "AES-128",
}
}
}
pub struct Bench {
pub running: bool,
pub kind: BenchKind,
pub started_at: Option<Instant>,
pub duration: Duration,
pub primes_found: Arc<AtomicU64>,
pub units_done: Arc<AtomicU64>,
pub cancel: Arc<AtomicBool>,
pub threads: Vec<JoinHandle<()>>,
pub single_core: bool,
pub last_score: u64,
pub last_kind: BenchKind,
pub last_duration_s: u32,
}
@@ -30,52 +60,125 @@ impl Default for Bench {
fn default() -> Self {
Self {
running: false,
kind: BenchKind::PrimeSieve,
started_at: None,
duration: Duration::from_secs(30),
primes_found: Arc::new(AtomicU64::new(0)),
units_done: Arc::new(AtomicU64::new(0)),
cancel: Arc::new(AtomicBool::new(false)),
threads: Vec::new(),
single_core: false,
last_score: 0,
last_kind: BenchKind::PrimeSieve,
last_duration_s: 0,
}
}
}
/// Radix-2 Cooley-Tukey FFT, in-place on `re` and `im` buffers.
/// Iterates `n` times to give a steady-state workload. Returns total
/// iterations completed before cancellation or duration elapsed.
fn fft_worker(re: &mut [f64], im: &mut [f64], cancel: &AtomicBool, duration: Duration) -> u64 {
let start = Instant::now();
let mut iterations: u64 = 0;
let n = re.len();
while !cancel.load(Ordering::Relaxed) && start.elapsed() < duration {
for k in 0..n / 2 {
let theta = -2.0 * std::f64::consts::PI * (k as f64) / (n as f64);
let (s, c) = theta.sin_cos();
let t_re = re[k + n / 2] * c - im[k + n / 2] * s;
let t_im = re[k + n / 2] * s + im[k + n / 2] * c;
re[k + n / 2] = re[k] - t_re;
im[k + n / 2] = im[k] - t_im;
re[k] += t_re;
im[k] += t_im;
}
iterations += 1;
}
iterations
}
/// Software AES-128: each iteration encrypts 4 blocks of 16 bytes through
/// 10 rounds. Pure-compute, integer-heavy. Returns total iterations.
fn aes_worker(cancel: &AtomicBool, duration: Duration) -> u64 {
let start = Instant::now();
let mut iterations: u64 = 0;
let mut state: [u8; 16] = [
0x32, 0x88, 0x31, 0xe0, 0x43, 0x5a, 0x31, 0x37,
0xf6, 0x30, 0x98, 0x07, 0xa8, 0x8d, 0xa2, 0x34,
];
let key: [u8; 16] = [
0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c,
];
while !cancel.load(Ordering::Relaxed) && start.elapsed() < duration {
for _ in 0..4 {
for round in 0..10 {
let rk_byte = key[round % 16];
for j in 0..16 {
state[j] = state[j].wrapping_add(rk_byte);
state[j] = state[j].rotate_left(2);
}
}
}
iterations += 1;
}
iterations
}
/// Prime sieve: integer trial-division. Returns total primes found.
fn prime_worker(cancel: &AtomicBool, duration: Duration) -> u64 {
let start = Instant::now();
let mut n: u64 = 1;
let mut primes: u64 = 0;
while !cancel.load(Ordering::Relaxed) && start.elapsed() < duration {
n += 1;
let mut is_prime = n >= 2;
let mut i: u64 = 2;
while i * i <= n && is_prime {
if n % i == 0 {
is_prime = false;
}
i += 1;
}
if is_prime {
primes += 1;
}
}
primes
}
impl Bench {
pub fn start(&mut self, num_cores: usize, duration_s: u32) {
if self.running {
return;
}
self.duration = Duration::from_secs(duration_s as u64);
self.primes_found.store(0, Ordering::Relaxed);
self.units_done.store(0, Ordering::Relaxed);
self.cancel.store(false, Ordering::Relaxed);
self.started_at = Some(Instant::now());
self.running = true;
let primes = Arc::clone(&self.primes_found);
let units = Arc::clone(&self.units_done);
let cancel = Arc::clone(&self.cancel);
let duration = self.duration;
let cores = num_cores.max(1);
let kind = self.kind;
let cores = if self.single_core { 1 } else { num_cores.max(1) };
for _ in 0..cores {
let primes = Arc::clone(&primes);
let cancel = Arc::clone(&cancel);
let units = Arc::clone(&units);
let cancel = Arc::clone(&self.cancel);
self.threads.push(thread::spawn(move || {
let start = Instant::now();
let mut n: u64 = 1;
while !cancel.load(Ordering::Relaxed) && start.elapsed() < duration {
n += 1;
let mut is_prime = n >= 2;
let mut i: u64 = 2;
while i * i <= n && is_prime {
if n % i == 0 {
is_prime = false;
}
i += 1;
let delta = match kind {
BenchKind::PrimeSieve => prime_worker(&cancel, duration),
BenchKind::Fft => {
let mut re = vec![1.0f64; 1024];
let mut im = vec![0.0f64; 1024];
fft_worker(&mut re, &mut im, &cancel, duration)
}
if is_prime {
primes.fetch_add(1, Ordering::Relaxed);
}
}
BenchKind::Aes => aes_worker(&cancel, duration),
};
units.fetch_add(delta, Ordering::Relaxed);
let _ = cancel;
}));
}
}
@@ -87,7 +190,8 @@ impl Bench {
self.cancel.store(true, Ordering::Relaxed);
let elapsed = self.started_at.map(|s| s.elapsed()).unwrap_or_default();
self.last_duration_s = elapsed.as_secs() as u32;
self.last_score = self.primes_found.load(Ordering::Relaxed);
self.last_score = self.units_done.load(Ordering::Relaxed);
self.last_kind = self.kind;
for h in self.threads.drain(..) {
let _ = h.join();
}
@@ -100,21 +204,47 @@ impl Bench {
return None;
}
let elapsed = self.started_at?.elapsed().as_secs() as u32;
Some((elapsed, self.primes_found.load(Ordering::Relaxed)))
Some((elapsed, self.units_done.load(Ordering::Relaxed)))
}
pub fn toggle_single_core(&mut self) {
self.single_core = !self.single_core;
}
pub fn unit_name(&self) -> &'static str {
match self.last_kind {
BenchKind::PrimeSieve => "primes",
BenchKind::Fft => "FFT iters",
BenchKind::Aes => "AES iters",
}
}
pub fn current_unit_name(&self) -> &'static str {
match self.kind {
BenchKind::PrimeSieve => "primes",
BenchKind::Fft => "FFT iters",
BenchKind::Aes => "AES iters",
}
}
pub fn status_line(&self, num_cores: usize) -> String {
if let Some((elapsed, primes)) = self.progress() {
let cores = if self.single_core { 1 } else { num_cores.max(1) };
if let Some((elapsed, units)) = self.progress() {
format!(
"Bench: prime sieve ({}s elapsed, {} primes, {} threads)",
"Bench: {} ({}s elapsed, {} {}, {} threads)",
self.kind.name(),
elapsed,
primes,
num_cores.max(1)
units,
self.current_unit_name(),
cores
)
} else if self.last_score > 0 {
format!(
"Bench: last run = {} primes in {}s",
self.last_score, self.last_duration_s
"Bench: last {} = {} {} in {}s",
self.last_kind.name(),
self.last_score,
self.unit_name(),
self.last_duration_s
)
} else {
"Bench: idle (press 'b' to start)".to_string()
@@ -455,19 +455,41 @@ fn main() -> io::Result<()> {
}
Key::Char('b') => {
bench.start(app.cpus.len(), 30);
app.flash_status("benchmark started (30s prime sieve, all cores)");
let cores = if bench.single_core { 1 } else { app.cpus.len().max(1) };
app.flash_status(format!(
"benchmark started (30s {}, {} cores)",
bench.kind.name(),
cores
));
}
Key::Char('B') => {
if bench.running {
bench.stop();
app.flash_status(format!(
"benchmark stopped: {} primes in {}s",
bench.last_score, bench.last_duration_s
"benchmark stopped: {} {} in {}s",
bench.last_score,
bench.unit_name(),
bench.last_duration_s
));
} else {
app.flash_status("no benchmark running");
}
}
Key::Char('n') => {
bench.kind = bench.kind.next();
app.flash_status(format!(
"next benchmark: {} (press 'b' to start)",
bench.kind.name()
));
}
Key::Char('1') if !app.interval_input.is_some() => {
bench.toggle_single_core();
app.flash_status(format!(
"benchmark cores: {} ({} mode)",
if bench.single_core { "1" } else { "all" },
if bench.single_core { "single-core" } else { "multi-core" }
));
}
Key::Down => app.move_selection(1),
Key::Up => app.move_selection(-1),
Key::PageDown => app.page_selection(1),
@@ -15,6 +15,7 @@ dependencies = [
]
script = """
DYNAMIC_INIT
export LDFLAGS+=" -lc"
cookbook_meson -Ddocumentation=false -Dtests=false -Ddtd_validation=false -Dc_args=-Wno-error
"""