17

I'm working on a C++ framework, and there's a few issues when I compile it on OSX with Clang.

First of, I'm using some other libraries, such as openssl, and clang complains that some symbols aren't solved when I build the library. They shouldn't be: these libraries will be linked with the final binary, it shouldn't happen on an intermediary.

Then, there's also a few methods and variables that are supposed to be implemented in the "client" binary... with GCC, no problems, but Clang also complains that these symbols can't be solved during compilation.

How come ? What should I do ?

Here's my CMakeLists.txt in case that can be useful:

cmake_minimum_required(VERSION 2.8)

project(crails_project)

set(CMAKE_CXX_FLAGS "-std=c++0x -Wall -Wno-deprecated-declarations -pedantic -DASYNC_SERVER -DSERVER_DEBUG -DUSE_MONGODB_SESSION_STORE")

find_package(cppnetlib REQUIRED)

include_directories(include /usr/local/include ${CPPNETLIB_INCLUDE_DIRS} .)

file(GLOB crails_core
     src/*.cpp)

file(GLOB crails_sql
     src/sql/*.cpp)

file(GLOB crails_mongodb
     src/mongodb/*.cpp)

add_library(crails-core    SHARED ${crails_core})
add_library(crails-sql     SHARED ${crails_sql})
add_library(crails-mongodb SHARED ${crails_mongodb})

This is the command that crashes:

/usr/bin/c++  -std=c++0x -Wall -Wno-deprecated-declarations -pedantic -DASYNC_SERVER -DSERVER_DEBUG -DUSE_MONGODB_SESSION_STORE -dynamiclib -Wl,-headerpad_max_install_names   -o libcrails-core.dylib -install_name /Users/michael/Personal/crails/build/libcrails-core.dylib CMakeFiles/crails-core.dir/src/assets.cpp.o CMakeFiles/crails-core.dir/src/cgi2params.cpp.o CMakeFiles/crails-core.dir/src/cipher.cpp.o [...]

And here are the two kinds of error I get:

Undefined symbols for architecture x86_64:

  "_BIO_ctrl", referenced from:
      Cipher::encode_base64(unsigned char*, unsigned int) const in cipher.cpp.o

And the second one:

  NOTE: a missing vtable usually means the first non-inline virtual member function has no definition.
  "vtable for boost::detail::thread_data_base", referenced from:
      boost::detail::thread_data_base::thread_data_base() in server.cpp.o
Michael
  • 1,357
  • 3
  • 15
  • 24

3 Answers3

20

I don't recommend to enable global dynamic lookup:

-undefined dynamic_lookup which will mark all undefined symbols as having to be looked up at runtime.

Much more safe way to resolve it for specific symbols:

-Wl,-U,symbol_name, which only does so for the given symbol (note: you have to prepend an underscore to the symbol name)

You could also use weak dynamic linking:

extern int SayHello() __attribute__((weak));
Bartosz
  • 319
  • 2
  • 4
  • 4
    Note that `-undefined dynamic_lookup` is OSX-specific. Linux shared libraries behave as if `-undefined dynamic_lookup` was enabled all the time. I'm not sure about Windows. – Timmmm Mar 28 '18 at 10:48
10

Solved it ! Clang needs to receive the option -undefined dynamic_lookup to ignore missing symbols when compiling a library.

Add this to the CMakeFile.txt to produce the expected effect:

if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
  set(CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS "${CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS} -undefined dynamic_lookup")
endif()
Michael
  • 1,357
  • 3
  • 15
  • 24
  • 2
    This is not a good answer, not really an answer at all. If you are missing `_open` because it should be `open`, `-undefined dynamic_lookup` isn't going to fix anything. Why the hell does clang add these _ to functions that are exported without? I am seeing all kinds of errors with stuff that should be there: _close, _write, _sleep. Do I need to link against some special LLVM libc that I dont know about? The functions in question are used without this underscore nonsense and defined in /lib/libc-2.27.so without! Where the ef is llvm libc? – Alex Barker Jun 17 '18 at 04:57
  • The point of this answer isn't to fix missing symbols. The symbols are *expected* to be missing in the library that I'm building. This answers shows how to achieve that with clang. In your case, I'd say that _open, _write, _sleep are just the mangled forms of open/write/sleep. As to why they're missing in your build, that's another issue that I don't know if I can help with. – Michael May 02 '21 at 11:45
2

According to one of the commenters you have to use -lcrypto to prevent the first error.

The second error seems to be due to an ABI incompatibility of clang and gcc. Rebuild boost with clang++ and libc++. See SO posts Is clang++ ABI same as g++?, Why can't clang with libc++ in c++0x mode link this boost::program_options example? and How to compile/link Boost with clang++/libc++?.

In case you run into linker troubles with other libraries you should also try to rebuild those with clang++.

Edit:

In order to instruct the OS X linker to allow unresolved symbols you should add -undefined dynamic_lookup to the linker options. See also SO post Error when making dynamic lib from .o

Community
  • 1
  • 1
user1225999
  • 912
  • 8
  • 14
  • That's actually one of the things I'm wondering: why am I supposed to use -lcrypto or worry about ABI compatibility ? I don't need to do any linking with GCC (and that's good, because there are symbols that *should* *not* be solved when building the library). Isn't there a way I can compile the library with Clang without linking ? In my scenario, I should be worrying about ABI compatibility when building my executable, not before. – Michael Aug 21 '14 at 11:02
  • Afaik clang should not behave differently. Are you sure that you do not link against those libraries when compiling with g++? You might want to use "nm -C -u libcrails-core.dylib" to check the library compiled with g++ for undefined symbols. – user1225999 Aug 21 '14 at 12:45
  • Alright, I just ran `nm -C -u /usr/lib/libcrails-core.so` (the g++ build has been made on Linux), and it returned all the symbols Clang talked about (in the same order), and more (string, stringstream, pthread stuff). – Michael Aug 21 '14 at 21:38
  • Did you try to compile on Mac OS X with g++? I would assume you run into the same trouble and you also need to add "-undefined dynamic_lookup" to the linker options. So it's not a clang problem... – user1225999 Aug 22 '14 at 09:24
  • I do indeed. So why is that happening ? Should I check for the OS, and always add this flag when the building scripts are running on OSX ? – Michael Aug 25 '14 at 12:32
  • The linkers on Linux and Mac OS X work differently. Refer to the respective man pages. I do not have experience with OS X linkers but yes that is what I would do. – user1225999 Aug 25 '14 at 16:10