mesonbuild / meson

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

Linking C++ executable with Objective-C dynamic library fails #3183

Open urdh opened 6 years ago

urdh commented 6 years ago

When linking a C++ application using C++11 threads to a library built from Objective-C sources, it seems like Meson incorrectly selects the Objective-C linker which leaves standard library symbols unresolved since no C++ standard library is linked. Linking a similar application with a library built from Objective-C++ sources works fine, because the Objective-C++ linker is selected (I believe this would be the correct behavior even in the first case).

Example:

project('test', ['cpp', 'objc', 'objcpp'], default_options: ['cpp_std=c++11'])

t = dependency('threads')

l1 = library('lib_1', 'lib.m')
d1 = declare_dependency(link_with: l1, include_directories: include_directories('.'))
e1 = executable('app_1', 'test.cpp', dependencies: [t, d1])

l2 = library('lib_2', 'lib.mm')
d2 = declare_dependency(link_with: l2, include_directories: include_directories('.'))
e2 = executable('app_2', 'test.cpp', dependencies: [t, d2])

The implementation of lib.m and lib.mm is irrelevant, but test.cpp must use C++11 threads or atomics. When building app_2, everything is fine, but building app_1 yields the following:

[1/1] Linking target app_1.
FAILED: app_1
cc  -o app_1 'app_1@exe/test.cpp.o' liblib_1.dylib -pthread -Wl,-rpath,/private/tmp/test/build/
clang: warning: argument unused during compilation: '-pthread' [-Wunused-command-line-argument]
Undefined symbols for architecture x86_64:
  "std::__1::__thread_struct::__thread_struct()", referenced from:
      std::__1::thread::thread<void (&)(), void>(void (&&&)()) in test.cpp.o
  "std::__1::__thread_struct::~__thread_struct()", referenced from:
      std::__1::thread::thread<void (&)(), void>(void (&&&)()) in test.cpp.o
      void* std::__1::__thread_proxy<std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct> >, void (*)()> >(void*) in test.cpp.o
  "std::__1::__thread_local_data()", referenced from:
      void* std::__1::__thread_proxy<std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct> >, void (*)()> >(void*) in test.cpp.o
  "std::__1::__throw_system_error(int, char const*)", referenced from:
      std::__1::thread::thread<void (&)(), void>(void (&&&)()) in test.cpp.o
  "std::__1::thread::~thread()", referenced from:
      _main in test.cpp.o
  "operator delete(void*)", referenced from:
      std::__1::thread::thread<void (&)(), void>(void (&&&)()) in test.cpp.o
      void* std::__1::__thread_proxy<std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct> >, void (*)()> >(void*) in test.cpp.o
  "operator new(unsigned long)", referenced from:
      std::__1::thread::thread<void (&)(), void>(void (&&&)()) in test.cpp.o
  "___gxx_personality_v0", referenced from:
      std::__1::thread::thread<void (&)(), void>(void (&&&)()) in test.cpp.o
      void* std::__1::__thread_proxy<std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct> >, void (*)()> >(void*) in test.cpp.o
      Dwarf Exception Unwind Info (__eh_frame) in test.cpp.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
ninja: build stopped: subcommand failed.
urdh commented 6 years ago

(This seems suspiciously similar to #3125, by the way.)

nirbheek commented 6 years ago

The fix for this is simpler though:

diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py
index c7ca4e43..ae93743b 100644
--- a/mesonbuild/compilers/compilers.py
+++ b/mesonbuild/compilers/compilers.py
@@ -49,7 +49,7 @@ cpp_suffixes = lang_suffixes['cpp'] + ('h',)
 c_suffixes = lang_suffixes['c'] + ('h',)
 # List of languages that can be linked with C code directly by the linker
 # used in build.py:process_compilers() and build.py:get_dynamic_linker()
-clike_langs = ('objcpp', 'objc', 'd', 'cpp', 'c', 'fortran',)
+clike_langs = ('objcpp', 'cpp', 'd', 'objc', 'c', 'fortran',)
 clike_suffixes = ()
 for _l in clike_langs:
     clike_suffixes += lang_suffixes[_l]

I'm actually surprised; I thought we already changed this.