# Velox Download Manager — top-level build. Owned by lane PKG/QA. # # Lanes land in parallel and merge to main independently, so every add_subdirectory() # here is guarded by EXISTS on the lane's own CMakeLists.txt: main always configures, # and a lane's targets light up the moment that lane merges — no coordinated edit here. # # cmake --preset dev && cmake --build --preset dev # ctest --preset dev cmake_minimum_required(VERSION 3.28) project(velox VERSION 0.1.0 DESCRIPTION "IDM-class download manager for Linux" LANGUAGES CXX) set(CMAKE_CXX_STANDARD 23) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) if(NOT CMAKE_RUNTIME_OUTPUT_DIRECTORY) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) endif() option(VELOX_BUILD_GUI "Build the Qt 6 GUI client" ON) option(VELOX_BUILD_TESTS "Build unit and integration tests" ON) option(VELOX_BUILD_FUZZ "Build libFuzzer targets (clang only)" OFF) option(VELOX_ENABLE_MEDIA "Build the HLS/DASH media grabber (M4)" OFF) option(VELOX_WERROR "Treat warnings as errors" ON) # Central OS detection (docs/adr/0020-cross-platform-strategy.md). Included early: the # dependency finds below gate Linux-only libraries on VELOX_OS_LINUX. include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/platform.cmake) # Project-wide warning flags. Set via add_compile_options (a directory property), not the # CMAKE_CXX_FLAGS cache variable, because the dev/tsan presets overwrite that cache var # wholesale for sanitizer flags — a target's warnings must not ride on it. add_compile_options(-Wall -Wextra -Wpedantic) if(VELOX_WERROR) add_compile_options(-Werror) endif() if(VELOX_BUILD_FUZZ AND NOT CMAKE_CXX_COMPILER_ID MATCHES "Clang") message(WARNING "VELOX_BUILD_FUZZ is ON but the compiler is ${CMAKE_CXX_COMPILER_ID}; " "libFuzzer needs Clang. Fuzz targets will be skipped.") endif() # --- Dependencies ------------------------------------------------------------------- # Found once here so a missing -dev package fails at configure with a clear name, rather # than deep in a lane. Each find is gated on the lane that needs it being present. find_package(Threads REQUIRED) if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/core/CMakeLists.txt) find_package(CURL 8.0 REQUIRED) find_package(OpenSSL REQUIRED) endif() if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/daemon/CMakeLists.txt) find_package(SQLite3 REQUIRED) find_package(nlohmann_json 3.11 REQUIRED) # libsecret / Secret Service is Linux-only (docs/adr/0020-cross-platform-strategy.md, # docs/08-porting.md): macOS uses Keychain behind the same credential-store seam, so # this stays REQUIRED on Linux and simply absent elsewhere — PORT's job is to add the # macOS side of that seam, not to touch this find. if(VELOX_OS_LINUX) find_package(PkgConfig REQUIRED) pkg_check_modules(LIBSECRET REQUIRED IMPORTED_TARGET libsecret-1) endif() endif() if(VELOX_BUILD_GUI AND EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/gui/CMakeLists.txt) # DBus (gui/docs/pkg-qa-requests-m1.md R4) backs the org.freedesktop.portal # GlobalShortcuts path — Linux/portal-only, same reasoning as libsecret above. if(VELOX_OS_LINUX) find_package(Qt6 6.6 REQUIRED COMPONENTS Widgets Svg Network DBus LinguistTools) else() find_package(Qt6 6.6 REQUIRED COMPONENTS Widgets Svg Network LinguistTools) endif() qt_standard_project_setup() endif() if(VELOX_ENABLE_MEDIA) find_package(PkgConfig REQUIRED) pkg_check_modules(FFMPEG REQUIRED IMPORTED_TARGET libavformat libavcodec libavutil) endif() # --- Tests -------------------------------------------------------------------------- if(VELOX_BUILD_TESTS) enable_testing() endif() # --- Lane targets (guarded; see header) ------------------------------------------- foreach(lane IN ITEMS core daemon cli nmhost) if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${lane}/CMakeLists.txt) add_subdirectory(${lane}) else() message(STATUS "velox: lane '${lane}' has not landed a CMakeLists yet — skipping.") endif() endforeach() if(VELOX_BUILD_GUI) if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/gui/CMakeLists.txt) add_subdirectory(gui) else() message(STATUS "velox: lane 'gui' has not landed a CMakeLists yet — skipping.") endif() endif() foreach(toolset tools/testserver tools/bench tools/fuzz tools/mockd) if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${toolset}/CMakeLists.txt) add_subdirectory(${toolset}) endif() endforeach() if(VELOX_BUILD_TESTS) foreach(suite tests/conformance tests/integration tests/e2e) if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${suite}/CMakeLists.txt) add_subdirectory(${suite}) endif() endforeach() endif() # --- Install rules (M6 packaging; docs/07-packaging.md; owned by PKG/QA) ------------ # # Guarded by `if(TARGET ...)`, not by editing each lane's own CMakeLists.txt: install() # is a packaging concern, and reaching into daemon/CMakeLists.txt (DAEMON's), cli's build # file (also DAEMON's) or gui/CMakeLists.txt (GUI's) to add it there would cross a lane # boundary CLAUDE.md draws on purpose. Every target below is defined by its own lane; # this only says where the packaged binary already built by that lane's rules goes. # # libveloxcore is intentionally absent here: it stays a static library linked into each # binary (user decision, see docs/07-packaging.md) — there is no .so to install. # # CMAKE_INSTALL_LIBDIR is multiarch-adjusted (lib/x86_64-linux-gnu/) by GNUInstallDirs on # Debian; systemd user units and the Mozilla native-messaging directory are NOT # architecture-specific paths, so those two destinations are written literally # (lib/systemd/user, lib/mozilla/...) rather than built from that variable. include(GNUInstallDirs) if(TARGET veloxd) install(TARGETS veloxd RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) install(FILES ${CMAKE_SOURCE_DIR}/packaging/man/veloxd.8 DESTINATION ${CMAKE_INSTALL_MANDIR}/man8) # velox.socket ships alongside velox.service: DAEMON wired real sd_listen_fds() # socket activation (daemon/src/rpc/systemd_activation.cpp) — see # packaging/systemd/README.md for the pair's own rationale. install(FILES ${CMAKE_SOURCE_DIR}/packaging/systemd/velox.service ${CMAKE_SOURCE_DIR}/packaging/systemd/velox.socket DESTINATION lib/systemd/user) endif() if(TARGET velox) install(TARGETS velox RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) # DAEMON owns cli/ and its man page (CLAUDE.md); packaging only installs it. install(FILES ${CMAKE_SOURCE_DIR}/cli/man/velox.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1) endif() if(TARGET velox-gui) install(TARGETS velox-gui RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) install(FILES ${CMAKE_SOURCE_DIR}/packaging/man/velox-gui.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1) install(FILES ${CMAKE_SOURCE_DIR}/packaging/desktop/velox.desktop DESTINATION ${CMAKE_INSTALL_DATADIR}/applications) foreach(iconsize 16 22 24 32 48 64 128 256) install(FILES ${CMAKE_SOURCE_DIR}/packaging/icons/hicolor/${iconsize}x${iconsize}/apps/velox.png DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/${iconsize}x${iconsize}/apps) endforeach() endif() # nmhost and its manifest are DAEMON's (CLAUDE.md: nmhost/ and packaging/nativehost/). # This lights up the moment DAEMON's target exists, the same way the add_subdirectory() # guards above do — no coordinated edit needed when it lands. if(TARGET velox-nmhost) install(TARGETS velox-nmhost RUNTIME DESTINATION libexec/velox) install(FILES ${CMAKE_SOURCE_DIR}/packaging/nativehost/com.velox.host.json DESTINATION lib/mozilla/native-messaging-hosts) else() message(STATUS "velox: nmhost has not landed yet — native-messaging manifest not installed.") endif()