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)
|
||||||
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].")
|
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
|
fi
|
||||||
done
|
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
|
# Step 1: Build Qt host tools (moc, rcc, uic) on the host
|
||||||
# These are needed for cross-compilation — Qt6 generates code
|
# These are needed for cross-compilation — Qt6 generates code
|
||||||
|
|||||||
@@ -205,16 +205,6 @@ cmake "${COOKBOOK_SOURCE}" \
|
|||||||
-DQT_BUILD_TESTS=OFF \
|
-DQT_BUILD_TESTS=OFF \
|
||||||
-DQT_GENERATE_SBOM=OFF \
|
-DQT_GENERATE_SBOM=OFF \
|
||||||
-DQT_FEATURE_qml_jit=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
|
-Wno-dev
|
||||||
|
|
||||||
HOST_QT6_LIBS="${DECL_HOST}/lib:${HOST_BUILD}/lib"
|
HOST_QT6_LIBS="${DECL_HOST}/lib:${HOST_BUILD}/lib"
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ use std::path::Path;
|
|||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
|
|
||||||
/// One action in a mc.ext section (Open, View, or Edit).
|
/// 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 {
|
pub enum ActionKind {
|
||||||
/// Execute on Enter / double-click.
|
/// Execute on Enter / double-click.
|
||||||
Open,
|
Open,
|
||||||
@@ -198,18 +198,94 @@ impl ExtDatabase {
|
|||||||
/// Find the first action of the given kind for the specified file.
|
/// Find the first action of the given kind for the specified file.
|
||||||
///
|
///
|
||||||
/// `filename` is the file's name (not full path). `is_dir` indicates
|
/// `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> {
|
pub fn find_action(&self, filename: &str, is_dir: bool, kind: ActionKind) -> Option<&ExtAction> {
|
||||||
for section in &self.sections {
|
for section in &self.sections {
|
||||||
if Self::section_matches(§ion.rule, filename, is_dir) {
|
if let Some(a) = self.find_action_in_section(section, filename, is_dir, kind, 0) {
|
||||||
if let Some(a) = section.actions.iter().find(|a| a.kind == kind) {
|
return Some(a);
|
||||||
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
|
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.
|
/// Check whether a match rule applies to the given filename.
|
||||||
fn section_matches(rule: &Option<MatchRule>, filename: &str, is_dir: bool) -> bool {
|
fn section_matches(rule: &Option<MatchRule>, filename: &str, is_dir: bool) -> bool {
|
||||||
match rule {
|
match rule {
|
||||||
@@ -468,4 +544,158 @@ Open=some_command
|
|||||||
let d = ExtDatabase::parse(text).unwrap();
|
let d = ExtDatabase::parse(text).unwrap();
|
||||||
assert!(d.find_action("any_file", false, ActionKind::Open).is_none());
|
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