Building a Unity exported Xcode project with LLVM and libc++ - c++

I'm currently attempting to build an Xcode project exported from Unity with LLVM against libc++ (the LLVM C++ standard library). The project compiles and links against libstdc++ (the GNU C++ standard library).
If I include "/usr/lib/libstdc++.dylib" amongst the Other Linker Flags this resolves most of the issues but leaves one problem:
Undefined symbols for architecture i386:
"__Z21UnityKeyboard_GetTextPSs", referenced from:
__ZNK16KeyboardOnScreen7getTextEv in libiPhone-lib.a(iPhoneKeyboard.o)
It seems to be looking for the method void UnityKeyboard_GetText(std::string* text) as part of Keyboard.mm.
When I dump the symbols for Keyboard.o I get
00002900 T __Z21UnityKeyboard_GetTextPNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE
000161c0 S __Z21UnityKeyboard_GetTextPNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE.eh
So the mangled names seem to be incompatible when I use libc++. Is there any possible of way of resolving this issue?

Related

LLVM symbol lookup difficulties

I'm following along with the tutorial LLVM provides to get familiar with its IR that can be found here.
Unfortunately, it seems that when I add in the JIT support, the linker has some difficulty following along. Namely, I get a number of undefined symbols,
Undefined symbols for architecture x86_64:
"_LLVMInitializeX86AsmParser", referenced from:
llvm::InitializeNativeTargetAsmParser() in lexer.cc.o
"_LLVMInitializeX86AsmPrinter", referenced from:
llvm::InitializeNativeTargetAsmPrinter() in lexer.cc.o
etc.
I'm building using CMAKE using the LLVM config and can find the headers in my include directories, so I'm unsure why the symbols can't be fine. My code is here, but isn't too specific to the problem. I'm on MacOS.
How can I make the linker find the header files or why is it not working?
If you are using CMake, you need to add some LLVM components. Here is an excerpt from my CMakeLists.txt for the same chapter.
llvm_map_components_to_libnames(llvm_libs analysis core executionengine instcombine object orcjit runtimedyld scalaropts support native)
Relevant links:
The official CMakeLists.txt for the chapter
A StackOverflow question about a similar problem
The example CMakeLists.txt from the documentation

Trouble linking C++ with Xcode 5

So I have this legacy project, which I am trying to bring to iOS 7 and Xcode 5. And by legacy, I mean real legacy. Like 2004 legacy.
Anyhow, I am trying to build this thing, and it spits out a few libraries, including some common third party libs. When linking, I get errors like these:
Undefined symbols for architecture ${arch}:
"google::protobuf::internal::WireFormatLite::WriteBytes(int, std::string const&, google::protobuf::io::CodedOutputStream*)"
Upon examination with nm, the old (arm only) binary library still included in the project contains this:
U __ZN6google8protobuf8internal14WireFormatLite10WriteBytesEiRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEPNS0_2io17CodedOutputStreamE
00000a8c T __ZN6google8protobuf8internal14WireFormatLite10WriteBytesEiRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEPNS0_2io17CodedOutputStreamE
00002b28 S __ZN6google8protobuf8internal14WireFormatLite10WriteBytesEiRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEPNS0_2io17CodedOutputStreamE.eh</code>
The new library (universal), created when I run the project through Xcode 5 (and thus, clang/llvm) contains this:
U __ZN6google8protobuf8internal14WireFormatLite10WriteBytesEiRKSsPNS0_2io17CodedOutputStreamE
00000514 T __ZN6google8protobuf8internal14WireFormatLite10WriteBytesEiRKSsPNS0_2io17CodedOutputStreamE
00000b2c S __ZN6google8protobuf8internal14WireFormatLite10WriteBytesEiRKSsPNS0_2io17CodedOutputStreamE.eh
To me, it looks like the parameters are missing in the mangled name.
Is this normal and I need to look somewhere else?
Or if this is the problem: Any idea how to solve it?
EDIT: I mixed up OLD and NEW. I left the original post unchanged
The old, arm only libary seems to indicate:
google::protobuf::internal::WireFormatLite::WriteBytes(int, std::string const&, google::protobuf::io::CodedOutputStream*)
Which has all the hallmarks of being compiled with libstdc++.
The new universal library indicates:
google::protobuf::internal::WireFormatLite::WriteBytes(int, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, google::protobuf::io::CodedOutputStream*)
This has all the hallmarks of being compiled with libc++
Your link error indicates that there is a problem finding:
google::protobuf::internal::WireFormatLite::WriteBytes(int, std::string const&, google::protobuf::io::CodedOutputStream*)
This would be the case if the code linking to the library was compiled using libstdc++ and, because your new universal library is compiled using libc++ the code will not link.
You have to compile everything with the same libc++/libstdc++ support, you cannot mix and match as they will refuse to link. Make sure that every element in your project is compiled using the same C++ Standard Library and the link error should be resolved.
In general, demangling the symbols (using c++filt) allows you to see the proper signatures, and in the case of this code, once you start seeing std::__1:: in the symbols, it indicates that the library was compiled using libc++, and when you see the link failing with unadorned std:: symbols (i.e. without the inner __1::), then it indicates that the item performing the linking is using libstdc++.
Are you perhaps mixing and matching SDKs or compilers? Name mangling might differ between compilers. The only other thing I know that might affect name mangling is the 'extern "C"' keyword, but that usually turns it off completely, so I don't think that's it.
So, if the old code was still built with GCC 2.x and your new code is clang-built, they probably just mangle differently.
Does the error message really say $(arch) ? Not a particular architecture? If it gave a concrete architecture, I'd expect that you have one project that builds e.g. for arm5 and arm6, linking in a library that only has one of these architectures. Then it usually complains about the symbols in that library not being available, I think.

Linker errors when using a c++/Objective C++ library

I am trying to build a static library for iOS. I have 4 C++ classes with Objective-C++ wrappers. It seems to be building fine but when I try to run my unit tests I get a bunch of linker errors similar to the one below. Is there some command I need to add in order to use my library?
(null): "std::__1::__vector_base_common<true>::__throw_length_error() const", referenced from:
edit:
I solved this by adding the libc++.dylib framework to both targets.
A hunch: The library and the unit test targets disagree on which C++ Standard Library they use. Double check the build setting in both targets.
In Xcode 4.6 the setting is found under the heading "Apple LLVM compiler 4.2 - Language"
In Xcode 5 the setting is found under the heading "Apple LLVM 5.0 - Language - C++"
In both cases the setting is named "C++ Standard Library" (duh!) and the two targets should agree on whether they use libstdc++ or libc++.

How I do compile a application against a static library compiled with libc++ in xcode/clang/macos?

When I try to compile a test console application to test some functionality on a static library on the same workspace, i run into problems in the linking stage of the binary, it only happen when I choose to use libc++ standard library.
The missing symbols error is the follow :
Undefined symbols for architecture x86_64:
"std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >::empty() const", referenced from:
libtorrent::torrent::replace_trackers(std::__1::vector<libtorrent::announce_entry, std::__1::allocator<libtorrent::announce_entry> > const&) in libLibOFFTorrent-xcode.a(torrent.o)
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
When I choose stdlibc++ in both targets everything compiles ok and it runs OK.
my questions are :
there are some restriction on using libc++ on static libraries?
its a bug in apple/clang++ linker tool?
how can I configure the project to use libc++ with my static
libraries?
why the linker tool does not find the symbols of a standard c++
libraries on a static lib?, (any other lib that depends on is compiled against libc++)
should I forget the idea on using libc++?
notes:
the static library depends on libboost_system, witch i had compiled with libc++ and libstdc++ with the same results
when i run the test with the 'bjam' tool it runs OK, maybe the jam files chooses libstdc++ to compile the files.
I know that changing the standard library fix the linking problem , I only want to know why is that.
UPDATE: when I remove the reference to string::empty in the static lib project, the project that depends on compiles with libc++ fine and runs, but it gets in a infinite loop.
UPDATE 2: removing the string::empty references causes no effect when I compile the whole thing with libstdc++ it runs fine. no loops, this makes me think that is a bug or something like that.
UPDATE 3: when it compiles this is the place where the programs loops indefinitely :
It seems that one of your dependencies (libtorrent) has been built against libstdc++.
Check the namespace : std::__1::basic_string. It has the __1 prefix, usually indicating libstdc++).
I may be wrong but I think you need to rebuild your libtorrent against libc++ if you absolutely want to use this one.
Note that it is pretty common to use the stdlibc++.
Did you by any chance compile libtorrent with a -D_LIBCPP_INLINE_VISIBILITY=""?
The reason I ask is that std::string::empty() isn't in libc++.dylib because it is marked up with "always_inline". And so it should have been inlined into libtorrent when it was used.

Preventing symbols from being stripped in IBM Visual Age C/C++ for AIX

I'm building a shared library which I dynamically load (using dlopen) into my AIX application using IBM's VisualAge C/C++ compiler. Unfortunately, it appears to be stripping out necessary symbols:
rtld: 0712-002 fatal error: exiting.
rtld: 0712-001 Symbol setVersion__Q2_3CIF17VersionReporterFRCQ2_3std12basic_stringXTcTQ2_3std11char_traitsXTc_TQ2_3std9allocatorXTc__ was referenced
from module ./object/AIX-6.1-ppc/plugins/plugin.so(), but a runtime definition
of the symbol was not found.
Both the shared library and the application which loads the shared library compile/link against the static library which contains the VersionReporter mentioned in the error message.
To link the shared library I'm using these options: -bM:SRE -bnoentry -bexpall
To link the application, I'm using this option: -brtl
Is there an option I can use to prevent this symbol from being stripped in the application? I've tried using -nogc as stated in the IBM docs, but that causes the shared library to be in an invalid format or the application to fail to link (depending on which one I use it with).
Yes. This is not really connected to a particular language or compiler. The same general technique is used for gcc for example. -bI:foo.exp is used to tell the linker that the symbols listed in foo.exp will come from the name at the top. Likewise, -BE:dog.exp is used to tell the linker that the symbols listed in dog.exp are exported and can be used by others.
You can see /bin/ldd and /bin/dump can be used to review these symbols.
I figured this out. The trick is to use an export list so that symbols used in the plugin but not used in the binary aren't stripped out.
# version.exp:
setVersion__Q2_3CIF17VersionReporterFRCQ2_3std12basic_stringXTcTQ2_3std11char_traitsXTc_TQ2_3std9allocatorXTc__
And then when linking the application use: -brtl -bexpfull -bE:version.exp
There's more information here: Developing and Porting C and C++ Applications on AIX.