[macos] SDL3.xcframework installed in /Library/Frameworks, clang not finding framework
On macOS Monterey, 12.7.4 - have both SDL2 and SDL3 installed in /Library/Frameworks:
% ls /Library/Frameworks | grep SDL
SDL2-2.28.framework
SDL2-2.30.0.framework
SDL2-2.30.1.framework
SDL2.framework
SDL3.xcframework
and while compiling with -framework SDL2 works, compiling with -framework SDL3 does not, and produces the error
clang -m64 -target x86_64-apple-darwin -std=gnu99 [...] -F /Library/Frameworks -framework SDL3 -o ../darwin.x86_64/ldesdl
ld: framework not found SDL3
clang: error: linker command failed with exit code 1 (use -v to see invocation)
It looks as though clang
% clang --version
Apple clang version 13.0.0 (clang-1300.0.29.30)
Target: x86_64-apple-darwin21.6.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
isn't prepared to deal with the .xcframework properly?
An .xcframework isn't the same as a .framework
Does it work if you put SDL3.framework in /Library/Frameworks?
I've recently upgraded the build system to run macOS Ventura.
@sridenour I tried symlinking /Library/Frameworks/SDL3.framework to the corresponding directory (for macOS) in SDL3.xcframework -- didn't work, but it did expose this warning:
CMake Warning (dev) at /Library/Frameworks/SDL3.framework/Resources/CMake/sdl3-config-version.cmake:14 (message):
Cannot not find SDL_version.h. This script is meant to be placed in
share/cmake/SDL3, next to SDL3.xcframework
Call Stack (most recent call first):
CMakeLists.txt:99 (FIND_PACKAGE)
This warning is for project developers. Use -Wno-dev to suppress it.
CMake Error at /Library/Frameworks/SDL3.framework/Resources/CMake/sdl3-config.cmake:17 (message):
File or directory
/Library/Frameworks/SDL3.xcframework/macos-arm64_x86_64/SDL3.framework/Versions/SDL3.xcframework
referenced by variable _sdl3_xcframework_path does not exist !
Call Stack (most recent call first):
/Library/Frameworks/SDL3.framework/Resources/CMake/sdl3-config.cmake:73 (set_and_check)
CMakeLists.txt:99 (FIND_PACKAGE)
and if you put a copy of .../SDL3.framework/Resources/CMake/sdl3-config-version.cmake in /Library/Frameworks/share/cmake/SDL3/, and get rid of the symlink so it's just /Library/Frameworks/SDL3.xcframework/... then it almost works. Configuration using find_package(SDL3 REQUIRED) is OK, compilation is OK, but the resulting executable (on macOS Ventura 13.6.7) fails because it depends on:
@rpath/SDL3.framework/Versions/A/SDL3 (compatibility version 101.0.0, current version 101.0.0)
and @rpath is not set (there's neither a system default that would point to the SDL3.framework under the SDL3.xcframework; nor is there an LC_RPATH in the executable). With SDL2 builds on Ventura I had to add a "-rpath /Library/Frameworks" to handle the dependency on @rpath/SDL2.framework/... - I suppose for SDL3 builds I could add -rpath /Library/Frameworks/SDL3.xcframework/macos-arm64_x86_64/ -- but this amount of tweaking is getting ridiculous.
A couple things:
-
Why are you using
SDL3.xcframework? I built and useSDL3.frameworkand it works just fine. -
Speaking of using a
.frameworkinstead of an.xcframework, it's better to embed SDL3 in your app bundle rather than require users to install it to a system location and have to deal with version conflicts, requiring extra steps to install, etc -
I don't know very much about CMake. For macOS, I use Xcode, which makes it so much easier to deal with stuff like building correct app bundles, embedding any
.frameworks and other resources in the bundle, code signing, etc. That said, it looks like trying to symlink into the.xcframeworkis part of the problem.
Are you using CMake 3.28+? That version introduced support for xcframeworks, which the xcframework cmake config file uses. https://github.com/libsdl-org/SDL/blob/4d32f66fe7a1946384b062cea87f520b75139536/Xcode/SDL/pkg-support/resources/CMake/sdl3-config.cmake#L93-L100
@sridenour -
- Because SDL3 is being released as SDL3.xcframework (in a .dmg) - and I'd rather install it rather than building it
- We're not delivering as a app bundle, and it's not been a problem for anyone that uses the executable to install the framework (SDL2 up to this point) from the released .dmg
- If we were only building for macOS then I might use only XCode, but we are building for various Linux flavors, FreeBSD, Solaris 10 and 11, other *BSDs, macOS, etc. In the past we released simple Makefiles, but now people want to build on odd systems and don't seem to be comfortable with fixing Makefiles (and the autoconf etc. have got completely out of control) so someone made the choice to use CMake as an alternative (we still release the hand crafted Makefiles too).
@madebr
% cmake --version
cmake version 3.29.2
@madebr - BTW, it's annoying that from the SDL3 dmg one can't just drop the SDL3.xcframework into /Library/Frameworks -- one has to then go and install /Library/Frameworks/share/cmake/SDL3/sdl3-config.cmake by hand. I think it's a CMake bug that they don't automatically look in the right places in the .xcframework -- there's a feature request in with Kitware to fix that, but no idea if/when they'll do it.
Let's verify things first, are you extracing the 2 complete directories from the dmg into /Library/Frameworks? SDL3.xcframework and share?
The share folder situation is annoying indeed. I created that issue upstream, but I don't know what priority they assigned it.
During generation of the release binaries, a small test project is built, that generates this output. Perhaps you can experiment a bit with your CMake arguments?
Also, I assume your project is not fiddling with *_RPATH cmake properties?
Looking at the actions output, it seems like we don't test running macos executables so the problem might appear there as well.
Does doing set_property(TARGET yourgame APPEND PROPERTY BUILD_RPATH "/Library/Frameworks/SDL3.xcframework/macos-arm64_x86_64") fix anything?
You might need to play a bit with the path: I can't test due to no access to an Apple.
edit: my initial message had a wrong cmake command. Please try the final iteration :)
I didn't initially copy over the share directory (it was hidden in/behind the SDL logo as Finder displayed the contents to me), but I did install the required file by hand. Thanks for putting in the CMake issue (I think that's where I commented on having the same problem)
Yeah, everything links OK, it just doesn't run - it would be good to test that in the verification ;-)
I haven't tried your set_property... hack yet - I was just seeing if I could get the target_link_options(...) to let me just add -rpath ...
BTW - the ReadMe.txt in the prerelease SDL3.dmg only talks about it as SDL3.framework, not SDL3.xcframework, and it doesn't mention the need to copy over the share directory.
I didn't initially copy over the
sharedirectory (it was hidden in/behind the SDL logo as Finder displayed the contents to me), but I did install the required file by hand. Thanks for putting in the CMake issue (I think that's where I commented on having the same problem)
Indeed, you were the only non-kitware person to comment on that issue. Before creating that issue, I asked on the #cmake channel at cpplang.slack.com, where the response was lukewarm. So I don't expect a fix anytime soon.
I haven't tried your
set_property...hack yet - I was just seeing if I could get thetarget_link_options(...)to let me just add-rpath ...
It would be nice if you can get it to work with set_property(...), and create a CMake issue with a minimum project (I'll help you trimming it down).
When using defaults, the binaries inside the build directory should "just work". (Installed binaries is another matter)
BTW - the ReadMe.txt in the prerelease SDL3.dmg only talks about it as SDL3.framework, not SDL3.xcframework, and it doesn't mention the need to copy over the share directory.
Thanks, I'll make sure to add a few lines to the readme.
Re: "I had to add a -rpath /Library/Frameworks for Ventura" -- that was in my alternative Makefile builds, not CMake. CMake for SDL2 appears to add an LC_RPATH command to the executable. It doesn't do that automatically for SDL3. Not sure if that's a difference between the sdl2-config.cmake and sdl3-config.cmake, or CMake itself doing something differently for .framework vs .xcframework, or...
I think it has everything to do with CMake's support for xcframworks not being complete.
The project below should reproduce your issue, with these commands to reproduce:
cmake -S /path/to/cmake/script -B /tmp/sdl3-minimum-example --fresh
cmake --build /tmp/sdl3-minimum-example
ctest --test-dir /tmp/sdl3-minimum-example
cmake_minimum_required(VERSION 3.29)
project(use_sdl3_xcframework LANGUAGES C)
set(SDL3_XCFRAMEWORK "/Library/Frameworks for Ventura/SDL3.xcframework")
# Create imported shared library for the SDL3 xcframework
add_library(SDL3::SDL3-shared SHARED IMPORTED)
set_property(SDL3::SDL3-shared PROPERTY IMPORTED_LOCATION "${SDL3_XCFRAMEWORK}")
# Source for minimal SDL3 executable
file(WRITE main.c [==[
#include <SDL3/SDL.h>
int main(int argc, char *argv[]) {
(void)argc; (void)argv;
SDL_Init(SDL_INIT_EVENTS);
SDL_Quit();
return 0;
}
]==])
enable_testing()
# Create executable, not setting rpath
add_executable(mygame_without_rpath main.c)
target_link_libraries(mygame_without_rpath PRIVATE SDL3::SDL3-shared)
add_test(NAME mygame_without_rpath COMMAND mygame_without_rpath)
# Create executable, setting rpath
add_executable(mygame_with_rpath main.c)
target_link_libraries(mygame_with_rpath PRIVATE SDL3::SDL3-shared)
set_property(TARGET mygame_with_rpath APPEND PROPERTY BUILD_RPATH "${SDL3_XCFRAMEWORK}")
add_test(NAME mygame_with_rpath COMMAND mygame_with_rpath)
I did not test this, so please correct my errors.
@madebr - cool, thanks -- I'll check that out. I had just made my program runnable by adding
SET_PROPERTY(TARGET ldesdl APPEND PROPERTY BUILD_RPATH "/Library/Frameworks/SDL3.xcframework/macos-arm64_x86_64/")
``
-- i'll swap over to using `"${SDL3_XCFRAMEWORK}"` instead of the raw path, and then run your example.
It would be nice if you could make my minimum project above working, and create a cmake issue for this. As I said before, the executable should work without setting rpath properties.
OK -- with your example, need this change:
diff CMakeLists.txt~ CMakeLists.txt
8c8
< set_property(SDL3::SDL3-shared PROPERTY IMPORTED_LOCATION "${SDL3_XCFRAMEWORK}")
---
> set_property(TARGET SDL3::SDL3-shared PROPERTY IMPORTED_LOCATION "${SDL3_XCFRAMEWORK}")
There are questions about what the value of SDL3_XCFRAMEWORK should be:
set(SDL3_XCFRAMEWORK "/Library/Frameworks/SDL3.xcframework/macos-arm64_x86_64/SDL3.framework")
compiles OK, but results in
% ./mygame_with_rpath
dyld[32771]: Library not loaded: @rpath/SDL3.framework/Versions/A/SDL3
Referenced from: <6A9B892D-AC32-3278-AD53-CD930FCA4A85> /private/tmp/sdl3-minimum-example/mygame_with_rpath
Reason: tried: '/Library/Frameworks/SDL3.xcframework/macos-arm64_x86_64/SDL3.framework/SDL3.framework/Versions/A/SDL3' (no such file), '/System/Volumes/Preboot/Cryptexes/OS/Library/Frameworks/SDL3.xcframework/macos-arm64_x86_64/SDL3.framework/SDL3.framework/Versions/A/SDL3' (no such file), '/Library/Frameworks/SDL3.xcframework/macos-arm64_x86_64/SDL3.framework/SDL3.framework/Versions/A/SDL3' (no such file), '/System/Volumes/Preboot/Cryptexes/OS/Library/Frameworks/SDL3.xcframework/macos-arm64_x86_64/SDL3.framework/SDL3.framework/Versions/A/SDL3' (no such file)
while
set(SDL3_XCFRAMEWORK "/Library/Frameworks/SDL3.xcframework/macos-arm64_x86_64")
results in the compile failing with
[ 25%] Building C object CMakeFiles/mygame_without_rpath.dir/main.c.o
/Users/briggs/Projects/sdl3link/main.c:1:10: fatal error: 'SDL3/SDL.h' file not found
#include <SDL3/SDL.h>
^~~~~~~~~~~~
1 error generated.
and
set(SDL3_XCFRAMEWORK "/Library/Frameworks/SDL3.xcframework")
compiles OK but fails with
% /tmp/sdl3-minimum-example/mygame_with_rpath
dyld[32956]: Library not loaded: @rpath/SDL3.framework/Versions/A/SDL3
Referenced from: <4D619860-ABA6-34EC-B463-DB565C4104DA> /private/tmp/sdl3-minimum-example/mygame_with_rpath
Reason: tried: '/Library/Frameworks/SDL3.xcframework/SDL3.framework/Versions/A/SDL3' (no such file), '/System/Volumes/Preboot/Cryptexes/OS/Library/Frameworks/SDL3.xcframework/SDL3.framework/Versions/A/SDL3' (no such file), '/Library/Frameworks/SDL3.xcframework/SDL3.framework/Versions/A/SDL3' (no such file), '/System/Volumes/Preboot/Cryptexes/OS/Library/Frameworks/SDL3.xcframework/SDL3.framework/Versions/A/SDL3' (no such file)
So there isn't a combination that seems to work for both compilation and running. I'm looking at what might need to be added to get things working.
We're trying to use the xcframework here, so it should be set(SDL3_XCFRAMEWORK "/Library/Frameworks/SDL3.xcframework").
Try doing set_property(TARGET mygame_with_rpath APPEND PROPERTY BUILD_RPATH "${SDL3_XCFRAMEWORK}/macos-arm64_x86_64").
Yes -- that's the answer. So, with CMakeLists.txt:
cmake_minimum_required(VERSION 3.29)
project(use_sdl3_xcframework LANGUAGES C)
set(SDL3_XCFRAMEWORK "/Library/Frameworks/SDL3.xcframework")
# Create imported shared library for the SDL3 xcframework
add_library(SDL3::SDL3-shared SHARED IMPORTED)
set_property(TARGET SDL3::SDL3-shared PROPERTY IMPORTED_LOCATION "${SDL3_XCFRAMEWORK}")
# Source for minimal SDL3 executable
file(WRITE main.c [==[
#include <SDL3/SDL.h>
int main(int argc, char *argv[]) {
(void)argc; (void)argv;
SDL_Init(SDL_INIT_EVENTS);
SDL_Quit();
return 0;
}
]==])
enable_testing()
# Create executable, not setting rpath
add_executable(mygame_without_rpath main.c)
target_link_libraries(mygame_without_rpath PRIVATE SDL3::SDL3-shared)
add_test(NAME mygame_without_rpath COMMAND mygame_without_rpath)
# Create executable, setting rpath
add_executable(mygame_with_rpath main.c)
target_link_libraries(mygame_with_rpath PRIVATE SDL3::SDL3-shared)
set_property(TARGET mygame_with_rpath APPEND PROPERTY BUILD_RPATH "${SDL3_XCFRAMEWORK}/macos-arm64_x86_64")
add_test(NAME mygame_with_rpath COMMAND mygame_with_rpath)
doing
cmake -S . -B /tmp/sdl3-minimum-example --fresh # from the directory with CMakeLists.txt
cmake --build /tmp/sdl3-minimum-example
ctest --test-dir /tmp/sdl3-minimum-example
produces, for the ctest output:
% ctest --test-dir /tmp/sdl3-minimum-example
Internal ctest changing into directory: /tmp/sdl3-minimum-example
Test project /tmp/sdl3-minimum-example
Start 1: mygame_without_rpath
1/2 Test #1: mygame_without_rpath .............Subprocess aborted***Exception: 0.00 sec
Start 2: mygame_with_rpath
2/2 Test #2: mygame_with_rpath ................ Passed 0.05 sec
50% tests passed, 1 tests failed out of 2
Total Test time (real) = 0.05 sec
The following tests FAILED:
1 - mygame_without_rpath (Subprocess aborted)
Errors while running CTest
Output from these tests are in: /tmp/sdl3-minimum-example/Testing/Temporary/LastTest.log
Use "--rerun-failed --output-on-failure" to re-run the failed cases verbosely.
That's a good reproducer, I'd say. Thanks for investing time into this!
No worries - it's a small amount of my time invested that (a) lets me fix my builds, and (b) may help others avoid the same issue. Thank you for sharing your knowledge of CMake to get to a workaround. I'll file an issue over on CMake's gitlab.
@madebr - would you like credit for working out the details over in CMake issue 25998 ?
There's no need for that.
I'm honestly not sure what's the appropriate solution for this.
The xcframework can theoretically have a macos-arm64 and a macos-x86_64 subdirectory (instead of macos-arm64_x86_64 ).
Then, a fat binary would need to add 2 paths to the runpath.
From a developer standpoint, being a consumer of the tools and libraries/frameworks, something that "just works" on all the different systems that CMake and SDLx are available on, without my having to special-case for macOS, would be a good choice. If I were creating frameworks, I think i'd prefer it to be a fix in CMake, so everybody doesn't have to fuss around in their cmake config. As it stands now, I have an if(APPLE)...fix the rpath... clause in the SDL3 part of my CMakeLists.txt, which will suffice until things get sorted, I guess.
Regarding the .xcframework subdirectories -- is that true? Would xcodebuild -create-xcframework [-framework path]+ not combine all the macOS architectures into a single universal blob? (as you can tell, I've never had to build a framework).
@nbriggs
Can you try the SDL3-3.1.2.dmg asset from the recent 3.1.2 release?
I think we might need to use the frameworks inside the xcframework, and unconditionally disable this if.
I have the same problem with the framework from the SDL 3.1.3 preview release. I copied both SDL3.xcframework and share to /Library/Frameworks
If I link to the SDL3.framework inside the xcframework, it links, but then it fails to link at runtime with
dyld[85945]: Library not loaded: @rpath/SDL3.framework/Versions/A/SDL3
Referenced from: <08A14158-99A6-3A5D-90BA-573BA6D06C04> /private/tmp/test
Reason: no LC_RPATH's found
zsh: abort ./test
This happens both with clang and with rust
Clang command that fails to find SDL:
clang -framework SDL3 test.c -o test
Clang command that links but fails to run with rpath error:
clang -F/Library/Frameworks/SDL3.xcframework/macos-arm64_x86_64 -framework SDL3 test.c -o test
When building on the command line, you always need to add the runpath yourself. This is also required on Linux, and other unixes.
The issue with CMake is that it should set the runpath automatically, but it doesn't.
On Linux the command is -Wl,-rpath,/path/to/directory/containing/library.
Try adding -Wl,-rpath,/Library/Frameworks/SDL3.xcframework/macos-arm64_x86_64
I'm new to building on mac, but on Linux the rpath is inherited from the library. From searching it seems this should happen on mac as well, but it doesn't here?
Anyway, adding the rpath makes it go a step further, but now it fails to verify the framework and wants to move it to the trash. Isn't the preview signed?
I'm new to building on mac, but on Linux the rpath is inherited from the library. From searching it seems this should happen on mac as well, but it doesn't here?
On Linux, when an executable does not have an rpath, then the loader looks in standard paths (amonst many LD_LIBRARY_PATH). When rpath is set, it first looks in those.
Anyway, adding the rpath makes it go a step further, but now it fails to verify the framework and wants to move it to the trash. Isn't the preview signed?
The assets were built on Github Actions, and supposedly signed by slouken.
About the warning, I've been told the following:
I've always had the warnings for SDL prebuilt frameworks, you have to go to the systems "Privacy & Security" settings to clear it the first time
GitHub actions don't sign the frameworks. Typical workflow is that Xcode will automatically sign and embed frameworks when assembling your app.