meson icon indicating copy to clipboard operation
meson copied to clipboard

Meson 151 breaks some Apple compilers from missing LC_RPATH

Open e-dant opened this issue 1 year ago • 1 comments

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 arm64 macOS 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 --version if 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

e-dant avatar Sep 08 '24 20:09 e-dant

I think this is related to #13534

bruchar1 avatar Sep 10 '24 00:09 bruchar1

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.

eli-schwartz avatar Sep 15 '24 23:09 eli-schwartz

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.

meson-log.txt

e-dant avatar Sep 15 '24 23:09 e-dant

c++ sanitycheckcpp.cc -o sanitycheckcpp.exe

If you run this, is the resulting executable supposed to be functional?

eli-schwartz avatar Sep 16 '24 00:09 eli-schwartz

c++ sanitycheckcpp.cc -o sanitycheckcpp.exe

If 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.

e-dant avatar Sep 16 '24 00:09 e-dant

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.

eli-schwartz avatar Sep 16 '24 00:09 eli-schwartz

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

e-dant avatar Sep 16 '24 00:09 e-dant

with 1.4.0

(Via a virtualenv + pip install of meson 1.4.0)

e-dant avatar Sep 16 '24 00:09 e-dant

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.

e-dant avatar Sep 16 '24 00:09 e-dant

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.

eli-schwartz avatar Sep 16 '24 00:09 eli-schwartz

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%

Livestock5 avatar Aug 07 '25 15:08 Livestock5

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

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. :/

eli-schwartz avatar Aug 07 '25 15:08 eli-schwartz

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)

Livestock5 avatar Aug 07 '25 16:08 Livestock5

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

eli-schwartz avatar Aug 07 '25 16:08 eli-schwartz

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)

Livestock5 avatar Aug 07 '25 16:08 Livestock5

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.

eli-schwartz avatar Aug 07 '25 16:08 eli-schwartz

Note my most promising theory is "PATH issues" but I don't understand why the PATH would be different.

eli-schwartz avatar Aug 07 '25 17:08 eli-schwartz

^

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.

dblsaiko avatar Aug 07 '25 17:08 dblsaiko

^

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

Livestock5 avatar Aug 07 '25 17:08 Livestock5

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)

dblsaiko avatar Aug 07 '25 17:08 dblsaiko

@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
>

Livestock5 avatar Aug 07 '25 20:08 Livestock5

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 avatar Aug 07 '25 20:08 eli-schwartz

@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.

Livestock5 avatar Aug 08 '25 13:08 Livestock5

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.

iamrecursion avatar Nov 07 '25 11:11 iamrecursion