cmake_minimum_required(VERSION 3.20) project(fire_gimbal_control LANGUAGES C CXX) # --------------------------------------------------------------------------- # Options (runtime toggles still select mock vs real at launch; these control # whether the heavy/proprietary dependencies are compiled in at all). # --------------------------------------------------------------------------- option(WITH_VIMBA "Build with Allied Vision Vimba X camera support" ON) option(WITH_MQTT "Build with Eclipse Paho MQTT support" ON) option(WITH_TUI "Build the terminal UI dashboard (FTXUI)" ON) option(BUILD_TESTING "Build unit tests" OFF) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake") if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE) endif() # --------------------------------------------------------------------------- # Always-required dependencies # --------------------------------------------------------------------------- find_package(Threads REQUIRED) find_package(OpenCV REQUIRED COMPONENTS core imgproc) # Boost.Asio is header-only (Boost >= 1.69); only program_options is a compiled lib. if(POLICY CMP0167) cmake_policy(SET CMP0167 NEW) endif() find_package(Boost REQUIRED CONFIG COMPONENTS program_options) # libjxl via pkg-config (Arch/Manjaro ship a .pc file) find_package(PkgConfig REQUIRED) pkg_check_modules(JXL REQUIRED IMPORTED_TARGET libjxl libjxl_threads) # --------------------------------------------------------------------------- # Build identity. deploy.sh computes `describe --always --dirty` and passes it in # the environment (GIT_REV=... cmake ...), so a deployed binary can name the # revision it came from in the TUI header. A plain local build has no GIT_REV and # falls back to "unknown", exactly as firmware/src/main.cpp does. # # Read at CONFIGURE time: `cmake --build` alone keeps whatever value the last # configure saw. deploy.sh reconfigures on every deploy, so the deployed path is # always fresh. # --------------------------------------------------------------------------- if(DEFINED ENV{GIT_REV} AND NOT "$ENV{GIT_REV}" STREQUAL "") set(FGC_GIT_REV "$ENV{GIT_REV}") else() set(FGC_GIT_REV "unknown") endif() # --------------------------------------------------------------------------- # fgc_core: SDK-independent core (config, path resolution, and - as the # refactor proceeds - logging, the capture scheduler and the I/O interfaces). # Builds and unit-tests WITHOUT Vimba X or Paho, so the core logic is # verifiable on any machine. # --------------------------------------------------------------------------- add_library(fgc_core STATIC src/core/Config.cpp src/core/IniEdit.cpp src/core/CameraStall.cpp src/core/RemoteCommands.cpp src/core/OperatingMode.cpp src/core/Paths.cpp src/core/SingleInstance.cpp src/core/Logger.cpp src/core/Geometry.cpp src/core/TmcCurrent.cpp src/core/HardwarePresence.cpp src/core/HardwareChecks.cpp src/core/FileLogSink.cpp src/core/AxisSpeed.cpp src/core/FirmwareConfig.cpp src/core/ScanGrid.cpp src/core/TelemetryParser.cpp src/core/CaptureScheduler.cpp src/core/CommandParser.cpp src/core/HelpText.cpp src/core/DumpParser.cpp src/core/DiagParser.cpp src/core/TestReport.cpp src/core/HostMetrics.cpp src/core/TestRunner.cpp src/core/Calibration.cpp src/core/HeadingFit.cpp src/core/PitchSetup.cpp src/core/MtiProtocol.cpp src/core/ImuMount.cpp src/core/CameraProfile.cpp src/core/CameraSettingsXml.cpp src/core/Hash.cpp src/core/ChannelHistory.cpp src/core/ChannelTopics.cpp src/core/RawImage.cpp src/core/SettleRule.cpp src/sensors/I2cBus.cpp src/sensors/Sht41Protocol.cpp src/sensors/McuEnvSensor.cpp src/ui/UiSnapshot.cpp src/ui/Scroll.cpp src/ui/HeadlessUi.cpp ini.c ) target_include_directories(fgc_core PUBLIC ${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR} # for the bundled ini.h ) target_link_libraries(fgc_core PUBLIC Threads::Threads) # PUBLIC so the application and the tests both see the same build identity. target_compile_definitions(fgc_core PUBLIC FGC_GIT_REV="${FGC_GIT_REV}") # --------------------------------------------------------------------------- # fgc_imaging: turning camera frames into saved images (de-Bayer, JPEG XL). Its # own library so the image tests can link OpenCV and libjxl without the rest of # the application; fgc_core stays free of both. # --------------------------------------------------------------------------- add_library(fgc_imaging STATIC src/camera/JpegXlEncoder.cpp src/camera/ImagePipeline.cpp ) target_include_directories(fgc_imaging PUBLIC ${OpenCV_INCLUDE_DIRS}) target_link_libraries(fgc_imaging PUBLIC fgc_core ${OpenCV_LIBS} PkgConfig::JXL) # --------------------------------------------------------------------------- # Application executable. Camera image pipeline + serial controller always # build (OpenCV/libjxl/Boost.Asio are available everywhere); MQTT and Vimba # sources are added only when their option is ON. # --------------------------------------------------------------------------- set(FGC_SOURCES main.cpp src/core/Application.cpp src/serial/SerialMotorController.cpp src/serial/MtiImuSource.cpp src/sensors/Sht41EnvSensor.cpp ) if(WITH_MQTT) list(APPEND FGC_SOURCES src/mqtt/MqttControlChannel.cpp) endif() if(WITH_VIMBA) list(APPEND FGC_SOURCES src/camera/VimbaCameraSource.cpp) endif() add_executable(fire_gimbal_control ${FGC_SOURCES}) target_include_directories(fire_gimbal_control PRIVATE ${CMAKE_SOURCE_DIR}) target_link_libraries(fire_gimbal_control PRIVATE fgc_core fgc_imaging ${OpenCV_LIBS} Boost::headers Boost::program_options PkgConfig::JXL ) # --------------------------------------------------------------------------- # Optional: MQTT (Eclipse Paho). Fetched + built from pinned, hash-verified # upstream release tarballs (no AUR, no system install required). # --------------------------------------------------------------------------- if(WITH_MQTT) include(cmake/Paho.cmake) target_link_libraries(fire_gimbal_control PRIVATE PahoMqttCpp::paho-mqttpp3-static) target_compile_definitions(fire_gimbal_control PRIVATE FGC_WITH_MQTT=1) else() target_compile_definitions(fire_gimbal_control PRIVATE FGC_WITH_MQTT=0) message(STATUS "WITH_MQTT=OFF: building without MQTT support") endif() # --------------------------------------------------------------------------- # Optional: Vimba X SDK (proprietary; install manually from Allied Vision). # --------------------------------------------------------------------------- if(WITH_VIMBA) find_package(Vmb REQUIRED) target_link_libraries(fire_gimbal_control PRIVATE Vmb::VmbC Vmb::VmbCPP) target_compile_definitions(fire_gimbal_control PRIVATE FGC_WITH_VIMBA=1) else() target_compile_definitions(fire_gimbal_control PRIVATE FGC_WITH_VIMBA=0) message(STATUS "WITH_VIMBA=OFF: building without Vimba X camera support (mock cameras only)") endif() # --------------------------------------------------------------------------- # Optional: terminal UI (FTXUI). The TuiUi source and the FTXUI link are added # only when ON; the SDK-independent core (HeadlessUi, UiSnapshot) is unaffected, # so a headless build needs no extra dependency. # --------------------------------------------------------------------------- if(WITH_TUI) include(cmake/Ftxui.cmake) target_sources(fire_gimbal_control PRIVATE src/ui/TuiUi.cpp) target_link_libraries(fire_gimbal_control PRIVATE ftxui::component ftxui::dom ftxui::screen) target_compile_definitions(fire_gimbal_control PRIVATE FGC_WITH_TUI=1) else() target_compile_definitions(fire_gimbal_control PRIVATE FGC_WITH_TUI=0) message(STATUS "WITH_TUI=OFF: building without the terminal dashboard (headless console only)") endif() # --------------------------------------------------------------------------- # fgc-config: writes and edits config.ini / hardware.ini, validating every # result through the same loader as the program. Core-only, so it builds # wherever fgc_core does; the tower installer depends on it. # --------------------------------------------------------------------------- add_executable(fgc-config tools/fgc_config.cpp) target_link_libraries(fgc-config PRIVATE fgc_core) # --------------------------------------------------------------------------- # Tests # --------------------------------------------------------------------------- if(BUILD_TESTING) enable_testing() add_subdirectory(tests) endif() # --------------------------------------------------------------------------- # Summary # --------------------------------------------------------------------------- message(STATUS "------------------------------------------------------------") message(STATUS "fire_gimbal_control configuration") message(STATUS " build type : ${CMAKE_BUILD_TYPE}") message(STATUS " WITH_VIMBA : ${WITH_VIMBA}") message(STATUS " WITH_MQTT : ${WITH_MQTT}") message(STATUS " WITH_TUI : ${WITH_TUI}") message(STATUS " tests : ${BUILD_TESTING}") message(STATUS " build id : ${FGC_GIT_REV}") message(STATUS "------------------------------------------------------------")