diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml new file mode 100644 index 000000000000..8fd7c9d3c981 --- /dev/null +++ b/.github/workflows/linux.yml @@ -0,0 +1,99 @@ +name: Linux Build + +on: + push: + branches: + - master + - 'Stable*' + tags: + - 'v*' + paths-ignore: + - 'docs/**' + - 'android/**' + pull_request: + paths-ignore: + - 'docs/**' + - 'android/**' + +defaults: + run: + shell: bash + +env: + ARTIFACT: QGroundControl-x86_64.AppImage + +jobs: + build: + runs-on: ubuntu-20.04 + + strategy: + matrix: + BuildType: [Debug, Release] + + steps: + - name: Checkout repo + uses: actions/checkout@v4 + with: + submodules: recursive + fetch-tags: true + + - name: Set up Cache + uses: hendrikmuhs/ccache-action@v1.2 + if: github.ref == 'refs/heads/master' && github.event_name != 'pull_request' + with: + create-symlink: true + key: ${{ runner.os }}-${{ matrix.BuildType }} + restore-keys: ${{ runner.os }}-${{ matrix.BuildType }} + max-size: 1G + append-timestamp: false + + - name: Install Qt + uses: jurplel/install-qt-action@v3 + with: + version: 6.6.3 + aqtversion: ==3.1.* + host: linux + target: desktop + dir: ${{ runner.temp }} + modules: qtcharts qtlocation qtpositioning qtspeech qtmultimedia qtserialport qtimageformats qtshadertools qtconnectivity qtquick3d + setup-python: true + cache: true + + - name: Install Dependencies + run: | + chmod a+x ./tools/setup/ubuntu.sh + ./tools/setup/ubuntu.sh + + - name: Create build directory + run: mkdir ${{ runner.temp }}/shadow_build_dir + + - name: Configure + working-directory: ${{ runner.temp }}/shadow_build_dir + run: cmake -S ${{ github.workspace }} -B . -G Ninja \ + -DCMAKE_BUILD_TYPE=${{ matrix.BuildType }} \ + -DQGC_STABLE_BUILD=${{ github.ref_type == 'tag' || contains(github.ref, 'Stable') && 'ON' || 'OFF' }} + + - name: Build + working-directory: ${{ runner.temp }}/shadow_build_dir + run: cmake --build . --target all --config ${{ matrix.BuildType }} + + - name: Create AppImage + working-directory: ${{ runner.temp }}/shadow_build_dir + run: cmake --install . + + - name: Run unit tests + if: matrix.BuildType == 'Debug' + working-directory: ${{ runner.temp }}/shadow_build_dir + run: | + mkdir -p ~/.config/QtProject/ + cp ${{ github.workspace }}/test/qtlogging.ini ~/.config/QtProject/ + xvfb-run -a ./${{ env.ARTIFACT }} --unittest + + - name: Upload Build File + uses: ./.github/actions/upload + if: matrix.BuildType == 'Release' + with: + artifact_name: ${{ env.ARTIFACT }} + aws_key_id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws_secret_access_key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + source: '.' diff --git a/.github/workflows/linux_debug.yml b/.github/workflows/linux_debug.yml deleted file mode 100644 index dd9184f17504..000000000000 --- a/.github/workflows/linux_debug.yml +++ /dev/null @@ -1,87 +0,0 @@ -name: Linux Debug and Test - -on: - push: - branches: - - 'master' - paths-ignore: - - 'docs/**' - pull_request: - branches: - - '*' - paths-ignore: - - 'docs/**' - -defaults: - run: - shell: bash - -env: - SOURCE_DIR: ${{ github.workspace }} - QT_VERSION: 6.6.* - BUILD_TYPE: ${{ fromJSON('["DailyBuild", "StableBuild"]')[ github.ref_type == 'tag' || contains(github.ref, 'Stable_' ) ] }} - -jobs: - build: - runs-on: ubuntu-20.04 - - steps: - - name: Checkout repo - uses: actions/checkout@v4 - with: - submodules: recursive - - - run: sudo apt update - - - name: ccache - uses: hendrikmuhs/ccache-action@v1.2 - with: - create-symlink: true - key: ${{ runner.os }}-Debug - restore-keys: ${{ runner.os }}-Debug - max-size: "2G" - append-timestamp: false - if: github.ref == 'refs/heads/master' && github.event_name != 'pull_request' - - - name: Get all tags for correct version determination - working-directory: ${{ github.workspace }} - run: | - git fetch --all --tags -f --depth 1 - - - name: Install Qt - uses: jurplel/install-qt-action@v3 - with: - version: ${{ env.QT_VERSION }} - aqtversion: ==3.1.* - host: linux - target: desktop - dir: ${{ runner.temp }} - modules: qtcharts qtlocation qtpositioning qtspeech qtmultimedia qtserialport qtimageformats qtshadertools qtconnectivity qtquick3d - setup-python: true - cache: true - - - name: Install Dependencies - run: | - chmod a+x ./tools/setup/ubuntu.sh - ./tools/setup/ubuntu.sh - - - name: Create build directory - run: mkdir ${{ runner.temp }}/shadow_build_dir - - - name: Build - working-directory: ${{ runner.temp }}/shadow_build_dir - run: | - cmake -S ${{ env.SOURCE_DIR }} -B ${{ runner.temp }}/shadow_build_dir/ -G Ninja -DCMAKE_BUILD_TYPE=Debug - cmake --build ${{ runner.temp }}/shadow_build_dir/ --target all --config Debug - cmake --install ${{ runner.temp }}/shadow_build_dir - - - name: Setup for unit tests - working-directory: ${{ runner.temp }}/shadow_build_dir - run: | - mkdir -p ~/.config/QtProject/ - cp ${SOURCE_DIR}/test/qtlogging.ini ~/.config/QtProject/ - export QT_FATAL_WARNINGS=1 - - - name: Run unit tests - working-directory: ${{ runner.temp }}/shadow_build_dir - run: xvfb-run -a ${{ runner.temp }}/shadow_build_dir/QGroundControl*.AppImage --unittest diff --git a/.github/workflows/linux_release.yml b/.github/workflows/linux_release.yml deleted file mode 100644 index 27da7bb6a526..000000000000 --- a/.github/workflows/linux_release.yml +++ /dev/null @@ -1,90 +0,0 @@ -name: Linux Release - -on: - push: - branches: - - 'master' - - 'Stable*' - tags: - - 'v*' - paths-ignore: - - 'docs/**' - pull_request: - branches: - - '*' - paths-ignore: - - 'docs/**' - -defaults: - run: - shell: bash - -env: - SOURCE_DIR: ${{ github.workspace }} - QT_VERSION: 6.6.* - ARTIFACT: QGroundControl.AppImage - BUILD_TYPE: ${{ fromJSON('["DailyBuild", "StableBuild"]')[ github.ref_type == 'tag' || contains(github.ref, 'Stable_' ) ] }} - -jobs: - build: - runs-on: ubuntu-20.04 - - steps: - - name: Checkout repo - uses: actions/checkout@v4 - with: - submodules: recursive - - - run: sudo apt update - - - name: ccache - uses: hendrikmuhs/ccache-action@v1.2 - with: - create-symlink: true - key: ${{ runner.os }}-Release - restore-keys: ${{ runner.os }}-Release - max-size: "2G" - append-timestamp: false - if: github.ref == 'refs/heads/master' && github.event_name != 'pull_request' - - - name: Get all tags for correct version determination - working-directory: ${{ github.workspace }} - run: | - git fetch --all --tags -f --depth 1 - - - name: Install Qt - uses: jurplel/install-qt-action@v3 - with: - version: ${{ env.QT_VERSION }} - aqtversion: ==3.1.* - host: linux - target: desktop - dir: ${{ runner.temp }} - modules: qtcharts qtlocation qtpositioning qtspeech qtmultimedia qtserialport qtimageformats qtshadertools qtconnectivity qtquick3d - setup-python: true - cache: true - - - name: Install Dependencies - run: | - chmod a+x ./tools/setup/ubuntu.sh - ./tools/setup/ubuntu.sh - - - name: Create build directory - run: mkdir ${{ runner.temp }}/shadow_build_dir - - - name: Build - working-directory: ${{ runner.temp }}/shadow_build_dir - run: | - qmake -r ${SOURCE_DIR}/qgroundcontrol.pro CONFIG+=installer CONFIG+=${BUILD_TYPE} - make -j2 - - - name: Create AppImage - working-directory: ${{ runner.temp }}/shadow_build_dir - run: ${SOURCE_DIR}/deploy/linux/create_linux_appimage.sh ${SOURCE_DIR} ./staging ./package; - - - name: Upload Build File - uses: ./.github/actions/upload - with: - artifact_name: ${{ env.ARTIFACT }} - aws_key_id: ${{ secrets.AWS_ACCESS_KEY_ID }} - aws_secret_access_key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} diff --git a/cmake/CreateAppImage.cmake b/cmake/CreateAppImage.cmake index 75937a3f39f2..e596e2af6676 100644 --- a/cmake/CreateAppImage.cmake +++ b/cmake/CreateAppImage.cmake @@ -1,25 +1,21 @@ message(STATUS Creating AppImage) set(APPDIR_PATH "${CMAKE_BINARY_DIR}/AppDir") -# set(AIT_PATH "${CMAKE_BINARY_DIR}/appimagetool-x86_64.AppImage") set(LD_PATH "${CMAKE_BINARY_DIR}/linuxdeploy-x86_64.AppImage") -#set(LD_QTPLUGIN_PATH "${CMAKE_BINARY_DIR}/linuxdeploy-plugin-qt-x86_64.AppImage") +set(LD_APPIMAGEPLUGIN_PATH "${CMAKE_BINARY_DIR}/linuxdeploy-plugin-appimage-x86_64.AppImage") +set(LD_QTPLUGIN_PATH "${CMAKE_BINARY_DIR}/linuxdeploy-plugin-qt-x86_64.AppImage") -# if(NOT EXISTS "${AIT_PATH}") -# file(DOWNLOAD https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage "${AIT_PATH}") -# execute_process(COMMAND chmod a+x "${AIT_PATH}") -# endif() if(NOT EXISTS "${LD_PATH}") - file(DOWNLOAD https://github.com/linuxdeploy/linuxdeploy/releases/download/1-alpha-20240109-1/linuxdeploy-x86_64.AppImage "${LD_PATH}") + file(DOWNLOAD https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage "${LD_PATH}") execute_process(COMMAND chmod a+x "${LD_PATH}") endif() -# if(NOT EXISTS "${LD_QTPLUGIN_PATH}") -# file(DOWNLOAD https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/1-alpha-20240109-1/linuxdeploy-plugin-qt-x86_64.AppImage "${LD_QTPLUGIN_PATH}") -# execute_process(COMMAND chmod a+x "${LD_QTPLUGIN_PATH}") -# endif() - -# execute_process(COMMAND chmod a+x "${APPDIR_PATH}/AppRun") +if(NOT EXISTS "${LD_APPIMAGEPLUGIN_PATH}") + file(DOWNLOAD https://github.com/linuxdeploy/linuxdeploy-plugin-appimage/releases/download/continuous/linuxdeploy-plugin-appimage-x86_64.AppImage "${LD_APPIMAGEPLUGIN_PATH}") + execute_process(COMMAND chmod a+x "${LD_APPIMAGEPLUGIN_PATH}") +endif() +if(NOT EXISTS "${LD_QTPLUGIN_PATH}") + file(DOWNLOAD https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/continuous/linuxdeploy-plugin-qt-x86_64.AppImage "${LD_QTPLUGIN_PATH}") + execute_process(COMMAND chmod a+x "${LD_QTPLUGIN_PATH}") +endif() -# execute_process(COMMAND ${AIT_PATH} --appdir ${APPDIR_PATH} --output appimage) -# execute_process(COMMAND ${LDQT_PATH} ${APPDIR_PATH}/usr/share/applications/org.mavlink.qgroundcontrol.desktop -unsupported-allow-new-glibc -verbose=2 -appimage) -execute_process(COMMAND ${LD_PATH} --appdir ${APPDIR_PATH} --output appimage) +execute_process(COMMAND ${LD_PATH} --appdir ${APPDIR_PATH} --output appimage) # --plugin qt diff --git a/deploy/linux/create_linux_appimage.sh b/deploy/linux/create_linux_appimage.sh deleted file mode 100755 index aa0588f9aed9..000000000000 --- a/deploy/linux/create_linux_appimage.sh +++ /dev/null @@ -1,93 +0,0 @@ -#!/bin/bash - -# This is causing master builds to fail. I'll figure it out once I get Stable out. -#set -Eeuxo pipefail # https://vaneyckt.io/posts/safer_bash_scripts_with_set_euxo_pipefail/ - -if [[ $# -eq 0 ]]; then - echo 'create_linux_appimage.sh QGC_SRC_DIR QGC_RELEASE_DIR' - exit 1 -fi - -QGC_SRC=$(readlink -f $1) - -QGC_CUSTOM_APP_NAME="${QGC_CUSTOM_APP_NAME:-QGroundControl}" -QGC_CUSTOM_GENERIC_NAME="${QGC_CUSTOM_GENERIC_NAME:-Ground Control Station}" -QGC_CUSTOM_BINARY_NAME="${QGC_CUSTOM_BINARY_NAME:-QGroundControl}" -QGC_CUSTOM_LINUX_START_SH="${QGC_CUSTOM_LINUX_START_SH:-${QGC_SRC}/deploy/linux/qgroundcontrol-start.sh}" -QGC_CUSTOM_APP_ICON="${QGC_CUSTOM_APP_ICON:-${QGC_SRC}/resources/icons/qgroundcontrol.png}" -QGC_CUSTOM_APP_ICON_NAME="${QGC_CUSTOM_APP_ICON_NAME:-QGroundControl}" - -if [ ! -f ${QGC_SRC}/qgroundcontrol.pro ]; then - echo "please specify path to ${QGC_CUSTOM_APP_NAME} source as the 1st argument" - exit 1 -fi - -QGC_RELEASE_DIR=$(readlink -f $2) -if [ ! -f ${QGC_RELEASE_DIR}/${QGC_CUSTOM_BINARY_NAME} ]; then - echo "please specify path to ${QGC_CUSTOM_BINARY_NAME} release as the 2nd argument" - exit 1 -fi - -OUTPUT_DIR=${3-`pwd`} -OUTPUT_DIR=$(readlink -f $OUTPUT_DIR) -echo "Output directory:" ${OUTPUT_DIR} - -# Generate AppImage using the binaries currently provided by the project. -# These require at least GLIBC 2.14, which older distributions might not have. -# On the other hand, 2.14 is not that recent so maybe we can just live with it. - -APP=${QGC_CUSTOM_BINARY_NAME} - -TMPDIR=`mktemp -d` -APPDIR=${TMPDIR}/$APP".AppDir" -mkdir -p ${APPDIR} - -cd ${TMPDIR} -wget -c --quiet http://ftp.us.debian.org/debian/pool/main/libs/libsdl2/libsdl2-2.0-0_2.0.2%2bdfsg1-6_amd64.deb - -cd ${APPDIR} -find ../ -name *.deb -exec dpkg -x {} . \; - -# copy libdirectfb-1.2.so.9 -cd ${TMPDIR} -wget -c --quiet http://ftp.us.debian.org/debian/pool/main/d/directfb/libdirectfb-1.2-9_1.2.10.0-5.1_amd64.deb -mkdir libdirectfb -dpkg -x libdirectfb-1.2-9_1.2.10.0-5.1_amd64.deb libdirectfb -cp -L libdirectfb/usr/lib/x86_64-linux-gnu/libdirectfb-1.2.so.9 ${APPDIR}/usr/lib/x86_64-linux-gnu/ -cp -L libdirectfb/usr/lib/x86_64-linux-gnu/libfusion-1.2.so.9 ${APPDIR}/usr/lib/x86_64-linux-gnu/ -cp -L libdirectfb/usr/lib/x86_64-linux-gnu/libdirect-1.2.so.9 ${APPDIR}/usr/lib/x86_64-linux-gnu/ - -# copy QGroundControl release into appimage -rsync -av --exclude=*.cpp --exclude=*.h --exclude=*.o --exclude="CMake*" --exclude="*.cmake" ${QGC_RELEASE_DIR}/* ${APPDIR}/ -rm -rf ${APPDIR}/package -cp ${QGC_CUSTOM_LINUX_START_SH} ${APPDIR}/AppRun - -# copy icon -cp ${QGC_CUSTOM_APP_ICON} ${APPDIR}/ - -cat > ./QGroundControl.desktop <<\EOF -[Desktop Entry] -Type=Application -Name=${QGC_CUSTOM_APP_NAME} -GenericName=${QGC_CUSTOM_GENERIC_NAME} -Comment=UAS ground control station -Icon=${QGC_CUSTOM_APP_ICON_NAME} -Exec=AppRun -Terminal=false -Categories=Utility; -Keywords=computer; -EOF - -VERSION=$(strings ${APPDIR}/${QGC_CUSTOM_BINARY_NAME} | grep '^v[0-9*]\.[0-9*].[0-9*]' | head -n 1) -echo ${QGC_CUSTOM_APP_NAME} Version: ${VERSION} - -# Go out of AppImage -cd ${TMPDIR} -wget -c --quiet "https://github.com/AppImage/AppImageKit/releases/download/12/appimagetool-x86_64.AppImage" -chmod a+x ./appimagetool-x86_64.AppImage - -./appimagetool-x86_64.AppImage ./$APP.AppDir/ ${TMPDIR}/$APP".AppImage" - -mkdir -p ${OUTPUT_DIR} -cp ${TMPDIR}/$APP".AppImage" ${OUTPUT_DIR}/$APP".AppImage" - diff --git a/deploy/linux/linux-fixup-rpaths.bash b/deploy/linux/linux-fixup-rpaths.bash deleted file mode 100755 index 4ea8c5fe74ae..000000000000 --- a/deploy/linux/linux-fixup-rpaths.bash +++ /dev/null @@ -1,93 +0,0 @@ -#!/usr/bin/env bash -# -# Premise: -# Shared libraries (Qt, airmap, etc) on Linux are built without knowing where -# they will be installed to; they assume they will be installed to the system. -# -# QGC does not install to the system. Instead it copies them to `Qt/libs`. The -# libraries need to have their rpath set correctly to ensure that the built -# application and its libraries are found at runtime. Without this step then the -# libraries won't be found. You might not notice it if you have the libraries -# installed in your system. A lot of systems will have the Qt libs installed, -# but they might be a different version. It "might" work, it might cause subtle -# bugs, or it might not work at all. -# -# It's possible there's no current rpath for a particular library. It's also -# possible that the library has other dependencies in its existing rpath. So -# updating the rpath is non-trivial and it's a real shame that qmake doesn't -# do this for us. -# -# To patch the libraries `readelf` and `patchelf` tools are used. -# -# If the libraries' rpath isn't set correctly then LD_LIBRARY_PATH would need -# to be used, like such: -# LD_LIBRARY_PATH=./Qt/libs ./QGroundControl -# - -# -e: stop on error -# -u: undefined variable use is an error -# -o pipefail: if any part of a pipeline fails, then the whole pipeline fails. -set -euo pipefail - -# To set these arguments, set them as an environment variable. For example: -# SEARCHDIR=/opt/qgc-deploy/Qt RPATHDIR=/opt/qgc-deploy/Qt/libs ./linux-post-link.sh -: "${SEARCHDIR:=./Qt}" -: "${RPATHDIR:="${SEARCHDIR}/libs"}" - -# find: -# type f (files) -# that end with '.so' -# or that end with '.so.5' -# and are executable -# silence stderr (find will complain if it doesn't have permission to traverse) -find "${SEARCHDIR}" \ - -type f \ - -iname '*.so' \ - -o -iname '*.so.5' \ - -executable \ - 2>/dev/null | -while IFS='' read -r library; do - - # readelf is expensive, so keep track of updates with a timestamp file - if [ ! -e "$library.stamp" ] || [ "$library" -nt "$library.stamp" ]; then - - # Get the library's current RPATH (RUNPATH) - # Example output of `readelf -d ./build/build-qgroundcontrol-Desktop_Qt_5_15_2_GCC_64bit-Debug/staging/QGroundControl`: - # 0x000000000000001d (RUNPATH) Library runpath: [$ORIGIN/Qt/libs:/home/kbennett/storage/Qt/5.15.2/gcc_64/lib] - # - # It's possible there's no current rpath for a particular library, so turn - # off pipefail to avoid grep causing it to die. - # If you find a better way to do this, please fix. - set +o pipefail - current_rpath="$( - # read the library, parsing its header - # search for the RUNPATH field - # filter out the human-readable text to leave only the RUNPATH value - readelf -d "${library}" | - grep -P '^ 0x[0-9a-f]+ +\(RUNPATH\) ' | - sed -r 's/^ 0x[0-9a-f]+ +\(RUNPATH\) +Library runpath: \[(.*)\]$/\1/g' - )" - set -o pipefail - - # Get the directory containing the library - library_dir="$(dirname "${library}")" - - # Get the relative path from the library's directory to the Qt/libs directory. - our_rpath="$(realpath --relative-to "${library_dir}" "${RPATHDIR}")" - - # Calculate a new rpath with our library's rpath prefixed. - # Note: '$ORIGIN' must not be expanded by the shell! - # shellcheck disable=SC2016 - new_rpath='$ORIGIN/'"${our_rpath}" - - # If the library already had an rpath, then prefix ours to it. - if [ -n "${current_rpath}" ]; then - new_rpath="${new_rpath}:${current_rpath}" - fi - - # patch the library's rpath - patchelf --set-rpath "${new_rpath}" "${library}" - - touch "$library.stamp" - fi -done diff --git a/tools/setup/ubuntu.sh b/tools/setup/ubuntu.sh index 742ab7495b82..1fc8cff8fd1b 100644 --- a/tools/setup/ubuntu.sh +++ b/tools/setup/ubuntu.sh @@ -17,7 +17,6 @@ sudo DEBIAN_FRONTEND=noninteractive apt-get -y --quiet --no-install-recommends i make \ ninja-build \ rsync \ - libsdl2-dev \ libgstreamer-plugins-base1.0-dev \ libgstreamer1.0-0:amd64 \ libgstreamer1.0-dev \