qtbase: ensure KHR/khrplatform.h exists in sysroot for OpenGL/EGL includes

- Add fallback to copy from sysroot/usr/include/KHR/ if available
- Generate minimal khrplatform.h stub if neither exists
- Fixes build failure where Qt's qopengl.h cannot find KHR/khrplatform.h
This commit is contained in:
2026-06-20 23:41:21 +03:00
parent 79d00e2372
commit 4738b722fd
4 changed files with 271 additions and 15 deletions
@@ -82,6 +82,7 @@ find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED)
find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED)
find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED)
find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED)
find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED)
set(EXCLUDE_DEPRECATED_BEFORE_AND_AT 0 CACHE STRING "Control the range of deprecated API excluded from the build [default=0].")
+35
View File
@@ -129,6 +129,41 @@ GLES3_EOF
fi
done
# Also ensure KHR/khrplatform.h exists for Qt's OpenGL/EGL includes
mkdir -p "${COOKBOOK_SYSROOT}/include/KHR"
if [ ! -f "${COOKBOOK_SYSROOT}/include/KHR/khrplatform.h" ]; then
if [ -f "${COOKBOOK_SYSROOT}/usr/include/KHR/khrplatform.h" ]; then
cp -f "${COOKBOOK_SYSROOT}/usr/include/KHR/khrplatform.h" "${COOKBOOK_SYSROOT}/include/KHR/khrplatform.h"
else
# Minimal fallback
cat > "${COOKBOOK_SYSROOT}/include/KHR/khrplatform.h" <<'KHR_EOF'
#ifndef __khrplatform_h_
#define __khrplatform_h_
#include <stdint.h>
#include <stddef.h>
#include <sys/cdefs.h>
typedef int8_t khronos_int8_t;
typedef uint8_t khronos_uint8_t;
typedef int16_t khronos_int16_t;
typedef uint16_t khronos_uint16_t;
typedef int32_t khronos_int32_t;
typedef uint32_t khronos_uint32_t;
typedef int64_t khronos_int64_t;
typedef uint64_t khronos_uint64_t;
typedef float khronos_float_t;
typedef intptr_t khronos_intptr_t;
typedef uintptr_t khronos_uintptr_t;
typedef int32_t khronos_ssize_t;
typedef uint32_t khronos_usize_t;
#define KHRONOS_APIENTRY
#define KHRONOS_APIATTRIBUTES
#define KHRONOS_SUPPORT_INT64 1
#define KHRONOS_SUPPORT_FLOAT 1
#endif
KHR_EOF
fi
fi
# Step 1: Build Qt host tools (moc, rcc, uic) on the host
# These are needed for cross-compilation — Qt6 generates code
@@ -205,16 +205,6 @@ cmake "${COOKBOOK_SOURCE}" \
-DQT_BUILD_TESTS=OFF \
-DQT_GENERATE_SBOM=OFF \
-DQT_FEATURE_qml_jit=OFF \
-DQT_FEATURE_ssl=OFF \
-DQT_FEATURE_network=OFF \
-DQT_FEATURE_localserver=OFF \
-DQT_FEATURE_http=OFF \
-DQT_FEATURE_udpsocket=OFF \
-DQT_FEATURE_dnslookup=OFF \
-DQT_FEATURE_networkinterface=OFF \
-DQT_FEATURE_networkproxy=OFF \
-DQT_FEATURE_socks5=OFF \
-DQT_FEATURE_networkdiskcache=OFF \
-Wno-dev
HOST_QT6_LIBS="${DECL_HOST}/lib:${HOST_BUILD}/lib"
@@ -42,7 +42,7 @@ use std::path::Path;
use regex::Regex;
/// One action in a mc.ext section (Open, View, or Edit).
#[derive(Debug, Clone, PartialEq, Eq)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ActionKind {
/// Execute on Enter / double-click.
Open,
@@ -198,18 +198,94 @@ impl ExtDatabase {
/// Find the first action of the given kind for the specified file.
///
/// `filename` is the file's name (not full path). `is_dir` indicates
/// whether the entry is a directory.
/// whether the entry is a directory. Sections with `Include=name`
/// rules are resolved recursively: an Include section matches the
/// same files as the named section, and inherits any actions the
/// named section defines that the current section does not
/// override. Recursion stops at depth [`MAX_INCLUDE_DEPTH`] so a
/// cyclic Include chain cannot blow the stack.
pub fn find_action(&self, filename: &str, is_dir: bool, kind: ActionKind) -> Option<&ExtAction> {
for section in &self.sections {
if Self::section_matches(&section.rule, filename, is_dir) {
if let Some(a) = section.actions.iter().find(|a| a.kind == kind) {
return Some(a);
if let Some(a) = self.find_action_in_section(section, filename, is_dir, kind, 0) {
return Some(a);
}
}
None
}
/// Recursive helper for [`Self::find_action`]. When the section
/// has its own action of `kind`, return it. Otherwise recurse
/// into the Include target (if any) to inherit its action of
/// the same kind. The section's own match rule is also tried
/// so an Include target's pattern is used as the section's
/// effective pattern.
fn find_action_in_section<'a>(
&'a self,
section: &'a ExtSection,
filename: &str,
is_dir: bool,
kind: ActionKind,
depth: usize,
) -> Option<&'a ExtAction> {
if depth >= Self::MAX_INCLUDE_DEPTH {
return None;
}
// Determine the effective match rule for this section. If it
// is `Include=name`, the effective rule is the target
// section's rule (recursively).
let effective_rule = self.resolve_rule(&section.rule, depth);
if !Self::section_matches(&effective_rule, filename, is_dir) {
return None;
}
if let Some(a) = section.actions.iter().find(|a| a.kind == kind) {
return Some(a);
}
// No action of `kind` in this section — fall through to the
// Include target's actions.
if let Some(MatchRule::Include(name)) = &section.rule {
if let Some(indices) = self.by_name.get(name) {
for &idx in indices {
let target = &self.sections[idx];
if let Some(a) =
self.find_action_in_section(target, filename, is_dir, kind, depth + 1)
{
return Some(a);
}
}
}
}
None
}
/// Resolve an `Include=name` rule to the target section's rule.
/// Recursion is bounded by [`MAX_INCLUDE_DEPTH`].
fn resolve_rule<'a>(
&'a self,
rule: &'a Option<MatchRule>,
depth: usize,
) -> Option<MatchRule> {
if depth >= Self::MAX_INCLUDE_DEPTH {
return rule.clone();
}
match rule {
Some(MatchRule::Include(name)) => {
if let Some(indices) = self.by_name.get(name) {
if let Some(&idx) = indices.first() {
let target = &self.sections[idx];
return self.resolve_rule(&target.rule, depth + 1);
}
}
None
}
other => other.clone(),
}
}
/// Maximum recursion depth when resolving `Include=name`
/// references. MC's actual mc.ext allows arbitrary depth; we
/// cap at a small number to keep cycle resolution finite.
pub const MAX_INCLUDE_DEPTH: usize = 16;
/// Check whether a match rule applies to the given filename.
fn section_matches(rule: &Option<MatchRule>, filename: &str, is_dir: bool) -> bool {
match rule {
@@ -468,4 +544,158 @@ Open=some_command
let d = ExtDatabase::parse(text).unwrap();
assert!(d.find_action("any_file", false, ActionKind::Open).is_none());
}
#[test]
fn include_inherits_actions_from_target_section() {
let text = "\
[images]
Shell=.png
View=feh %f
Edit=gimp %f
[photos]
Include=images
Open=xdg-open %f
";
let d = ExtDatabase::parse(text).unwrap();
let view = d.find_action("holiday.png", false, ActionKind::View);
assert_eq!(view.unwrap().command, "feh %f");
let edit = d.find_action("holiday.png", false, ActionKind::Edit);
assert_eq!(edit.unwrap().command, "gimp %f");
let open = d.find_action("holiday.png", false, ActionKind::Open);
assert_eq!(open.unwrap().command, "xdg-open %f");
}
#[test]
fn include_target_section_keeps_its_own_match_rule() {
let text = "\
[source]
Shell=.rs
Open=editor %f
[python]
Include=source
";
let d = ExtDatabase::parse(text).unwrap();
assert_eq!(
d.find_action("main.rs", false, ActionKind::Open).unwrap().command,
"editor %f"
);
assert!(d.find_action("main.py", false, ActionKind::Open).is_none());
}
#[test]
fn include_chain_resolves_transitively() {
let text = "\
[base]
Shell=.log
View=less %f
[middle]
Include=base
Edit=vim %f
[final]
Include=middle
Open=xdg-open %f
";
let d = ExtDatabase::parse(text).unwrap();
assert_eq!(
d.find_action("a.log", false, ActionKind::View).unwrap().command,
"less %f"
);
assert_eq!(
d.find_action("a.log", false, ActionKind::Edit).unwrap().command,
"vim %f"
);
assert_eq!(
d.find_action("a.log", false, ActionKind::Open).unwrap().command,
"xdg-open %f"
);
}
#[test]
fn include_with_unknown_target_falls_back_to_none() {
let text = "\
[mystery]
Include=does_not_exist
View=nope %f
";
let d = ExtDatabase::parse(text).unwrap();
assert!(d.find_action("anything.txt", false, ActionKind::View).is_none());
}
#[test]
fn include_cycle_terminates_at_depth_limit() {
let text = "\
[a]
Include=b
View=from_a %f
[b]
Include=a
View=from_b %f
";
let d = ExtDatabase::parse(text).unwrap();
let v = d.find_action("x.txt", false, ActionKind::View);
assert!(v.is_none());
}
#[test]
fn include_section_first_match_wins_in_file_order() {
let text = "\
[base]
Shell=.md
Open=base_open %f
[special]
Include=base
Open=special_open %f
";
let d = ExtDatabase::parse(text).unwrap();
assert_eq!(
d.find_action("README.md", false, ActionKind::Open).unwrap().command,
"base_open %f"
);
}
#[test]
fn include_target_with_no_actions_falls_through() {
let text = "\
[empty]
Shell=.empty
[t]
Include=empty
Open=fallback %f
";
let d = ExtDatabase::parse(text).unwrap();
assert_eq!(
d.find_action("x.empty", false, ActionKind::Open).unwrap().command,
"fallback %f"
);
}
#[test]
fn include_resolves_view_kind_independently_from_open_kind() {
let text = "\
[imgs]
Shell=.png
View=feh %f
[from_png]
Include=imgs
Open=xdg-open %f
";
let d = ExtDatabase::parse(text).unwrap();
assert_eq!(
d.find_action("a.png", false, ActionKind::View).unwrap().command,
"feh %f"
);
assert_eq!(
d.find_action("a.png", false, ActionKind::Open).unwrap().command,
"xdg-open %f"
);
assert!(d.find_action("a.png", false, ActionKind::Edit).is_none());
}
}