From 8554c441fbf9d589c506251c6fce97755262b60b Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Sat, 19 Sep 2026 14:31:36 +0200 Subject: [PATCH] macOS groundwork: what a static read says will stop an Apple Clang / libc++ build None of this has been built on a Mac - there is none yet. It is the list a read-only audit of the viewer/rugnux subtree produced, plus a serial -fsyntax-only pass of every reachable .cpp with clang 16 + libc++ on Linux, which found exactly one error (the first item). - JFJochDatasetInfoChartView: std::vector does not compile with libc++, whose construct_at refuses an array element type (float[2]). Use std::vector> and the reinterpret_cast every other FFTW call site already uses. - libcurl: GSSAPI off on Linux, and neither TLS nor GSSAPI on macOS. The viewer never sets CURLOPT_HTTPAUTH, so Negotiate was dead weight that cost a krb5-devel build dependency; on macOS curl's FindGSS refuses the system Heimdal outright, and with Secure Transport gone from curl (8.15) TLS would mean a Homebrew OpenSSL - the only host library a Mac build would need. Linux keeps OpenSSL. CURL_USE_GSSAPI is forced OFF rather than left unset so an existing build tree drops its cached ON. - libjpeg-turbo ExternalProject: CMAKE_SYSTEM_NAME/PROCESSOR were forwarded unconditionally, which puts even a native sub-build into cross-compiling mode, and CMAKE_OSX_ARCHITECTURES / SYSROOT / DEPLOYMENT_TARGET were not forwarded at all. Now the same rule the zlib-ng sub-build follows. - ShadowAccumulatorGPU.cu was added on the JFJOCH_USE_CUDA option (default ON) instead of JFJOCH_CUDA_AVAILABLE like every other .cu, so a machine without nvcc got a CUDA source in a target with no CUDA language. - CMAKE_OSX_DEPLOYMENT_TARGET defaults to 12.0 (overridable). Left unset, CMake takes the build machine's OS version and the .dmg starts nowhere older. - Standard headers that were only arriving transitively (, , , , , , ); newer libc++ releases keep removing such transitive includes. Checked: the seven changed sources pass clang 16 + libc++ -fsyntax-only. The CMake changes are not configured or built. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_015eAE2K7i5JGDwgwifiCfuA (cherry picked from commit 5a7282759ac5245277d8541b75d591fe4c61d671) --- CMakeLists.txt | 23 +++++++++++---- common/DatasetSettings.h | 1 + common/Histogram.h | 1 + common/ThreadSafeFIFO.h | 1 + common/ZMQWrappers.h | 2 ++ compression/JFJochZstdCompressor.cpp | 1 + docs/SOFTWARE.md | 5 ++-- image_analysis/CMakeLists.txt | 2 +- image_analysis/UpdateReflectionResolution.h | 1 + image_analysis/scale_merge/ScaleOnTheFly.cpp | 2 ++ preview/CMakeLists.txt | 30 +++++++++++++------- tools/XdsIntegrateParser.cpp | 1 + viewer/charts/JFJochDatasetInfoChartView.cpp | 9 +++--- viewer/widgets/SliderPlusBox.cpp | 2 ++ 14 files changed, 57 insertions(+), 24 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8e62becf9..d01f22eff 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,6 +8,11 @@ CMAKE_MINIMUM_REQUIRED(VERSION 3.26) FILE(STRINGS VERSION JFJOCH_VERSION) STRING(REGEX MATCH "^[0-9]+\\.[0-9]+\\.[0-9]+" JFJOCH_VERSION_NUMERIC "${JFJOCH_VERSION}") +# Oldest macOS the binaries run on (ignored elsewhere). Without it CMake takes the version of the +# build machine, and a .dmg would refuse to start on anything older. 12 is the floor of current Qt 6; +# our own needs (, ) stop at 11. Has to be set before PROJECT(). +SET(CMAKE_OSX_DEPLOYMENT_TARGET "12.0" CACHE STRING "Minimum macOS version") + PROJECT(jfjoch VERSION ${JFJOCH_VERSION_NUMERIC} LANGUAGES C CXX) SET(CMAKE_POLICY_DEFAULT_CMP0077 NEW) INCLUDE(GNUInstallDirs) @@ -473,10 +478,10 @@ IF (WIN32) ENDIF() # libcurl: the jfjoch_viewer HTTP client (viewer/JFJochHttpReader). Fetched and STATICALLY linked -# ONLY for viewer builds, so the broker/writer never pull in a TLS/Kerberos stack. Backends are -# OS-native per platform to keep the Windows build self-contained: Schannel (TLS) + SSPI -# (Negotiate/Kerberos) on Windows -- no external OpenSSL/krb5 -- and system OpenSSL + GSSAPI (krb5) -# on Linux. Trimmed to HTTP(S) only, mirroring the libtiff codec pruning above. +# ONLY for viewer builds, so the broker/writer never pull in a TLS stack. Windows gets its OS-native +# backends, Schannel (TLS) + SSPI (Negotiate/Kerberos), because they cost nothing there. Linux gets +# OpenSSL and no Kerberos; macOS gets neither. Trimmed to HTTP(S) only, mirroring the libtiff codec +# pruning above. IF (JFJOCH_VIEWER_BUILD OR JFJOCH_VIEWER_ONLY) SET(BUILD_CURL_EXE OFF CACHE BOOL "" FORCE) SET(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE) # static libcurl only, never a shared lib @@ -490,9 +495,15 @@ IF (JFJOCH_VIEWER_BUILD OR JFJOCH_VIEWER_ONLY) IF (WIN32) SET(CURL_USE_SCHANNEL ON CACHE BOOL "" FORCE) # native Windows TLS (no OpenSSL) SET(CURL_USE_SSPI ON CACHE BOOL "" FORCE) # native Negotiate/Kerberos (no krb5) + ELSEIF (APPLE) + # Plain HTTP only: curl dropped Secure Transport in 8.15, so TLS would mean OpenSSL, which + # the macOS SDK does not have - it would be the one library a Mac build takes from Homebrew. + SET(CURL_ENABLE_SSL OFF CACHE BOOL "" FORCE) ELSE() - SET(CURL_USE_OPENSSL ON CACHE BOOL "" FORCE) - SET(CURL_USE_GSSAPI ON CACHE BOOL "" FORCE) # Kerberos via system krb5 (needs krb5-dev) + SET(CURL_USE_OPENSSL ON CACHE BOOL "" FORCE) + # The viewer never asks for Negotiate. Set explicitly so that a build tree configured when + # this was ON does not keep the cached value. + SET(CURL_USE_GSSAPI OFF CACHE BOOL "" FORCE) ENDIF() FetchContent_Declare(curl URL https://github.com/curl/curl/archive/refs/tags/curl-8_22_0.tar.gz diff --git a/common/DatasetSettings.h b/common/DatasetSettings.h index b85e13eee..a103362a9 100644 --- a/common/DatasetSettings.h +++ b/common/DatasetSettings.h @@ -3,6 +3,7 @@ #pragma once +#include #include #include #include diff --git a/common/Histogram.h b/common/Histogram.h index 1e3b44d9b..af3f4720e 100644 --- a/common/Histogram.h +++ b/common/Histogram.h @@ -3,6 +3,7 @@ #pragma once +#include #include #include #include diff --git a/common/ThreadSafeFIFO.h b/common/ThreadSafeFIFO.h index 208923f1a..cbff3dc03 100644 --- a/common/ThreadSafeFIFO.h +++ b/common/ThreadSafeFIFO.h @@ -3,6 +3,7 @@ #pragma once +#include #include #include #include diff --git a/common/ZMQWrappers.h b/common/ZMQWrappers.h index 0aaaf6f00..a7f56daab 100644 --- a/common/ZMQWrappers.h +++ b/common/ZMQWrappers.h @@ -4,6 +4,8 @@ #pragma once +#include +#include #include #include #include diff --git a/compression/JFJochZstdCompressor.cpp b/compression/JFJochZstdCompressor.cpp index 9290b90f5..41e2d2438 100644 --- a/compression/JFJochZstdCompressor.cpp +++ b/compression/JFJochZstdCompressor.cpp @@ -3,6 +3,7 @@ #include "JFJochZstdCompressor.h" +#include #include #include #include diff --git a/docs/SOFTWARE.md b/docs/SOFTWARE.md index e1c8c2ad9..eb515b9c5 100644 --- a/docs/SOFTWARE.md +++ b/docs/SOFTWARE.md @@ -34,9 +34,8 @@ Optional: * FFTW library - for indexing if GPU/CUDA is absent (also auto-downloaded by CMake) * Node.js - to build the frontend * Qt version 6 (for jfjoch_viewer) -* OpenSSL 3.0 or newer and the Kerberos development headers (`krb5-devel` / `libkrb5-dev`) - - required to build jfjoch_viewer on Linux, where the fetched libcurl uses them for TLS and - Negotiate; a build on OpenSSL 1.1 fails in libcurl +* OpenSSL 3.0 or newer - required to build jfjoch_viewer on Linux, where the fetched libcurl uses + it for TLS; a build on OpenSSL 1.1 fails in libcurl Many further dependencies (spdlog, Zstandard, HDF5, slsDetectorPackage, libzmq, libtiff, libjpeg-turbo, Ceres, the fast feedback indexer, Catch2, ...) are downloaded automatically diff --git a/image_analysis/CMakeLists.txt b/image_analysis/CMakeLists.txt index 4e01b85d3..6abc665d9 100644 --- a/image_analysis/CMakeLists.txt +++ b/image_analysis/CMakeLists.txt @@ -98,7 +98,7 @@ ADD_LIBRARY(JFJochImageAnalysis STATIC dark_mask_analysis/DarkMaskAnalysis.h beam_stop/ShadowFinder.cpp beam_stop/ShadowFinder.h - $<$:beam_stop/ShadowAccumulatorGPU.cu> + $<$:beam_stop/ShadowAccumulatorGPU.cu> beam_stop/ShadowAccumulatorGPU.h rotation_indexer/RotationIndexer.cpp rotation_indexer/RotationIndexer.h diff --git a/image_analysis/UpdateReflectionResolution.h b/image_analysis/UpdateReflectionResolution.h index 695d2ba01..d5c373269 100644 --- a/image_analysis/UpdateReflectionResolution.h +++ b/image_analysis/UpdateReflectionResolution.h @@ -3,6 +3,7 @@ #pragma once +#include #include #include "../common/Reflection.h" #include "../common/UnitCell.h" diff --git a/image_analysis/scale_merge/ScaleOnTheFly.cpp b/image_analysis/scale_merge/ScaleOnTheFly.cpp index e2135dbd5..6d4ccf030 100644 --- a/image_analysis/scale_merge/ScaleOnTheFly.cpp +++ b/image_analysis/scale_merge/ScaleOnTheFly.cpp @@ -6,9 +6,11 @@ #include "../../common/Logger.h" #include +#include #include #include #include +#include #include namespace { diff --git a/preview/CMakeLists.txt b/preview/CMakeLists.txt index 2b0c38547..ede0b312c 100644 --- a/preview/CMakeLists.txt +++ b/preview/CMakeLists.txt @@ -14,6 +14,25 @@ SET(LIBJPEG_TURBO_DIR "${CMAKE_CURRENT_BINARY_DIR}/libjpeg-turbo") SET(LIBJPEG_TURBO_LIBRARY "${LIBJPEG_TURBO_DIR}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}jpeg${LIBJPEG_TURBO_STATIC_SUFFIX}${CMAKE_STATIC_LIBRARY_SUFFIX}") SET(LIBJPEG_TURBO_INCLUDE_DIRS "${LIBJPEG_TURBO_DIR}/include") +# An ExternalProject is a separate cmake invocation and inherits nothing, so without these it +# configures for the BUILD host: a cross build would link an x86_64 libjpeg.a into an aarch64 +# binary and only fail at the final link, and a macOS build would get a libjpeg.a for another +# architecture or deployment target than the binary it goes into. CMAKE_SYSTEM_NAME only when +# actually cross-compiling: setting it is what PUTS a build into cross mode (same as zlib-ng in the +# top-level CMakeLists). libjpeg-turbo picks its own SIMD from the target arch, so NEON comes for +# free on aarch64 and nasm is simply not consulted there. +SET(LIBJPEG_TURBO_FORWARD CMAKE_TOOLCHAIN_FILE CMAKE_C_COMPILER + CMAKE_OSX_ARCHITECTURES CMAKE_OSX_SYSROOT CMAKE_OSX_DEPLOYMENT_TARGET) +IF (CMAKE_CROSSCOMPILING) + LIST(APPEND LIBJPEG_TURBO_FORWARD CMAKE_SYSTEM_NAME CMAKE_SYSTEM_PROCESSOR) +ENDIF() +SET(LIBJPEG_TURBO_FORWARD_ARGS "") +FOREACH (_var IN LISTS LIBJPEG_TURBO_FORWARD) + IF (${_var}) + LIST(APPEND LIBJPEG_TURBO_FORWARD_ARGS "-D${_var}:STRING=${${_var}}") + ENDIF() +ENDFOREACH() + ExternalProject_Add(libjpeg-turbo-project URL https://github.com/libjpeg-turbo/libjpeg-turbo/archive/refs/tags/3.2.0.tar.gz URL_HASH SHA256=980dd81f425082aa6d7c9e47fef27554ce7a9ffc8e2f6e863b97d263c5c50858 @@ -35,16 +54,7 @@ ExternalProject_Add(libjpeg-turbo-project -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE} -DCMAKE_INSTALL_PREFIX:PATH= -DCMAKE_INSTALL_LIBDIR:PATH=/lib - # An ExternalProject is a separate cmake invocation and inherits nothing, so without these - # it configures for the BUILD host: a cross build would link an x86_64 libjpeg.a into an - # aarch64 binary and only fail at the final link. Forward the toolchain file (empty when not - # cross-compiling, which cmake ignores) and the compilers, so it follows the parent build. - # libjpeg-turbo picks its own SIMD from the target arch, so NEON comes for free on aarch64 - # and nasm is simply not consulted there. - -DCMAKE_TOOLCHAIN_FILE:FILEPATH=${CMAKE_TOOLCHAIN_FILE} - -DCMAKE_C_COMPILER:FILEPATH=${CMAKE_C_COMPILER} - -DCMAKE_SYSTEM_NAME:STRING=${CMAKE_SYSTEM_NAME} - -DCMAKE_SYSTEM_PROCESSOR:STRING=${CMAKE_SYSTEM_PROCESSOR}) + ${LIBJPEG_TURBO_FORWARD_ARGS}) # Create the include dir up front so setting INTERFACE_INCLUDE_DIRECTORIES below does not fail. FILE(MAKE_DIRECTORY ${LIBJPEG_TURBO_INCLUDE_DIRS}) diff --git a/tools/XdsIntegrateParser.cpp b/tools/XdsIntegrateParser.cpp index f5f7f363b..cbd7f9ab8 100644 --- a/tools/XdsIntegrateParser.cpp +++ b/tools/XdsIntegrateParser.cpp @@ -4,6 +4,7 @@ #include "XdsIntegrateParser.h" #include +#include #include #include diff --git a/viewer/charts/JFJochDatasetInfoChartView.cpp b/viewer/charts/JFJochDatasetInfoChartView.cpp index 068699d7d..738d7a4f4 100644 --- a/viewer/charts/JFJochDatasetInfoChartView.cpp +++ b/viewer/charts/JFJochDatasetInfoChartView.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include "JFJochDatasetInfoChartView.h" @@ -963,12 +964,12 @@ void JFJochDatasetInfoChartView::buildFFTChart() { const int n = static_cast(N); const int nComplex = n / 2 + 1; - std::vector out(static_cast(nComplex)); + std::vector> out(static_cast(nComplex)); fftwf_plan plan = fftwf_plan_dft_r2c_1d( n, in.data(), - out.data(), + reinterpret_cast(out.data()), FFTW_ESTIMATE); if (!plan) { @@ -987,8 +988,8 @@ void JFJochDatasetInfoChartView::buildFFTChart() { const double df = fs / static_cast(n); // frequency resolution for (int k = 0; k < nComplex; ++k) { - const double re = out[static_cast(k)][0]; - const double im = out[static_cast(k)][1]; + const double re = out[static_cast(k)].real(); + const double im = out[static_cast(k)].imag(); const double mag = std::hypot(re, im); // amplitude m_fftMagnitudes[static_cast(k)] = mag; diff --git a/viewer/widgets/SliderPlusBox.cpp b/viewer/widgets/SliderPlusBox.cpp index ab4571b3f..98e06cd09 100644 --- a/viewer/widgets/SliderPlusBox.cpp +++ b/viewer/widgets/SliderPlusBox.cpp @@ -1,6 +1,8 @@ // SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute // SPDX-License-Identifier: GPL-3.0-only +#include + #include "SliderPlusBox.h" #include "../common/JFJochException.h" SliderPlusBox::SliderPlusBox(double min, double max, double step, int decimals, QWidget *parent, ScaleType scaleType)