Skip to content

Commit 91978c1

Browse files
committed
Add macOS CPU build support
CI: - Add testMacOS.yaml workflow for macOS CPU build (no rayx-ui, no CUDA). - Set MACOSX_DEPLOYMENT_TARGET=13.3 and pass it consistently to CMake. - Install required toolchain dependencies (compiler, OpenMP, HDF5, zlib, make). Build: - Add AppleClang to platform detection so RAYX_API exports symbols correctly. - Implement macOS getExecutablePath() (was static_assert(false)) using _NSGetExecutablePath. - Drop spurious baseDir from the macOS resource lookup so Data/PALIK, NFF, CROMER, MOLEC are found next to the executable (matches Linux). - Set CMAKE_OSX_DEPLOYMENT_TARGET only as fallback so it does not override the workflow value. Source / tests: - Fix formatAsVec redefinition on Linux (RandCounter == unsigned long there). - Add CPU-build fallback for the test runner so it works without GPU build. - Reduce noisy tolerances in testSchwingerDipole, testBessel1, PlaneGratingDevAzMisVLS.
1 parent f6ca1f8 commit 91978c1

12 files changed

Lines changed: 235 additions & 116 deletions

File tree

.github/workflows/testMacOS.yaml

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
name: testMacOS
2+
3+
on:
4+
push:
5+
branches:
6+
- '**'
7+
tags-ignore:
8+
- 'v*'
9+
pull_request:
10+
branches:
11+
- '**'
12+
13+
env:
14+
BUILD_TYPE: Release
15+
MACOSX_DEPLOYMENT_TARGET: "13.3"
16+
17+
jobs:
18+
build:
19+
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name
20+
runs-on: macos-14
21+
22+
steps:
23+
- uses: actions/checkout@v4
24+
with:
25+
submodules: recursive
26+
27+
- name: Install dependencies (Homebrew)
28+
run: |
29+
brew update
30+
brew install cmake boost gtk+3 hdf5 libomp llvm make zlib
31+
32+
- name: Add Homebrew to PATH
33+
run: echo "/opt/homebrew/bin" >> $GITHUB_PATH
34+
35+
- name: Add Homebrew LLVM to PATH
36+
run: echo "/opt/homebrew/opt/llvm/bin" >> $GITHUB_PATH
37+
38+
- name: Set Xcode toolchain as default
39+
run: sudo xcode-select -s /Applications/Xcode.app/Contents/Developer
40+
41+
- name: Ensure system linker is used
42+
run: echo "LD=/usr/bin/ld" >> $GITHUB_ENV
43+
44+
- name: Configure Homebrew clang (symlink for easier access)
45+
run: |
46+
brew unlink llvm && brew link llvm --force --overwrite
47+
48+
- name: Symlink system ld for Homebrew clang
49+
run: |
50+
ln -sf /usr/bin/ld /opt/homebrew/bin/ld
51+
ln -sf /usr/bin/ld /opt/homebrew/opt/llvm/bin/ld
52+
53+
- name: Configure CMake with Homebrew clang and OpenMP support
54+
env:
55+
LDFLAGS: "-L/opt/homebrew/opt/libomp/lib -L/opt/homebrew/opt/zlib/lib"
56+
CPPFLAGS: "-I/opt/homebrew/opt/libomp/include -I/opt/homebrew/opt/zlib/include"
57+
PKG_CONFIG_PATH: "/opt/homebrew/opt/zlib/lib/pkgconfig:/opt/homebrew/lib/pkgconfig"
58+
CC: "/opt/homebrew/opt/llvm/bin/clang"
59+
CXX: "/opt/homebrew/opt/llvm/bin/clang++"
60+
run: |
61+
cmake -B build \
62+
-DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} \
63+
-DCMAKE_MACOSX_RPATH=ON \
64+
-DCMAKE_OSX_DEPLOYMENT_TARGET=${{env.MACOSX_DEPLOYMENT_TARGET}} \
65+
-DCMAKE_INSTALL_RPATH="@loader_path;@rpath" \
66+
-DCMAKE_PREFIX_PATH="/opt/homebrew/opt/hdf5;/opt/homebrew/opt/zlib;/opt/homebrew/opt/libomp" \
67+
-DHDF5_ROOT=/opt/homebrew/opt/hdf5 \
68+
-DZLIB_ROOT=/opt/homebrew/opt/zlib \
69+
-DZLIB_INCLUDE_DIR=/opt/homebrew/opt/zlib/include \
70+
-DZLIB_LIBRARY=/opt/homebrew/opt/zlib/lib/libz.dylib \
71+
-DRAYX_WERROR=ON \
72+
-DRAYX_REQUIRE_CUDA=OFF \
73+
-DRAYX_ENABLE_CUDA=OFF \
74+
-DRAYX_BUILD_RAYX_UI=OFF \
75+
-DRAYX_BUILD_RAYX_CLI=ON \
76+
-DRAYX_BUILD_RAYX_TESTS=ON \
77+
-DCMAKE_C_COMPILER="$CC" \
78+
-DCMAKE_CXX_COMPILER="$CXX" \
79+
-DCMAKE_CXX_FLAGS="-stdlib=libc++ -Xpreprocessor -fopenmp -I/opt/homebrew/opt/libomp/include -I/opt/homebrew/opt/zlib/include" \
80+
-DCMAKE_EXE_LINKER_FLAGS="-L/opt/homebrew/opt/libomp/lib -L/opt/homebrew/opt/zlib/lib -lomp -lz"
81+
82+
- name: Build
83+
run: |
84+
cmake --build build --config ${{env.BUILD_TYPE}}
85+
86+
- name: Run
87+
working-directory: ${{github.workspace}}
88+
run: |
89+
./build/bin/release/rayx -x -c -m 1 -i Intern/rayx-core/tests/input/BoringImagePlane.rml
90+
./build/bin/release/rayx -x -m 1 -i Intern/rayx-core/tests/input/BoringImagePlane.rml
91+
git checkout -- Intern/rayx-core/tests/input/BoringImagePlane.csv
92+
93+
- name: Test
94+
working-directory: ${{github.workspace}}/build/bin/release
95+
run: ./rayx-core-tst -x
96+
97+
- name: Upload artifact
98+
uses: actions/upload-artifact@v4
99+
with:
100+
name: RAYX-macOS-${{env.BUILD_TYPE}}
101+
path: ${{github.workspace}}/build/bin/release

CMakeLists.txt

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
cmake_minimum_required(VERSION 3.15 FATAL_ERROR)
22

3+
if(APPLE)
4+
set(CMAKE_MACOSX_RPATH ON)
5+
if(NOT DEFINED CMAKE_OSX_DEPLOYMENT_TARGET)
6+
set(CMAKE_OSX_DEPLOYMENT_TARGET "13.3")
7+
endif()
8+
endif()
9+
310
# ---- Project ----
411
project(RAYX VERSION 1.1.0)
512
if(MSVC)
@@ -29,6 +36,65 @@ option(RAYX_BUILD_RAYX_TESTS "This option builds the RAYX test suite." ON)
2936
option(RAYX_STATIC_LIB "This option builds 'rayx-core' as a static library." OFF)
3037
# ------------------
3138

39+
# ---- Specific macos compiler options and flags concerning OpenMP ----
40+
if(APPLE)
41+
# Detect installed package manager. MacPorts wins if both are present, since
42+
# its layout (libs directly under /opt/local) does not overlap with Homebrew.
43+
# CMAKE_SYSTEM_PROCESSOR is only populated after project(), so this lives below it.
44+
if(EXISTS "/opt/local/bin/port")
45+
set(MACOS_PKG_PREFIX "/opt/local")
46+
set(MACOS_PKG_KIND "macports")
47+
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "arm64")
48+
set(MACOS_PKG_PREFIX "/opt/homebrew")
49+
set(MACOS_PKG_KIND "homebrew")
50+
else()
51+
set(MACOS_PKG_PREFIX "/usr/local")
52+
set(MACOS_PKG_KIND "homebrew")
53+
endif()
54+
message(STATUS "macOS package manager: ${MACOS_PKG_KIND} at ${MACOS_PKG_PREFIX}")
55+
set(CMAKE_INSTALL_RPATH "@loader_path;@rpath;${MACOS_PKG_PREFIX}/lib")
56+
57+
# OpenMP: MacPorts ships libomp directly under /opt/local; Homebrew uses an
58+
# opt/<formula> subdirectory.
59+
if(MACOS_PKG_KIND STREQUAL "macports")
60+
set(OpenMP_INCLUDE_DIR "${MACOS_PKG_PREFIX}/include/libomp")
61+
set(OpenMP_LIBRARY "${MACOS_PKG_PREFIX}/lib/libomp.dylib")
62+
else()
63+
set(OpenMP_INCLUDE_DIR "${MACOS_PKG_PREFIX}/opt/libomp/include")
64+
set(OpenMP_LIBRARY "${MACOS_PKG_PREFIX}/opt/libomp/lib/libomp.dylib")
65+
endif()
66+
67+
# Common OpenMP settings
68+
set(OpenMP_C_FLAGS "-Xpreprocessor -fopenmp -I${OpenMP_INCLUDE_DIR}")
69+
set(OpenMP_CXX_FLAGS "-Xpreprocessor -fopenmp -I${OpenMP_INCLUDE_DIR}")
70+
set(OpenMP_C_LIB_NAMES "omp")
71+
set(OpenMP_CXX_LIB_NAMES "omp")
72+
set(OpenMP_omp_LIBRARY "${OpenMP_LIBRARY}")
73+
set(OpenMP_omp_INCLUDE_DIRS "${OpenMP_INCLUDE_DIR}")
74+
75+
if(RAYX_ENABLE_OPENMP)
76+
find_package(OpenMP REQUIRED)
77+
if(OpenMP_CXX_FOUND)
78+
message(STATUS "OpenMP found:")
79+
message(STATUS " Include dirs: ${OpenMP_CXX_INCLUDE_DIRS}")
80+
message(STATUS " Libraries: ${OpenMP_CXX_LIBRARIES}")
81+
82+
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
83+
include_directories(${OpenMP_omp_INCLUDE_DIRS})
84+
link_libraries(${OpenMP_omp_LIBRARY})
85+
endif()
86+
endif()
87+
88+
# HDF5: MacPorts installs into /opt/local directly; Homebrew uses opt/hdf5.
89+
if(MACOS_PKG_KIND STREQUAL "macports")
90+
set(HDF5_ROOT "${MACOS_PKG_PREFIX}")
91+
else()
92+
set(HDF5_ROOT "${MACOS_PKG_PREFIX}/opt/hdf5")
93+
endif()
94+
find_package(HDF5 REQUIRED COMPONENTS C HL)
95+
96+
endif()
97+
3298

3399
# ---- Build options ----
34100
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR}/bin/release)

Intern/rayx-core/CMakeLists.txt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
cmake_minimum_required(VERSION 3.15 FATAL_ERROR)
22

3+
# ---- Install directories ----
4+
include(GNUInstallDirs)
5+
set(INSTALL_DATA_DIR ${CMAKE_INSTALL_DATADIR})
6+
37
# ---- for files compiled with cuda compiler, prepend -Xcompiler flags ----
48
function(prepend_xcompiler FLAG_LIST PREPENDED_FLAG_LIST)
59
set(SRC ${${FLAG_LIST}})
@@ -144,7 +148,7 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
144148
set(COMPILE_PLATFORM RAYX_PLATFORM_GCC)
145149
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
146150
set(COMPILE_PLATFORM RAYX_PLATFORM_MSVC)
147-
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
151+
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
148152
set(COMPILE_PLATFORM RAYX_PLATFORM_CLANG)
149153
else()
150154
message(STATUS "Use undefined compiler: ${CMAKE_CXX_COMPILER_ID}")

Intern/rayx-core/src/Debug/Debug.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,8 +193,14 @@ inline std::vector<double> formatAsVec(T) {
193193
}
194194

195195
inline std::vector<double> formatAsVec(int arg) { return {static_cast<double>(arg)}; }
196+
inline std::vector<double> formatAsVec(long arg) { return {static_cast<double>(arg)}; }
196197
inline std::vector<double> formatAsVec(RandCounter arg) { return {static_cast<double>(arg)}; }
197198
inline std::vector<double> formatAsVec(EventType arg) { return {static_cast<double>(arg)}; }
199+
// Catch remaining integral types (e.g. size_t) not already covered above.
200+
// size_t == unsigned long on Linux (same as RandCounter) but differs on macOS arm64.
201+
template <typename T>
202+
requires(std::is_integral_v<T> && !std::is_same_v<T, int> && !std::is_same_v<T, RandCounter>)
203+
inline std::vector<double> formatAsVec(T arg) { return {static_cast<double>(arg)}; }
198204
inline std::vector<double> formatAsVec(double arg) { return {arg}; }
199205
inline std::vector<double> formatAsVec(complex::Complex arg) { return {arg.real(), arg.imag()}; }
200206

Intern/rayx-core/src/Rml/Locate.cpp

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
#if defined(_WIN32)
99
#include <windows.h>
1010
#elif defined(__APPLE__)
11-
#include <cassert>
11+
#include <climits>
12+
#include <mach-o/dyld.h>
1213
#else
1314
#include <limits.h>
1415
#include <unistd.h>
@@ -63,8 +64,13 @@ std::filesystem::path ResourceHandler::getExecutablePath() {
6364
buffer.resize(buffer.size() * 2);
6465
}
6566

66-
#else
67-
static_assert(false, "macOS support is not implemented yet");
67+
#elif defined(__APPLE__)
68+
std::vector<char> buffer(PATH_MAX);
69+
uint32_t size = buffer.size();
70+
if (_NSGetExecutablePath(buffer.data(), &size) != 0) {
71+
buffer.resize(size);
72+
_NSGetExecutablePath(buffer.data(), &size);
73+
}
6874
#endif
6975
return std::filesystem::path(buffer.data());
7076
}
@@ -112,7 +118,11 @@ std::filesystem::path ResourceHandler::getFullPath(const std::filesystem::path&
112118
if (fileExists(path)) return found(path);
113119

114120
#elif defined(__APPLE__)
115-
static_assert(false, "macOS support is not implemented yet");
121+
// Look next to the executable
122+
std::filesystem::path execDir = getExecutablePath().parent_path();
123+
std::filesystem::path path = execDir / relativePath;
124+
RAYX_VERB << "\tlooking at " << path;
125+
if (fileExists(path)) return found(path);
116126

117127
#endif
118128
// Not found -> empty path

0 commit comments

Comments
 (0)