diff --git a/3rdparty/discord-rpc/CMakeLists.txt b/3rdparty/discord-rpc/CMakeLists.txt index b86973762..1877bb61d 100644 --- a/3rdparty/discord-rpc/CMakeLists.txt +++ b/3rdparty/discord-rpc/CMakeLists.txt @@ -37,5 +37,9 @@ if(WIN32) target_link_libraries(discord-rpc PRIVATE psapi advapi32) endif() -target_include_directories(discord-rpc SYSTEM PRIVATE ${RapidJSON_INCLUDE_DIRS}) +if(TARGET RapidJSON::RapidJSON) + target_link_libraries(discord-rpc PRIVATE RapidJSON::RapidJSON) +elseif(RapidJSON_INCLUDE_DIRS) + target_include_directories(discord-rpc SYSTEM PRIVATE ${RapidJSON_INCLUDE_DIRS}) +endif() target_include_directories(discord-rpc PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/Brewfile b/Brewfile index 289630a2b..74fcd8648 100644 --- a/Brewfile +++ b/Brewfile @@ -14,6 +14,7 @@ brew "ninja" # Core runtime/build dependencies (required by CMakeLists.txt) brew "qt" # Qt 6 (Core/Gui/Widgets/Network/Sql/Concurrent) +brew "vulkan-headers" # helps Qt6Gui's WrapVulkanHeaders dependency on some setups brew "boost" brew "icu4c" brew "glib" # provides glib-2.0 + gobject-2.0 (via pkg-config) @@ -30,6 +31,8 @@ brew "gstreamer" # brew untap strawberry/local && brew tap strawberry/local "file://$PWD" tap "strawberry/local", "file://#{Dir.pwd}" brew "strawberry/local/kdsingleapplication-qt6" +brew "strawberry/local/qtsparkle-qt6" # optional: QtSparkle integration +brew "strawberry/local/sparkle-framework" # optional: Sparkle integration (framework) # Recommended GStreamer plugin sets for broad codec support (matches README guidance) brew "gst-plugins-base" @@ -38,6 +41,16 @@ brew "gst-plugins-bad" brew "gst-plugins-ugly" brew "gst-libav" +# Optional features (silences CMake warnings / enables extra functionality) +brew "rapidjson" # enables Discord Rich Presence (DISCORD_RPC) +brew "google-sparsehash" # enables stream tagreader (STREAMTAGREADER / libsparsehash) +brew "chromaprint" # enables MusicBrainz + song fingerprinting +brew "fftw" # enables Moodbar (fftw3) +brew "libebur128" # enables EBU R 128 loudness normalization +brew "libcdio" # enables Audio CD support +brew "libmtp" # enables MTP device support +brew "libgpod" # enables iPod classic support + # Helpful for Strawberry's macOS "deploy" target (GStreamer dynamically loads libsoup) brew "libsoup" diff --git a/CMakeLists.txt b/CMakeLists.txt index db3dadaad..a5fa98170 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -252,7 +252,18 @@ endif() find_package(KDSingleApplication-qt${QT_VERSION_MAJOR} 1.1.0 REQUIRED) if(APPLE) - find_library(SPARKLE Sparkle) + # Sparkle may be installed as a developer framework (e.g. via a package manager). + # Help CMake find it by searching typical Homebrew prefix locations as well. + find_library(SPARKLE Sparkle + PATHS + /Library/Frameworks + /System/Library/Frameworks + /opt/homebrew/Frameworks + /opt/homebrew/opt/sparkle-framework/Frameworks + /usr/local/Frameworks + /usr/local/opt/sparkle-framework/Frameworks + PATH_SUFFIXES Frameworks + ) endif() if(WIN32) @@ -271,7 +282,7 @@ if(WIN32) endif() if(APPLE OR WIN32) - find_package(qtsparkle-qt${QT_VERSION_MAJOR}) + find_package(qtsparkle-qt${QT_VERSION_MAJOR} QUIET) if(TARGET "qtsparkle-qt${QT_VERSION_MAJOR}::qtsparkle") set(QTSPARKLE_FOUND ON) endif() diff --git a/Formula/qtsparkle-qt6.rb b/Formula/qtsparkle-qt6.rb new file mode 100644 index 000000000..286887403 --- /dev/null +++ b/Formula/qtsparkle-qt6.rb @@ -0,0 +1,45 @@ +class QtsparkleQt6 < Formula + desc "Qt wrapper library for in-app updates (Qt 6 build)" + homepage "https://github.com/strawberrymusicplayer/qtsparkle" + url "https://github.com/strawberrymusicplayer/qtsparkle/archive/95ca3b77a79540d632b29e9a4df9aed30af5f901.tar.gz" + sha256 "945c9e96d2f6175b134a8ccfd6ec1acd268266d31969b5870d4037e8e5877834" + license "GPL-3.0-or-later" + + depends_on "cmake" => :build + depends_on "ninja" => :build + depends_on "qt" + + def install + args = std_cmake_args + %W[ + -GNinja + -DBUILD_WITH_QT6=ON + -DBUILD_WITH_QT5=OFF + -DBUILD_SHARED_LIBS=ON + -DBUILD_STATIC_LIBS=OFF + ] + + system "cmake", "-S", ".", "-B", "build", *args + system "cmake", "--build", "build" + system "cmake", "--install", "build" + end + + test do + # Strawberry expects: find_package(qtsparkle-qt6) and target qtsparkle-qt6::qtsparkle + (testpath/"CMakeLists.txt").write <<~CMAKE + cmake_minimum_required(VERSION 3.16) + project(qtsparkle_test LANGUAGES CXX) + find_package(qtsparkle-qt6 CONFIG REQUIRED) + add_library(dummy STATIC dummy.cpp) + target_link_libraries(dummy PRIVATE qtsparkle-qt6::qtsparkle) + CMAKE + + (testpath/"dummy.cpp").write <<~CPP + int dummy() { return 0; } + CPP + + system "cmake", "-S", ".", "-B", "build", + "-DCMAKE_PREFIX_PATH=#{opt_prefix}" + system "cmake", "--build", "build" + end +end + diff --git a/Formula/qtsparkle-qt6/README.md b/Formula/qtsparkle-qt6/README.md new file mode 100644 index 000000000..c6732cec1 --- /dev/null +++ b/Formula/qtsparkle-qt6/README.md @@ -0,0 +1,10 @@ +# qtsparkle-qt6 (local Homebrew formula) + +This installs Strawberry’s Qt updater helper library as a CMake package: + +- `find_package(qtsparkle-qt6 CONFIG REQUIRED)` +- target: `qtsparkle-qt6::qtsparkle` + +Strawberry will pick it up automatically when present and enable the optional +**QtSparkle integration**. + diff --git a/Formula/sparkle-framework.rb b/Formula/sparkle-framework.rb new file mode 100644 index 000000000..37dba97c5 --- /dev/null +++ b/Formula/sparkle-framework.rb @@ -0,0 +1,19 @@ +class SparkleFramework < Formula + desc "Sparkle.framework for macOS app updates (framework-only packaging)" + homepage "https://sparkle-project.org/" + url "https://github.com/sparkle-project/Sparkle/releases/download/2.8.1/Sparkle-2.8.1.tar.xz" + sha256 "5cddb7695674ef7704268f38eccaee80e3accbf19e61c1689efff5b6116d85be" + license "MIT" + + depends_on :macos + + def install + frameworks = prefix/"Frameworks" + frameworks.install "Sparkle.framework" + end + + test do + assert_predicate prefix/"Frameworks/Sparkle.framework", :exist? + end +end + diff --git a/Formula/sparkle-framework/README.md b/Formula/sparkle-framework/README.md new file mode 100644 index 000000000..5a37d5c07 --- /dev/null +++ b/Formula/sparkle-framework/README.md @@ -0,0 +1,9 @@ +# sparkle-framework (local Homebrew formula) + +Installs the upstream `Sparkle.framework` into: + +- `$(brew --prefix sparkle-framework)/Frameworks/Sparkle.framework` + +This is used to enable Strawberry’s optional **Sparkle integration** on macOS +(`find_library(SPARKLE Sparkle)` in the main `CMakeLists.txt`). + diff --git a/cmake/Dmg.cmake b/cmake/Dmg.cmake index 7967d60ca..837a83f72 100644 --- a/cmake/Dmg.cmake +++ b/cmake/Dmg.cmake @@ -1,18 +1,20 @@ -find_program(MACDEPLOYQT_EXECUTABLE NAMES macdeployqt PATHS /usr/bin /usr/local/bin /opt/local/bin /usr/local/opt/qt6/bin REQUIRED) +# NOTE: Packaging helpers should not be REQUIRED at configure time. +# Missing tools should simply disable the related custom targets. +find_program(MACDEPLOYQT_EXECUTABLE NAMES macdeployqt PATHS /usr/bin /usr/local/bin /opt/local/bin /usr/local/opt/qt6/bin) if(MACDEPLOYQT_EXECUTABLE) message(STATUS "Found macdeployqt: ${MACDEPLOYQT_EXECUTABLE}") else() message(WARNING "Missing macdeployqt executable.") endif() -find_program(MACDEPLOYCHECK_EXECUTABLE NAMES macdeploycheck PATHS /usr/bin /usr/local/bin /opt/local/bin /usr/local/opt/qt6/bin REQUIRED) +find_program(MACDEPLOYCHECK_EXECUTABLE NAMES macdeploycheck PATHS /usr/bin /usr/local/bin /opt/local/bin /usr/local/opt/qt6/bin) if(MACDEPLOYCHECK_EXECUTABLE) message(STATUS "Found macdeploycheck: ${MACDEPLOYCHECK_EXECUTABLE}") else() - message(WARNING "Missing macdeploycheck executable.") + message(STATUS "macdeploycheck not found (optional): 'deploycheck' target will be unavailable.") endif() -find_program(CREATEDMG_EXECUTABLE NAMES create-dmg REQUIRED) +find_program(CREATEDMG_EXECUTABLE NAMES create-dmg) if(CREATEDMG_EXECUTABLE) message(STATUS "Found create-dmg: ${CREATEDMG_EXECUTABLE}") else() diff --git a/cmake/FindRapidJSON.cmake b/cmake/FindRapidJSON.cmake new file mode 100644 index 000000000..084f76e3e --- /dev/null +++ b/cmake/FindRapidJSON.cmake @@ -0,0 +1,31 @@ +# Try to find RapidJSON (header-only). +# +# This project uses `find_package(RapidJSON)` and expects: +# - RapidJSON_FOUND +# - RapidJSON_INCLUDE_DIRS +# +# Homebrew's `rapidjson` formula commonly installs headers to: +# /opt/homebrew/include/rapidjson +# but does not always ship a `RapidJSONConfig.cmake`, so we provide this +# Find-module fallback. + +find_path(RapidJSON_INCLUDE_DIR + NAMES rapidjson/document.h +) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(RapidJSON + REQUIRED_VARS RapidJSON_INCLUDE_DIR +) + +if(RapidJSON_FOUND) + set(RapidJSON_INCLUDE_DIRS "${RapidJSON_INCLUDE_DIR}") +endif() + +if(RapidJSON_FOUND AND NOT TARGET RapidJSON::RapidJSON) + add_library(RapidJSON::RapidJSON INTERFACE IMPORTED) + set_target_properties(RapidJSON::RapidJSON PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${RapidJSON_INCLUDE_DIR}" + ) +endif() + diff --git a/cmake/OptionalComponent.cmake b/cmake/OptionalComponent.cmake index 843176bc6..882597801 100644 --- a/cmake/OptionalComponent.cmake +++ b/cmake/OptionalComponent.cmake @@ -1,6 +1,23 @@ set(summary_willbuild "") set(summary_willnotbuild "") +# On some platforms (notably macOS via Homebrew), many "optional" dependencies are +# not installed by default. Historically, Strawberry treated missing optional deps +# as a hard error when the option defaulted to ON, which makes first-time builds +# frustrating. +# +# This toggle controls that behavior: +# - ON => missing optional deps abort the configure (packager/CI-friendly) +# - OFF => missing optional deps auto-disable the component (dev-friendly) +set(_optional_components_fatal_default ON) +if(APPLE) + set(_optional_components_fatal_default OFF) +endif() +option(OPTIONAL_COMPONENTS_MISSING_DEPS_ARE_FATAL + "If ON, missing optional component dependencies are fatal (otherwise components auto-disable)" + ${_optional_components_fatal_default} +) + macro(optional_component_summary_add name test) if (${test}) list(APPEND summary_willbuild ${name}) @@ -80,8 +97,13 @@ function(optional_component name default description) set(text "${description} (missing ${deplist_text})") set(summary_willnotbuild "${summary_willnotbuild};${text}" PARENT_SCOPE) - - message(FATAL_ERROR "${text}, to disable this optional feature, pass -D${option_variable}=OFF to CMake") + if(OPTIONAL_COMPONENTS_MISSING_DEPS_ARE_FATAL) + message(FATAL_ERROR "${text}, to disable this optional feature, pass -D${option_variable}=OFF to CMake") + else() + message(STATUS "${text} - disabling ${option_variable}") + set(${option_variable} OFF CACHE BOOL "${description}" FORCE) + return() + endif() else() set(${have_variable} ON PARENT_SCOPE)