#!/usr/bin/env bash set -euo pipefail # build_grantlee_qt6.sh - build grantlee with pragmatic Qt6 patches and install to INSTALL_PREFIX QT_ROOT=${QT_ROOT:-/opt/Qt/6.8.3/gcc_64} INSTALL_PREFIX=${INSTALL_PREFIX:-/usr/local} echo "Building Grantlee (attempt Qt6 port) into ${INSTALL_PREFIX} using QT_ROOT=${QT_ROOT}" TMPDIR=$(mktemp -d) trap 'rm -rf "$TMPDIR"' EXIT cd "$TMPDIR" if ! git clone --depth 1 https://github.com/steveire/grantlee.git grantlee; then echo "Failed to clone grantlee" >&2 exit 1 fi # Ensure dev packages required for building (xkb headers etc.) if command -v sudo >/dev/null 2>&1; then sudo apt-get update -y || true sudo apt-get install -y --no-install-recommends libxkbcommon-dev libxkbcommon-x11-dev pkg-config || true fi pushd grantlee >/dev/null # Backup relevant files git ls-files | grep -E "CMakeLists.txt|\\.cmake$" | xargs -r -n1 -I{} cp {} {}.bak || true # Python-based safe patches python3 - <<'PY' import re from pathlib import Path # first, convert find_package(Qt5 COMPONENTS ...) preserving components pat_fp = re.compile(r'find_package\s*\(\s*Qt5\s+COMPONENTS\s+([^\)]+)\)', re.M) # map find_package(Qt5 Test) forms to Qt6 Test pat_test_simple = re.compile(r'find_package\s*\(\s*Qt5\s+Test(?:\s+REQUIRED)?\s*\)', re.M) for p in Path('.').rglob('*'): if p.is_file() and (p.name=='CMakeLists.txt' or p.suffix=='.cmake'): try: s = p.read_text() s2 = pat_fp.sub(lambda m: 'find_package(Qt6 REQUIRED COMPONENTS %s)'%m.group(1).strip(), s) s2 = pat_test_simple.sub('find_package(Qt6 Test REQUIRED)', s2) if s2 != s: p.write_text(s2) print('Patched find_package components in', p) except Exception as e: print('Skipping', p, 'error', e) # generic replacements patterns = [ (re.compile(r'find_package\s*\(\s*Qt5[^)]*\)', re.M), 'find_package(Qt6 REQUIRED COMPONENTS Core Widgets)'), (re.compile(r'Qt5::'), 'Qt6::'), (re.compile(r'QT5_WRAP_CPP'), 'QT_WRAP_CPP'), (re.compile(r'qt5_add_resources'), 'qt_add_resources'), (re.compile(r'qt5_add_translations'), 'qt_add_translations'), (re.compile(r'qt5_add_translation'), 'qt_add_translation'), ] for p in Path('.').rglob('*'): if p.is_file() and (p.name=='CMakeLists.txt' or p.suffix=='.cmake'): try: s = p.read_text() orig = s for pat, repl in patterns: s = pat.sub(repl, s) if s != orig: p.write_text(s) print('Patched', p) except Exception as e: print('Skipping', p, 'error', e) # remove explicit QT_TESTCASE_BUILDDIR compile definitions to avoid duplicate -D on command line pat_qt_test_def = re.compile(r"^\s*target_compile_definitions\([^\n]*QT_TESTCASE_BUILDDIR[^\n]*\)\s*$", re.M) for p in Path('.').rglob('*'): if p.is_file() and p.name=='CMakeLists.txt': try: s = p.read_text() s2 = pat_qt_test_def.sub(lambda m: '# PATCHED: removed QT_TESTCASE_BUILDDIR definition to avoid macro redefinition', s) if s2 != s: p.write_text(s2) print('Removed QT_TESTCASE_BUILDDIR in', p) except Exception as e: print('Skipping', p, 'error', e) # ensure files linking to Qt6::Test have a find_package(Qt6 Test REQUIRED) for p in Path('.').rglob('*'): if p.is_file() and (p.name=='CMakeLists.txt' or p.suffix=='.cmake'): try: s = p.read_text() if 'Qt6::Test' in s and 'find_package(Qt6 Test' not in s: s = 'find_package(Qt6 COMPONENTS Test REQUIRED)\n' + s p.write_text(s) print('Inserted find_package(Qt6 Test REQUIRED) in', p) except Exception as e: print('Skipping', p, 'error', e) PY popd >/dev/null mkdir -p grantlee/build cd grantlee/build cmake -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_INSTALL_PREFIX="${INSTALL_PREFIX}" \ -DCMAKE_PREFIX_PATH="${QT_ROOT}:${INSTALL_PREFIX}" \ ${DISABLE_TESTS:+-DBUILD_TESTING=OFF} .. cmake --build . -- -j$(nproc) || true cmake --install . || true echo "Grantlee attempted build finished" exit 0