mirror of
https://github.com/harry7557558/spirula-studio.git
synced 2026-10-02 02:44:54 +08:00
macos: link libomp statically so the bundle stays one file (#42)
package_macos.sh rejects a binary that links anything outside /usr/lib and /System/Library, and Homebrew's libomp.dylib is exactly that, so `--target macos_app` failed on any Mac where CMake found OpenMP. ss_mac_prefer_static() (cmake/SsMacBundle.cmake) links the archive beside the dylib instead, the way MoltenVK is already static. libomp is keg-only, so build_develop.bash now passes -DOpenMP_ROOT at the keg: without it CMake finds no OpenMP and meshing, UV unwrap and metrics run serial with nothing said. Configure now reports either way.
This commit is contained in:
@@ -40,6 +40,25 @@ if command -v python3 >/dev/null 2>&1; then
|
||||
python3 tools/check_comment_length.py || exit 1
|
||||
fi
|
||||
|
||||
# Homebrew's libomp is keg-only: nothing points at it, so CMake finds no
|
||||
# OpenMP and meshing, UV unwrap and metrics run serial (cmake/SsMacBundle.cmake
|
||||
# then has no dylib to make static either).
|
||||
if [ "$(uname)" = "Darwin" ]; then
|
||||
case " $* " in
|
||||
*" -DOpenMP_ROOT="*) ;;
|
||||
*)
|
||||
for omp_root in "$(brew --prefix libomp 2>/dev/null)" \
|
||||
/opt/homebrew/opt/libomp /usr/local/opt/libomp; do
|
||||
[ -n "$omp_root" ] || continue
|
||||
[ -f "$omp_root/lib/libomp.a" ] ||
|
||||
[ -f "$omp_root/lib/libomp.dylib" ] || continue
|
||||
set -- "$@" "-DOpenMP_ROOT=$omp_root"
|
||||
echo "OpenMP: passing -DOpenMP_ROOT=$omp_root (keg-only formula)"
|
||||
break
|
||||
done ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
cmake -G Ninja -B build "$@" || exit $?
|
||||
|
||||
# Repair the ninja dependency log.
|
||||
|
||||
@@ -13,6 +13,7 @@ message(STATUS "SS_BACKEND=vulkan: portable engine layer + "
|
||||
set(SS_BUILD_CLI ON)
|
||||
|
||||
include(SsVulkan)
|
||||
include(SsMacBundle)
|
||||
ss_vulkan_lib()
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
@@ -35,7 +36,12 @@ target_link_libraries(csrc_portable PUBLIC ss_i18n)
|
||||
|
||||
find_package(OpenMP)
|
||||
if(OpenMP_CXX_FOUND)
|
||||
ss_mac_prefer_static(OpenMP::OpenMP_CXX
|
||||
"`brew install libomp` ships the archive; \
|
||||
-DCMAKE_DISABLE_FIND_PACKAGE_OpenMP=ON drops OpenMP instead.")
|
||||
target_link_libraries(csrc_portable PUBLIC OpenMP::OpenMP_CXX)
|
||||
else()
|
||||
message(STATUS "No OpenMP: meshing, UV unwrap and metrics run serial")
|
||||
endif()
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
# The macOS bundle carries one binary (docs/build.md#packaging), so nothing it
|
||||
# links may sit outside /usr/lib and /System/Library: a recorded /opt/homebrew
|
||||
# path runs only on the machine that built it. MoltenVK is static for that
|
||||
# reason (cmake/SsVulkan.cmake), tools/package_macos.sh rejects a bundle that
|
||||
# breaks the rule, and a dependency found as a dylib goes through here.
|
||||
|
||||
# ss_mac_prefer_static(<imported target> [<hint>]) -- links the .a beside each
|
||||
# dylib in the target's link interface. Warns with <hint> and leaves the target
|
||||
# alone when an archive is missing; a no-op off macOS.
|
||||
function(ss_mac_prefer_static target)
|
||||
if(NOT APPLE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
get_target_property(_libs ${target} INTERFACE_LINK_LIBRARIES)
|
||||
if(NOT _libs)
|
||||
return()
|
||||
endif()
|
||||
|
||||
set(_static "")
|
||||
foreach(_lib IN LISTS _libs)
|
||||
# Anything that is not an absolute dylib path -- a genex, a link flag,
|
||||
# another target -- is not ours to rewrite.
|
||||
if(NOT _lib MATCHES "\\.dylib$")
|
||||
list(APPEND _static "${_lib}")
|
||||
continue()
|
||||
endif()
|
||||
string(REGEX REPLACE "\\.dylib$" ".a" _archive "${_lib}")
|
||||
if(NOT EXISTS "${_archive}")
|
||||
message(WARNING "No ${_archive}, so ${target} keeps ${_lib}, which "
|
||||
"packaging rejects (tools/package_macos.sh). ${ARGV1}")
|
||||
return()
|
||||
endif()
|
||||
list(APPEND _static "${_archive}")
|
||||
endforeach()
|
||||
|
||||
set_property(TARGET ${target} PROPERTY INTERFACE_LINK_LIBRARIES "${_static}")
|
||||
list(JOIN _static " " _joined)
|
||||
message(STATUS "${target}: ${_joined} linked statically")
|
||||
endfunction()
|
||||
+21
-12
@@ -30,6 +30,7 @@ Always build through the dev scripts.
|
||||
| `SsEmbed.cmake` | `ss_embed_file()` — bake a file into a byte-array header |
|
||||
| `SsApps.cmake` | the `spirula` executable — every tool the build has, in one binary (backend-agnostic) |
|
||||
| `SsPackage.cmake` | the `macos_app` / `macos_dmg` targets ([Packaging](#packaging)) |
|
||||
| `SsMacBundle.cmake` | `ss_mac_prefer_static()` — the static linking a one-file bundle depends on ([Packaging](#packaging)) |
|
||||
| `SsChecks.cmake` | the source lints ([Lints](#lints)) — included last, so every target above depends on them |
|
||||
|
||||
Exactly one backend module runs. It leaves behind `SS_WITH_TORCH` and
|
||||
@@ -204,15 +205,19 @@ embedded into the binary. On an offline machine, transfer a matching `slangc`
|
||||
and point `-DSS_SLANGC=` at it.
|
||||
|
||||
**macOS.** Vulkan backend only, through MoltenVK; `build_develop.bash` works
|
||||
as on Linux. Dependencies: `brew install cmake ninja`. Four things are
|
||||
macOS-only in the build: `cmake/SsVulkan.cmake` fetches a pinned universal
|
||||
MoltenVK and links it *statically* (`SS_MACOS_VULKAN=static`, the default) so
|
||||
the binary carries its own driver and copies to any Mac — the release tarball
|
||||
supplies the Vulkan headers too, so nothing comes from Homebrew;
|
||||
`cmake/SsSlang.cmake` pins a different Slang release (the one this project
|
||||
pins publishes no macOS assets); `build_develop.bash` reads free memory from
|
||||
`vm_stat` rather than `/proc`; and `ss_i18n` links CoreFoundation, which
|
||||
`i18n/Locale.cpp` asks for the user's locale.
|
||||
as on Linux. Dependencies: `brew install cmake ninja libomp`. The last is
|
||||
keg-only, so nothing finds it on its own — `build_develop.bash` passes
|
||||
`-DOpenMP_ROOT` at the keg, and a build without OpenMP runs meshing, UV unwrap
|
||||
and metrics serial. Five things are macOS-only in the build:
|
||||
`cmake/SsVulkan.cmake` fetches a pinned universal MoltenVK and links it
|
||||
*statically* (`SS_MACOS_VULKAN=static`, the default) so the binary carries its
|
||||
own driver and copies to any Mac — the release tarball supplies the Vulkan
|
||||
headers too, so nothing comes from Homebrew; `cmake/SsSlang.cmake` pins a
|
||||
different Slang release (the one this project pins publishes no macOS assets);
|
||||
`build_develop.bash` reads free memory from `vm_stat` rather than `/proc`;
|
||||
`ss_i18n` links CoreFoundation, which `i18n/Locale.cpp` asks for the user's
|
||||
locale; and `cmake/SsMacBundle.cmake` links the archive beside a dependency's
|
||||
dylib, which is what keeps the bundle one file ([Packaging](#packaging)).
|
||||
|
||||
A static build has no loader, so it cannot load validation layers.
|
||||
`-DSS_MACOS_VULKAN=loader` links the installed loader instead (needs
|
||||
@@ -297,10 +302,14 @@ taskbar. The banner carries no text — the product name and tagline are drawn
|
||||
over it by ImGui, so they stay translatable.
|
||||
|
||||
The bundle carries **one binary**. That is only honest because a default
|
||||
macOS build links MoltenVK statically (`cmake/SsVulkan.cmake`), and the script
|
||||
checks rather than trusts it: `otool -L` output naming anything outside
|
||||
macOS build links MoltenVK statically (`cmake/SsVulkan.cmake`) and swaps every
|
||||
other dependency found as a dylib for the archive beside it
|
||||
(`ss_mac_prefer_static()` in `cmake/SsMacBundle.cmake` — libomp today), and the
|
||||
script checks rather than trusts it: `otool -L` output naming anything outside
|
||||
`/usr/lib` or `/System/Library` fails the packaging, since a bundle missing a
|
||||
dylib works on the build machine and nowhere else.
|
||||
dylib works on the build machine and nowhere else. Homebrew builds its archives
|
||||
for the host alone, so a bundle linking one is arm64-only and inherits that
|
||||
keg's minimum macOS version.
|
||||
|
||||
Signing is ad-hoc (`--sign -`) by default. That is not optional decoration:
|
||||
Apple silicon kills an unsigned arm64 binary on exec, and copying the
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
# bash tools/package_macos.sh [--build-dir DIR] [--out DIR]
|
||||
# [--sign IDENTITY] [--dmg]
|
||||
#
|
||||
# The bundle carries one binary and its icon, which only works because a static
|
||||
# MoltenVK build links nothing outside the system frameworks
|
||||
# (cmake/SsVulkan.cmake) -- verified below, not assumed.
|
||||
# The bundle carries one binary and its icon, which only works because MoltenVK
|
||||
# and libomp are linked statically (cmake/SsVulkan.cmake,
|
||||
# cmake/SsMacBundle.cmake) -- verified below, not assumed.
|
||||
#
|
||||
# --sign defaults to ad-hoc ("-"): enough for a Mac the app is copied to
|
||||
# directly, not enough to survive the quarantine flag a download attaches.
|
||||
@@ -121,7 +121,9 @@ STRAY=$(otool -L "$APP/Contents/MacOS/spirula" | tail -n +2 | awk '{print $1}' \
|
||||
if [ -n "$STRAY" ]; then
|
||||
echo "package_macos.sh: the binary links libraries this bundle does not carry:" >&2
|
||||
echo "$STRAY" | sed 's/^/ /' >&2
|
||||
echo " build with -DSS_MACOS_VULKAN=static (the default) to avoid it" >&2
|
||||
echo " such a bundle runs only on this machine. libvulkan: rebuild with" >&2
|
||||
echo " -DSS_MACOS_VULKAN=static (the default). Anything else: install its" >&2
|
||||
echo " .a so cmake/SsMacBundle.cmake links that (brew install libomp)." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
Reference in New Issue
Block a user