158 lines
7.2 KiB
CMake
158 lines
7.2 KiB
CMake
cmake_minimum_required(VERSION 3.24)
|
|
project(udpscope VERSION 0.1.0 LANGUAGES C CXX)
|
|
|
|
set(CMAKE_CXX_STANDARD 20)
|
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
|
set(CMAKE_CXX_EXTENSIONS OFF)
|
|
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
|
|
|
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
|
|
set(CMAKE_BUILD_TYPE Release CACHE STRING "" FORCE)
|
|
endif()
|
|
|
|
find_package(Threads REQUIRED)
|
|
|
|
# --- libadwaita: the shortcut overview ---------------------------------------
|
|
# GTK4's own `GtkShortcutsWindow` is deprecated as of 4.18 and libadwaita's
|
|
# `AdwShortcutsDialog` (1.8) is its replacement, so the overview is built from the
|
|
# platform widget rather than from a hand-rolled grid. This is the only thing libadwaita
|
|
# is used for; `adw_init()` is called for it, which also means the app picks up
|
|
# libadwaita's stylesheet.
|
|
find_package(PkgConfig REQUIRED)
|
|
pkg_check_modules(ADWAITA REQUIRED IMPORTED_TARGET libadwaita-1>=1.8)
|
|
|
|
# --- deps/plotter: built from the submodule, GTK4 adapter only ----------------
|
|
set(PLOT_BUILD_TESTS OFF CACHE BOOL "" FORCE)
|
|
set(PLOT_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE)
|
|
set(PLOT_BUILD_GLFW OFF CACHE BOOL "" FORCE)
|
|
set(PLOT_BUILD_IMGUI OFF CACHE BOOL "" FORCE)
|
|
set(PLOT_BUILD_QT6 OFF CACHE BOOL "" FORCE)
|
|
set(PLOT_BUILD_GTK4 ON CACHE BOOL "" FORCE)
|
|
set(PLOT_INSTALL OFF CACHE BOOL "" FORCE)
|
|
add_subdirectory(deps/plotter EXCLUDE_FROM_ALL)
|
|
|
|
# --- deps/udpsclient: vendored C99 receiver ----------------------------------
|
|
add_library(udpsclient STATIC deps/udpsclient/udps_client.c)
|
|
target_include_directories(udpsclient PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/deps/udpsclient)
|
|
set_target_properties(udpsclient PROPERTIES C_STANDARD 99 C_STANDARD_REQUIRED ON)
|
|
if(CMAKE_C_COMPILER_ID MATCHES "GNU|Clang")
|
|
target_compile_options(udpsclient PRIVATE -Wall -Wextra)
|
|
endif()
|
|
|
|
# --- icons: six SVGs compiled into the binary --------------------------------
|
|
# There is no stock icon for an oscilloscope trigger, a pair of cursors or a measurement
|
|
# ruler, so this app draws its own. They go in a GResource rather than beside the binary
|
|
# because udpscope is run straight out of the build tree and has no install step: a
|
|
# search path would have to be located at runtime, and the failure mode of not locating
|
|
# it is a silent missing-image placeholder.
|
|
find_program(GLIB_COMPILE_RESOURCES NAMES glib-compile-resources REQUIRED)
|
|
set(UDPSCOPE_ICON_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src/icons)
|
|
file(GLOB UDPSCOPE_ICON_FILES CONFIGURE_DEPENDS
|
|
${UDPSCOPE_ICON_DIR}/scalable/actions/*.svg
|
|
${UDPSCOPE_ICON_DIR}/scalable/apps/*.svg)
|
|
add_custom_command(
|
|
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/udpscope_resources.c
|
|
COMMAND ${GLIB_COMPILE_RESOURCES}
|
|
--target=${CMAKE_CURRENT_BINARY_DIR}/udpscope_resources.c
|
|
--sourcedir=${UDPSCOPE_ICON_DIR}
|
|
--generate-source
|
|
${UDPSCOPE_ICON_DIR}/udpscope.gresource.xml
|
|
DEPENDS ${UDPSCOPE_ICON_DIR}/udpscope.gresource.xml ${UDPSCOPE_ICON_FILES}
|
|
COMMENT "Compiling udpscope icon resources"
|
|
VERBATIM)
|
|
|
|
# --- help pages: Pango markup in a GResource ----------------------------------
|
|
# A second bundle beside the icons'. --c-name is given explicitly so the two generated
|
|
# sources cannot collide on symbol names.
|
|
set(UDPSCOPE_HELP_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src/help)
|
|
file(GLOB UDPSCOPE_HELP_FILES CONFIGURE_DEPENDS ${UDPSCOPE_HELP_DIR}/*.txt)
|
|
add_custom_command(
|
|
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/udpscope_help_resources.c
|
|
COMMAND ${GLIB_COMPILE_RESOURCES}
|
|
--target=${CMAKE_CURRENT_BINARY_DIR}/udpscope_help_resources.c
|
|
--sourcedir=${UDPSCOPE_HELP_DIR}
|
|
--c-name=udpscope_help
|
|
--generate-source
|
|
${UDPSCOPE_HELP_DIR}/udpscope-help.gresource.xml
|
|
DEPENDS ${UDPSCOPE_HELP_DIR}/udpscope-help.gresource.xml ${UDPSCOPE_HELP_FILES}
|
|
COMMENT "Compiling udpscope help resources"
|
|
VERBATIM)
|
|
|
|
# --- build info: version, commit and timestamp compiled into the binary -------
|
|
# Written at configure time so add_executable can name the file, and again on every
|
|
# build so the commit and the timestamp belong to the binary that is running rather
|
|
# than to whenever the tree was last configured.
|
|
set(UDPSCOPE_BUILD_INFO ${CMAKE_CURRENT_BINARY_DIR}/build_info.cpp)
|
|
set(UDPSCOPE_BUILD_INFO_ARGS
|
|
-DSRC=${CMAKE_CURRENT_SOURCE_DIR}
|
|
-DOUT=${UDPSCOPE_BUILD_INFO}
|
|
-DVERSION=${PROJECT_VERSION}
|
|
-P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/write_build_info.cmake)
|
|
execute_process(COMMAND ${CMAKE_COMMAND} ${UDPSCOPE_BUILD_INFO_ARGS})
|
|
add_custom_target(udpscope_build_info
|
|
BYPRODUCTS ${UDPSCOPE_BUILD_INFO}
|
|
COMMAND ${CMAKE_COMMAND} ${UDPSCOPE_BUILD_INFO_ARGS}
|
|
COMMENT "Writing udpscope build info"
|
|
VERBATIM)
|
|
set_source_files_properties(${UDPSCOPE_BUILD_INFO} PROPERTIES GENERATED TRUE)
|
|
|
|
# --- the application ----------------------------------------------------------
|
|
add_executable(udpscope
|
|
${CMAKE_CURRENT_BINARY_DIR}/udpscope_resources.c
|
|
${CMAKE_CURRENT_BINARY_DIR}/udpscope_help_resources.c
|
|
${UDPSCOPE_BUILD_INFO}
|
|
src/main.cpp
|
|
src/config.cpp
|
|
src/channel.cpp
|
|
src/model.cpp
|
|
src/condition.cpp
|
|
src/trigger.cpp
|
|
src/acquisition.cpp
|
|
src/plot_host.cpp
|
|
src/export.cpp
|
|
src/search.cpp
|
|
src/layout_store.cpp
|
|
src/source_dialog.cpp
|
|
src/measure.cpp
|
|
src/math_channel.cpp
|
|
src/status_text.cpp
|
|
src/shortcuts.cpp
|
|
src/help_window.cpp
|
|
src/ui.cpp
|
|
)
|
|
|
|
target_include_directories(udpscope PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src)
|
|
target_link_libraries(udpscope PRIVATE plot::gtk4 udpsclient Threads::Threads
|
|
PkgConfig::ADWAITA)
|
|
add_dependencies(udpscope udpscope_build_info)
|
|
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
|
|
target_compile_options(udpscope PRIVATE -Wall -Wextra -Wpedantic)
|
|
endif()
|
|
|
|
# --- the desktop entry: opt-in, never part of `cmake --build` ------------------
|
|
# `Exec` is the built binary's absolute path in the build tree, so the entry always launches
|
|
# exactly the binary that was last built -- and moving or deleting the build directory breaks
|
|
# it. That is the price of having no install step, and it is the right one here: an install()
|
|
# rule would create a second copy of the app that can diverge from the build tree, and a
|
|
# documented `cp` would need the binary on PATH, which it is not.
|
|
#
|
|
# configure_file() cannot evaluate a generator expression and file(GENERATE) cannot substitute
|
|
# an @VAR@, so the two run in sequence: the first writes the genex out literally, the second
|
|
# evaluates it. This is the documented idiom.
|
|
set(UDPSCOPE_EXEC "$<TARGET_FILE:udpscope>")
|
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/data/org.udpscope.app.desktop.in
|
|
${CMAKE_CURRENT_BINARY_DIR}/desktop-entry.in @ONLY)
|
|
file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/org.udpscope.app.desktop
|
|
INPUT ${CMAKE_CURRENT_BINARY_DIR}/desktop-entry.in)
|
|
|
|
# No ALL: this runs only when it is named, so `cmake --build build` is unaffected.
|
|
add_custom_target(desktop-entry
|
|
COMMAND ${CMAKE_COMMAND}
|
|
-DENTRY=${CMAKE_CURRENT_BINARY_DIR}/org.udpscope.app.desktop
|
|
-DICON=${UDPSCOPE_ICON_DIR}/scalable/apps/org.udpscope.app.svg
|
|
-DSYMBOLIC=${UDPSCOPE_ICON_DIR}/scalable/apps/org.udpscope.app-symbolic.svg
|
|
-P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/install_desktop_entry.cmake
|
|
COMMENT "Installing the udpscope desktop entry into XDG_DATA_HOME"
|
|
VERBATIM)
|
|
add_dependencies(desktop-entry udpscope)
|