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:
@@ -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].")
|
||||
|
||||
|
||||
@@ -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(§ion.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(§ion.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)) = §ion.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());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user