diff --git a/.github/workflows/build_and_release.yml b/.github/workflows/build_and_release.yml index 0ab5f0661..4202bcb74 100644 --- a/.github/workflows/build_and_release.yml +++ b/.github/workflows/build_and_release.yml @@ -11,70 +11,29 @@ on: workflow_dispatch: +permissions: + contents: write + jobs: upload-release: if: ${{ (github.event_name == 'workflow_dispatch') || (github.event_name != 'pull_request') }} - runs-on: ubuntu-20.04 + runs-on: ubuntu-24.04 needs: [build-mac, build-mac-arm, build-linux, build-windows] steps: - - uses: actions/checkout@v1 - - name: create release - id: create_release - uses: actions/create-release@master - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - tag_name: ${{ github.ref }} - release_name: Release ${{ github.sha }} - draft: false - prerelease: false - name: download artifacts uses: actions/download-artifact@v4 - # with: - # name: uploads - - name: upload mac - id: upload-mac - uses: actions/upload-release-asset@v1.0.1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: ./mac-uploads/sioyek-release-mac.zip - asset_name: sioyek-release-mac.zip - asset_content_type: application/zip - - - name: upload mac arm - id: upload-mac-arm - uses: actions/upload-release-asset@v1.0.1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: ./mac-arm-uploads/sioyek-release-mac-arm.zip - asset_name: sioyek-release-mac-arm.zip - asset_content_type: application/zip - - - name: upload linux - id: upload-linux - uses: actions/upload-release-asset@v1.0.1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: ./linux-uploads/sioyek-release-linux.zip - asset_name: sioyek-release-linux.zip - asset_content_type: application/zip - - name: upload windows - id: upload-windows - uses: actions/upload-release-asset@v1.0.1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: ./windows-uploads/sioyek-release-windows.zip - asset_name: sioyek-release-windows.zip - asset_content_type: application/zip + - name: publish release + uses: softprops/action-gh-release@v2 + with: + tag_name: ${{ github.ref_name }} + name: Release ${{ github.sha }} + prerelease: false + files: | + mac-uploads/sioyek-release-mac.zip + mac-arm-uploads/sioyek-release-mac-arm.zip + linux-uploads/sioyek-release-linux.zip + windows-uploads/sioyek-release-windows.zip build-linux: @@ -170,41 +129,22 @@ jobs: build-mac: - runs-on: macos-13 + runs-on: macos-15-intel + env: + HOMEBREW_NO_AUTO_UPDATE: 1 + HOMEBREW_NO_BOTTLE_SOURCE_FALLBACK: 1 + HOMEBREW_NO_INSTALL_CLEANUP: 1 steps: - uses: actions/checkout@v4 - with: - submodules: 'recursive' - - - name: Cache Homebrew packages - uses: actions/cache@v4 - env: - cache-name: homebrew - with: - path: ~/Library/Caches/Homebrew - key: ${{ runner.os }}-intel-build-${{ env.cache-name }}-${{ github.sha }} - restore-keys: | - ${{ runner.os }}-intel-build-${{ env.cache-name }}- - ${{ runner.os }}-intel-build- - ${{ runner.os }}-intel- - name: Install dependencies - run: brew install freeglut mesa harfbuzz - - - name: Install Qt - uses: jurplel/install-qt-action@v4 - with: - version: '6.7.2' - modules: 'all' - cache: true + run: brew install cmake mupdf qtspeech - name: Build working-directory: ${{env.GITHUB_WORKSPACE}} - run: | - chmod +x build_mac.sh - MAKE_PARALLEL=$(sysctl -n hw.logicalcpu) ./build_mac.sh + run: MAKE_PARALLEL=$(sysctl -n hw.logicalcpu) bash ./build_mac.sh - name: upload mac artifact uses: actions/upload-artifact@v4 @@ -214,41 +154,23 @@ jobs: build-mac-arm: - runs-on: macos-14 + runs-on: macos-15 + env: + HOMEBREW_NO_AUTO_UPDATE: 1 + HOMEBREW_NO_BOTTLE_SOURCE_FALLBACK: 1 + HOMEBREW_NO_INSTALL_CLEANUP: 1 steps: - uses: actions/checkout@v4 - with: - submodules: 'recursive' - - - name: Cache Homebrew packages - uses: actions/cache@v4 - env: - cache-name: homebrew - with: - path: ~/Library/Caches/Homebrew - key: ${{ runner.os }}-arm-build-${{ env.cache-name }}-${{ github.sha }} - restore-keys: | - ${{ runner.os }}-arm-build-${{ env.cache-name }}- - ${{ runner.os }}-arm-build- - ${{ runner.os }}-arm- - name: Install dependencies - run: brew install freeglut mesa harfbuzz - - - name: Install Qt - uses: jurplel/install-qt-action@v4 - with: - version: '6.7.2' - modules: 'all' - cache: true + run: brew install cmake mupdf qtspeech - name: Build working-directory: ${{env.GITHUB_WORKSPACE}} run: | - chmod +x build_mac.sh - MAKE_PARALLEL=$(sysctl -n hw.logicalcpu) ./build_mac.sh + MAKE_PARALLEL=$(sysctl -n hw.logicalcpu) bash ./build_mac.sh mv sioyek-release-mac.zip sioyek-release-mac-arm.zip - name: upload mac artifact diff --git a/.github/workflows/preview_release.yml b/.github/workflows/preview_release.yml index 98c211b51..a3021c063 100644 --- a/.github/workflows/preview_release.yml +++ b/.github/workflows/preview_release.yml @@ -11,70 +11,29 @@ on: workflow_dispatch: +permissions: + contents: write + jobs: upload-release: if: ${{ (github.event_name == 'workflow_dispatch') || (github.event_name != 'pull_request') }} - runs-on: ubuntu-20.04 + runs-on: ubuntu-24.04 needs: [build-mac, build-mac-arm, build-linux, build-windows] steps: - - uses: actions/checkout@v1 - - name: create release - id: create_release - uses: actions/create-release@master - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - tag_name: ${{ github.ref }} - release_name: Release ${{ github.sha }} - draft: false - prerelease: true - name: download artifacts uses: actions/download-artifact@v4 - # with: - # name: uploads - - name: upload mac - id: upload-mac - uses: actions/upload-release-asset@v1.0.1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: ./mac-uploads/sioyek-release-mac.zip - asset_name: sioyek-release-mac.zip - asset_content_type: application/zip - - - name: upload mac arm - id: upload-mac-arm - uses: actions/upload-release-asset@v1.0.1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: ./mac-arm-uploads/sioyek-release-mac-arm.zip - asset_name: sioyek-release-mac-arm.zip - asset_content_type: application/zip - - - name: upload linux - id: upload-linux - uses: actions/upload-release-asset@v1.0.1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: ./linux-uploads/sioyek-release-linux.zip - asset_name: sioyek-release-linux.zip - asset_content_type: application/zip - - name: upload windows - id: upload-windows - uses: actions/upload-release-asset@v1.0.1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: publish release + uses: softprops/action-gh-release@v2 with: - upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: ./windows-uploads/sioyek-release-windows.zip - asset_name: sioyek-release-windows.zip - asset_content_type: application/zip + tag_name: ${{ github.ref_name }} + name: Release ${{ github.sha }} + prerelease: true + files: | + mac-uploads/sioyek-release-mac.zip + mac-arm-uploads/sioyek-release-mac-arm.zip + linux-uploads/sioyek-release-linux.zip + windows-uploads/sioyek-release-windows.zip build-linux: @@ -107,7 +66,6 @@ jobs: - uses: actions/checkout@v4 with: submodules: 'recursive' - ref: development - name: Install dependencies run: sudo apt install libharfbuzz-dev libxrandr-dev libxi-dev libglu1-mesa-dev fuse libxcb-cursor0 libspeechd2 @@ -144,7 +102,6 @@ jobs: - uses: actions/checkout@v4 with: submodules: 'recursive' - ref: development - name: Install Qt uses: jurplel/install-qt-action@v4 @@ -172,42 +129,22 @@ jobs: build-mac: - runs-on: macos-13 + runs-on: macos-15-intel + env: + HOMEBREW_NO_AUTO_UPDATE: 1 + HOMEBREW_NO_BOTTLE_SOURCE_FALLBACK: 1 + HOMEBREW_NO_INSTALL_CLEANUP: 1 steps: - uses: actions/checkout@v4 - with: - submodules: 'recursive' - ref: development - - - name: Cache Homebrew packages - uses: actions/cache@v4 - env: - cache-name: homebrew - with: - path: ~/Library/Caches/Homebrew - key: ${{ runner.os }}-intel-build-${{ env.cache-name }}-${{ github.sha }} - restore-keys: | - ${{ runner.os }}-intel-build-${{ env.cache-name }}- - ${{ runner.os }}-intel-build- - ${{ runner.os }}-intel- - name: Install dependencies - run: brew install freeglut mesa harfbuzz - - - name: Install Qt - uses: jurplel/install-qt-action@v4 - with: - version: '6.7.2' - modules: 'all' - cache: true + run: brew install cmake mupdf qtspeech - name: Build working-directory: ${{env.GITHUB_WORKSPACE}} - run: | - chmod +x build_mac.sh - MAKE_PARALLEL=$(sysctl -n hw.logicalcpu) ./build_mac.sh + run: MAKE_PARALLEL=$(sysctl -n hw.logicalcpu) bash ./build_mac.sh - name: upload mac artifact uses: actions/upload-artifact@v4 @@ -217,42 +154,23 @@ jobs: build-mac-arm: - runs-on: macos-14 + runs-on: macos-15 + env: + HOMEBREW_NO_AUTO_UPDATE: 1 + HOMEBREW_NO_BOTTLE_SOURCE_FALLBACK: 1 + HOMEBREW_NO_INSTALL_CLEANUP: 1 steps: - uses: actions/checkout@v4 - with: - submodules: 'recursive' - ref: development - - - name: Cache Homebrew packages - uses: actions/cache@v4 - env: - cache-name: homebrew - with: - path: ~/Library/Caches/Homebrew - key: ${{ runner.os }}-arm-build-${{ env.cache-name }}-${{ github.sha }} - restore-keys: | - ${{ runner.os }}-arm-build-${{ env.cache-name }}- - ${{ runner.os }}-arm-build- - ${{ runner.os }}-arm- - name: Install dependencies - run: brew install freeglut mesa harfbuzz - - - name: Install Qt - uses: jurplel/install-qt-action@v4 - with: - version: '6.7.2' - modules: 'all' - cache: true + run: brew install cmake mupdf qtspeech - name: Build working-directory: ${{env.GITHUB_WORKSPACE}} run: | - chmod +x build_mac.sh - MAKE_PARALLEL=$(sysctl -n hw.logicalcpu) ./build_mac.sh + MAKE_PARALLEL=$(sysctl -n hw.logicalcpu) bash ./build_mac.sh mv sioyek-release-mac.zip sioyek-release-mac-arm.zip - name: upload mac artifact diff --git a/CMakeLists.txt b/CMakeLists.txt index a4df57ac2..427d8908e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,29 +1,62 @@ cmake_minimum_required(VERSION 3.16) project(sioyek VERSION 2.0.0 LANGUAGES C CXX) +include(FindPackageHandleStandardArgs) +include(GNUInstallDirs) + set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) -# Qt Stuff +if(APPLE) + enable_language(OBJCXX) + if(NOT CMAKE_OSX_DEPLOYMENT_TARGET) + set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15" CACHE STRING "Minimum macOS deployment target") + endif() +endif() + set(CMAKE_AUTOMOC ON) set(CMAKE_AUTORCC ON) set(CMAKE_AUTOUIC ON) -find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Core) -if(QT_VERSION_MAJOR GREATER_EQUAL 6) - find_package(Qt6 REQUIRED COMPONENTS - Core Gui Widgets Network OpenGL QuickWidgets - Svg TextToSpeech OpenGLWidgets - ) -else() - find_package(Qt5 REQUIRED COMPONENTS - Core Gui Widgets Network OpenGL QuickWidgets - Svg TextToSpeech OpenGLExtensions - ) +find_package(Qt6 6.7 REQUIRED COMPONENTS + Core Gui Widgets Network OpenGL QuickWidgets + Svg Multimedia TextToSpeech OpenGLWidgets +) + +find_package(ZLIB REQUIRED) +find_package(SQLite3 REQUIRED) + +set(SIOYEK_HOMEBREW_PREFIXES "$ENV{HOMEBREW_PREFIX}" /opt/homebrew /usr/local) +set(SIOYEK_MUPDF_PREFIX_HINTS) +if(APPLE) + foreach(prefix IN LISTS SIOYEK_HOMEBREW_PREFIXES) + if(prefix) + list(APPEND SIOYEK_MUPDF_PREFIX_HINTS "${prefix}" "${prefix}/opt/mupdf") + endif() + endforeach() endif() +find_path(MUPDF_INCLUDE_DIR + NAMES mupdf/fitz.h + HINTS ${SIOYEK_MUPDF_PREFIX_HINTS} + PATH_SUFFIXES include +) +find_library(MUPDF_LIBRARY + NAMES mupdf + HINTS ${SIOYEK_MUPDF_PREFIX_HINTS} + PATH_SUFFIXES lib +) +find_package_handle_standard_args(MuPDF REQUIRED_VARS MUPDF_LIBRARY MUPDF_INCLUDE_DIR) +mark_as_advanced(MUPDF_INCLUDE_DIR MUPDF_LIBRARY) + +add_library(MuPDF::MuPDF UNKNOWN IMPORTED) +set_target_properties(MuPDF::MuPDF PROPERTIES + IMPORTED_LOCATION "${MUPDF_LIBRARY}" + INTERFACE_INCLUDE_DIRECTORIES "${MUPDF_INCLUDE_DIR}" +) + qt_standard_project_setup() qt_add_executable(sioyek WIN32 MACOSX_BUNDLE @@ -80,12 +113,12 @@ if(APPLE) ) endif() -target_compile_options(sioyek PRIVATE -Wno-inconsistent-missing-override) +target_compile_options(sioyek PRIVATE + $<$:-Wno-inconsistent-missing-override> +) target_include_directories(sioyek PRIVATE - pdf_viewer - mupdf/include - ${SQLite3_INCLUDE_DIRS} + pdf_viewer ) target_compile_definitions(sioyek PRIVATE @@ -95,14 +128,15 @@ target_compile_definitions(sioyek PRIVATE ) target_link_libraries(sioyek PRIVATE - Qt::Core - Qt::Gui - Qt::Network - Qt::OpenGL - Qt::QuickWidgets - Qt::Svg - Qt::TextToSpeech - Qt::Widgets + Qt6::Core + Qt6::Gui + Qt6::Network + Qt6::OpenGL + Qt6::QuickWidgets + Qt6::Svg + Qt6::TextToSpeech + Qt6::Widgets + Qt6::OpenGLWidgets ) if(NOT ANDROID) @@ -134,19 +168,9 @@ if(UNIX AND NOT APPLE) ) endif() -find_package(ZLIB REQUIRED) -find_package(HarfBuzz REQUIRED) -find_package(SQLite3 REQUIRED) - -if((QT_VERSION_MAJOR GREATER 5)) - target_compile_definitions(sioyek PRIVATE - SIOYEK_QT6 - ) - - target_link_libraries(sioyek PRIVATE - Qt::OpenGLWidgets - ) -endif() +target_compile_definitions(sioyek PRIVATE + SIOYEK_QT6 +) add_library(fzf STATIC fzf/fzf.c @@ -155,40 +179,90 @@ add_library(fzf STATIC target_link_libraries(sioyek PRIVATE ${CMAKE_DL_LIBS} - mupdf - ${HARFBUZZ_LIBRARIES} + MuPDF::MuPDF ZLIB::ZLIB fzf - SQLite::SQLite3 + SQLite3::SQLite3 ) if(APPLE) - # target_link_libraries(sioyek PRIVATE - # "-framework AppKit" - # mupdf-third - # mupdf-threads - # ) target_link_libraries(sioyek PRIVATE "-framework AppKit" - -ldl - -L${CMAKE_CURRENT_SOURCE_DIR}/mupdf/build/release - -lmupdf - -lmupdf-third - -lmupdf-threads - -lz ) else() string(REPLACE "-mno-direct-extern-access" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") endif() +if(APPLE) + set(EXECUTABLE sioyek) + set(ICON "") + set(SHORT_VERSION "${PROJECT_VERSION}") + set_target_properties(sioyek PROPERTIES + MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/resources/Info.plist" + MACOSX_BUNDLE_BUNDLE_NAME sioyek + MACOSX_BUNDLE_GUI_IDENTIFIER info.sioyek.sioyek + MACOSX_BUNDLE_SHORT_VERSION_STRING "${PROJECT_VERSION}" + MACOSX_BUNDLE_BUNDLE_VERSION "${PROJECT_VERSION}" + ) + + set(SIOYEK_BUNDLE_FILES + pdf_viewer/prefs.config + pdf_viewer/prefs_user.config + pdf_viewer/keys.config + pdf_viewer/keys_user.config + tutorial.pdf + ) + + add_custom_command(TARGET sioyek POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_directory + "${CMAKE_CURRENT_SOURCE_DIR}/pdf_viewer/shaders" + "$/Resources/shaders" + COMMAND ${CMAKE_COMMAND} -E copy_if_different + ${SIOYEK_BUNDLE_FILES} + "$/Resources" + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + VERBATIM + ) +endif() + install(TARGETS sioyek BUNDLE DESTINATION . RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ) +if(APPLE) + install(FILES ${SIOYEK_BUNDLE_FILES} + DESTINATION sioyek.app/Contents/Resources + ) + install(DIRECTORY pdf_viewer/shaders + DESTINATION sioyek.app/Contents/Resources + ) +endif() + +set(SIOYEK_DEPLOY_TOOL_OPTIONS_ARG) +if(APPLE) + list(APPEND SIOYEK_DEPLOY_TOOL_OPTIONS_ARG + DEPLOY_TOOL_OPTIONS + -no-codesign + "-qmldir=${CMAKE_CURRENT_SOURCE_DIR}/pdf_viewer/touchui" + ) + foreach(prefix IN LISTS CMAKE_PREFIX_PATH) + if(EXISTS "${prefix}/lib") + list(APPEND SIOYEK_DEPLOY_TOOL_OPTIONS_ARG "-libpath=${prefix}/lib") + endif() + if(EXISTS "${prefix}/qml") + list(APPEND SIOYEK_DEPLOY_TOOL_OPTIONS_ARG "-qmlimport=${prefix}/qml") + endif() + if(EXISTS "${prefix}/share/qt/qml") + list(APPEND SIOYEK_DEPLOY_TOOL_OPTIONS_ARG "-qmlimport=${prefix}/share/qt/qml") + endif() + endforeach() +endif() + qt_generate_deploy_app_script( TARGET sioyek OUTPUT_SCRIPT deploy_script NO_UNSUPPORTED_PLATFORM_ERROR + ${SIOYEK_DEPLOY_TOOL_OPTIONS_ARG} ) install(SCRIPT ${deploy_script}) diff --git a/README.md b/README.md index 45ba5b41c..b2385d59a 100644 --- a/README.md +++ b/README.md @@ -162,29 +162,18 @@ build_windows.bat ``` ### Mac -1. Uninstall previous Qt6 installed by Homebrew -2. Install Xcode. -3. Install Qt6. +1. Install Xcode command line tools. +2. Install the Homebrew dependencies. The macOS build uses Homebrew bottles for Qt and MuPDF instead of building the vendored submodules. ``` -pip install aqtinstall -cd /path/to/qt -aqt install-qt mac desktop 6.8.2 clang_64 -m all -export Qt6_DIR=/path/to/qt/6.8.2/macos/ -export QT_PLUGIN_PATH=/path/to/qt/6.8.2/macos/plugins -export PKG_CONFIG_PATH=/path/to/qt/6.8.2/macos/lib/pkgconfig -export QML2_IMPORT_PATH=/path/to/qt/6.8.2/macos/qml -export PATH="/path/to/qt/6.8.2/macos/bin:$PATH" +brew install cmake mupdf qtspeech ``` -4. Clone the repository, build and install: +3. Clone the repository, build and install: ``` -git clone --recursive --branch development https://github.com/ahrm/sioyek +git clone --branch development https://github.com/ahrm/sioyek cd sioyek -chmod +x build_mac.sh -setopt PIPE_FAIL PRINT_EXIT_VALUE ERR_RETURN SOURCE_TRACE XTRACE MAKE_PARALLEL=8 ./build_mac.sh -mv build/sioyek.app /Applications/ -sudo codesign --force --sign - --deep /Applications/sioyek.app +mv build/package/sioyek.app /Applications/ ``` ## Donation diff --git a/build_mac.sh b/build_mac.sh index 4a70399dc..e5d964303 100755 --- a/build_mac.sh +++ b/build_mac.sh @@ -1,64 +1,111 @@ #!/usr/bin/env bash -set -e -# prerequisite: brew install qt@5 freeglut mesa harfbuzz +set -euo pipefail -#sys_glut_clfags=`pkg-config --cflags glut gl` -#sys_glut_libs=`pkg-config --libs glut gl` -#sys_harfbuzz_clfags=`pkg-config --cflags harfbuzz` -#sys_harfbuzz_libs=`pkg-config --libs harfbuzz` - -if [ -z ${MAKE_PARALLEL+x} ]; then export MAKE_PARALLEL=1; else echo "MAKE_PARALLEL defined"; fi -echo "MAKE_PARALLEL set to $MAKE_PARALLEL" +if [[ -z ${MAKE_PARALLEL+x} ]]; then + MAKE_PARALLEL=$(sysctl -n hw.logicalcpu) +fi -cd mupdf -#make USE_SYSTEM_HARFBUZZ=yes USE_SYSTEM_GLUT=yes SYS_GLUT_CFLAGS="${sys_glut_clfags}" SYS_GLUT_LIBS="${sys_glut_libs}" SYS_HARFBUZZ_CFLAGS="${sys_harfbuzz_clfags}" SYS_HARFBUZZ_LIBS="${sys_harfbuzz_libs}" -j 4 -make HAVE_GLUT=no -j$MAKE_PARALLEL -cd .. +if ! command -v brew >/dev/null 2>&1; then + echo "Homebrew is required for the macOS CMake build." >&2 + exit 1 +fi -sed -Ei '' "s/QMAKE_MACOSX_DEPLOYMENT_TARGET.=.[0-9]+/QMAKE_MACOSX_DEPLOYMENT_TARGET = $(sw_vers -productVersion | cut -d. -f1)/" pdf_viewer_build_config.pro +CMAKE=${CMAKE:-cmake} +if ! command -v "$CMAKE" >/dev/null 2>&1; then + CMAKE="$(brew --prefix cmake)/bin/cmake" +fi -if [[ $1 == portable ]]; then - qmake pdf_viewer_build_config.pro -else - qmake "CONFIG+=non_portable" pdf_viewer_build_config.pro +required_formulae=(cmake mupdf qtspeech) +cmake_prefixes=() +for formula in qtbase qtdeclarative qtsvg qtmultimedia qtspeech mupdf; do + prefix=$(brew --prefix "$formula" 2>/dev/null || true) + if [[ -z $prefix || ! -d $prefix ]]; then + echo "Missing Homebrew formula '$formula'. Install dependencies with:" >&2 + echo " brew install ${required_formulae[*]}" >&2 + exit 1 + fi + cmake_prefixes+=("$prefix") +done + +for formula in qtquicktimeline qtquick3d qtshadertools; do + prefix=$(brew --prefix "$formula" 2>/dev/null || true) + if [[ -n $prefix && -d $prefix ]]; then + cmake_prefixes+=("$prefix") + fi +done + +cmake_prefix_path=$(IFS=';'; printf '%s' "${cmake_prefixes[*]}") +if [[ -n ${CMAKE_PREFIX_PATH:-} ]]; then + cmake_prefix_path="$cmake_prefix_path;$CMAKE_PREFIX_PATH" fi -make -j$MAKE_PARALLEL +build_dir=${BUILD_DIR:-build} +case "$build_dir" in + /*) ;; + *) build_dir="$PWD/$build_dir" ;; +esac -rm -rf build 2> /dev/null -mkdir build -mv sioyek.app build/ -cp -r pdf_viewer/shaders build/sioyek.app/Contents/MacOS/shaders +package_dir=${PACKAGE_DIR:-$build_dir/package} +case "$package_dir" in + /*) ;; + *) package_dir="$PWD/$package_dir" ;; +esac -cp pdf_viewer/prefs.config build/sioyek.app/Contents/MacOS/prefs.config -cp pdf_viewer/prefs_user.config build/sioyek.app/Contents/MacOS/prefs_user.config -cp pdf_viewer/keys.config build/sioyek.app/Contents/MacOS/keys.config -cp pdf_viewer/keys_user.config build/sioyek.app/Contents/MacOS/keys_user.config -cp tutorial.pdf build/sioyek.app/Contents/MacOS/tutorial.pdf +release_zip=${RELEASE_ZIP:-sioyek-release-mac.zip} -# Capture the current PATH -CURRENT_PATH=$(echo $PATH) +rm -rf "$package_dir" "$build_dir/sioyek.app" "$build_dir/sioyek.dmg" -# Define the path to the Info.plist file inside the app bundle -INFO_PLIST="build/sioyek.app/Contents/Info.plist" +"$CMAKE" -S . -B "$build_dir" \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_PREFIX_PATH="$cmake_prefix_path" \ + -DQT_ADDITIONAL_PACKAGES_PREFIX_PATH="$cmake_prefix_path" -# Add LSEnvironment key with PATH to Info.plist -/usr/libexec/PlistBuddy -c "Add :LSEnvironment dict" "$INFO_PLIST" || echo "LSEnvironment already exists" -/usr/libexec/PlistBuddy -c "Add :LSEnvironment:PATH string $CURRENT_PATH" "$INFO_PLIST" || /usr/libexec/PlistBuddy -c "Set :LSEnvironment:PATH $CURRENT_PATH" "$INFO_PLIST" +"$CMAKE" --build "$build_dir" --parallel "$MAKE_PARALLEL" +"$CMAKE" --install "$build_dir" --prefix "$package_dir" -# Hack is required to avoid race condition in macos in CI -# See https://github.com/actions/runner-images/issues/7522 -if [[ -n "$GITHUB_ACTIONS" ]]; then - echo killing...; sudo pkill -9 XProtect >/dev/null || true; - echo waiting...; while pgrep XProtect; do sleep 3; done; -fi +app_path="$package_dir/sioyek.app" -sleep 5 +qtquicktimeline_prefix=$(brew --prefix qtquicktimeline 2>/dev/null || true) +if [[ -n $qtquicktimeline_prefix && -d $qtquicktimeline_prefix/lib ]]; then + for framework in "$qtquicktimeline_prefix"/lib/*.framework; do + [[ -d "$framework" ]] || continue + ditto "$framework" "$app_path/Contents/Frameworks/$(basename "$framework")" + done +fi -# mac deploys with qml currently don't work due to a qt bug -# macdeployqt build/sioyek.app -qmldir=./pdf_viewer/touchui -dmg -macdeployqt build/sioyek.app -dmg +frameworks_dir="$app_path/Contents/Frameworks" +# Normalize install names that macdeployqt leaves pointing at Homebrew. +while IFS= read -r binary; do + otool_output=$(otool -L "$binary" 2>/dev/null || true) + [[ -n $otool_output ]] || continue + + if [[ $binary == "$frameworks_dir"/* ]]; then + relative_path=${binary#"$frameworks_dir"/} + install_name_tool -id "@rpath/$relative_path" "$binary" 2>/dev/null || true + fi + + while IFS= read -r line; do + dependency=${line#"${line%%[![:space:]]*}"} + dependency=${dependency%% (*} + case "$dependency" in + /opt/homebrew/*/lib/*|/usr/local/opt/*/lib/*|/usr/local/Cellar/*/lib/*) + relative_path=${dependency#*/lib/} + if [[ -e "$frameworks_dir/$relative_path" ]]; then + install_name_tool -change "$dependency" "@executable_path/../Frameworks/$relative_path" "$binary" + fi + ;; + esac + done <<< "$otool_output" +done < <(find "$app_path/Contents" -type f) + +# Avoid intermittent CI failures caused by XProtect scanning newly created bundles. +if [[ -n ${GITHUB_ACTIONS:-} ]]; then + sudo pkill -9 XProtect >/dev/null 2>&1 || true + while pgrep XProtect >/dev/null; do sleep 3; done +fi -codesign --force --deep --sign - build/sioyek.app +codesign --force --deep --sign - "$app_path" -zip -r sioyek-release-mac.zip build/sioyek.dmg +rm -f "$build_dir/sioyek.dmg" "$release_zip" +hdiutil create -volname sioyek -srcfolder "$app_path" -ov -format UDZO "$build_dir/sioyek.dmg" +ditto -c -k --keepParent "$build_dir/sioyek.dmg" "$release_zip" diff --git a/pdf_viewer/main.cpp b/pdf_viewer/main.cpp index 4fa2b7c67..c8ac2d9b4 100644 --- a/pdf_viewer/main.cpp +++ b/pdf_viewer/main.cpp @@ -224,16 +224,14 @@ void configure_paths() { Path parent_path(QCoreApplication::applicationDirPath().toStdWString()); + Path app_data_path = parent_path; std::string exe_path = utf8_encode(QCoreApplication::applicationFilePath().toStdWString()); - shader_path = parent_path.slash(L"shaders"); - - #ifdef Q_OS_MACOS - Path mac_home_path(QDir::homePath().toStdWString()); - Path mac_standard_config_path = mac_home_path.slash(L".config").slash(L"sioyek"); - user_keys_paths.push_back(mac_standard_config_path.slash(L"keys_user.config")); - user_config_paths.push_back(mac_standard_config_path.slash(L"prefs_user.config")); + app_data_path = parent_path.slash(L"..").slash(L"Resources"); + shader_path = app_data_path.slash(L"shaders"); +#else + shader_path = parent_path.slash(L"shaders"); #endif #ifdef Q_OS_LINUX @@ -304,9 +302,9 @@ void configure_paths() { standard_data_path.create_directories(); - default_config_path = parent_path.slash(L"prefs.config"); - default_keys_path = parent_path.slash(L"keys.config"); - tutorial_path = parent_path.slash(L"tutorial.pdf"); + default_config_path = app_data_path.slash(L"prefs.config"); + default_keys_path = app_data_path.slash(L"keys.config"); + tutorial_path = app_data_path.slash(L"tutorial.pdf"); #if defined(NON_PORTABLE) || defined(Q_OS_MACOS) user_config_paths.push_back(standard_data_path.slash(L"prefs_user.config")); @@ -319,6 +317,14 @@ void configure_paths() { local_database_file_path = standard_data_path.slash(L"local.db"); global_database_file_path = standard_data_path.slash(L"shared.db"); last_opened_file_address_path = standard_data_path.slash(L"last_document_path.txt"); +#ifdef Q_OS_MACOS + // XDG-style ~/.config path is pushed last so it is the preferred write location (back()) + // while AppDataLocation paths above serve as read-only fallbacks + Path mac_home_path(QDir::homePath().toStdWString()); + Path mac_standard_config_path = mac_home_path.slash(L".config").slash(L"sioyek"); + user_keys_paths.push_back(mac_standard_config_path.slash(L"keys_user.config")); + user_config_paths.push_back(mac_standard_config_path.slash(L"prefs_user.config")); +#endif #else user_config_paths.push_back(parent_path.slash(L"prefs_user.config")); user_keys_paths.push_back(parent_path.slash(L"keys_user.config"));