diff --git a/.github/workflows/build_cmake.yml b/.github/workflows/build_cmake.yml new file mode 100644 index 0000000000..ba48c22eaf --- /dev/null +++ b/.github/workflows/build_cmake.yml @@ -0,0 +1,307 @@ +name: CMake Build Matrix +# Many thanks to Cristian Adam for examples +# e.g. https://github.com/cristianadam/HelloWorld/blob/master/.github/workflows/build_cmake.yml +# https://cristianadam.eu/20191222/using-github-actions-with-c-plus-plus-and-cmake/ + + +on: [push, pull_request, workflow_dispatch] + +env: + QT_VERSION: 5.15.2 + # this is different from MACOSX_DEPLOYMENT_TARGET to prevent build problems + # we set MACOSX_DEPLOYMENT_TARGET later + MACOS_TARGET: 10.12 + FEATURES: -DBUILD_GPL_PLUGINS=ON -DWITH_COORDGEN=OFF -DUSE_VTK=ON + +jobs: + build: + name: ${{ matrix.config.name }} + runs-on: ${{ matrix.config.os }} + strategy: + fail-fast: false + matrix: + config: + - { + name: "Ubuntu GCC", artifact: "Ubuntu-Latest.tar.gz", + os: ubuntu-latest, + cc: "gcc", cxx: "g++", + build_type: "Release", + cmake_flags: "-G Ninja -DENABLE_TESTING=ON -DTEST_QTGL=OFF", + cpack: "", + } + - { + name: "Ubuntu AppImage", artifact: "Avogadro2.AppImage", + os: ubuntu-20.04, + cc: "gcc", cxx: "g++", + build_type: "Release", + cmake_flags: "-G Ninja -DINSTALL_BUNDLE_FILES=ON", + cpack: "", + } + - { + name: "macOS Latest Clang", artifact: "macOS.dmg", + os: macos-latest, + cc: "clang", cxx: "clang++", + build_type: "Release", + cmake_flags: "-G Ninja", + cpack_flags: "-G DragNDrop", + } + - { + name: "Windows Latest MSVC", artifact: "Win64.exe", + os: windows-latest, + cc: "cl", cxx: "cl", + build_type: "Release", + cmake_flags: "", + build_flags: "-j 2", + cpack_flags: "-G NSIS", + } + - { + name: "Ubuntu Address Sanitizer", artifact: "", + os: ubuntu-latest, + cc: "gcc", cxx: "g++", + build_type: "asan", + cmake_flags: "-G Ninja -DENABLE_TESTING=ON -DTEST_QTGL=OFF", + cpack: "", + } + - { + name: "Ubuntu Leak Sanitizer", artifact: "", + os: ubuntu-latest, + cc: "gcc", cxx: "g++", + build_type: "lsan", + cmake_flags: "-G Ninja -DENABLE_TESTING=ON -DTEST_QTGL=OFF", + cpack: "", + } + - { + name: "Ubuntu Thread Sanitizer", artifact: "", + os: ubuntu-latest, + cc: "gcc", cxx: "g++", + build_type: "tsan", + cmake_flags: "-G Ninja -DENABLE_TESTING=ON -DTEST_QTGL=OFF", + cpack: "", + } + - { + name: "Ubuntu Undefined Behavior Sanitizer", artifact: "", + os: ubuntu-latest, + cc: "gcc", cxx: "g++", + build_type: "ubsan", + cmake_flags: "-G Ninja -DENABLE_TESTING=ON -DTEST_QTGL=OFF", + cpack: "", + } + + steps: + + - name: Install Dependencies (Linux) + if: runner.os == 'Linux' + run: | + sudo apt-get -qq update + sudo apt-get -qq install ninja-build libeigen3-dev libboost-all-dev libglew-dev libxml2-dev + sudo apt-get -qq install qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools libqt5x11extras5-dev libqt5svg5-dev + - name: Install Dependencies (macOS) + if: runner.os == 'macOS' + run: | + if uname -p | grep -q "arm" ; then + export PATH=/opt/homebrew/bin:$PATH + else # not self-hosted runner + brew install ninja eigen glew + fi + - name: Install Dependencies (Windows) + if: runner.os == 'Windows' + run: choco install ninja + + - name: Checkout openchemistry + uses: actions/checkout@v3 + with: + repository: openchemistry/openchemistry + submodules: recursive + + - name: Checkout avogadroapp + uses: actions/checkout@v3 + with: + repository: openchemistry/avogadroapp + path: avogadroapp + + - name: Checkout avogadrolibs + uses: actions/checkout@v3 + with: + path: avogadrolibs + + - name: Install Qt + uses: jurplel/install-qt-action@v3 + with: + cache: true + version: ${{ env.QT_VERSION }} + + - name: Configure MSVC Command Prompt + if: runner.os == 'Windows' + uses: ilammy/msvc-dev-cmd@v1 + with: + arch: x64 + + - name: Grab cache files + uses: actions/cache@v3 + if: runner.os != 'Windows' + with: + path: | + ${{ runner.workspace }}/build/thirdparty + ${{ runner.workspace }}/build/Downloads + key: ${{ matrix.config.name }}-thirdparty + + - name: Configure + run: | + if [ ! -d "${{ runner.workspace }}/build" ]; then mkdir "${{ runner.workspace }}/build"; fi + cd "${{ runner.workspace }}/build" + # won't have any effect except on Mac + echo "MACOSX_DEPLOYMENT_TARGET=${{ env.MACOS_TARGET }}" >> $GITHUB_ENV + CC=${{matrix.config.cc}} CXX=${{matrix.config.cxx}} cmake $GITHUB_WORKSPACE ${{env.FEATURES}} -DCMAKE_BUILD_TYPE=${{matrix.config.build_type}} ${{matrix.config.cmake_flags}} + shell: bash + + - name: Build + run: | + CC=${{matrix.config.cc}} CXX=${{matrix.config.cxx}} cmake --build . --config ${{matrix.config.build_type}} ${{matrix.config.build_flags}} + shell: bash + working-directory: ${{ runner.workspace }}/build + + - name: Fix Mac plugins + if: runner.os == 'macOS' + working-directory: ${{ runner.workspace }}/build/prefix/lib/openbabel + run: | + for plugin in *.so; do + for libpath in `otool -L ${plugin} | grep '/Users/runner/work' | awk '{print $1}'`; do + export lib=`echo $libpath | cut -d '/' -f 9`; + echo "Fixing $plugin $lib $libpath" + install_name_tool -change $libpath @executable_path/../Frameworks/$lib $plugin + done + done + cd .. # build/prefix/lib + for plugin in libinchi.?.?.?.dylib; do + for libpath in `otool -L ${plugin} | grep '/Users/runner/work' | awk '{print $1}'`; do + export lib=`echo $libpath | cut -d '/' -f 9`; + echo "Fixing $plugin $lib $libpath" + install_name_tool -change $libpath @executable_path/../Frameworks/$lib $plugin + done + done + otool -L libinchi.?.?.?.dylib + cp -p libinchi* ../Avogadro2.app/Contents/Frameworks/ + + - name: Run tests + if: matrix.config.os == 'ubuntu-latest' + shell: cmake -P {0} + run: | + include(ProcessorCount) + ProcessorCount(N) + set(ENV{CTEST_OUTPUT_ON_FAILURE} "ON") + set(ENV{ASAN_OPTIONS} "new_delete_type_mismatch=0") + execute_process( + COMMAND ctest -j ${N} + WORKING_DIRECTORY ${{ runner.workspace }}/build/avogadrolibs + RESULT_VARIABLE result + ) + if (NOT result EQUAL 0) + message(FATAL_ERROR "Running tests failed!") + endif() + + - name: Install the Apple certificate + # From GitHub docs: https://docs.github.com/en/actions/guides/installing-an-apple-certificate-on-macos-runners-for-xcode-development + if: runner.os == 'macOS' + working-directory: ${{ runner.workspace }}/build + env: + BUILD_CERTIFICATE_BASE64: ${{ secrets.BUILD_CERTIFICATE_BASE64 }} + P12_PASSWORD: ${{ secrets.P12_PASSWORD }} + KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }} + NOTARIZE_USERNAME: ${{ secrets.AC_USERNAME }} + NOTARIZE_PASSWORD: ${{ secrets.AC_PASSWORD }} + CODESIGN_IDENTITY: ${{ secrets.CODESIGN_ID }} + PRODUCT_BUNDLE_IDENTIFIER: cc.avogadro + run: | + # create variables + if [ -n "${P12_PASSWORD}" ]; then + CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12 + KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db + + # import certificate and provisioning profile from secrets + echo -n "$BUILD_CERTIFICATE_BASE64" | base64 --decode --output $CERTIFICATE_PATH + + # create temporary keychain if the cert is non-zero + if [ -s $CERTIFICATE_PATH ]; then + security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH + security set-keychain-settings -lut 21600 $KEYCHAIN_PATH + security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH + + # import certificate to keychain + security import $CERTIFICATE_PATH -P "$P12_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH + security list-keychain -d user -s $KEYCHAIN_PATH + + # signing occurs via avogadroapp cpack instructions + fi # certificate exists + fi # password exists + + - name: Pack + if: matrix.config.artifact != 0 + shell: bash + run: | + if [ -z "${P12_PASSWORD}" ]; then + unset CODESIGN_IDENTITY # to prevent cpack failing when trying to sign + fi + cpack ${{ matrix.config.cpack_flags }} + env: + P12_PASSWORD: ${{ secrets.P12_PASSWORD }} + CODESIGN_IDENTITY: ${{ secrets.CODESIGN_ID }} + working-directory: ${{ runner.workspace }}/build/avogadroapp + + - name: AppImage + if: matrix.config.os == 'ubuntu-18.04' + shell: bash + run: | + mkdir appdir + mv prefix appdir/usr + wget -c -nv "https://github.com/probonopd/linuxdeployqt/releases/download/continuous/linuxdeployqt-continuous-x86_64.AppImage" + wget -c -nv "https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage" + chmod a+x *.AppImage + ./linuxdeployqt-continuous-x86_64.AppImage appdir/usr/share/applications/*.desktop -bundle-non-qt-libs -extra-plugins=iconengines + # add the custom AppRun + rm appdir/AppRun + cp ../avogadrolibs/avogadrolibs/scripts/AppImage.sh appdir/AppRun + chmod a+x appdir/AppRun + ./appimagetool-x86_64.AppImage appdir + mv Avogadro2*.AppImage avogadroapp # for upload + # remove the cpack files + rm avogadroapp/Avogadro2*Linux.* + working-directory: ${{ runner.workspace }}/build + + - name: Notarize Mac DMG + if: runner.os == 'macOS' + run: | + # check current directory (failing signing) + echo `pwd` + ls -ld + # check if we have the password and the username + if [ -n "${NOTARIZE_PASSWORD}" ] && [ -n "${NOTARIZE_USERNAME}" ]; then + codesign -s "$CODESIGN_IDENTITY" --timestamp Avogadro2*.dmg + npx notarize-cli --file Avogadro2*.dmg + fi + working-directory: ${{ runner.workspace }}/build/avogadroapp + env: + NOTARIZE_USERNAME: ${{ secrets.AC_USERNAME }} + NOTARIZE_PASSWORD: ${{ secrets.AC_PASSWORD }} + CODESIGN_IDENTITY: ${{ secrets.CODESIGN_ID }} + PRODUCT_BUNDLE_IDENTIFIER: cc.avogadro + + - name: Setup tmate session + if: ${{ failure() }} + uses: mxschmitt/action-tmate@v3 + + - name: Upload + if: matrix.config.artifact != 0 + uses: actions/upload-artifact@v3 + with: + path: ${{ runner.workspace }}/build/avogadroapp/Avogadro2*.* + name: ${{ matrix.config.artifact }} + + - name: Cleanup + if: ${{ always() }} # To ensure this step runs even when earlier steps fail + shell: bash + run: | + ls -la ./ + rm -rf ./* || true + rm -rf ./.??* || true + ls -la ./ + diff --git a/.github/workflows/build_qt6.yml b/.github/workflows/build_qt6.yml new file mode 100644 index 0000000000..906bfcd80a --- /dev/null +++ b/.github/workflows/build_qt6.yml @@ -0,0 +1,277 @@ +name: Qt6 Build Matrix +# Many thanks to Cristian Adam for examples +# e.g. https://github.com/cristianadam/HelloWorld/blob/master/.github/workflows/build_cmake.yml +# https://cristianadam.eu/20191222/using-github-actions-with-c-plus-plus-and-cmake/ + + +on: [push, pull_request, workflow_dispatch] + +env: + QT_VERSION: 6.5.0 + # this is different from MACOSX_DEPLOYMENT_TARGET to prevent build problems + # we set MACOSX_DEPLOYMENT_TARGET later + MACOS_TARGET: 10.15 + FEATURES: -DBUILD_GPL_PLUGINS=ON -DWITH_COORDGEN=OFF -DUSE_VTK=ON -DQT_VERSION=6 + +jobs: + build: + name: ${{ matrix.config.name }} + runs-on: ${{ matrix.config.os }} + strategy: + fail-fast: false + matrix: + config: + - { + name: "Ubuntu Qt6", artifact: "Ubuntu-Latest.tar.gz", + os: ubuntu-latest, + cc: "gcc", cxx: "g++", + build_type: "Release", + cmake_flags: "-G Ninja", + cpack: "", + } + - { + name: "Ubuntu Qt6 AppImage", artifact: "Avogadro2.AppImage", + os: ubuntu-20.04, + cc: "gcc", cxx: "g++", + build_type: "Release", + cmake_flags: "-G Ninja -DINSTALL_BUNDLE_FILES=ON", + cpack: "", + } + - { + name: "macOS Qt6", artifact: "macOS.dmg", + os: macos-latest, + cc: "clang", cxx: "clang++", + build_type: "Release", + cmake_flags: "-G Ninja", + cpack_flags: "-G DragNDrop", + } + - { + name: "Windows Qt6", artifact: "Win64.exe", + os: windows-latest, + cc: "cl", cxx: "cl", + build_type: "Release", + cmake_flags: "", + build_flags: "-j 2", + cpack_flags: "-G NSIS", + } + + steps: + + - name: Install Dependencies (Linux) + if: runner.os == 'Linux' + run: | + sudo apt-get -qq update + sudo apt-get -qq install ninja-build libeigen3-dev libboost-all-dev libglew-dev libxml2-dev + sudo apt-get -qq install qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools libqt5x11extras5-dev libqt5svg5-dev + - name: Install Dependencies (macOS) + if: runner.os == 'macOS' + run: | + if uname -p | grep -q "arm" ; then + export PATH=/opt/homebrew/bin:$PATH + else # not self-hosted runner + brew install ninja eigen glew + fi + - name: Install Dependencies (Windows) + if: runner.os == 'Windows' + run: choco install ninja + + - name: Checkout openchemistry + uses: actions/checkout@v3 + with: + repository: openchemistry/openchemistry + submodules: recursive + + - name: Checkout avogadroapp + uses: actions/checkout@v3 + with: + repository: openchemistry/avogadroapp + path: avogadroapp + + - name: Checkout avogadrolibs + uses: actions/checkout@v3 + with: + path: avogadrolibs + + - name: Install Qt + uses: jurplel/install-qt-action@v3 + with: + cache: true + version: ${{ env.QT_VERSION }} + aqtversion: '==3.1.*' + modules: 'qt5compat' + + - name: Configure MSVC Command Prompt + if: runner.os == 'Windows' + uses: ilammy/msvc-dev-cmd@v1 + with: + arch: x64 + + - name: Grab cache files + uses: actions/cache@v3 + if: runner.os != 'Windows' + with: + path: | + ${{ runner.workspace }}/build/thirdparty + ${{ runner.workspace }}/build/Downloads + key: ${{ matrix.config.name }}-thirdparty + + - name: Configure + run: | + if [ ! -d "${{ runner.workspace }}/build" ]; then mkdir "${{ runner.workspace }}/build"; fi + cd "${{ runner.workspace }}/build" + # won't have any effect except on Mac + echo "MACOSX_DEPLOYMENT_TARGET=${{ env.MACOS_TARGET }}" >> $GITHUB_ENV + CC=${{matrix.config.cc}} CXX=${{matrix.config.cxx}} cmake $GITHUB_WORKSPACE ${{env.FEATURES}} -DCMAKE_BUILD_TYPE=${{matrix.config.build_type}} ${{matrix.config.cmake_flags}} + shell: bash + + - name: Build + run: | + CC=${{matrix.config.cc}} CXX=${{matrix.config.cxx}} cmake --build . --config ${{matrix.config.build_type}} ${{matrix.config.build_flags}} + shell: bash + working-directory: ${{ runner.workspace }}/build + + - name: Fix Mac plugins + if: runner.os == 'macOS' + working-directory: ${{ runner.workspace }}/build/prefix/lib/openbabel + run: | + for plugin in *.so; do + for libpath in `otool -L ${plugin} | grep '/Users/runner/work' | awk '{print $1}'`; do + export lib=`echo $libpath | cut -d '/' -f 9`; + echo "Fixing $plugin $lib $libpath" + install_name_tool -change $libpath @executable_path/../Frameworks/$lib $plugin + done + done + cd .. # build/prefix/lib + for plugin in libinchi.?.?.?.dylib; do + for libpath in `otool -L ${plugin} | grep '/Users/runner/work' | awk '{print $1}'`; do + export lib=`echo $libpath | cut -d '/' -f 9`; + echo "Fixing $plugin $lib $libpath" + install_name_tool -change $libpath @executable_path/../Frameworks/$lib $plugin + done + done + otool -L libinchi.?.?.?.dylib + cp -p libinchi* ../Avogadro2.app/Contents/Frameworks/ + + - name: Run tests + if: matrix.config.os == 'ubuntu-latest' + shell: cmake -P {0} + run: | + include(ProcessorCount) + ProcessorCount(N) + set(ENV{CTEST_OUTPUT_ON_FAILURE} "ON") + set(ENV{ASAN_OPTIONS} "new_delete_type_mismatch=0") + execute_process( + COMMAND ctest -j ${N} + WORKING_DIRECTORY ${{ runner.workspace }}/build/avogadrolibs + RESULT_VARIABLE result + ) + if (NOT result EQUAL 0) + message(FATAL_ERROR "Running tests failed!") + endif() + + - name: Install the Apple certificate + # From GitHub docs: https://docs.github.com/en/actions/guides/installing-an-apple-certificate-on-macos-runners-for-xcode-development + if: runner.os == 'macOS' + working-directory: ${{ runner.workspace }}/build + env: + BUILD_CERTIFICATE_BASE64: ${{ secrets.BUILD_CERTIFICATE_BASE64 }} + P12_PASSWORD: ${{ secrets.P12_PASSWORD }} + KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }} + NOTARIZE_USERNAME: ${{ secrets.AC_USERNAME }} + NOTARIZE_PASSWORD: ${{ secrets.AC_PASSWORD }} + CODESIGN_IDENTITY: ${{ secrets.CODESIGN_ID }} + PRODUCT_BUNDLE_IDENTIFIER: cc.avogadro + run: | + # create variables + if [ -n "${P12_PASSWORD}" ]; then + CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12 + KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db + + # import certificate and provisioning profile from secrets + echo -n "$BUILD_CERTIFICATE_BASE64" | base64 --decode --output $CERTIFICATE_PATH + + # create temporary keychain if the cert is non-zero + if [ -s $CERTIFICATE_PATH ]; then + security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH + security set-keychain-settings -lut 21600 $KEYCHAIN_PATH + security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH + + # import certificate to keychain + security import $CERTIFICATE_PATH -P "$P12_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH + security list-keychain -d user -s $KEYCHAIN_PATH + + # signing occurs via avogadroapp cpack instructions + fi # certificate exists + fi # password exists + + - name: Pack + if: matrix.config.artifact != 0 + shell: bash + run: | + if [ -z "${P12_PASSWORD}" ]; then + unset CODESIGN_IDENTITY # to prevent cpack failing when trying to sign + fi + cpack ${{ matrix.config.cpack_flags }} + env: + P12_PASSWORD: ${{ secrets.P12_PASSWORD }} + CODESIGN_IDENTITY: ${{ secrets.CODESIGN_ID }} + working-directory: ${{ runner.workspace }}/build/avogadroapp + + - name: AppImage + if: matrix.config.os == 'ubuntu-18.04' + shell: bash + run: | + mkdir appdir + mv prefix appdir/usr + wget -c -nv "https://github.com/probonopd/linuxdeployqt/releases/download/continuous/linuxdeployqt-continuous-x86_64.AppImage" + wget -c -nv "https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage" + chmod a+x *.AppImage + ./linuxdeployqt-continuous-x86_64.AppImage appdir/usr/share/applications/*.desktop -bundle-non-qt-libs -extra-plugins=iconengines + # add the custom AppRun + rm appdir/AppRun + cp ../avogadrolibs/avogadrolibs/scripts/AppImage.sh appdir/AppRun + chmod a+x appdir/AppRun + ./appimagetool-x86_64.AppImage appdir + mv Avogadro2*.AppImage avogadroapp # for upload + # remove the cpack files + rm avogadroapp/Avogadro2*Linux.* + working-directory: ${{ runner.workspace }}/build + + - name: Notarize Mac DMG + if: runner.os == 'macOS' + run: | + # check current directory (failing signing) + echo `pwd` + ls -ld + # check if we have the password and the username + if [ -n "${NOTARIZE_PASSWORD}" ] && [ -n "${NOTARIZE_USERNAME}" ]; then + codesign -s "$CODESIGN_IDENTITY" --timestamp Avogadro2*.dmg + npx notarize-cli --file Avogadro2*.dmg + fi + working-directory: ${{ runner.workspace }}/build/avogadroapp + env: + NOTARIZE_USERNAME: ${{ secrets.AC_USERNAME }} + NOTARIZE_PASSWORD: ${{ secrets.AC_PASSWORD }} + CODESIGN_IDENTITY: ${{ secrets.CODESIGN_ID }} + PRODUCT_BUNDLE_IDENTIFIER: cc.avogadro + + - name: Setup tmate session + if: ${{ failure() }} + uses: mxschmitt/action-tmate@v3 + + - name: Upload + if: matrix.config.artifact != 0 + uses: actions/upload-artifact@v3 + with: + path: ${{ runner.workspace }}/build/avogadroapp/Avogadro2*.* + name: ${{ matrix.config.artifact }} + + - name: Cleanup + if: ${{ always() }} # To ensure this step runs even when earlier steps fail + shell: bash + run: | + ls -la ./ + rm -rf ./* || true + rm -rf ./.??* || true + ls -la ./ +