Meson 151 breaks some Apple compilers from missing LC_RPATH
Describe the bug Some built-in Apple Clang compilers don't pass the sanitycheck. Whatever Github's Apple runners are working with are ok. Locally, my built-in Apple clangs don't work. Same macOS major version, 14, on the Github runner as I have locally.
The sanitycheck was passing just a couple months ago. I don't know what specific version, but it was relatively recent.
To Reproduce I've created a repo here: https://github.com/e-dant/meson-151-breaks-on-apple
It's a tiny meson build around the sanitycheckcpp target.
project(
'meson-151-breaks-on-apple',
['cpp', 'c'],
version : '0.0.0',
default_options : ['c_std=c99', 'cpp_std=c++20'],
)
executable('sanitycheckcpp', 'sanitycheckcpp.cc')
class breakCCompiler;int main(void) { return 0; }
The GitHub Actions show them compiling successfully. I expect mixed results in other environments. My machines don't pass.
Abbreviated error logs from meson-log.txt
...
-----
Sanity check compile stderr:
-----
Running test binary command: /.../out/host/meson-private/sanitycheckcpp.exe
../meson.build:1:0: ERROR: Executables created by cpp compiler c++ are not runnable.
What I see running is manually:
.../out/host/meson-private/sanitycheckcpp.exe
dyld[86071]: Library not loaded: @rpath/libc++.1.dylib
Referenced from: <4123351D-CCA6-3D20-AE0E-E72FF485CE1E> .../out/host/meson-private/sanitycheckcpp.exe
Reason: no LC_RPATH's found
[1] 86071 abort
Expected behavior Either some notion of what to configure to get this passing (What does Github do?) or manually installed rpaths (does Apple want them?)
system parameters
- Is this a cross build or just a plain native build (for the same computer)? Native build
- what operating system (e.g. MacOS Catalina, Windows 10, CentOS 8.0, Ubuntu 18.04, etc.)
Darwin macosbuilder.local 23.4.0 Darwin Kernel Version 23.4.0: Fri Mar 15 00:12:41 PDT 2024; root:xnu-10063.101.17~1/RELEASE_ARM64_T8103 arm64macOS Sonoma 14 - what Python version are you using e.g. 3.8.0
python3 --version
Python 3.12.4
- what
meson --version
meson --version
1.5.1
- what
ninja --versionif it's a Ninja build
ninja --version
1.12.1
Each of the above are from my local system. Below is what Github is running:
ninja -> 1.12.1
meson -> 1.5.1
python -> Python 3.12.5
uname -a -> Darwin Mac-1725824516951.local 23.6.0 Darwin Kernel Version 23.6.0: Mon Jul 29 21:13:03 PDT 2024; root:xnu-10063.141.2~1/RELEASE_ARM64_VMAPPLE arm64
I think this is related to #13534
Abbreviated error logs from meson-log.txt
The full error logs as an attachment would be elucidative here, I think. It would include the exact compiler command line used to create the test executable.
Abbreviated error logs from meson-log.txt
The full error logs as an attachment would be elucidative here, I think. It would include the exact compiler command line used to create the test executable.
c++ sanitycheckcpp.cc -o sanitycheckcpp.exe
If you run this, is the resulting executable supposed to be functional?
c++ sanitycheckcpp.cc -o sanitycheckcpp.exeIf you run this, is the resulting executable supposed to be functional?
The above command does not produce runnable executables on this macos builder when run straight on the command line. I assume it probably should, right? But I've completely given up trying to guess what Apple thinks is right; The whole landscape seems arbitrary.
Maybe Apple wants rpaths, maybe they don't; Maybe my built-in Apple compiler is completely nonfunctional because it expects install_name_tool or something to come along after it -- But if it's broken in that way, chances are there are many other computers and build bots out there with the same broken built-in compiler.
Sure, and I'm just trying to reduce the problem in order to better understand what the the scenario is.
I don't think this particular part of the code has changed in 1.5.1 though.
The sanitycheck was passing just a couple months ago. I don't know what specific version, but it was relatively recent.
Have you tested with meson 1.4.0? Because as far as I can tell it should fail with that version as well.
Sure, and I'm just trying to reduce the problem in order to better understand what the the scenario is.
TYVM and apologies if I came off as hostile -- My frustrations are entirely with Apple
Have you tested with meson 1.4.0? Because as far as I can tell it should fail with that version as well.
It does not pass with 1.4.0, huh...?
meson setup out/host . --reconfigure && meson compile -C out/host
The Meson build system
Version: 1.4.0
Source dir: /Users/macosbuilder/dev/meson-151-breaks-on-apple
Build dir: /Users/macosbuilder/dev/meson-151-breaks-on-apple/out/host
Build type: native build
Project name: meson-151-breaks-on-apple
Project version: 0.0.0
C compiler for the host machine: cc (clang 15.0.0 "Apple clang version 15.0.0 (clang-1500.3.9.4)")
C linker for the host machine: cc ld64 1053.12
meson.build:1:0: ERROR: Executables created by cpp compiler c++ are not runnable.
A full log can be found at /Users/macosbuilder/dev/meson-151-breaks-on-apple/out/host/meson-logs/meson-log.txt
with 1.4.0
(Via a virtualenv + pip install of meson 1.4.0)
The sanitycheck was passing just a couple months ago
By "a couple months ago" I mean that it was passing while I was developing this project for a python+c+cpp wheel.
I did lots of the initial development and testing on this machine with whatever the latest version of meson/ninja/etc were in brew two months ago.
Thanks for clarifying, and no problem! :)
There are some people here who use macOS but I am not one of them -- I hope they will be able to help you, though.
I've removed the regression label so that no one will lose time trying to diff the changes between 1.4.0 and 1.5.1 to see if one of them is to blame.
I'm getting this issue as well. Seems like meson shouldn't be trying to compile and generate an .exe since I'm using a Mac. Also worth noting that I'm using the meson-python package. meson-python - v0.18.0
Device Info:
Macbook Pro Apple M3 Pro MacOS Sonoma Version 14.7.6 36 GB Memory
invocation
subprocess.run(
[
"uv",
"pip",
"install",
"--no-index",
"--no-build-isolation",
"--offline",
".",
"-Cbuild-dir=../.nanobind",
f'--config-settings=setup-args=-Dlibdir="{lib_path}"',
]
meson.build
project(
**,
'cpp',
meson_version: '>=1.3.0',
default_options: ['cpp_std=c++20', 'b_ndebug=if-release'],
)
py = import('python').find_installation()
fs = import('fs')
lib_dir = fs.as_posix(get_option('libdir'))
if lib_dir.startswith('"') and lib_dir.endswith('"')
lib_dir = lib_dir.substring(1, -1)
endif
cpp = meson.get_compiler('cpp')
collect = run_command('python', '**.py', 'collect', check: true)
sources = collect.stdout().strip().split('\n')
subdir('src')
meson-log.txt
Build started at 2025-08-07T09:23:54.692136
Main binary: /**/*/bin/python3.12
Build Options: -Dbuildtype=release -Db_ndebug=if-release -Db_vscrt=md '-Dlibdir="/**/*/lib"' --native-file=/**/*/../.nanobind/meson-python-native-file.ini
Python system: Darwin
The Meson build system
Version: 1.8.3
Source dir: **
Build dir: /**/*/.nanobind
Build type: native build
Project name: **
Project version: undefined
-----------
Detecting compiler via: `c++ --version` -> 0
stdout:
Apple clang version 16.0.0 (clang-1600.0.26.6)
Target: arm64-apple-darwin23.6.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin
-----------
Running command: -x c++ -E -dM -
-----
-----------
Detecting linker via: `c++ -Wl,--version` -> 1
stderr:
ld: unknown options: --version
clang++: error: linker command failed with exit code 1 (use -v to see invocation)
-----------
-----------
Detecting Apple linker via: `c++ -Wl,-v` -> 0
stderr:
@(#)PROGRAM:ld PROJECT:ld-1115.7.3
BUILD 23:52:02 Dec 5 2024
configured to support archs: armv6 armv7 armv7s arm64 arm64e arm64_32 i386 x86_64 x86_64h armv6m armv7k armv7m armv7em
will use ld-classic for: armv6 armv7 armv7s i386 armv6m armv7k armv7m armv7em
LTO support using: LLVM version 16.0.0 (static support for 29, runtime is 29)
TAPI support using: Apple TAPI version 16.0.0 (tapi-1600.0.11.9)
-----------
Sanity testing C++ compiler: c++
Is cross compiler: False.
Sanity check compiler command line: c++ sanitycheckcpp.cc -o sanitycheckcpp.exe
Sanity check compile stdout:
-----
Sanity check compile stderr:
-----
Running test binary command: /**/*/.nanobind/meson-private/sanitycheckcpp.exe
../backend-fs/meson.build:1:0: ERROR: Executables created by cpp compiler c++ are not runnable.
rpath check
> otool -L .nanobind/meson-private/sanitycheckcpp.exe
.nanobind/meson-private/sanitycheckcpp.exe:
@rpath/libc++.1.dylib (compatibility version 1.0.0, current version 1.0.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1351.0.0)
compiler check
I ran this:
echo -e '#include<iostream>\nint main(){std::cout<<"Hello";return 0;}' > test.cpp
c++ test.cpp -o test
./test
and the output was:
Hello%
I'm getting this issue as well. Seems like meson shouldn't be trying to compile and generate an
.exesince I'm using a Mac
That shouldn't be the problem -- unix doesn't care what the "program name" is, which is exactly why it is simplest to always include it in early sanity checks.
I ran this:
echo -e '#include<iostream>\nint main(){std::cout<<"Hello";return 0;}' > test.cpp c++ test.cpp -o test ./test
What's the otool output for it?
Note the sanity check we use is instead,
echo -e 'class breakCCompiler;int main(void) { return 0; }\n'
I don't think it should matter though. :/
The otool output is:
.nanobind/meson-private/sanitycheckcpp.exe:
@rpath/libc++.1.dylib (compatibility version 1.0.0, current version 1.0.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1351.0.0)
You gave the otool output for meson's failing sanitycheck already. I asked you for the corresponding otool output of your own working test program. Not sure why you're repeating the part you already provided. :P
Ohhhh my bad 😅
➜ echo -e '#include<iostream>\nint main(){std::cout<<"Hello";return 0;}' > test.cpp
➜ c++ test.cpp -o test
➜ ./test
Hello%
➜ otool -L test
test:
/usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 1800.105.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1351.0.0)
Okay so for some strange reason when running
# in meson as a python subprocess
c++ sanitycheckcpp.cc -o sanitycheckcpp.exe
It links libc++ via rpath.
But when running:
# interactive shell command
c++ test.cpp -o test
It links libc++ via absolute path.
What causes this? Baffling. Is c++ the same $PATH item each time? Is it .cc versus .cpp? Is it because of .exe? Is it choosing based on isatty()? Is it because the program used iostreams instead of C-with-classes? Something else?
There is no reason why any of this should matter, but seemingly something does. If you can experiment with tweaking some of these details I'd be very curious to hear the results. For absolute reproducibility of the meson issue I'd start with our exact C++ source code + filenames and then tweak things until it works.
Note my most promising theory is "PATH issues" but I don't understand why the PATH would be different.
^
InstalledDir: /Library/Developer/CommandLineTools/usr/bin
What’s the output when you run c++ --version, with the compiler that works? On my system, the used tools are inside the Xcode bundle: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
~~Interestingly, if I use the tools in CommandLineTools, even the C compielr fails to link with libSystem:~~
EDIT: (snip) nvm, if I correctly set /Library/Developer/CommandLineTools via xcode-select it works with these as well here.
^
InstalledDir: /Library/Developer/CommandLineTools/usr/bin
What’s the output when you run c++ --version, with the compiler that works? On my system, the used tools are inside the Xcode bundle: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
~Interestingly, if I use the tools in CommandLineTools, even the C compielr fails to link with libSystem:~
EDIT: (snip) nvm, if I correctly set /Library/Developer/CommandLineTools via xcode-select it works with these as well here.
> c++ --version
Apple clang version 16.0.0 (clang-1600.0.26.6)
Target: arm64-apple-darwin23.6.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin
Just to test, does it work with the Xcode toolchain? Run xcode-select -s /Applications/Xcode.app/Contents/Developer
(to switch back, xcode-select -s /Library/Developer/CommandLineTools)
@eli-schwartz You were in the right direction with the rpath mention 💪 I fixed it by providing the linker with the rpath by adding the following env variable:
LDFLAGS="-Wl,-rpath,/usr/lib"
Prior to adding that env variable, the rpath didn't exist for the sanitycheckcpp.exe:
Running this otool -l .nanobind/meson-private/sanitycheckcpp.exe | grep -A2 LC_RPATH . . . returned nothing. Here are all load commands. You can see that LC_RPATH is missing from these results.
However, after adding the env var mentioned above, the error no longer occurred. And running the otool -l command from above returns this:
cmd LC_RPATH
cmdsize 24
path /usr/lib (offset 12)
I can also now run the executable as well (although it does nothing).
> ./.nanobind/meson-private/sanitycheckcpp.exe
>
The thing is that none of this is supposed to be necessary because the compiler is supposed to be able to produce freestanding binaries that depend on nothing but the compiler's own built-in system libraries, if you just tell it to compile a single test file into a single binary without any options. And it's not working in your environment, or the original reporter's environment, but it works for lots of other people.
"You must manually specify some rpath" isn't a good solution for users encountering this problem, but it's not clear what exactly the problem is.
So I don't really consider my rpath mention "on the right track", it's just background details on what is going wrong in the first place. :(
@eli-schwartz That's a good point. What would you suggest I try then? From the "short-term" solution I posted, it tells me that the linker (ld) on my computer is having trouble finding dependencies.
For whatever this is worth I am observing the same type of failure as described in this thread when it comes to the Objective-C sanity check binary. Compilation is similarly successful but the binary exits with a non-zero code.
In particular I am using the tools from the latest XCode 26.1 which has tools version 17.0.0 for Apple clang, ld, and so on. I, however, cannot seem to get the above band-aid with setting LDFLAGS to work, though I suspect this is down to peculiarities of my project rather than it just plain having stopped working.