diff --git a/.github/workflows/android-linux.yml b/.github/workflows/android-linux.yml deleted file mode 100644 index 64ade02b724..00000000000 --- a/.github/workflows/android-linux.yml +++ /dev/null @@ -1,110 +0,0 @@ -name: Android-Linux - -on: - push: - branches: - - master - - 'Stable*' - tags: - - 'v*' - paths-ignore: - - 'deploy/**' - - 'docs/**' - pull_request: - paths-ignore: - - 'deploy/**' - - 'docs/**' - - '.github/workflows/docs_deploy.yml' - - '.github/workflows/linux.yml' - - '.github/workflows/macos.yml' - - '.github/workflows/windows.yml' - -jobs: - build: - runs-on: ubuntu-latest - - strategy: - matrix: - BuildType: [Release] - - defaults: - run: - shell: bash - - env: - ARTIFACT: QGroundControl.apk - QT_VERSION: 6.8.1 - GST_VERSION: 1.22.12 - QT_ANDROID_KEYSTORE_PATH: ${{ github.workspace }}/deploy/android/android_release.keystore - QT_ANDROID_KEYSTORE_ALIAS: QGCAndroidKeyStore - QT_ANDROID_KEYSTORE_STORE_PASS: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }} - QT_ANDROID_KEYSTORE_KEY_PASS: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }} - QT_ANDROID_ABIS: ${{ matrix.BuildType == 'Release' && 'armeabi-v7a;arm64-v8a' || 'arm64-v8a' }} - - steps: - - name: Free Disk Space (Ubuntu) - uses: jlumbroso/free-disk-space@main - with: - android: 'false' - continue-on-error: true - - - name: Checkout repo - uses: actions/checkout@v4 - with: - submodules: recursive - fetch-tags: true - fetch-depth: 0 - - - uses: seanmiddleditch/gha-setup-ninja@v5 - - uses: lukka/get-cmake@latest - - - name: Install CCache - run: | - wget --quiet https://github.com/ccache/ccache/releases/download/v4.10.2/ccache-4.10.2-linux-x86_64.tar.xz - tar -xvf ccache-*-linux-x86_64.tar.xz - cd ccache-*-linux-x86_64 - sudo make install - - - name: Install Qt for Android - uses: ./.github/actions/qt-android - with: - host: linux - arch: linux_gcc_64 - version: ${{ env.QT_VERSION }} - abis: ${{ env.QT_ANDROID_ABIS }} - - - run: mkdir ${{ runner.temp }}/shadow_build_dir - - - name: Configure - working-directory: ${{ runner.temp }}/shadow_build_dir - run: ${{ env.QT_ROOT_DIR }}/bin/qt-cmake -S ${{ github.workspace }} -B . -G Ninja - -DCMAKE_BUILD_TYPE=${{ matrix.BuildType }} - -DQT_ANDROID_ABIS="${{ env.QT_ANDROID_ABIS }}" - -DQT_ANDROID_BUILD_ALL_ABIS=OFF - -DQT_HOST_PATH="${{ env.QT_ROOT_DIR }}/../gcc_64" - -DQT_ANDROID_SIGN_APK=${{ github.ref == 'refs/heads/master' && github.event_name != 'pull_request' && 'ON' || 'OFF' }} - -DQT_DEBUG_FIND_PACKAGE=ON - -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 }} - - - run: cp ${{ runner.temp }}/shadow_build_dir/android-build/*.apk ${{ runner.temp }}/shadow_build_dir/${{ env.ARTIFACT }} - - - name: Upload Build File - if: matrix.BuildType == 'Release' - 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 }} - source: '' - github_token: ${{ secrets.GITHUB_TOKEN }} - - # - name: Deploy to Play Store - # if: matrix.BuildType == 'Release' - # uses: ./.github/actions/playstore - # with: - # artifact_name: ${{ runner.temp }}/shadow_build_dir/${{ env.ARTIFACT }} - # service_account_json: ${{ secrets.SERVICE_ACCOUNT }} diff --git a/.github/workflows/android-macos.yml b/.github/workflows/android-macos.yml deleted file mode 100644 index dae5c9a367f..00000000000 --- a/.github/workflows/android-macos.yml +++ /dev/null @@ -1,74 +0,0 @@ -name: Android-MacOS - -on: - workflow_dispatch: - -jobs: - build: - runs-on: macos-latest - - strategy: - matrix: - BuildType: [Release] - - defaults: - run: - shell: bash - - env: - ARTIFACT: QGroundControl.apk - QT_VERSION: 6.8.1 - GST_VERSION: 1.22.12 - QT_ANDROID_KEYSTORE_PATH: ${{ github.workspace }}/deploy/android/android_release.keystore - QT_ANDROID_KEYSTORE_ALIAS: QGCAndroidKeyStore - QT_ANDROID_KEYSTORE_STORE_PASS: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }} - QT_ANDROID_KEYSTORE_KEY_PASS: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }} - QT_ANDROID_ABIS: 'arm64-v8a' - - steps: - - name: Checkout repo - uses: actions/checkout@v4 - with: - submodules: recursive - fetch-tags: true - fetch-depth: 0 - - - uses: seanmiddleditch/gha-setup-ninja@v5 - - uses: lukka/get-cmake@latest - - - name: Install Dependencies - run: | - brew update - brew install cmake ninja ccache - continue-on-error: true - - - name: Install Qt for Android - uses: ./.github/actions/qt-android - with: - host: mac - arch: clang_64 - version: ${{ env.QT_VERSION }} - abis: ${{ env.QT_ANDROID_ABIS }} - - - run: mkdir ${{ runner.temp }}/shadow_build_dir - - - name: Configure - working-directory: ${{ runner.temp }}/shadow_build_dir - run: ${{ env.QT_ROOT_DIR }}/bin/qt-cmake -S ${{ github.workspace }} -B . -G Ninja - -DCMAKE_BUILD_TYPE=${{ matrix.BuildType }} - -DQT_ANDROID_ABIS="${{ env.QT_ANDROID_ABIS }}" - -DQT_ANDROID_BUILD_ALL_ABIS=OFF - -DQT_HOST_PATH="${{ env.QT_ROOT_DIR }}/../macos" - -DQT_ANDROID_SIGN_APK=${{ github.ref == 'refs/heads/master' && github.event_name != 'pull_request' && 'ON' || 'OFF' }} - -DQT_DEBUG_FIND_PACKAGE=ON - -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: Save APK - uses: actions/upload-artifact@v4 - with: - name: ${{ env.ARTIFACT }} - path: ${{ runner.temp }}/shadow_build_dir/android-build/*.apk diff --git a/.github/workflows/android-windows.yml b/.github/workflows/android-windows.yml deleted file mode 100644 index 01bb551375d..00000000000 --- a/.github/workflows/android-windows.yml +++ /dev/null @@ -1,90 +0,0 @@ -name: Android-Windows - -on: - push: - branches: - - master - - 'Stable*' - tags: - - 'v*' - paths-ignore: - - 'deploy/**' - - 'docs/**' - pull_request: - paths-ignore: - - 'deploy/**' - - 'docs/**' - - '.github/workflows/docs_deploy.yml' - - '.github/workflows/linux.yml' - - '.github/workflows/macos.yml' - - '.github/workflows/windows.yml' - -jobs: - build: - runs-on: windows-latest - - strategy: - matrix: - BuildType: [Release] - - defaults: - run: - shell: cmd - - env: - ARTIFACT: QGroundControl.apk - QT_VERSION: 6.8.1 - GST_VERSION: 1.22.12 - QT_ANDROID_KEYSTORE_PATH: ${{ github.workspace }}/deploy/android/android_release.keystore - QT_ANDROID_KEYSTORE_ALIAS: QGCAndroidKeyStore - QT_ANDROID_KEYSTORE_STORE_PASS: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }} - QT_ANDROID_KEYSTORE_KEY_PASS: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }} - QT_ANDROID_ABIS: 'arm64-v8a' - - steps: - - name: Checkout repo - uses: actions/checkout@v4 - with: - submodules: recursive - fetch-tags: true - fetch-depth: 0 - - - uses: seanmiddleditch/gha-setup-ninja@v5 - - uses: lukka/get-cmake@latest - - uses: mozilla-actions/sccache-action@v0.0.7 - - - name: Install Qt for Android - uses: ./.github/actions/qt-android - with: - host: windows - arch: win64_msvc2022_64 - version: ${{ env.QT_VERSION }} - abis: ${{ env.QT_ANDROID_ABIS }} - - - name: Set up Visual Studio shell - uses: ilammy/msvc-dev-cmd@v1 - with: - arch: x64 - - - run: mkdir ${{ runner.temp }}\shadow_build_dir - - - name: Configure - working-directory: ${{ runner.temp }}/shadow_build_dir - run: ${{ env.QT_ROOT_DIR }}/bin/qt-cmake -S ${{ github.workspace }} -B . -G Ninja - -DCMAKE_BUILD_TYPE=${{ matrix.BuildType }} - -DQT_ANDROID_ABIS="${{ env.QT_ANDROID_ABIS }}" - -DQT_ANDROID_BUILD_ALL_ABIS=OFF - -DQT_HOST_PATH="${{ env.QT_ROOT_DIR }}/../msvc2022_64" - -DQT_ANDROID_SIGN_APK=OFF - -DQT_DEBUG_FIND_PACKAGE=ON - -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: Save APK - uses: actions/upload-artifact@v4 - with: - name: ${{ env.ARTIFACT }} - path: ${{ runner.temp }}/shadow_build_dir/android-build/*.apk diff --git a/.github/workflows/custom.yml b/.github/workflows/custom.yml deleted file mode 100644 index 7ce2482e6a0..00000000000 --- a/.github/workflows/custom.yml +++ /dev/null @@ -1,117 +0,0 @@ -name: Custom build - -on: - push: - branches: - - master - - 'Stable*' - tags: - - 'v*' - paths-ignore: - - 'android/**' - - 'deploy/**' - - 'docs/**' - pull_request: - paths-ignore: - - 'android/**' - - 'deploy/**' - - 'docs/**' - - '.github/workflows/docs_deploy.yml' - - '.github/workflows/android.yml' - - '.github/workflows/linux.yml' - - '.github/workflows/macos.yml' - -jobs: - build: - runs-on: windows-latest - - strategy: - matrix: - BuildType: [Release] - Arch: [x64] - - defaults: - run: - shell: cmd - - env: - ARTIFACT: QGroundControl-installer.exe - QT_VERSION: 6.8.1 - GST_VERSION: 1.22.12 - SCCACHE_GHA_ENABLED: "true" - - steps: - - name: Checkout repo - uses: actions/checkout@v4 - with: - submodules: recursive - fetch-tags: true - fetch-depth: 0 - - - name: Enable custom build - run: | - if not exist ".\custom-example" ( - echo Directory ".\custom-example" does not exist. && exit /b 1 - ) - xcopy /E /I ".\custom-example" ".\custom" - - - uses: seanmiddleditch/gha-setup-ninja@v5 - - uses: lukka/get-cmake@latest - - # - name: Install Vulkan - # working-directory: ${{ runner.temp }} - # shell: pwsh - # run: | - # Invoke-WebRequest -Uri "https://sdk.lunarg.com/sdk/download/latest/windows/vulkan-sdk.exe" -OutFile vulkan-sdk.exe - # .\vulkan-sdk.exe --root C:\VulkanSDK\latest --accept-licenses --default-answer --confirm-command install com.lunarg.vulkan.glm com.lunarg.vulkan.volk com.lunarg.vulkan.vma com.lunarg.vulkan.debug - # echo "VULKAN_SDK=C:\VulkanSDK\latest" >> $env:GITHUB_ENV - - - name: Install GStreamer - uses: blinemedical/setup-gstreamer@v1 - with: - version: ${{ env.GST_VERSION }} - - # - name: Install Gstreamer - # run: choco install --no-progress gstreamer gstreamer-devel --version=${{ env.GST_VERSION }} - - - name: Set Up sccache - uses: mozilla-actions/sccache-action@v0.0.7 - - - name: Set Up Cache - uses: hendrikmuhs/ccache-action@main - with: - key: ${{ runner.os }}-${{ matrix.Arch }}-${{ matrix.BuildType }}-custom - max-size: 1G - variant: sccache - save: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }} - evict-old-files: 'job' - - - name: Install Qt for Windows (x64) - if: matrix.Arch == 'x64' - uses: jurplel/install-qt-action@v4 - with: - version: ${{ env.QT_VERSION }} - aqtversion: ==3.1.19 - host: windows - target: desktop - arch: win64_msvc2022_64 - dir: ${{ runner.temp }} - modules: qtcharts qtlocation qtpositioning qtspeech qt5compat qtmultimedia qtserialport qtimageformats qtshadertools qtconnectivity qtquick3d qtsensors - cache: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }} - - - name: Set up Visual Studio shell - uses: ilammy/msvc-dev-cmd@v1 - with: - arch: x64 - - - run: mkdir ${{ runner.temp }}\shadow_build_dir - - - name: Configure - working-directory: ${{ runner.temp }}\shadow_build_dir - run: ${{ env.QT_ROOT_DIR }}/bin/qt-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 }} diff --git a/.github/workflows/docker-linux.yml b/.github/workflows/docker-linux.yml deleted file mode 100644 index 0ebabcacbff..00000000000 --- a/.github/workflows/docker-linux.yml +++ /dev/null @@ -1,43 +0,0 @@ -name: Docker-Linux - -on: - push: - branches: - - master - - 'Stable*' - tags: - - 'v*' - paths-ignore: - - 'android/**' - - 'deploy/**' - - 'docs/**' - pull_request: - paths-ignore: - - 'android/**' - - 'deploy/**' - - 'docs/**' - - '.github/workflows/docs_deploy.yml' - - '.github/workflows/android.yml' - - '.github/workflows/macos.yml' - - '.github/workflows/windows.yml' - -jobs: - build: - runs-on: ubuntu-latest - - defaults: - run: - shell: bash - - steps: - - name: Checkout repo - uses: actions/checkout@v4 - with: - submodules: recursive - fetch-tags: true - fetch-depth: 0 - - - run: chmod a+x ./deploy/docker/run-docker-ubuntu.sh - - - name: Run Docker Build - run: ./deploy/docker/run-docker-ubuntu.sh diff --git a/.github/workflows/docs_deploy.yml b/.github/workflows/docs_deploy.yml deleted file mode 100644 index 2e4de6e6db2..00000000000 --- a/.github/workflows/docs_deploy.yml +++ /dev/null @@ -1,75 +0,0 @@ -name: Docs - -on: - push: - branches: - - master - - 'Stable*' - tags: - - 'v*' - paths: - - 'docs/**' - pull_request: - paths: - - 'docs/**' - - workflow_dispatch: - -env: - BRANCH_NAME: ${{ github.head_ref || github.ref_name }} - -jobs: - build: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Setup Node - uses: actions/setup-node@v4 - with: - node-version: 20 - cache: npm - - - name: Install dependencies - run: npm ci - - - name: Build with VitePress - run: | - npm run docs:build - touch docs/.vitepress/dist/.nojekyll - - - name: Upload artifact - uses: actions/upload-artifact@v4 - with: - name: qgc_docs_build - path: docs/.vitepress/dist/ - retention-days: 1 - - deploy: - if: ${{ github.event_name == 'push' || github.event_name == 'workflow_dispatch' || (github.event_name == 'pull_request' && github.event.pull_request.merged) }} - needs: build - runs-on: ubuntu-latest - - steps: - - name: Download Artifact - uses: actions/download-artifact@v4 - with: - name: qgc_docs_build - path: ~/_book - - - name: Deploy - env: - GIT_USER: ${{ secrets.PX4BUILDBOT_USER }} - GIT_PASS: ${{ secrets.PX4BUILDBOT_PASS }} - run: | - git clone https://${{ secrets.PX4BUILDBOT_USER }}:${{ secrets.PX4BUILDBOT_ACCESSTOKEN }}@github.com/mavlink/docs.qgroundcontrol.com.git - rm -rf docs.qgroundcontrol.com/${{ env.BRANCH_NAME }} - mkdir -p docs.qgroundcontrol.com/${{ env.BRANCH_NAME }} - cp -r ~/_book/* docs.qgroundcontrol.com/${{ env.BRANCH_NAME }}/ - cd docs.qgroundcontrol.com - git config user.email "bot@px4.io" - git config user.name "PX4BuildBot" - git add ${{ env.BRANCH_NAME }} - git commit -a -m "QGC docs build update `date`" - git push origin master diff --git a/.github/workflows/ios.yml b/.github/workflows/ios.yml deleted file mode 100644 index eaef8e962a2..00000000000 --- a/.github/workflows/ios.yml +++ /dev/null @@ -1,110 +0,0 @@ -name: iOS - -on: - workflow_dispatch: - -jobs: - build: - runs-on: macos-latest - - strategy: - matrix: - BuildType: [Release] - - defaults: - run: - shell: bash - - env: - ARTIFACT: QGroundControl.app - QT_VERSION: 6.8.1 - GST_VERSION: 1.22.12 - - steps: - - name: Recover disk space - run: | - df -h - ls /Applications - brew uninstall google-chrome - sudo rm -rf /Users/runner/Library/Android - sudo rm -rf /Applications/Xcode_14* - sudo rm -rf /Applications/Xcode_15.0* - sudo rm -rf /Applications/Xcode_15.1* - sudo rm -rf /Applications/Xcode_15.2* - sudo rm -rf /Applications/Xcode_15.3* - ls /Applications - df -h - - - name: Checkout repo - uses: actions/checkout@v4 - with: - submodules: recursive - fetch-tags: true - fetch-depth: 0 - - - name: Setup Xcode - uses: maxim-lobanov/setup-xcode@v1 - with: - xcode-version: latest-stable - - - uses: seanmiddleditch/gha-setup-ninja@v5 - - - name: Install Dependencies - run: | - brew update - brew install cmake ninja ccache - - - uses: seanmiddleditch/gha-setup-ninja@v5 - - uses: lukka/get-cmake@latest - - - name: Set Up Cache - uses: hendrikmuhs/ccache-action@main - with: - key: ${{ runner.os }}-iOS-${{ matrix.BuildType }} - max-size: 1G - save: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }} - evict-old-files: 'job' - - - name: Install Qt for MacOS - uses: jurplel/install-qt-action@v4 - with: - version: ${{ env.QT_VERSION }} - aqtversion: ==3.1.* - host: mac - target: desktop - arch: clang_64 - dir: ${{ runner.temp }} - modules: qtcharts qtlocation qtpositioning qtspeech qt5compat qtmultimedia qtserialport qtimageformats qtshadertools qtconnectivity qtquick3d qtsensors - cache: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }} - - - name: Install Qt for iOS - uses: jurplel/install-qt-action@v4 - with: - version: ${{ env.QT_VERSION }} - aqtversion: ==3.1.* - host: mac - target: ios - arch: ios - dir: ${{ runner.temp }} - extra: --autodesktop - modules: qtcharts qtlocation qtpositioning qtspeech qt5compat qtmultimedia qtimageformats qtshadertools qtconnectivity qtquick3d qtsensors - cache: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }} - - - run: mkdir ${{ runner.temp }}/shadow_build_dir - - - name: Configure - working-directory: ${{ runner.temp }}/shadow_build_dir - run: ${{ env.QT_ROOT_DIR }}/bin/qt-cmake -S ${{ github.workspace }} -B . -G Ninja - -DCMAKE_BUILD_TYPE=${{ matrix.BuildType }} - -DQT_HOST_PATH="${{ env.QT_ROOT_DIR }}/../macos" - -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: Save App - uses: actions/upload-artifact@v4 - with: - name: ${{ env.ARTIFACT }} - path: ${{ runner.temp }}/shadow_build_dir/*.app diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml deleted file mode 100644 index be4dd0feb25..00000000000 --- a/.github/workflows/linux.yml +++ /dev/null @@ -1,139 +0,0 @@ -name: Linux - -on: - push: - branches: - - master - - 'Stable*' - tags: - - 'v*' - paths-ignore: - - 'android/**' - - 'deploy/**' - - 'docs/**' - pull_request: - paths-ignore: - - 'android/**' - - 'deploy/**' - - 'docs/**' - - '.github/workflows/docs_deploy.yml' - - '.github/workflows/android.yml' - - '.github/workflows/macos.yml' - - '.github/workflows/windows.yml' - -jobs: - build: - runs-on: ubuntu-22.04 - - strategy: - matrix: - BuildType: [Debug, Release] - - defaults: - run: - shell: bash - - env: - ARTIFACT: QGroundControl-x86_64.AppImage - QT_VERSION: 6.8.1 - GST_VERSION: 1.22.12 - - steps: - - name: Free Disk Space (Ubuntu) - uses: jlumbroso/free-disk-space@main - with: - large-packages: false - continue-on-error: true - - - name: Checkout repo - uses: actions/checkout@v4 - with: - submodules: recursive - fetch-tags: true - fetch-depth: 0 - - - name: Install Dependencies - run: | - chmod a+x ./tools/setup/install-dependencies-debian.sh - sudo ./tools/setup/install-dependencies-debian.sh - python3 -m pip install --user ninja cmake - - - name: Install Vulkan - run: | - wget -qO- https://packages.lunarg.com/lunarg-signing-key-pub.asc | sudo tee /etc/apt/trusted.gpg.d/lunarg.asc - sudo wget -qO /etc/apt/sources.list.d/lunarg-vulkan-jammy.list http://packages.lunarg.com/vulkan/lunarg-vulkan-jammy.list - sudo apt update - sudo apt install vulkan-sdk - - - name: Install Compiler - run: | - sudo add-apt-repository ppa:ubuntu-toolchain-r/test - sudo apt install gcc-11 g++-11 - sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-11 100 --slave /usr/bin/g++ g++ /usr/bin/g++-11 --slave /usr/bin/gcov gcov /usr/bin/gcov-11 - sudo update-alternatives --set gcc /usr/bin/gcc-11 - - - name: Install CCache - run: | - wget --quiet https://github.com/ccache/ccache/releases/download/v4.10.2/ccache-4.10.2-linux-x86_64.tar.xz - tar -xvf ccache-*-linux-x86_64.tar.xz - cd ccache-*-linux-x86_64 - sudo make install - - - name: Set Up Cache - uses: hendrikmuhs/ccache-action@main - with: - create-symlink: true - key: ${{ runner.os }}-${{ matrix.BuildType }} - max-size: 1G - save: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }} - evict-old-files: 'job' - - - name: Install Qt for Linux (x64) - uses: jurplel/install-qt-action@v4 - with: - version: ${{ env.QT_VERSION }} - aqtversion: ==3.1.* - host: linux - target: desktop - arch: linux_gcc_64 - dir: ${{ runner.temp }} - modules: qtcharts qtlocation qtpositioning qtspeech qt5compat qtmultimedia qtserialport qtimageformats qtshadertools qtconnectivity qtquick3d qtsensors - cache: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }} - - # - name: Build GStreamer - # uses: ./.github/actions/gstreamer - - - uses: lukka/get-cmake@latest - - uses: seanmiddleditch/gha-setup-ninja@v5 - - - run: mkdir ${{ runner.temp }}/shadow_build_dir - - - name: Configure - working-directory: ${{ runner.temp }}/shadow_build_dir - run: ${{ env.QT_ROOT_DIR }}/bin/qt-cmake -S ${{ github.workspace }} -B . -G Ninja - -DCMAKE_BUILD_TYPE=${{ matrix.BuildType }} - -DQGC_BUILD_TESTING=${{ matrix.BuildType == 'Debug' && 'ON' || 'OFF' }} - -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 . --config ${{ matrix.BuildType }} - - - name: Run unit tests - if: matrix.BuildType == 'Debug' - working-directory: ${{ runner.temp }}/shadow_build_dir - run: xvfb-run -a ./${{ env.ARTIFACT }} --unittest - - - name: Upload Build File - if: matrix.BuildType == 'Release' - 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 }} - source: '' - github_token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml deleted file mode 100644 index 965daae8b96..00000000000 --- a/.github/workflows/windows.yml +++ /dev/null @@ -1,140 +0,0 @@ -name: Windows - -on: - push: - branches: - - master - - 'Stable*' - tags: - - 'v*' - paths-ignore: - - 'android/**' - - 'deploy/**' - - 'docs/**' - pull_request: - paths-ignore: - - 'android/**' - - 'deploy/**' - - 'docs/**' - - '.github/workflows/docs_deploy.yml' - - '.github/workflows/android.yml' - - '.github/workflows/linux.yml' - - '.github/workflows/macos.yml' - -jobs: - build: - runs-on: windows-latest - - strategy: - matrix: - BuildType: [Release] - Arch: [x64] # Arm64 - - defaults: - run: - shell: cmd - - env: - ARTIFACT: QGroundControl-installer.exe - QT_VERSION: 6.8.1 - GST_VERSION: 1.22.12 - SCCACHE_GHA_ENABLED: "true" - - steps: - - name: Checkout repo - uses: actions/checkout@v4 - with: - submodules: recursive - fetch-tags: true - fetch-depth: 0 - - - uses: seanmiddleditch/gha-setup-ninja@v5 - - uses: lukka/get-cmake@latest - - - name: Install Vulkan - working-directory: ${{ runner.temp }} - shell: pwsh - run: | - Invoke-WebRequest -Uri "https://sdk.lunarg.com/sdk/download/latest/windows/vulkan-sdk.exe" -OutFile vulkan-sdk.exe - .\vulkan-sdk.exe --root C:\VulkanSDK\latest --accept-licenses --default-answer --confirm-command install com.lunarg.vulkan.glm com.lunarg.vulkan.volk com.lunarg.vulkan.vma com.lunarg.vulkan.debug - echo "VULKAN_SDK=C:\VulkanSDK\latest" >> $env:GITHUB_ENV - - - name: Install GStreamer - uses: blinemedical/setup-gstreamer@v1 - with: - version: ${{ env.GST_VERSION }} - - # - name: Install Gstreamer - # run: choco install --no-progress gstreamer gstreamer-devel --version=${{ env.GST_VERSION }} - - - name: Set Up sccache - uses: mozilla-actions/sccache-action@v0.0.7 - - - name: Set Up Cache - uses: hendrikmuhs/ccache-action@main - with: - key: ${{ runner.os }}-${{ matrix.Arch }}-${{ matrix.BuildType }} - max-size: 1G - variant: sccache - save: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }} - evict-old-files: 'job' - - - name: Install Qt for Windows (x64) - uses: jurplel/install-qt-action@v4 - with: - version: ${{ env.QT_VERSION }} - aqtversion: ==3.1.19 - host: windows - target: desktop - arch: win64_msvc2022_64 - dir: ${{ runner.temp }} - modules: qtcharts qtlocation qtpositioning qtspeech qt5compat qtmultimedia qtserialport qtimageformats qtshadertools qtconnectivity qtquick3d qtsensors - cache: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }} - - # Note: Must Use QtMultimedia VideoReceiver or build GStreamer manually - - name: Install Qt for Windows (Arm64) - if: matrix.Arch == 'Arm64' - uses: jurplel/install-qt-action@v4 - with: - version: ${{ env.QT_VERSION }} - aqtversion: ==3.1.* - host: windows - target: desktop - arch: win64_msvc2022_arm64_cross_compiled - dir: ${{ runner.temp }} - extra: --autodesktop - modules: qtcharts qtlocation qtpositioning qtspeech qt5compat qtmultimedia qtserialport qtimageformats qtshadertools qtconnectivity qtquick3d qtsensors - cache: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }} - - - name: Set up Visual Studio shell - uses: ilammy/msvc-dev-cmd@v1 - with: - arch: ${{ matrix.Arch == 'Arm64' && 'amd64_arm64' || 'x64' }} - - - run: mkdir ${{ runner.temp }}\shadow_build_dir - - - name: Configure - working-directory: ${{ runner.temp }}\shadow_build_dir - run: ${{ env.QT_ROOT_DIR }}/bin/qt-cmake -S ${{ github.workspace }} -B . -G Ninja - -DCMAKE_BUILD_TYPE=${{ matrix.BuildType }} - -DQT_HOST_PATH="${{ env.QT_ROOT_DIR }}/../msvc2022_64" - -DQT_DEBUG_FIND_PACKAGE=ON - -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: Install - working-directory: ${{ runner.temp }}\shadow_build_dir - run: cmake --install . --config ${{ matrix.BuildType }} - - - name: Upload Build File - if: matrix.BuildType == 'Release' - 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 }} - source: '' - github_token: ${{ secrets.GITHUB_TOKEN }} diff --git a/CMakeLists.txt b/CMakeLists.txt index 3d22793042e..0f4a4270eb5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -541,8 +541,8 @@ install( ) set(deploy_tool_options_arg "") -if(APPLE) - set(deploy_tool_options_arg -qmldir=${CMAKE_SOURCE_DIR}/src -hardened-runtime -timestamp -appstore-compliant) +if(MACOS) + set(deploy_tool_options_arg -qmldir=${CMAKE_SOURCE_DIR}/src -hardened-runtime -timestamp -appstore-compliant) # -dmg endif() qt_generate_deploy_qml_app_script( diff --git a/cmake/CreateMacDMG.cmake b/cmake/CreateMacDMG.cmake index 672f3c3b9f5..bba442072f0 100644 --- a/cmake/CreateMacDMG.cmake +++ b/cmake/CreateMacDMG.cmake @@ -1,38 +1,52 @@ message(STATUS "Creating Mac Bundle") set(TARGET_NAME QGroundControl) -set(SYSTEM_FRAMEWORK_PATH /Library/Frameworks) -set(BUNDLE_FRAMEWORK_PATH staging/${TARGET_NAME}.app/Contents/Frameworks) - -message(STATUS "Copy GStreamer framework into bundle") -file(COPY ${SYSTEM_FRAMEWORK_PATH}/GStreamer.framework DESTINATION ${BUNDLE_FRAMEWORK_PATH}) -file(REMOVE_RECURSE ${BUNDLE_FRAMEWORK_PATH}/GStreamer.framework/Versions/1.0/bin) -file(REMOVE_RECURSE ${BUNDLE_FRAMEWORK_PATH}/GStreamer.framework/Versions/1.0/etc) -file(REMOVE_RECURSE ${BUNDLE_FRAMEWORK_PATH}/GStreamer.framework/Versions/1.0/share) -file(REMOVE_RECURSE ${BUNDLE_FRAMEWORK_PATH}/GStreamer.framework/Versions/1.0/Headers) -file(REMOVE_RECURSE ${BUNDLE_FRAMEWORK_PATH}/GStreamer.framework/Versions/1.0/include) -file(REMOVE_RECURSE ${BUNDLE_FRAMEWORK_PATH}/GStreamer.framework/Versions/1.0/Commands) -file(REMOVE_RECURSE ${BUNDLE_FRAMEWORK_PATH}/GStreamer.framework/Versions/1.0/lib/pkgconfig) -file(REMOVE_RECURSE ${BUNDLE_FRAMEWORK_PATH}/GStreamer.framework/Versions/1.0/lib/glib-2.0) -file(REMOVE_RECURSE ${BUNDLE_FRAMEWORK_PATH}/GStreamer.framework/Versions/1.0/lib/graphene-1.0) -file(REMOVE_RECURSE ${BUNDLE_FRAMEWORK_PATH}/GStreamer.framework/Versions/1.0/lib/gst-validate-launcher) -file(GLOB REMOVE_LIB_FILES ${BUNDLE_FRAMEWORK_PATH}/GStreamer.framework/Versions/1.0/lib/*.a) -file(REMOVE ${REMOVE_LIB_FILES}) -file(GLOB REMOVE_LIB_FILES ${BUNDLE_FRAMEWORK_PATH}/GStreamer.framework/Versions/1.0/lib/*.la) -file(REMOVE ${REMOVE_LIB_FILES}) -file(GLOB REMOVE_LIB_FILES ${BUNDLE_FRAMEWORK_PATH}/GStreamer.framework/Versions/1.0/lib/gstreamer-1.0/*.a) -file(REMOVE ${REMOVE_LIB_FILES}) -file(GLOB REMOVE_LIB_FILES ${BUNDLE_FRAMEWORK_PATH}/GStreamer.framework/Versions/1.0/lib/gstreamer-1.0/*.la) -file(REMOVE ${REMOVE_LIB_FILES}) -file(REMOVE_RECURSE ${BUNDLE_FRAMEWORK_PATH}/GStreamer.framework/Versions/1.0/lib/gstreamer-1.0/include) -file(REMOVE_RECURSE ${BUNDLE_FRAMEWORK_PATH}/GStreamer.framework/Versions/1.0/lib/gstreamer-1.0/pkgconfig) +# set(SYSTEM_FRAMEWORK_PATH /Library/Frameworks) +# set(BUNDLE_FRAMEWORK_PATH staging/${TARGET_NAME}.app/Contents/Frameworks) + +# execute_process( +# COMMAND ${CMAKE_SOURCE_DIR}/deploy/mac/prepare_gstreamer_framework.sh ${CMAKE_BINARY_DIR}/gstwork/ staging/${TARGET_NAME}.app ${TARGET_NAME} +# RESULT_VARIABLE GSTREAMER_FRAMEWORK_RESULT +# OUTPUT_VARIABLE GSTREAMER_FRAMEWORK_OUTPUT +# ERROR_VARIABLE GSTREAMER_FRAMEWORK_ERROR +# ) + +# include(CMakePrintHelpers) +# cmake_print_variables(GSTREAMER_FRAMEWORK_RESULT GSTREAMER_FRAMEWORK_OUTPUT GSTREAMER_FRAMEWORK_ERROR) + +# message(STATUS "Copy GStreamer framework into bundle") +# file(COPY ${SYSTEM_FRAMEWORK_PATH}/GStreamer.framework DESTINATION ${BUNDLE_FRAMEWORK_PATH}) +# file(REMOVE_RECURSE ${BUNDLE_FRAMEWORK_PATH}/GStreamer.framework/Versions/1.0/bin) +# file(REMOVE_RECURSE ${BUNDLE_FRAMEWORK_PATH}/GStreamer.framework/Versions/1.0/etc) +# file(REMOVE_RECURSE ${BUNDLE_FRAMEWORK_PATH}/GStreamer.framework/Versions/1.0/share) +# file(REMOVE_RECURSE ${BUNDLE_FRAMEWORK_PATH}/GStreamer.framework/Versions/1.0/Headers) +# file(REMOVE_RECURSE ${BUNDLE_FRAMEWORK_PATH}/GStreamer.framework/Versions/1.0/include) +# file(REMOVE_RECURSE ${BUNDLE_FRAMEWORK_PATH}/GStreamer.framework/Versions/1.0/Commands) +# file(REMOVE_RECURSE ${BUNDLE_FRAMEWORK_PATH}/GStreamer.framework/Versions/1.0/lib/pkgconfig) +# file(REMOVE_RECURSE ${BUNDLE_FRAMEWORK_PATH}/GStreamer.framework/Versions/1.0/lib/glib-2.0) +# file(REMOVE_RECURSE ${BUNDLE_FRAMEWORK_PATH}/GStreamer.framework/Versions/1.0/lib/graphene-1.0) +# file(REMOVE_RECURSE ${BUNDLE_FRAMEWORK_PATH}/GStreamer.framework/Versions/1.0/lib/gst-validate-launcher) +# file(GLOB REMOVE_LIB_FILES ${BUNDLE_FRAMEWORK_PATH}/GStreamer.framework/Versions/1.0/lib/*.a) +# file(REMOVE ${REMOVE_LIB_FILES}) +# file(GLOB REMOVE_LIB_FILES ${BUNDLE_FRAMEWORK_PATH}/GStreamer.framework/Versions/1.0/lib/*.la) +# file(REMOVE ${REMOVE_LIB_FILES}) +# file(GLOB REMOVE_LIB_FILES ${BUNDLE_FRAMEWORK_PATH}/GStreamer.framework/Versions/1.0/lib/gstreamer-1.0/*.a) +# file(REMOVE ${REMOVE_LIB_FILES}) +# file(GLOB REMOVE_LIB_FILES ${BUNDLE_FRAMEWORK_PATH}/GStreamer.framework/Versions/1.0/lib/gstreamer-1.0/*.la) +# file(REMOVE ${REMOVE_LIB_FILES}) +# file(REMOVE_RECURSE ${BUNDLE_FRAMEWORK_PATH}/GStreamer.framework/Versions/1.0/lib/gstreamer-1.0/include) +# file(REMOVE_RECURSE ${BUNDLE_FRAMEWORK_PATH}/GStreamer.framework/Versions/1.0/lib/gstreamer-1.0/pkgconfig) + +# execute_process(COMMAND otool -L ${SYSTEM_FRAMEWORK_PATH}/GStreamer.framework/GStreamer) # Fix up library paths to point into bundle -execute_process(COMMAND ln -sf ${BUNDLE_FRAMEWORK_PATH} ${BUNDLE_FRAMEWORK_PATH}/GStreamer.framework/Versions/1.0/libexec/Frameworks) -execute_process(COMMAND install_name_tool -change ${SYSTEM_FRAMEWORK_PATH}/GStreamer.framework/Versions/1.0/lib/GStreamer @executable_path/../Frameworks/GStreamer.framework/Versions/1.0/lib/GStreamer staging/${TARGET_NAME}.app/Contents/MacOS/${TARGET_NAME}) +# execute_process(COMMAND ln -sf ${BUNDLE_FRAMEWORK_PATH} ${BUNDLE_FRAMEWORK_PATH}/GStreamer.framework/Versions/1.0/libexec) +# execute_process(COMMAND install_name_tool -id @executable_path/../Frameworks/GStreamer.framework/Versions/1.0/lib/GStreamer staging/${TARGET_NAME}.app/Contents/Frameworks/GStreamer.framework/Versions/1.0/GStreamer) +# execute_process(COMMAND install_name_tool -change ${SYSTEM_FRAMEWORK_PATH}/GStreamer.framework/Versions/1.0/lib/GStreamer @executable_path/../Frameworks/GStreamer.framework/Versions/1.0/lib/GStreamer staging/${TARGET_NAME}.app/Contents/MacOS/${TARGET_NAME}) + +execute_process(COMMAND otool -L staging/${TARGET_NAME}.app/Contents/MacOS/${TARGET_NAME}) # include(BundleUtilities) -# include(CMakePrintHelpers) # fixup_bundle("${CMAKE_BINARY_DIR}/staging/${TARGET_NAME}.app" "" "${SYSTEM_FRAMEWORK_PATH}/GStreamer.framework/Versions/1.0/lib/GStreamer") # verify_app("${CMAKE_BINARY_DIR}/staging/${TARGET_NAME}.app") diff --git a/cmake/find-modules/FindGStreamer.cmake b/cmake/find-modules/FindGStreamer.cmake index 3f000ac404e..e28544c2363 100644 --- a/cmake/find-modules/FindGStreamer.cmake +++ b/cmake/find-modules/FindGStreamer.cmake @@ -44,7 +44,8 @@ if(WIN32) ) elseif(MACOS) list(APPEND CMAKE_FRAMEWORK_PATH "/Library/Frameworks") - set(GSTREAMER_PREFIX "/Library/Frameworks/GStreamer.framework/Versions/1.0") + set(GSTREAMER_FRAMEWORK_PATH "/Library/Frameworks/GStreamer.framework" CACHE PATH "GStreamer Framework Path") + set(GSTREAMER_PREFIX "${GSTREAMER_FRAMEWORK_PATH}/Versions/1.0") find_program(PKG_CONFIG_PROGRAM pkg-config PATHS ${GSTREAMER_PREFIX}/bin NO_DEFAULT_PATH) if(PKG_CONFIG_PROGRAM) set(PKG_CONFIG_EXECUTABLE ${PKG_CONFIG_PROGRAM}) @@ -636,6 +637,9 @@ if(GStreamer_FOUND AND NOT TARGET GStreamer::GStreamer) GStreamer::Gl ) set_target_properties(GStreamer::GStreamer PROPERTIES VERSION ${GStreamer_VERSION}) + # if(MACOS) + # target_link_libraries(GStreamer::GStreamer INTERFACE "-F /Library/Frameworks -framework GStreamer") + # endif() endif() ################################################################################ diff --git a/deploy/mac/osxrelocator.py b/deploy/mac/osxrelocator.py new file mode 100755 index 00000000000..9a6999b5dfb --- /dev/null +++ b/deploy/mac/osxrelocator.py @@ -0,0 +1,160 @@ +#!/usr/bin/env python +# cerbero - a multi-platform build system for Open Source software +# Copyright (C) 2012 Andoni Morales Alastruey +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +import os +import subprocess + + +INT_CMD = 'install_name_tool' +OTOOL_CMD = 'otool' + + +def shell_call(cmd, cmd_dir='.', fail=True): + #print("call", cmd) + try: + ret = subprocess.check_call( + cmd, cwd=cmd_dir, + env=os.environ.copy()) + except subprocess.CalledProcessError: + if fail: + raise SystemError("Error running command: {}".format(cmd)) + else: + ret = 0 + return ret + + +def shell_check_call(cmd): + #print("ccall", cmd) + try: + process = subprocess.Popen( + cmd, stdout=subprocess.PIPE) + output, _ = process.communicate() + except Exception: + raise SystemError("Error running command: {}".format(cmd)) + return output + + +class OSXRelocator(object): + ''' + Wrapper for OS X's install_name_tool and otool commands to help + relocating shared libraries. + + It parses lib/ /libexec and bin/ directories, changes the prefix path of + the shared libraries that an object file uses and changes it's library + ID if the file is a shared library. + ''' + + def __init__(self, root, lib_prefix, new_lib_prefix, recursive): + self.root = root + self.lib_prefix = self._fix_path(lib_prefix).encode('utf-8') + self.new_lib_prefix = self._fix_path(new_lib_prefix).encode('utf-8') + self.recursive = recursive + + def relocate(self): + self.parse_dir(self.root, filters=['', '.dylib', '.so']) + + def relocate_file(self, object_file, id=None): + self.change_libs_path(object_file) + self.change_id(object_file, id) + + def change_id(self, object_file, id=None): + id = id or object_file.replace(self.lib_prefix.decode('utf-8'), self.new_lib_prefix.decode('utf-8')) + filename = os.path.basename(object_file) + if not (filename.endswith('so') or filename.endswith('dylib')): + return + cmd = [INT_CMD, "-id", id, object_file] + shell_call(cmd, fail=False) + + def change_libs_path(self, object_file): + for lib in self.list_shared_libraries(object_file): + if self.lib_prefix in lib: + new_lib = lib.replace(self.lib_prefix, self.new_lib_prefix) + cmd = [INT_CMD, "-change", lib, new_lib, object_file] + shell_call(cmd) + + def parse_dir(self, dir_path, filters=None): + for dirpath, dirnames, filenames in os.walk(dir_path): + for f in filenames: + if filters is not None and \ + os.path.splitext(f)[1] not in filters: + continue + fn = os.path.join(dirpath, f) + if os.path.islink(fn): + continue + if not os.path.isfile(fn): + continue + self.relocate_file(fn) + if not self.recursive: + break + + @staticmethod + def list_shared_libraries(object_file): + cmd = [OTOOL_CMD, "-L", object_file] + res = shell_check_call(cmd).split(b'\n') + # We don't use the first line + libs = res[1:] + # Remove the first character tabulation + libs = [x[1:] for x in libs] + # Remove the version info + libs = [x.split(b' ', 1)[0] for x in libs] + return libs + + @staticmethod + def library_id_name(object_file): + cmd = [OTOOL_CMD, "-D", object_file] + res = shell_check_call(cmd).split('\n')[0] + # the library name ends with ':' + lib_name = res[:-1] + return lib_name + + def _fix_path(self, path): + if path.endswith('/'): + return path[:-1] + return path + + +class Main(object): + + def run(self): + # We use OptionParser instead of ArgumentsParse because this script + # might be run in OS X 10.6 or older, which do not provide the argparse + # module + import optparse + usage = "usage: %prog [options] directory old_prefix new_prefix" + description = 'Rellocates object files changing the dependent '\ + ' dynamic libraries location path with a new one' + parser = optparse.OptionParser(usage=usage, description=description) + parser.add_option('-r', '--recursive', action='store_true', + default=False, dest='recursive', + help='Scan directories recursively') + + options, args = parser.parse_args() + if len(args) != 3: + parser.print_usage() + exit(1) + relocator = OSXRelocator(args[0], args[1], args[2], options.recursive) + relocator.relocate() + exit(0) + +def main(): + main = Main() + main.run() + +if __name__ == "__main__": + main() diff --git a/deploy/mac/osxrelocator2.py b/deploy/mac/osxrelocator2.py new file mode 100755 index 00000000000..eb7a678b817 --- /dev/null +++ b/deploy/mac/osxrelocator2.py @@ -0,0 +1,342 @@ +#!/usr/bin/env python3 +# cerbero - a multi-platform build system for Open Source software +# Copyright (C) 2012 Andoni Morales Alastruey +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +import os + +INT_CMD = 'install_name_tool' +OTOOL_CMD = 'otool' + + +def _cmd_string_to_array(cmd, env): + if isinstance(cmd, list): + return _resolve_cmd(cmd, env) + assert isinstance(cmd, str) + # If we've been given a string, run it through sh to get scripts working on + # Windows and shell syntax such as && and env var setting working on all + # platforms. + return ['sh', '-c', cmd] + + +def check_output(cmd, cmd_dir=None, fail=True, logfile=None, env=None, quiet=False): + cmd = _cmd_string_to_array(cmd, env) + stderr = logfile + if quiet and not logfile: + stderr = subprocess.DEVNULL + if logfile: + logfile.write(f'Running command {cmd!r} in {cmd_dir}\n') + logfile.flush() + + try: + o = subprocess.check_output(cmd, cwd=cmd_dir, env=env, stderr=stderr) + except SUBPROCESS_EXCEPTIONS as e: + msg = getattr(e, 'output', '') + if isinstance(msg, bytes): + msg = msg.decode(sys.stdout.encoding, errors='replace') + if not fail: + return msg + if logfile: + msg += '\nstderr in logfile {}'.format(logfile.name) + raise CommandError(msg, cmd, getattr(e, 'returncode', -1)) + + if sys.stdout.encoding: + o = o.decode(sys.stdout.encoding, errors='replace') + return o + + + +def new_call( + cmd, cmd_dir=None, fail=True, logfile=None, env=None, verbose=False, interactive=False, shell=False, input=None +): + cmd = _cmd_string_to_array(cmd, env) + if logfile: + if input: + logfile.write(f'Running command {cmd!r} with stdin {input} in {cmd_dir}\n') + else: + logfile.write(f'Running command {cmd!r} in {cmd_dir}\n') + logfile.flush() + if verbose: + m.message('Running {!r}\n'.format(cmd)) + if input: + stdin = None + elif not interactive: + stdin = subprocess.DEVNULL + else: + stdin = None + try: + subprocess.run( + cmd, + cwd=cmd_dir, + env=env, + stdout=logfile, + stderr=subprocess.STDOUT, + stdin=stdin, + input=input, + shell=shell, + check=True, + ) + except SUBPROCESS_EXCEPTIONS as e: + returncode = getattr(e, 'returncode', -1) + if not fail: + stream = logfile or sys.stderr + if isinstance(e, FileNotFoundError): + stream.write('{}: file not found\n'.format(cmd[0])) + if isinstance(e, PermissionError): + stream.write('{!r}: permission error\n'.format(cmd)) + return returncode + msg = '' + if logfile: + msg = 'Output in logfile {}'.format(logfile.name) + raise CommandError(msg, cmd, returncode) + return 0 + + + +class CerberoException(Exception): + header = '' + msg = '' + + def __init__(self, msg=''): + self.msg = msg + Exception.__init__(self, self.header + msg) + + + +class FatalError(CerberoException): + header = 'Fatal Error: ' + + def __init__(self, msg='', arch=''): + self.arch = arch + CerberoException.__init__(self, msg) + + + +class OSXRelocator(object): + """ + Wrapper for OS X's install_name_tool and otool commands to help + relocating shared libraries. + + It parses lib/ /libexec and bin/ directories, changes the prefix path of + the shared libraries that an object file uses and changes it's library + ID if the file is a shared library. + """ + + def __init__(self, root, install_prefix, recursive, logfile=None): + self.root = root + self.install_prefix = self._fix_path(install_prefix) + self.recursive = recursive + self.use_relative_paths = True + self.logfile = None + + def relocate(self): + self.parse_dir(self.root) + + def relocate_dir(self, dirname): + self.parse_dir(os.path.join(self.root, dirname)) + + def relocate_file(self, object_file, original_file=None): + self.change_libs_path(object_file, original_file) + + def change_id(self, object_file, id=None): + """ + Changes the `LC_ID_DYLIB` of the given object file. + @object_file: Path to the object file + @id: New ID; if None, it'll be `@rpath/` + """ + id = id or object_file.replace(self.install_prefix, '@rpath') + if not self._is_mach_o_file(object_file): + return + cmd = [INT_CMD, '-id', id, object_file] + shell.new_call(cmd, fail=False, logfile=self.logfile) + + def change_libs_path(self, object_file, original_file=None): + """ + Sanitizes the `LC_LOAD_DYLIB` and `LC_RPATH` load commands, + setting the former to be of the form `@rpath/libyadda.dylib`, + and the latter to point to the /lib folder within the GStreamer prefix. + @object_file: the actual file location + @original_file: where the file will end up in the output directory + structure and the basis of how to calculate rpath entries. This may + be different from where the file is currently located e.g. when + creating a fat binary from copy of the original file in a temporary + location. + """ + if not self._is_mach_o_file(object_file): + return + if original_file is None: + original_file = object_file + # First things first: ensure the load command of future consumers + # points to the real ID of this library + # This used to be done only at Universal lipo time, but by then + # it's too late -- unless one wants to run through all load commands + # If the library isn't a dylib, it's a framework, in which case + # assert that it's already rpath'd + dylib_id = self.get_dylib_id(object_file) + is_dylib = dylib_id is not None + is_framework = is_dylib and not object_file.endswith('.dylib') + if not is_framework: + self.change_id(object_file, id='@rpath/{}'.format(os.path.basename(original_file))) + elif '@rpath' not in dylib_id: + raise FatalError(f'Cannot relocate a fixed location framework: {dylib_id}') + # With that out of the way, we need to sort out how many parents + # need to be navigated to reach the root of the GStreamer prefix + depth = len(os.path.dirname(original_file).split('/')) - len(self.install_prefix.split('/')) + p_depth = '/..' * depth + # These paths assume that the file being relocated resides within + # /lib + rpaths = [ + # From a deeply nested library + f'@loader_path{p_depth}/lib', + # From a deeply nested framework or binary + f'@executable_path{p_depth}/lib', + # From a library within the prefix + '@loader_path/../lib', + # From a binary within the prefix + '@executable_path/../lib', + ] + if depth > 1: + rpaths += [ + # Allow loading from the parent (e.g. GIO plugin) + '@loader_path/..', + '@executable_path/..', + ] + if is_framework: + # Start with framework's libraries + rpaths = [ + '@loader_path/lib', + ] + rpaths + # Make them unique + rpaths = list(set(rpaths)) + # Remove absolute RPATHs, we don't want or need these + existing_rpaths = list(set(self.list_rpaths(object_file))) + for p in filter(lambda p: p.startswith('/'), self.list_rpaths(object_file)): + cmd = [INT_CMD, '-delete_rpath', p, object_file] + shell.new_call(cmd, fail=False) + # Add relative RPATHs + for p in filter(lambda p: p not in existing_rpaths, rpaths): + cmd = [INT_CMD, '-add_rpath', p, object_file] + shell.new_call(cmd, fail=False) + # Change dependencies' paths from absolute to @rpath/ + for lib in self.list_shared_libraries(object_file): + new_lib = lib.replace(self.install_prefix, '@rpath').replace('@rpath/lib/', '@rpath/') + # These are leftovers from meson thinking RPATH == prefix + if new_lib == lib: + continue + cmd = [INT_CMD, '-change', lib, new_lib, object_file] + shell.new_call(cmd, fail=False, logfile=self.logfile) + + def change_lib_path(self, object_file, old_path, new_path): + for lib in self.list_shared_libraries(object_file): + if old_path in lib: + new_path = lib.replace(old_path, new_path) + cmd = [INT_CMD, '-change', lib, new_path, object_file] + shell.new_call(cmd, fail=True, logfile=self.logfile) + + def parse_dir(self, dir_path, filters=None): + for dirpath, dirnames, filenames in os.walk(dir_path): + for f in filenames: + if filters is not None and os.path.splitext(f)[1] not in filters: + continue + self.change_libs_path(os.path.join(dirpath, f)) + if not self.recursive: + break + + @staticmethod + def get_dylib_id(object_file): + res = shell.check_output([OTOOL_CMD, '-D', object_file]).splitlines() + return res[-1] if len(res) > 1 else None + + @staticmethod + def list_shared_libraries(object_file): + res = shell.check_output([OTOOL_CMD, '-L', object_file]).splitlines() + # We don't use the first line + libs = res[1:] + # Remove the first character tabulation + libs = [x[1:] for x in libs] + # Remove the version info + libs = [x.split(' ', 1)[0] for x in libs] + return libs + + @staticmethod + def list_rpaths(object_file): + res = shell.check_output([OTOOL_CMD, '-l', object_file]).splitlines() + i = iter(res) + paths = [] + for line in i: + if 'LC_RPATH' not in line: + continue + next(i) + path_line = next(i) + # Extract the path from a line that looks like this: + # path @loader_path/.. (offset 12) + path = path_line.split('path ', 1)[1].split(' (offset', 1)[0] + paths.append(path) + return paths + + def _fix_path(self, path): + if path.endswith('/'): + return path[:-1] + return path + + def _is_mach_o_file(self, filename): + fileext = os.path.splitext(filename)[1] + + if '.dylib' in fileext: + return True + + filedesc = shell.check_output(['file', '-bh', filename]) + + if fileext == '.a' and 'ar archive' in filedesc: + return False + + return filedesc.startswith('Mach-O') + + +class Main(object): + def run(self): + # We use OptionParser instead of ArgumentsParse because this script + # might be run in OS X 10.6 or older, which do not provide the argparse + # module + import optparse + + usage = 'usage: %prog [options] library_path old_prefix new_prefix' + description = ( + 'Rellocates object files changing the dependant ' ' dynamic libraries location path with a new one' + ) + parser = optparse.OptionParser(usage=usage, description=description) + parser.add_option( + '-r', + '--recursive', + action='store_true', + default=False, + dest='recursive', + help='Scan directories recursively', + ) + + options, args = parser.parse_args() + if len(args) != 3: + parser.print_usage() + exit(1) + relocator = OSXRelocator(args[1], args[2], options.recursive) + relocator.relocate_file(args[0]) + exit(0) + + +if __name__ == '__main__': + main = Main() + main.run() diff --git a/deploy/mac/prepare_gstreamer_framework.sh b/deploy/mac/prepare_gstreamer_framework.sh new file mode 100755 index 00000000000..f59f4c93bbd --- /dev/null +++ b/deploy/mac/prepare_gstreamer_framework.sh @@ -0,0 +1,84 @@ +#!/bin/bash +# +# Author: Gus Grubba +# +# Copies the regular distribution of the gstreamer framework +# into the libs directory (to be used for creating the Mac OS +# bundle). It also prunes unnecessary files and relocates the +# dynamic libraries. +# +# This script is run by the build process and should not be +# executed manually. +# +# Usage: $script [framework destination path] [app bundle path] [qgc executable name] +# +# destination is usually: ../libs/lib/Frameworks/ +# app bundle is something like: /path/qgroundcontrol.app +# executable name is usually: qgroundcontrol + +die () { + echo "$@" 1>&2 + exit 1 +} + +GST_VER=1.0 +GST_ROOT=/Library/Frameworks/GStreamer.framework +GST_BASE=$GST_ROOT/Versions/$GST_VER +RELOC=$(dirname $0)/osxrelocator.py + +OLDDLPATH=/Library/Frameworks/GStreamer.framework/ +NEWDLPATH=@executable_path/../Frameworks/GStreamer.framework/ + +echo "GST Installer" +[ "$#" -eq 3 ] || die "3 arguments required, $# provided" +[ -d "$2" ] || die "Could not find $2" + +FMWORK_TARGET=$1 +BUNDLE_TARGET=$2 +GST_SOURCE=${1%/}/GStreamer.framework +GST_TARGET=$GST_SOURCE/Versions/$GST_VER +QGC_BINARY=$BUNDLE_TARGET/Contents/MacOS/$3 +[ -e "$QGC_BINARY" ] || die "Could not find $QGC_BINARY" + +process_framework() { + #-- Start looking for the source framework + [ -d "$GST_ROOT" ] || die "Could not find gstreamer framework in $GST_ROOT" + [ -d "$GST_BASE" ] || die "Wrong version of gstreamer framework found in $GST_ROOT" + [ -e $RELOC ] || die "Cannot find $RELOC" + echo "GST Installer: Copying $GST_ROOT to $FMWORK_TARGET" + rsync -a --delete "$GST_ROOT" "$FMWORK_TARGET" || die "Error copying $GST_ROOT to $FMWORK_TARGET" + #-- Prune unused stuff + rm -rf $GST_TARGET/bin + rm -rf $GST_TARGET/etc + rm -rf $GST_TARGET/share + rm -rf $GST_TARGET/Headers + rm -rf $GST_TARGET/include + rm -rf $GST_TARGET/lib/*.a + rm -rf $GST_TARGET/lib/*.la + rm -rf $GST_TARGET/lib/gio/modules/static + rm -rf $GST_TARGET/lib/glib-2.0 + rm -rf $GST_TARGET/lib/gst-validate-launcher + rm -rf $GST_TARGET/lib/gstreamer-1.0/static + rm -rf $GST_TARGET/lib/libffi-3.0.13 + rm -rf $GST_TARGET/lib/pkgconfig + rm $GST_TARGET/Commands + #-- Now relocate the embedded paths + echo "GST Installer: Relocating" + python $RELOC -r "$GST_TARGET" "$OLDDLPATH" "$NEWDLPATH" > /dev/null || die "Error relocating binaries in $GST_TARGET/lib" +} + +#-- Check and see if we've already processed the framework +echo "GST Installer: Checking $GST_TARGET" +[ -d $GST_TARGET ] || process_framework +#-- Now copy the framework to the app bundle +echo "GST Installer: Copying $GST_SOURCE to $BUNDLE_TARGET/Contents/Frameworks/" +rsync -a --delete $GST_SOURCE $BUNDLE_TARGET/Contents/Frameworks/ || die "Error copying framework into app bundle" +#-- The plugin scanner needs to find the GStreamer libraries +GSTINBUNDLE=$BUNDLE_TARGET/Contents/Frameworks/GStreamer.framework/Versions/$GST_VER +pushd $GSTINBUNDLE/libexec && ln -sf ../../../../../Frameworks . && popd || die "Error creating Frameworks symlink in $GST_TARGET/libexec" +#-- Fix main binary +install_name_tool -change /Library/Frameworks/GStreamer.framework/Versions/1.0/lib/GStreamer @executable_path/../Frameworks/GStreamer.framework/Versions/1.0/lib/GStreamer "$QGC_BINARY" > /dev/null || die "Error relocating $QGC_BINARY" +pushd $GSTINBUNDLE && install_name_tool -id @executable_path/../Frameworks/GStreamer.framework/Versions/1.0/lib/GStreamer GStreamer && popd || die "Error relocating GStreamer" + + + diff --git a/src/VideoManager/VideoReceiver/GStreamer/gstqml6gl/CMakeLists.txt b/src/VideoManager/VideoReceiver/GStreamer/gstqml6gl/CMakeLists.txt index a0560146264..495b9c6d955 100644 --- a/src/VideoManager/VideoReceiver/GStreamer/gstqml6gl/CMakeLists.txt +++ b/src/VideoManager/VideoReceiver/GStreamer/gstqml6gl/CMakeLists.txt @@ -65,6 +65,13 @@ elseif(MACOS) # cmake_path(CONVERT "${GSTREAMER_PREFIX}/libexec/gstreamer-1.0/*" TO_CMAKE_PATH_LIST GST_HELPER_BINS_PATH) # file(GLOB GST_HELPER_BINS ${GST_HELPER_BINS_PATH}) # install(FILES ${GST_HELPER_BINS} DESTINATION ${CMAKE_INSTALL_LIBEXECDIR}/gstreamer-1.0) + + if(GSTREAMER_FRAMEWORK_PATH) + install( + DIRECTORY "${GSTREAMER_FRAMEWORK_PATH}" + DESTINATION "${CMAKE_INSTALL_PREFIX}/${CMAKE_PROJECT_NAME}.app/Contents/Frameworks/GStreamer.framework" + ) + endif() elseif(ANDROID) if(CMAKE_HOST_WIN32) cmake_path(CONVERT "${GSTREAMER_PREFIX}/share/gst-android/ndk-build/tools/windows/*.dll" TO_CMAKE_PATH_LIST GST_WIN_TOOLS_PATH)