mesonbuild / meson

The Meson Build System
http://mesonbuild.com
Apache License 2.0
5.41k stars 1.55k forks source link

c++ -Wl,--as-needed doesn't work in OpenBSD #3593

Open kernigh opened 6 years ago

kernigh commented 6 years ago

This might be a bug in OpenBSD, not in Meson, but it causes many test failures in OpenBSD. (Sorry if this bug is a duplicate; a search for -Wl,--as-needed found unrelated bugs that have this option in the command line.)

I have OpenBSD/amd64 6.3 with its system compiler (clang 5.0.1) and linker (GNU ld 2.17). Meson links everything with -Wl,--as-needed, but this doesn't work work with C++ programs. I get errors about missing pthread functions. This causes multiple failures in Meson's tests. If I remove -Wl,--as-needed from the link command, then the errors don't happen.

I can reproduce the errors with any C++ program that uses libc++:

$ cat simple.cc                                                                
#include <iostream>
int main() { std::cout << std::endl; }
$ c++ -o simple simple.cc -Wl,--as-needed
/usr/bin/../lib/libc++abi.so.0.0: undefined reference to `pthread_rwlock_rdlock'
/usr/bin/../lib/libc++.so.1.0: undefined reference to `pthread_mutexattr_destroy'
/usr/bin/../lib/libc++abi.so.0.0: undefined reference to `pthread_rwlock_unlock'
/usr/bin/../lib/libc++.so.1.0: undefined reference to `pthread_detach'
/usr/bin/../lib/libc++abi.so.0.0: undefined reference to `pthread_rwlock_wrlock'
/usr/bin/../lib/libc++.so.1.0: undefined reference to `pthread_mutexattr_settype'
/usr/bin/../lib/libc++.so.1.0: undefined reference to `pthread_mutexattr_init'
/usr/bin/../lib/libc++.so.1.0: undefined reference to `pthread_join'
c++: error: linker command failed with exit code 1 (use -v to see invocation)

I observe that libc++ and libc++abi don't linked to libpthread. They also don't link to libc.

$ ldd /usr/lib/libc++.so.1.0 /usr/lib/libc++abi.so.0.0
/usr/lib/libc++.so.1.0:
        Start            End              Type  Open Ref GrpRef Name
        0000067f98119000 0000067f983d9000 dlib  1    0   0      /usr/lib/libc++.so.1.0
/usr/lib/libc++abi.so.0.0:
        Start            End              Type  Open Ref GrpRef Name
        000006802b68f000 000006802b8ef000 dlib  1    0   0      /usr/lib/libc++abi.so.0.0

If I don't use -Wl,--as-needed, then the executable links to both libraries:

$ c++ -o simple simple.cc
$ ldd simple
simple:
        Start            End              Type  Open Ref GrpRef Name
        000004d52b800000 000004d52ba03000 exe   2    0   0      simple
        000004d7a8c76000 000004d7a8f36000 rlib  0    1   0      /usr/lib/libc++.so.1.0
        000004d7c9b00000 000004d7c9d60000 rlib  0    1   0      /usr/lib/libc++abi.so.0.0
        000004d7a2edc000 000004d7a30e5000 rlib  0    1   0      /usr/lib/libpthread.so.25.1
        000004d80c5f5000 000004d80c81d000 rlib  0    1   0      /usr/lib/libm.so.10.1
        000004d807aad000 000004d807d8e000 rlib  0    1   0      /usr/lib/libc.so.92.3
        000004d7d7900000 000004d7d7900000 ld.so 0    1   0      /usr/libexec/ld.so

libc++ does need symbols from both libc and libpthread:

$ nm /usr/lib/libc++.so.1.0 | less
...
         U pthread_mutexattr_destroy
         U pthread_mutexattr_init
         U pthread_mutexattr_settype
         U pthread_self
         U realloc
         U sched_yield
         U setlocale
         U snprintf
...

Some pthread functions are in libc, some are in libpthread:

$ nm /usr/lib/libc.so.92.3 | grep pthread_self                                 
00041f00 t _libc_pthread_self
00041f00 T pthread_self
$ nm /usr/lib/libpthread.so.25.1 | grep pthread_join                           
00002680 T pthread_join

The errors from -Wl,--as-needed only mention the functions in libpthread, not in libc. Is this how -Wl,--as-needed is should work, or is there a problem in libc++, libpthread, or the linker? I have not yet sent a bug report to OpenBSD.

jpakkane commented 6 years ago
$ cat simple.cc                                                                
#include <iostream>
int main() { std::cout << std::endl; }
$ c++ -o simple simple.cc -Wl,--as-needed

The fact that this does not work would seem to indicate that the compiler toolchain itself is broken.

kernigh commented 6 years ago

Thanks for the reply, @jpakkane. I wasn't sure if the toolchain's -Wl,--as-needed was broken, or if Meson's use of -Wl,--as-needed was broken. I haven't found any other build system that uses -Wl,--as-needed.

For now, I don't need to build any C++ code with Meson, so I may allow the test to fail. When I run Meson's own tests, I get many failures with the same "undefined reference to pthread..." messages. These and other failures don't fit in my terminal. The problem is that ./run_project.tests.py prints

Total configuration time: 166.77s
Total build time: 289.62s
Total test time: 9.03s

Total passed tests: 276
Total failed tests: 20
Total skipped tests: 102

Mesonlogs of failing tests

The Meson build system
Version: 0.47.0.dev1
Source dir: /home/kernigh/park/meson/test cases/common/2 cpp
...

and the logs of the 20 failing tests are so long that that the line "Total failed tests" falls off the top of my terminal, so I can neither count the failing tests, nor identify the first tests that failed.

For contrast, if I am testing another project, meson test prints the line FAIL: 0 (or more than 0) and Full log written to .../meson-logs/testlog.txt, without filling my terminal.

kernigh commented 6 years ago

In OpenBSD, clang++ -Wl,--as-needed doesn't work, but g++ -Wl,--as-needed does work. The difference is that libc++ for clang has undefined symbols for pthread functions, but libstdc++ for gcc has weak symbols for them. Therefore, clang needs to link to libpthread, but gcc doesn't need to. So when --as-needed drops libpthread, it breaks clang but doesn't break gcc.

I'm finding more weirdness with OpenBSD shared libraries, but I will report such weirdness under #3570 instead of opening new issues.

mcandre commented 2 years ago

Are the OpenBSD maintainers aware of this situation with clang libc++ and pthread?

I am having success by using -pthread on OpenBSD, and -lpthread for other targets.

For comparison, I haven't had any trouble with this in either FreeBSD or NetBSD.

kernigh commented 2 years ago

@mcandre, can you describe your situation in more detail? 8 years ago, OpenBSD's intro(3) manual changed from -pthread to -lpthread. So I think -pthread has been obsolete for 8 years.

My simple.cc from 2018 no longer has a problem with -Wl,--as-needed:

$ c++ --version
OpenBSD clang version 11.1.0
Target: powerpc-unknown-openbsd7.0
Thread model: posix
InstalledDir: /usr/bin
$ ld --version
LLD 11.1.0 (compatible with GNU linkers)
$ cat simple.cc
#include <iostream>
int main() { std::cout << std::endl; }
$ c++ -o simple simple.cc -Wl,--as-needed
$ ./simple

$

My computers are running OpenBSD-current (which is almost 7.0). The last release, OpenBSD 6.9, has an older toolchain (clang/lld 10.x), so it might have different problems.

The OpenBSD community knows that -Wl,--as-needed still has problems on a few platforms that use a different toolchain. Most platforms (like amd64) use ld.lld (LLD 11.1.0) as the linker. A few platforms (like mips64 and sparc64) use ld.bfd (GNU ld 2.17) as the linker. I have no ld.bfd platforms (after powerpc switched to ld.lld), so I always use ld.lld.

ld.bfd -Wl,--as-needed causes build failures. Multiple times, OpenBSD's Charlène Wendling removed -Wl,--as-needed for ld.bfd but kept it for ld.lld:

mcandre commented 2 years ago

For context, I don't write software specifically targeting OpenBSD. Rather, OpenBSD is one of several target platforms that I happen to support, determined by the effort required to maintain the build target.

I mainly test my stuff on macOS, Windows, and (Debian) Linux. Though I noticed that a few small changes are sometimes necessary in order to support FreeBSD cross-compilation targets. And then even more tweaks to support OpenBSD targets.

From that perspective, I suppose I am discovering and remarking that the OpenBSD cross-compilation build chain appears to deviate in observable ways from native GNU/Linux clang/gcc.

Would be nice to unify these flags, so that devs can enjoy more confidence that our apps will build without issue for all the different UNIX implementations. Instead of being tripped up by this or that idiosyncracy.