Files
Jungfraujoch/viewer/CMakeLists.txt
T
leonarski_fandClaude Opus 5 8d32024dd1
Build Packages / build:rugnux:windows (push) Failing after 2s
Build Packages / build:rugnux-tgz (x86_64) (push) Failing after 14s
Build Packages / build:rugnux:aarch64 (cross) (push) Failing after 30s
Build Packages / Unit tests (push) Canceled after 2m33s
Build Packages / build:rpm (rocky8) (push) Canceled after 0s
Build Packages / build:rpm (rocky9_sls9) (push) Canceled after 0s
Build Packages / build:rpm (rocky9) (push) Canceled after 0s
Build Packages / build:rpm (ubuntu2204) (push) Canceled after 0s
Build Packages / build:rpm (ubuntu2404) (push) Canceled after 0s
Build Packages / DIALS test (push) Canceled after 0s
Build Packages / XDS test (durin plugin) (push) Canceled after 0s
Build Packages / XDS test (JFJoch plugin) (push) Canceled after 0s
Build Packages / XDS test (neggia plugin) (push) Canceled after 0s
Build Packages / Generate python client (push) Canceled after 0s
Build Packages / build:viewer-tgz:cuda (push) Canceled after 2m29s
Build Packages / Build documentation (push) Canceled after 0s
Build Packages / Create release (push) Canceled after 0s
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Canceled after 2m19s
Build Packages / build:viewer-tgz:cpu (push) Canceled after 2m31s
Build Packages / build:rpm (rocky8_sls9) (push) Canceled after 1m54s
Build Packages / build:rpm (rocky9_nocuda) (push) Canceled after 2m21s
Build Packages / build:rpm (rocky8_nocuda) (push) Canceled after 2m23s
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Canceled after 2m13s
Build Packages / build:windows:cuda (push) Canceled after 2m42s
Build Packages / build:windows:nocuda (push) Canceled after 2m45s
Ship jfjoch_viewer and rugnux as two packages, and cross-build rugnux for arm64
The viewer tarball also carried rugnux, jfjoch_extract_hkl and jfjoch_recompress.
A GUI download that contains a batch processor is confusing on its own, and it
forced anyone who only wanted rugnux to take Qt with it. JFJOCH_RUGNUX_ONLY is
the viewer-only subtree minus viewer/ and tools/, so it needs no Qt at all, and
each of the two options now yields one artifact holding one program:

  JFJOCH_VIEWER_ONLY   jfjoch_viewer   .tar.gz / installer / .dmg
  JFJOCH_RUGNUX_ONLY   rugnux          .tar.gz / .zip

The two CLI tools are still built and no longer installed anywhere. rugnux gets
a CPack component of its own, so its notices land in share/doc/jfjoch_rugnux.

What makes the split possible is linking cuFFT statically in both products. It
was the only CUDA component still dynamic - cudart and the fast-feedback indexer
were already static - and shipping it as a .so meant each self-contained archive
had to carry the library beside its executables and find it again through an
$ORIGIN rpath. That rpath was set on jfjoch_viewer alone, while the same tarball
installed three more executables, so those shipped with no runpath at all (cmake
strips the build-tree one, which points at the build host's CUDA directory) and
could not load the libcufft lying next to them. Static, an artifact is one file
that runs: the x86_64 rugnux tarball needs only libc, libstdc++, libgcc_s, libm,
libpthread, librt and libdl. The bundling code and the rpath both go away.

libcufft_static.a carries a relocatable-device-code object, so a consuming
executable needs a CUDA device link; CUDA 13 no longer ships the
libcufft_static_nocallback.a that used to avoid this. CUDA_RESOLVE_DEVICE_SYMBOLS
emits that step while leaving the host link driver alone, so the -march and
-flto flags CI passes still apply. The server build keeps the shared library:
its .deb/.rpm take CUDA from the distro, and every executable there would
otherwise need the same device link.

The guards that exclude server-side targets keyed on NOT JFJOCH_VIEWER_ONLY,
which a rugnux-only build does not satisfy - it failed on jfjoch_writer pulling
in JFJochImagePuller. They now key on JFJOCH_PORTABLE_ONLY, true for either
product, rather than on one product's option in five places.

docker/ubuntu2404 additionally cross-compiles rugnux for arm64 SBSA, which is
both DGX Spark (GB10, sm_121) and Grace Hopper (GH200, sm_90); one binary with
both fatbins runs on either. It needed three things beyond a cross gcc. arm64 is
published on ports.ubuntu.com and Noble's deb822 sources carry no Architectures:
field, so adding the architecture without splitting the entries 404s on every
index. The CUDA cross packages are in neither the x86_64 repo nor the sbsa one
but in cross-linux-sbsa, whose fatbinary_section.h ships only in the x86_64
target tree even though it is architecture-neutral. And HDF5 has two try_run
probes, so qemu-user-static is needed as CMAKE_CROSSCOMPILING_EMULATOR; every
other fetched dependency either guards its run-checks or has none.

The cross-built tarball is one ELF aarch64 binary carrying all 17 GPU modules
for both sm_90 and sm_121, needing no cuFFT and no CUDA runtime at run time.
It is untested on hardware: XDS is x86-64 only, so CI can show it links but only
a Spark or a GH200 can show it works.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SQjneRUssfhi1k9rq8Ts3h
2026-08-25 19:23:59 +02:00

208 lines
8.7 KiB
CMake

# SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
# SPDX-License-Identifier: GPL-3.0-only
SET(CMAKE_AUTOMOC ON)
SET(CMAKE_AUTOUIC ON)
# D-Bus (single-instance / remote control) is Linux-only: Qt6::DBus does not
# exist on Windows or macOS. Default ON on Linux, OFF elsewhere.
IF(UNIX AND NOT APPLE)
OPTION(JFJOCH_VIEWER_DBUS "Build viewer with D-Bus support (Linux only)" ON)
ELSE()
OPTION(JFJOCH_VIEWER_DBUS "Build viewer with D-Bus support (Linux only)" OFF)
ENDIF()
SET(JFJOCH_VIEWER_QT_COMPONENTS Core Gui Widgets Charts Concurrent OpenGL OpenGLWidgets)
IF(JFJOCH_VIEWER_DBUS)
LIST(APPEND JFJOCH_VIEWER_QT_COMPONENTS DBus)
ENDIF()
FIND_PACKAGE(Qt6 COMPONENTS ${JFJOCH_VIEWER_QT_COMPONENTS} REQUIRED)
QT_ADD_RESOURCES(APP_RESOURCES resources/resources.qrc)
ADD_EXECUTABLE(jfjoch_viewer jfjoch_viewer.cpp JFJochViewerWindow.cpp JFJochViewerWindow.h
JFJochViewerMenu.cpp
JFJochViewerMenu.h
image_viewer/JFJochDiffractionImage.cpp
image_viewer/JFJochDiffractionImage.h
image_viewer/JFJochSimpleImage.cpp
image_viewer/JFJochSimpleImage.h
JFJochImageReadingWorker.cpp
JFJochImageReadingWorker.h
JFJochHttpReader.cpp
JFJochHttpReader.h
RunData.h
JFJochProcessController.cpp
JFJochProcessController.h
JFJochViewerDatasetInfo.cpp
JFJochViewerDatasetInfo.h
JFJochViewerSidePanel.cpp
JFJochViewerSidePanel.h
widgets/TitleLabel.cpp
widgets/TitleLabel.h
charts/JFJochDatasetInfoChartView.cpp
charts/JFJochDatasetInfoChartView.h
widgets/JFJochViewerImageStatistics.cpp
widgets/JFJochViewerImageStatistics.h
charts/JFJochSimpleChartView.cpp
charts/JFJochSimpleChartView.h
JFJochViewerStatusBar.cpp
JFJochViewerStatusBar.h
windows/JFJochViewerImageListWindow.cpp
windows/JFJochViewerImageListWindow.h
widgets/NumericComboBox.cpp
widgets/NumericComboBox.h
windows/JFJochViewerMetadataWindow.cpp
windows/JFJochViewerMetadataWindow.h
windows/JFJochMergeStatsWindow.cpp
windows/JFJochMergeStatsWindow.h
windows/JFJochCalibrationResultWindow.cpp
windows/JFJochCalibrationResultWindow.h
widgets/NumberLineEdit.cpp
widgets/NumberLineEdit.h
widgets/SliderPlusBox.cpp
widgets/SliderPlusBox.h
widgets/JFJochViewerSidePanelChart.cpp
widgets/JFJochViewerSidePanelChart.h
widgets/JFJochViewerSettingsDock.cpp
widgets/JFJochViewerSettingsDock.h
widgets/CollapsibleSection.cpp
widgets/CollapsibleSection.h
widgets/ToolbarIcons.cpp
widgets/ToolbarIcons.h
widgets/JFJochViewerImageStrip.cpp
widgets/JFJochViewerImageStrip.h
windows/JFJochViewerSpotListWindow.cpp
windows/JFJochViewerSpotListWindow.h
image_viewer/JFJochAzIntImage.cpp
image_viewer/JFJochAzIntImage.h
windows/JFJochViewerReflectionListWindow.cpp
windows/JFJochViewerReflectionListWindow.h
toolbar/JFJochViewerToolbarImage.cpp
toolbar/JFJochViewerToolbarImage.h
toolbar/JFJochViewerToolbarDisplay.cpp
toolbar/JFJochViewerToolbarDisplay.h
SimpleImage.h
windows/JFJochCalibrationWindow.cpp
windows/JFJochCalibrationWindow.h
windows/JFJochHelperWindow.cpp
windows/JFJochHelperWindow.h
windows/JFJochLicenseWindow.cpp
windows/JFJochLicenseWindow.h
image_viewer/JFJochImage.cpp
image_viewer/JFJochImage.h
image_viewer/JFJochFollowerImage.cpp
image_viewer/JFJochFollowerImage.h
windows/JFJoch2DAzintImageWindow.cpp
windows/JFJoch2DAzintImageWindow.h
widgets/JFJochViewerROIResult.cpp
widgets/JFJochViewerROIResult.h
widgets/JFJochViewerROIList.cpp
widgets/JFJochViewerROIList.h
widgets/ResolutionRingWidget.cpp
widgets/ResolutionRingWidget.h
image_viewer/JFJochGridScanImage.cpp
image_viewer/JFJochGridScanImage.h
widgets/PowderCalibrationWidget.cpp
widgets/PowderCalibrationWidget.h
${APP_RESOURCES}
windows/JFJochViewerReciprocalSpaceWindow.cpp
windows/JFJochViewerReciprocalSpaceWindow.h
windows/JFJochMagnifierWindow.cpp
windows/JFJochMagnifierWindow.h
windows/JFJochProcessingJobsWindow.cpp
windows/JFJochProcessingJobsWindow.h
)
TARGET_LINK_LIBRARIES(jfjoch_viewer Qt6::Core Qt6::Gui Qt6::Widgets Qt6::Charts Qt6::Concurrent
Qt6::OpenGL Qt6::OpenGLWidgets
JFJochReader JFJochLogger JFJochCommon JFJochWriter JFJochImageAnalysis Rugnux
fftw3f libcurl_static) # vendored static libcurl by concrete name, not the CURL::libcurl
# alias, which a system libcurl can shadow (see top-level CMakeLists)
# Native GUI app per platform: a .app bundle on macOS, GUI subsystem (no console window) on
# Windows. Each property is ignored on the platforms it does not apply to, so set both always.
SET_TARGET_PROPERTIES(jfjoch_viewer PROPERTIES
MACOSX_BUNDLE ON
WIN32_EXECUTABLE ON)
# Application icon: embedded into the .exe via a Windows resource script, and copied into
# the macOS .app bundle (referenced from Info.plist through MACOSX_BUNDLE_ICON_FILE).
IF(WIN32)
TARGET_SOURCES(jfjoch_viewer PRIVATE resources/jfjoch.rc)
ELSEIF(APPLE)
SET(_viewer_icns ${CMAKE_CURRENT_SOURCE_DIR}/resources/jfjoch.icns)
TARGET_SOURCES(jfjoch_viewer PRIVATE ${_viewer_icns})
SET_SOURCE_FILES_PROPERTIES(${_viewer_icns} PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
SET_TARGET_PROPERTIES(jfjoch_viewer PROPERTIES MACOSX_BUNDLE_ICON_FILE jfjoch.icns)
ENDIF()
INSTALL(TARGETS jfjoch_viewer
BUNDLE DESTINATION . COMPONENT viewer # macOS .app bundle
RUNTIME DESTINATION bin COMPONENT viewer) # Windows .exe / Linux binary
# libcufft_static.a carries a relocatable-device-code object (separate_callback.o), so an executable
# linking it needs a CUDA device-link step -- without it the host link fails on an undefined
# __cudaRegisterLinkedBinary_* symbol. CUDA 13 no longer ships libcufft_static_nocallback.a, which
# used to be the way around it. CUDA_RESOLVE_DEVICE_SYMBOLS makes CMake emit that step while leaving
# the host link driver alone, so the -march/-flto flags CI passes still apply.
IF (JFJOCH_PORTABLE_ONLY AND JFJOCH_CUDA_AVAILABLE)
SET_TARGET_PROPERTIES(jfjoch_viewer PROPERTIES CUDA_RESOLVE_DEVICE_SYMBOLS ON)
ENDIF()
IF(JFJOCH_VIEWER_DBUS)
TARGET_SOURCES(jfjoch_viewer PRIVATE dbus/JFJochViewerAdaptor.cpp dbus/JFJochViewerAdaptor.h)
TARGET_LINK_LIBRARIES(jfjoch_viewer Qt6::DBus)
TARGET_COMPILE_DEFINITIONS(jfjoch_viewer PRIVATE JFJOCH_VIEWER_DBUS)
INSTALL(
FILES ${CMAKE_CURRENT_SOURCE_DIR}/dbus/ch.psi.jfjoch_viewer.service
DESTINATION share/dbus-1/services
COMPONENT viewer
)
ENDIF()
# Freedesktop menu entry and its icon: Linux only. On Windows the Start Menu shortcut comes from
# CPACK_PACKAGE_EXECUTABLES and on macOS from the .app bundle, so shipping these there would only
# put two dead files into the installer.
IF(UNIX AND NOT APPLE)
INSTALL(
FILES resources/jfjoch.png
DESTINATION share/pixmaps
COMPONENT viewer
)
INSTALL(
FILES jfjoch_viewer.desktop
DESTINATION share/applications
COMPONENT viewer
)
ENDIF()
# Platform integration plugin: XCB on Linux, native plugin on Windows/macOS.
IF(WIN32)
qt_import_plugins(jfjoch_viewer INCLUDE Qt::QWindowsIntegrationPlugin)
ELSEIF(APPLE)
qt_import_plugins(jfjoch_viewer INCLUDE Qt::QCocoaIntegrationPlugin)
ELSE()
qt_import_plugins(jfjoch_viewer INCLUDE Qt::QXcbIntegrationPlugin)
ENDIF()
# Bundle the Qt runtime into the install tree at install time: this drives windeployqt on Windows
# and macdeployqt on macOS, copying the Qt shared libraries + plugins next to the app. With a
# static Qt (e.g. our Linux build) there is nothing to copy, so it is a no-op. Requires Qt >= 6.5,
# which is when the OUTPUT_SCRIPT signature and the Linux deploy path landed (6.3/6.4 used the older
# FILENAME_VARIABLE and had no Linux support); skipped on older Qt. NO_UNSUPPORTED_PLATFORM_ERROR
# keeps it from hard-failing on configurations it does not handle.
IF(Qt6_VERSION VERSION_GREATER_EQUAL "6.5")
qt_generate_deploy_app_script(
TARGET jfjoch_viewer
OUTPUT_SCRIPT jfjoch_viewer_deploy_script
NO_UNSUPPORTED_PLATFORM_ERROR)
INSTALL(SCRIPT ${jfjoch_viewer_deploy_script} COMPONENT viewer)
ENDIF()
# cuFFT is linked statically (see image_analysis/indexing/CMakeLists.txt), so there is no CUDA
# runtime library to ship beside jfjoch_viewer on any platform.
ENDIF()