Linker warnings in Mac OS Ventura
PascalLeMerrer opened this issue ยท 24 comments
Bug Report
I installed Crystal on MacOS Ventura, using Homebrew.
It worked, however compiling a simple hello world generates 280 warnings like:
ld: warning: no platform load command found in '/Users/pascal/.cache/crystal/Users-pascal-Documents-tutorials-crystal-hello_world.cr/F-loat32.o', assuming: macOS
ld: warning: no platform load command found in '/Users/pascal/.cache/crystal/Users-pascal-Documents-tutorials-crystal-hello_world.cr/C-rystal.o', assuming: macOS
Crystal version: 1.9.2
OS Version: Ventura, then Sonoma (I upgraded it, but it did not change anything)
Brew doctor does not signal anything wrong.
The steps I followed:
brew update
brew install crystal
echo 'puts "Hello, World!"' > hello.cr
crystal hello.cr
This seems to be related to a "new linker" in Xcode 15, see https://projects.blender.org/blender/blender/pulls/110243 for example. I couldn't reproduce this warning but it looks like you could try passing --link-flags=-Wl,-ld_classic
to use the old linker
crystal hello.cr --link-flags=-Wl,-ld_classic
has no visible effect on this issue
crystal hello.cr --link-flags=-Wl,-ld_classic
has no visible effect on this issue
@PascalLeMerrer in order to pass parameters to the run
command you need to provide explicitly the command:
crystal run --link-flags=-Wl,-ld_classic hello.cr
It works much better indeed! Thanks @beta-ziliani
Just an observation:
crystal eval
has the same issue, and it doesn't take --link-flags
.
export LDFLAGS="-Wl,-ld_classic"
doesn't seem to get picked up.
You should be able to do CRYSTAL_OPTS="--link-flags=-Wl,-ld_classic"
Just to note that macOS Sonoma (14) is also affected (as one might expect) by the same issue, and that setting the --link-flags
as above avoids the warnings.
Out of interest: I happened to notice that binaries created with the "new linker" are about 10% smaller than when using these flags.
Same problem
FYI, I upgraded to Sonoma today and was getting linker warnings like this:
object file (H-ash5858E-ntry40S-tring4432S-tring41.o) was built for newer macOS version (14.0) than being linked (13.3)
There is also an update for xcode-tools that once installed resolved the linker warnings.
@PascalLeMerrer in order to pass parameters to the
run
command you need to provide explicitly the command:crystal run --link-flags=-Wl,-ld_classic hello.cr
This works for me. I'm running macOS Sonoma 14 and XCode 15.0 (15A240d).
CRYSTAL_OPTS="--link-flags=-Wl,-ld_classic" crystal run hello.cr
works for me . I'm on:
macOS 14.0 23A344 x86_64 Sonoma
Yes even better is to just put this export in your bashrc or .zshrc
export CRYSTAL_OPTS="--link-flags=-Wl,-ld_classic"
then crystal build, crystal run etc all work without the ld warnings.
I've been investigating this and it's related to the default target triple produced by Crystal during compilation. It seems like in order to fix a bug back in 2015, we stripped the minimum deployment target from the target triple in this commit. Since then, further work has been put into place to normalize target triples from different architectures.
Lines 91 to 109 in 1675145
With the release of Xcode 15, a new linker was introduced and with it came these warning messages. It appears that the new linker is stricter in which target triples it considers valid. Specifically, it looks like the minimum deployment target is required. E.g., aarch64-apple-darwin23.3.0
is valid, while aarch64-apple-darwin
is not.
Before I go ahead and submit the pull request, I'd love to discuss what the correct path forward is. We could change the behaviour of LLVM#default_target_triple
to only strip the minimum deployment target for macOS versions below a certain threshold or we could drop the stripping behaviour entirely (not sure that's a good idea). An alternative would be to hard-code the minimum deployment target to something like 10.14.6
. Judging by the last two available SDKs that sounds reasonable at first sight.
$ cd /Library/Developer/CommandLineTools/SDKs
$ find . -maxdepth 1 ! -type l ! -path . -exec bash -c 'echo {} && gojq ".SupportedTargets.macosx | { MinimumDeploymentTarget, MaximumDeploymentTarget, RecommendedDeploymentTarget }" {}/SDKSettings.json' \;
./MacOSX13.3.sdk
{
"MaximumDeploymentTarget": "13.3.99",
"MinimumDeploymentTarget": "10.13",
"RecommendedDeploymentTarget": "10.14.6"
}
./MacOSX14.4.sdk
{
"MaximumDeploymentTarget": "14.4.99",
"MinimumDeploymentTarget": "10.13",
"RecommendedDeploymentTarget": "10.14.6"
}
10.14.6
would support versions down to Xcode 10, which was publicly released on September 17, 2018.
Does this also explain why I couldn't reproduce this on my M2 since the normalization fails due to #14052?
It does, yes. I'm seeing the same behaviour on my machine since the default triple returned by LLVM is arm64-apple-darwin23.3.0
and thus it doesn't get normalised by LLVM#default_target_triple
. The architecture still gets normalized by Crystal::Codegen::Target
:
crystal/src/compiler/crystal/codegen/target.cr
Lines 22 to 34 in 1675145
but the new linker seem to accept that anyway.
It turns out we hard-code the target in the distribution-scripts. This is definitely also an issue.
I'm also not entirely sure that comment is correct (at least not any more). Running /usr/bin/clang --print-targets
produces:
Registered Targets:
aarch64 - AArch64 (little endian)
aarch64_32 - AArch64 (little endian ILP32)
aarch64_be - AArch64 (big endian)
arm - ARM
arm64 - ARM64 (little endian)
arm64_32 - ARM64 (little endian ILP32)
armeb - ARM (big endian)
thumb - Thumb
thumbeb - Thumb (big endian)
x86 - 32-bit X86: Pentium-Pro and above
x86-64 - 64-bit X86: EM64T and AMD64
I've also confirmed that the following all compile without any warnings:
$ clang -Xclang '-triple=arm64-apple-macosx14.0.0' hello.c -o hello
$ clang -Xclang '-triple=aarch64-apple-macosx14.0.0' heloc.c -o hello
$ clang -Xclang '-triple=arm64-apple-darwin23.2.0' hello.c -o hello
$ clang -Xclang '-triple=aarch64-apple-darwin23.2.0' hello.c -o hello
while the following does not:
$ clang -Xclang '-triple=arm64-apple-darwin' hello.c -o hello
$ clang -Xclang '-triple=aarch64-apple-darwin' hello.c -o hello
$ clang -Xclang '-triple=arm64-apple-macosx' hello.c -o hello
$ clang -Xclang '-triple=aarch64-apple-macosx' hello.c -o hello
they all produce a warning like the following:
ld: warning: no platform load command found in '/private/var/folders/lp/053qjqyj1cg5gx_23kr9fphc0000gn/T/hello-b3b8c6.o', assuming: macOS
This is great work, thanks Kevin for digging into this ๐
I guess there's a reason why LLVM doesn't normalize target triples. Our normalization is quite significant in some places.
Before we make changes that bring back version numbers, we need to check where these triples are used and whether some use cases may depend on normalized values. We may have to offer both, the full raw triple as well as a normalized version.
I am running into this issue when I use Intel macs on GitHub Actions since this week.
Moreover, presumably due to the same root cause, I am unable to link against any C libraries that I built myself in CI, whereas just a week ago I was able to. This is an error in addition to the warnings that others already reported.
This is probably because GitHub Actions updated their Xcode.
ld: warning: REFERENCED_DYNAMICALLY flag on symbol '_catch_exception_raise' is deprecated
...
ld: warning: no platform load command found in '/Users/runner/.cache/crystal/Users-runner-work-crystal-chipmunk-crystal-chipmunk-spec/T-uple40U-I-nt6441.o0.o', assuming: macOS
dyld[15199]: Symbol not found: _cpArbiterGetContactPointSet
https://github.com/oprypin/crystal-chipmunk/actions/runs/8859208139/job/24329593971
https://github.com/oprypin/crsfml/actions/runs/8859272671/job/24328862277
The warnings are now always reproducible on GitHub Actions with runs-on: macos-13
.
https://github.com/crystal-lang/install-crystal/actions/runs/8859670657/job/24329698775
Back to the C library troubles-
Even if I apply CRYSTAL_OPTS="--link-flags=-Wl,-ld_classic"
I am still building my C libraries with the new linker. (Presumably would need to apply such flags to the step that builds the C library as well).
As such, I get this error instead:
ld: warning: dylib (/usr/local/lib/libchipmunk.dylib) was built for newer macOS version (13.6) than being linked (13.0)
dyld[15192]: Symbol not found: _cpArbiterGetContactPointSet
https://github.com/oprypin/crystal-chipmunk/actions/runs/8859789088/job/24329985809
I met the same warnings on GitHub Actions, with the full warning message here.
https://github.com/yanecc/MockGPT/actions/runs/8913041997/job/24477764716#step:4:24
I am also getting errors in GitHub Actions when using MacOS based runners. Builds on Linux work fine:
[14/13] Codegen (linking)
cc _main.o3.o -o /Users/runner/work/runway/runway/bin/runway -rdynamic -L/Users/runner/work/_temp/crystal-latest-true-undefined/embedded/lib -lssh2 -lxml2 -lz `command -v pkg-config > /dev/null && pkg-config --libs --silence-errors libssl || printf %s '-lssl -lcrypto'` `command -v pkg-config > /dev/null && pkg-config --libs --silence-errors libcrypto || printf %s '-lcrypto'` -L/opt/homebrew/Cellar/libyaml/0.2.5/lib -lyaml -lpcre2-8 -lgc -L/opt/homebrew/Cellar/libevent/2.1.12_1/lib -levent_pthreads -levent -L/opt/homebrew/Cellar/libevent/2.1.12_1/lib -levent -liconv
E: Error target runway failed to compile:
ld: warning: ignoring duplicate libraries: '-levent'
ld: library 'ssh2' not found
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Error: execution of command failed with exit status 1: cc "${@}" -o /Users/runner/work/runway/runway/bin/runway -rdynamic -L/Users/runner/work/_temp/crystal-latest-true-undefined/embedded/lib -lssh2 -lxml2 -lz `command -v pkg-config > /dev/null && pkg-config --libs --silence-errors libssl || printf %s '-lssl -lcrypto'` `command -v pkg-config > /dev/null && pkg-config --libs --silence-errors libcrypto || printf %s '-lcrypto'` -L/opt/homebrew/Cellar/libyaml/0.2.5/lib -lyaml -lpcre2-8 -lgc -L/opt/homebrew/Cellar/libevent/2.1.12_1/lib -levent_pthreads -levent -L/opt/homebrew/Cellar/libevent/2.1.12_1/lib -levent -liconv
Update
I swapped from macos-latest
to macos-13
and now my CI is working. Not ideal, but points to a greater issue in later MacOS versions: