Einführung

In einer früheren Serie von Blogposts

Ich habe über die Installation von Raspbian auf dem Raspberry Compute Module geschrieben und die Cross-Kompilierung für QtCreator unter Ubuntu 20 eingerichtet.

Dieser Blogpost ist ein Update auf die - zu diesem Zeitpunkt - neueste Version 6.8 von Qt, raspi OS Bookworm und Ubuntu 22.04 LTS.

Voraussetzungen

Ich habe die folgende Hard- und Software verwendet:

  • Raspberry Pi 4
  • raspi OS Bookworm, ohne empfohlene Software
  • Ubuntu 22.04 LTS
  • Qt 6.8
  • QtCreator 14.02

Anmerkungen

Wenn Sie einen Laptop oder Desktop-Computer mit genügend RAM und CPU-Kernen haben, können Sie die Cross-Compilation in einer virtuellen Maschine durchführen. Ich habe jedoch die Erfahrung gemacht, dass ein nativer Computer viel schneller ist und weniger Fehler produziert.

Schauen Sie sich die Dateipfade und IP-Adressen in meinen Codebeispielen an und passen Sie sie an Ihre Bedürfnisse an.

Einrichtung Raspberry Pi

  • raspiOS von https://www.raspberrypi.com/software/operating-systemsherunterladen.
  • 2024-07-04-raspios-bookworm-arm64.img.xz: 64bit mit Raspberry Pi OS mit Desktop (nicht mit empfohlener Software)
  • Flash-Image auf SD-Karte mit Balena Etcher
  • Folgen Sie der Installation und vergessen Sie nicht die Einstellung für die Fernverbindung (ssh)
  • Verbinden Sie sich mit dem RPi mit ssh -> in meinem Fall mit der IP-Adresse 192.168.2.167 und dem Benutzer pi -> von Ihrem Ubuntu-Host
ssh [email protected]
  • Installieren Sie die benötigte Software:
sudo apt-get install libboost-all-dev libudev-dev libinput-dev libts-dev libmtdev-dev libjpeg-dev libfontconfig1-dev libssl-dev libdbus-1-dev libglib2.0-dev libxkbcommon-dev libegl1-mesa-dev libgbm-dev libgles2-mesa-dev mesa-common-dev libasound2-dev libpulse-dev gstreamer1.0-omx libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev  gstreamer1.0-alsa libvpx-dev libsrtp2-dev libsnappy-dev libnss3-dev "^libxcb.*" flex bison libxslt-dev ruby gperf libbz2-dev libcups2-dev libatkmm-1.6-dev libxi6 libxcomposite1 libfreetype6-dev libicu-dev libsqlite3-dev libxslt1-dev 
sudo apt-get install libavcodec-dev libavformat-dev libswscale-dev libx11-dev freetds-dev libsqlite3-dev libpq-dev libiodbc2-dev firebird-dev libxext-dev libxcb1 libxcb1-dev libx11-xcb1 libx11-xcb-dev libxcb-keysyms1 libxcb-keysyms1-dev libxcb-image0 libxcb-image0-dev libxcb-shm0 libxcb-shm0-dev libxcb-icccm4 libxcb-icccm4-dev libxcb-sync1 libxcb-sync-dev libxcb-render-util0 libxcb-render-util0-dev libxcb-xfixes0-dev libxrender-dev libxcb-shape0-dev libxcb-randr0-dev libxcb-glx0-dev libxi-dev libdrm-dev libxcb-xinerama0 libxcb-xinerama0-dev libatspi2.0-dev libxcursor-dev libxcomposite-dev libxdamage-dev libxss-dev libxtst-dev libpci-dev libcap-dev libxrandr-dev libdirectfb-dev libaudio-dev libxkbcommon-x11-dev gdbserver
  • Erstellen Sie einen Ordner für die Installation von Qt 6:
sudo mkdir /usr/local/qt6
  • Ermitteln Sie die Versionen von gcc, ld und ldd. Der Quellcode der gleichen Version sollte heruntergeladen werden, um später einen Cross-Compiler zu erstellen.
pi@raspberrypi:~ $ gcc --version
gcc (Debian 12.2.0-14) 12.2.0
Copyright (C) 2022 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

pi@raspberrypi:~ $ ld --version
GNU ld (GNU Binutils for Debian) 2.40
Copyright (C) 2023 Free Software Foundation, Inc.
This program is free software; you may redistribute it under the terms of
the GNU General Public License version 3 or (at your option) a later version.
This program has absolutely no warranty.

pi@raspberrypi:~ $ ldd --version
ldd (Debian GLIBC 2.36-9+rpt2+deb12u8) 2.36
Copyright (C) 2022 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Written by Roland McGrath and Ulrich Drepper.
  • Fügen Sie den folgenden Code an das Ende von ~/.bashrc an und aktualisieren Sie die Änderungen:
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/qt6/lib/
source ~/.bashrc

Einrichtung Ubuntu 22.04 LTS

  • Aktualisierung auf die neuesten Versionen der Softwarepakete:
sudo apt update
sudo apt upgrade
  • Installieren Sie die folgenden Pakete:
sudo apt-get install make build-essential libclang-dev ninja-build gcc git bison python3 gperf pkg-config libfontconfig1-dev libfreetype6-dev libx11-dev libx11-xcb-dev libxext-dev libxfixes-dev libxi-dev libxrender-dev libxcb1-dev libxcb-glx0-dev libxcb-keysyms1-dev libxcb-image0-dev libxcb-shm0-dev libxcb-icccm4-dev libxcb-sync-dev libxcb-xfixes0-dev libxcb-shape0-dev libxcb-randr0-dev libxcb-render-util0-dev libxcb-util-dev libxcb-xinerama0-dev libxcb-xkb-dev libxkbcommon-dev libxkbcommon-x11-dev libatspi2.0-dev libgl1-mesa-dev libglu1-mesa-dev freeglut3-dev build-essential gawk git texinfo bison file wget libssl-dev gdbserver gdb-multiarch libxcb-cursor-dev

Erstellen Sie die neueste cmake-Version aus den Quellen:

cd ~
wget https://github.com/Kitware/CMake/releases/download/v3.30.5/cmake-3.30.5.tar.gz
tar -xzvf cmake-3.30.5.tar.gz
cd cmake-3.30.5
./bootstrap
make -j$(nproc)
sudo make install
# Update PATH Environment Variable
which cmake
/usr/local/bin/cmake
export PATH=/usr/local/bin/cmake:$PATH
source ~/.bashrc
cmake --version

Bauen Sie gcc als Cross-Compiler

Laden Sie den erforderlichen Quellcode herunter. Sie sollten die folgenden Befehle an Ihre Bedürfnisse anpassen. Für die Zeit, in der ich diese Seite erstelle, sind sie das:

  • gcc 12.2.0
  • binutils 2.40(ld-Version)
  • glibc 2.36(ldd-Version)
cd ~
mkdir gcc_all && cd gcc_all
wget https://ftpmirror.gnu.org/binutils/binutils-2.40.tar.bz2
wget https://ftpmirror.gnu.org/glibc/glibc-2.36.tar.bz2
wget https://ftpmirror.gnu.org/gcc/gcc-12.2.0/gcc-12.2.0.tar.gz
git clone --depth=1 https://github.com/raspberrypi/linux
tar xf binutils-2.40.tar.bz2
tar xf glibc-2.36.tar.bz2
tar xf gcc-12.2.0.tar.gz
rm *.tar.*
cd gcc-12.2.0
contrib/download_prerequisites
  • Erstellen Sie einen Ordner für die Installation des Compilers.
sudo mkdir -p /opt/cross-pi-gcc
sudo chown $USER /opt/cross-pi-gcc
export PATH=/opt/cross-pi-gcc/bin:$PATH
  • Kopieren Sie die Kernel-Header in den obigen Ordner.
cd ~/gcc_all
cd linux
KERNEL=kernel7
make ARCH=arm64 INSTALL_HDR_PATH=/opt/cross-pi-gcc/aarch64-linux-gnu headers_install
  • Binutils erstellen.
cd ~/gcc_all
mkdir build-binutils && cd build-binutils
../binutils-2.40/configure --prefix=/opt/cross-pi-gcc --target=aarch64-linux-gnu --with-arch=armv8 --disable-multilib
make -j 8
make install
  • Bearbeiten Sie gcc-12.2.0/libsanitizer/asan/asan_linux.cpp. Fügen Sie das folgende Stück Code hinzu.
#ifndef PATH_MAX
#define PATH_MAX 4096
#endif
  • Führen Sie einen partiellen Build von gcc durch.
cd ~/gcc_all
mkdir build-gcc && cd build-gcc
../gcc-12.2.0/configure --prefix=/opt/cross-pi-gcc --target=aarch64-linux-gnu --enable-languages=c,c++ --disable-multilib
make -j8 all-gcc
make install-gcc
  • Teilweise Erstellung von Glibc.
cd ~/gcc_all
mkdir build-glibc && cd build-glibc
../glibc-2.36/configure --prefix=/opt/cross-pi-gcc/aarch64-linux-gnu --build=$MACHTYPE --host=aarch64-linux-gnu --target=aarch64-linux-gnu --with-headers=/opt/cross-pi-gcc/aarch64-linux-gnu/include --disable-multilib libc_cv_forced_unwind=yes
make install-bootstrap-headers=yes install-headers
make -j8 csu/subdir_lib
install csu/crt1.o csu/crti.o csu/crtn.o /opt/cross-pi-gcc/aarch64-linux-gnu/lib
aarch64-linux-gnu-gcc -nostdlib -nostartfiles -shared -x c /dev/null -o /opt/cross-pi-gcc/aarch64-linux-gnu/lib/libc.so
touch /opt/cross-pi-gcc/aarch64-linux-gnu/include/gnu/stubs.h
  • Zurück zu gcc.
cd ~/gcc_all/build-gcc
make -j8 all-target-libgcc
make install-target-libgcc
  • Fertigstellung der Glibc.
cd ~/gcc_all/build-glibc
make -j8
make install
  • Fertigstellung von gcc.
cd ~/gcc_all/build-gcc
make -j8
make install

An diesem Punkt haben wir eine vollständige Cross-Compiler-Toolchain mit gcc. Der Ordner gcc_all wird nicht mehr benötigt. Sie können ihn löschen.

Qt6 bauen

Es gibt zwei Möglichkeiten, Qt6 zu bauen. Es gibt eine "single" (https://download.qt.io/official_releases/qt/6.8/6.8.0/single/qt-everywhere-src-6.8.0.tar.xz) Version zum Herunterladen, die qtbase und alle Untermodule enthält. Diese Version ist sehr schwer und benötigt viel Energie und Zeit, um sie zu kompilieren.

Meine Empfehlung ist, qtbase als Basis zu kompilieren und danach nur jedes Submodul, das Sie benötigen, separat zu kompilieren.

  • Erstellen Sie Ordner für sysroot und qt6. Ich erstelle diese Ordner in meinem workspace/qt-rpi-cross-compilation Verzeichnis.
cd ~/workspace/qt-rpi-cross-compilation
mkdir rpi-sysroot rpi-sysroot/usr rpi-sysroot/opt
mkdir qt6 qt6/host qt6/pi qt6/host-build qt6/pi-build qt6/src
  • QtBase-Quellcode herunterladen
cd ~/workspace/qt-rpi-cross-compilation/qt6/src
wget https://download.qt.io/official_releases/qt/6.8/6.8.0/submodules/qtbase-everywhere-src-6.8.0.tar.xz
tar xf qtbase-everywhere-src-6.8.0.tar.xz

Qt6 für den Host erstellen

cd ~/workspace/qt-rpi-cross-compilation/qt6/host-build/
cmake ../src/qtbase-everywhere-src-6.8.0/ -GNinja -DCMAKE_BUILD_TYPE=Release -DQT_BUILD_EXAMPLES=OFF -DQT_BUILD_TESTS=OFF -DCMAKE_INSTALL_PREFIX=$HOME/qt6/host
cmake --build . --parallel 8
cmake --install .

Die Binärdateien werden in ~/workspace/qt-rpi-cross-compilation/qt6/host

Qt6 für rpi bauen

Kopieren Sie ein paar Ordner von rpi und fügen Sie sie mit rsync über SSH ein.

cd ~
rsync -avz --rsync-path="sudo rsync" [email protected]:/usr/include workspace/qt-rpi-cross-compilation/rpi-sysroot/usr
rsync -avz --rsync-path="sudo rsync" [email protected]:/lib workspace/qt-rpi-cross-compilation/rpi-sysroot
rsync -avz --rsync-path="sudo rsync" [email protected]:/usr/lib workspace/qt-rpi-cross-compilation/rpi-sysroot/usr 
rsync -avz --rsync-path="sudo rsync" [email protected]:/opt/vc workspace/qt-rpi-cross-compilation/rpi-sysroot/opt
  • Erstellen Sie eine Datei namens toolchain.cmake in ~/workspace/qt-rpi-cross-compilation/qt6. Sie müssen die Zeile "set(TARGET_SYSROOT /home/factory/workspace/qt-rpi-cross-compilation/rpi-sysroot)" an Ihre Umgebung anpassen.
cmake_minimum_required(VERSION 3.18)
include_guard(GLOBAL)

set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)

# You should change location of sysroot to your needs.
set(TARGET_SYSROOT /home/factory/workspace/qt-rpi-cross-compilation/rpi-sysroot)
set(TARGET_ARCHITECTURE aarch64-linux-gnu)
set(CMAKE_SYSROOT ${TARGET_SYSROOT})

set(ENV{PKG_CONFIG_PATH} $PKG_CONFIG_PATH:${CMAKE_SYSROOT}/usr/lib/${TARGET_ARCHITECTURE}/pkgconfig)
set(ENV{PKG_CONFIG_LIBDIR} /usr/lib/pkgconfig:/usr/share/pkgconfig/:${TARGET_SYSROOT}/usr/lib/${TARGET_ARCHITECTURE}/pkgconfig:${TARGET_SYSROOT}/usr/lib/pkgconfig)
set(ENV{PKG_CONFIG_SYSROOT_DIR} ${CMAKE_SYSROOT})

set(CMAKE_C_COMPILER /opt/cross-pi-gcc/bin/${TARGET_ARCHITECTURE}-gcc)
set(CMAKE_CXX_COMPILER /opt/cross-pi-gcc/bin/${TARGET_ARCHITECTURE}-g++)

set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -isystem=/usr/include -isystem=/usr/local/include -isystem=/usr/include/${TARGET_ARCHITECTURE}")
set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS}")

set(QT_COMPILER_FLAGS "-march=armv8-a")
set(QT_COMPILER_FLAGS_RELEASE "-O2 -pipe")
set(QT_LINKER_FLAGS "-Wl,-O1 -Wl,--hash-style=gnu -Wl,--as-needed -Wl,-rpath-link=${TARGET_SYSROOT}/usr/lib/${TARGET_ARCHITECTURE} -Wl,-rpath-link=$HOME/qt6/pi/lib")

set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
set(CMAKE_BUILD_RPATH ${TARGET_SYSROOT})

include(CMakeInitializeConfigs)

function(cmake_initialize_per_config_variable _PREFIX _DOCSTRING)
  if (_PREFIX MATCHES "CMAKE_(C|CXX|ASM)_FLAGS")
    set(CMAKE_${CMAKE_MATCH_1}_FLAGS_INIT "${QT_COMPILER_FLAGS}")
        
    foreach (config DEBUG RELEASE MINSIZEREL RELWITHDEBINFO)
      if (DEFINED QT_COMPILER_FLAGS_${config})
        set(CMAKE_${CMAKE_MATCH_1}_FLAGS_${config}_INIT "${QT_COMPILER_FLAGS_${config}}")
      endif()
    endforeach()
  endif()


  if (_PREFIX MATCHES "CMAKE_(SHARED|MODULE|EXE)_LINKER_FLAGS")
    foreach (config SHARED MODULE EXE)
      set(CMAKE_${config}_LINKER_FLAGS_INIT "${QT_LINKER_FLAGS}")
    endforeach()
  endif()

  _cmake_initialize_per_config_variable(${ARGV})
endfunction()

set(XCB_PATH_VARIABLE ${TARGET_SYSROOT})

set(GL_INC_DIR ${TARGET_SYSROOT}/usr/include)
set(GL_LIB_DIR ${TARGET_SYSROOT}:${TARGET_SYSROOT}/usr/lib/${TARGET_ARCHITECTURE}/:${TARGET_SYSROOT}/usr:${TARGET_SYSROOT}/usr/lib)

set(EGL_INCLUDE_DIR ${GL_INC_DIR})
set(EGL_LIBRARY ${XCB_PATH_VARIABLE}/usr/lib/${TARGET_ARCHITECTURE}/libEGL.so)

set(OPENGL_INCLUDE_DIR ${GL_INC_DIR})
set(OPENGL_opengl_LIBRARY ${XCB_PATH_VARIABLE}/usr/lib/${TARGET_ARCHITECTURE}/libOpenGL.so)

set(GLESv2_INCLUDE_DIR ${GL_INC_DIR})
set(GLIB_LIBRARY ${XCB_PATH_VARIABLE}/usr/lib/${TARGET_ARCHITECTURE}/libGLESv2.so)

set(GLESv2_INCLUDE_DIR ${GL_INC_DIR})
set(GLESv2_LIBRARY ${XCB_PATH_VARIABLE}/usr/lib/${TARGET_ARCHITECTURE}/libGLESv2.so)

set(gbm_INCLUDE_DIR ${GL_INC_DIR})
set(gbm_LIBRARY ${XCB_PATH_VARIABLE}/usr/lib/${TARGET_ARCHITECTURE}/libgbm.so)

set(Libdrm_INCLUDE_DIR ${GL_INC_DIR})
set(Libdrm_LIBRARY ${XCB_PATH_VARIABLE}/usr/lib/${TARGET_ARCHITECTURE}/libdrm.so)

set(XCB_XCB_INCLUDE_DIR ${GL_INC_DIR})
set(XCB_XCB_LIBRARY ${XCB_PATH_VARIABLE}/usr/lib/${TARGET_ARCHITECTURE}/libxcb.so)

list(APPEND CMAKE_LIBRARY_PATH ${CMAKE_SYSROOT}/usr/lib/${TARGET_ARCHITECTURE})
list(APPEND CMAKE_PREFIX_PATH "/usr/lib/${TARGET_ARCHITECTURE}/cmake")
  • Absolute symbolische Links korrigieren
cd ~/workspace/qt-rpi-cross-compilation
wget https://raw.githubusercontent.com/riscv/riscv-poky/master/scripts/sysroot-relativelinks.py
chmod +x sysroot-relativelinks.py 
python3 sysroot-relativelinks.py rpi-sysroot
  • Kompilieren Sie den Quellcode für rpi.
cd $HOME/workspace/qt-rpi-cross-compilation/qt6/pi-build
cmake ../src/qtbase-everywhere-src-6.8.0/ -GNinja -DCMAKE_BUILD_TYPE=Release -DINPUT_opengl=es2 -DQT_BUILD_EXAMPLES=OFF -DQT_BUILD_TESTS=OFF -DQT_HOST_PATH=$HOME/workspace/qt-rpi-cross-compilation/qt6/host -DCMAKE_STAGING_PREFIX=$HOME/workspace/qt-rpi-cross-compilation/qt6/pi -DCMAKE_INSTALL_PREFIX=/usr/local/qt6 -DCMAKE_TOOLCHAIN_FILE=$HOME/workspace/qt-rpi-cross-compilation/qt6/toolchain.cmake -DQT_QMAKE_TARGET_MKSPEC=devices/linux-rasp-pi4-aarch64 -DQT_FEATURE_xcb=ON -DFEATURE_xcb_xlib=ON -DQT_FEATURE_xlib=ON
cmake --build . --parallel 8
cmake --install .
  • Senden der Binärdateien an rpi.
rsync -avz --rsync-path="sudo rsync" $HOME/workspace/qt-rpi-cross-compilation/qt6/pi/* [email protected]:/usr/local/qt6

QtCreator konfigurieren

  • Compiler einrichten

    Qt 6.8 Cross-Compilation für Raspberry Pi ein Bildschirmfoto eines Computers
    Qt 6.8 Cross-Compilation für Raspberry Pi ein Bildschirmfoto eines Computers
  • Debugger einrichten

    Qt 6.8 Cross-Compilation für Raspberry Pi ein Bildschirmfoto eines Computers
  • Geräte einrichten

    Qt 6.8 Cross-Compilation für Raspberry Pi ein Bildschirmfoto eines Computers Testen Sie die Verbindung mit der Schaltfläche "Testen".
  • Qt-Versionen einrichten

    Qt 6.8 Cross-Compilation für Raspberry Pi ein Bildschirmfoto eines Computers
  • Kits einrichten

    Qt 6.8 Cross-Compilation für Raspberry Pi ein Bildschirmfoto eines Computers
  • Auf "CMake Configuration" klicken Sie auf Change und fügen folgende Befehle hinzu.

-DCMAKE_TOOLCHAIN_FILE:UNINITIALIZED=/home/pmy/qt6/pi/lib/cmake/Qt6/qt.toolchain.cmake

QtCreator Projekteinstellungen

Wenn Sie ein Projekt in QtCreator erstellen, müssen Sie die "Run" Konfiguration anpassen. Unter "Environment" müssen Sie hinzufügen:

-LD_LIBRARY_PATH=:/usr/local/qt6/lib/

Qt-Submodule hinzufügen

QML-Modul hinzufügen

  • Quellcodes herunterladen:
cd ~/workspace/qt-rpi-cross-compilation/qt6/src
wget https://download.qt.io/official_releases/qt/6.8/6.8.0/submodules/qtshadertools-everywhere-src-6.8.0.tar.xz
tar xf qtshadertools-everywhere-src-6.8.0.tar.xz
wget https://download.qt.io/official_releases/qt/6.8/6.8.0/submodules/qtdeclarative-everywhere-src-6.8.0.tar.xz
tar xf qtdeclarative-everywhere-src-6.8.0.tar.xz

Sie müssen die Abhängigkeiten unter ~/workspace/qt-rpi-cross-compilation/qt6/src/qtdeclarative-everywhere-src-6.8.0/dependencies.yaml und ~/workspace/qt-rpi-cross-compilation/qt6/src/qtshadertools-everywhere-src-6.8.0/dependencies.yaml überprüfen.

Stellen Sie sicher, dass die benötigten Module zuerst gebaut und installiert werden.

  • Bauen Sie die Module für den Host.
cd ~/workspace/qt-rpi-cross-compilation/qt6/host-build
rm -rf *
$HOME/workspace/qt-rpi-cross-compilation/qt6/host/bin/qt-configure-module ../src/qtshadertools-everywhere-src-6.8.0
cmake --build . --parallel 8
cmake --install .
rm -rf *
$HOME/workspace/qt-rpi-cross-compilation/qt6/host/bin/qt-configure-module ../src/qtdeclarative-everywhere-src-6.8.0
cmake --build . --parallel 8
cmake --install .
  • Erstellen Sie die Module für rpi.
cd ~/workspace/qt-rpi-cross-compilation/qt6/pi-build
rm -rf *
$HOME/workspace/qt-rpi-cross-compilation/qt6/pi/bin/qt-configure-module ../src/qtshadertools-everywhere-src-6.8.0
cmake --build . --parallel 8
cmake --install .
rm -rf *
$HOME/workspace/qt-rpi-cross-compilation/qt6/pi/bin/qt-configure-module ../src/qtdeclarative-everywhere-src-6.8.0
cmake --build . --parallel 8
cmake --install .
  • Senden Sie die Binärdateien an rpi.
rsync -avz --rsync-path="sudo rsync" $HOME/workspace/qt-rpi-cross-compilation/qt6/pi/* [email protected]:/usr/local/qt6

Danksagungen

Für die Erstellung dieser Anleitung verwendete Quellen:

Danke an alle.

admin

Aktualisiert am: 16. October 2024
Lesedauer: 6 Minuten