XCode 4.2 static libraries linking issue - c++

I have Core static library, a few Component static libraries that relays on the Core one, and then there is an App that links against both Core and Component libraries. My App can link both against Core and Component as long as Component don't uses classes from Core (App uses classes from Core).
I got the following error in both armv6 and armv7 versions. So my problem is not the very popular linking issue that everyone has.
ld: symbol(s) not found for architecture armv6
clang: error: linker command failed with exit code 1 (use -v to see invocation)
I added reference to Core in Component and even added it in "Link Binary With Libraries" which shouldn't be necessary for static lib.
Since I start having this issue I start doubting my design... It probably makes more sense in dynamically linking environment but still it should be doable in static one, especially since this already works under Windows with MSVC compilers.
Edit:
I made some progress! Although I still don't know where to go with it.
Here is my setup:
Core has a class cResourceManager that has a templated method GetResource<T>(int id)
Core also has class cResource
Component has class cMesh that inherits cResource
Here are some tests:
If I try from App to call rm->GetResource<cMesh>(...) I get the linking error
If I try from App to construct cMesh I get linking the linking error
If I try from App to call static method that will return new instance of cMesh I get the linking error
If I comment out the construction of cMesh but leave other member cMesh function calls the App links fine. I can even call delete mesh.
I have never seen anything like it!

If you remove the cMesh constructor, then you are then using the default (no argument, no body) cMesh constructor that is given to you. It almost sounds like there's a build error or missing code as a result of some code in your cMesh constructor and so the library isn't actually getting generated, and perhaps Xcode isn't reporting the error. Xcode is no good at reporting linker errors.
I would suggest looking at what symbols the linker says are missing and double-check that they are actually defined in your code. My guess is that you're using one of those symbols in your cMesh constructor. A lot of times with virtual base classes, you may forget to define and implement a method or two in a child class. Could be a result of missing a method based on your template, or your template isn't #included correctly. This could compile fine but result in linker errors like you're seeing.
If Xcode isn't showing you the full linker error, show the Log Navigator (Command ⌘+7), double-click the last "Build " entry, select the error, and then press the button on the far-right of the row that appears when selected. The symbols should be listed there. If not, it's time for xcodebuild in the Terminal.
If it's not that case, I'd be interested in seeing the results of whether or not the library is being built for the appropriate architecture, or maybe this can spur some progress:
In the Xcode Organizer Shift ⇧+Command ⌘+2, click Projects and find the path to the DerivedData for your project.
In the Terminal, navigate to that directory (cd ~/Library/Developer/Xcode/DerivedData/proj-<random value>/)
Remove (or move aside) the Build directory (rm -r Build)
In Xcode, try to build with the cMesh constructor present.
Find the Library product file (cd Build/Products/<scheme>-iphoneos)
Your compiled static libraries (<libname>.a) should be in this directory. If they're not there, they didn't build (unless you put your products elsewhere). If your libraries are there, let's confirm that they actually are getting built for the appropriate architecture. Run otool -vh <library>.a. You should see something like:
$ otool -vh libtesting.a
Archive : libtesting.a
libtesting.a(testing.o):
Mach header
magic cputype cpusubtype caps filetype ncmds sizeofcmds flags
MH_MAGIC ARM V7 0x00 OBJECT 3 1928 SUBSECTIONS_VIA_SYMBOLS
As you can see, my test library was built for ARMv7.

Make sure you are linking them in the correct order.
If Component depends on symbols in Core, then Component needs to be first in the link order, so the linker knows which symbols to look for in Core.
In MSVC the order doesn't matter, but in most other compiler suites it does.

I don't think Clang generates code for armv6, if you're targeting devices that old you still need to use GCC.

Related

dynamic_cast fails between "long distance" siblings on linux compilation

There is a class DerivedClass which inherits from both BaseClassA and BaseClassB publicly. All classes have virtual functions to make sure the virtual table is built properly.
BaseClassA and BaseClassB are located in Library1 and DerivedClass is in Library2.
One function in Library1 retrieves a DerivedClass in the form of a BaseClassA pointer and tries to dynamic_cast to BaseClassB but it fails. The same function works in different environments and compilers (visual studio for instance).
Extra information:
Reproduced with 4.1.2 and 4.5 gcc versions (read about the old gcc bug)
Derived class name is "Match" (thought it may collide with other library? python?)
There are tens of libraries compiling one after the other while linking between them.
nm -gC: Found the vtable address for Match
gdb (7.0.1): used to check the vtable address for the class but couldn't understand much. (gdb version doesnt support "info vtbl". gdb can't show direct information about the class claiming it is a typedef)
readelf -s: I saw the symbol
I figured it might be one of the following problems
duplicated symbol
HIDDEN symbol somewhere in the libraries linked
Duplicated vtables
-E and RTLD_GLOBAL dlopen flag linker flag didn't work (the linking is made using the makefile linker stage and probably not the dlopen.
non-inline function manipulation (didnt work as well - but could be my mistake with understanding what exactly has to be done)
Been farming the web trying to find a solution. But what I want to know first is What Is The Problem? How can I focus on it?
(5) looks promising even though I didnt manage to use it.
Any suggestions would be greatly appreciated (a solution would be great as well ;) )
Apparently #4 was the answer.
The was a hidden feature that loads functions dynamically and had to be handles separately. Adding the -Wl,-E flags to the linking process and changing the loader flags did the trick.
What I want to know if there is any linuxy way of understanding this is the error.
Something like "ldd" command or others (top, nm, readelf, etc) that I tried but couldn't see anything that pointed to this exact error.
Thanks SOF for continuous help in various subjects

Symbol lookup error at runtime instead of load time

I have an application which uses a class Foo from an .so shared library. I've come across a problem where at runtime it prints
<appname>: symbol lookup error: <appname>: undefined symbol: <mangled_Foo_symbol_name>
Now, it turned out that the unmangled symbol was for the constructor of the class Foo, and the problem was simply that an old version of the library was loaded, which didn't contain Foo yet.
My question isn't about resolving the error (that's obviously to use the correct library), but why it appears at runtime instead of at time of load / startup.
The line of code causing the error just instantiates an object of class Foo, so I'm not using anything like dlopen here, at least not explicitly / to my knowledge.
In contrast, if I remove the whole library from the load search path, I get this error at startup:
<appname>: error while loading shared libraries: libname.so.2: cannot open shared object file: No such file or directory
When the wrong version of gcc / libstdc++ is on the load path, an error also appears at starup:
<appname>: /path/to/gcc-4.8.0/lib64/libstdc++.so.6: version `GLIBCXX_3.4.20' not found (required by <appname>)
This "fail fast" behavior is much more desirable, I don't want to run my application for quite awhile first, until I finally realize it's using the wrong library.
What causes the load error to appear at runtime and how can I make it appear immediately?
From the man page of ld.so:
ENVIRONMENT
LD_BIND_NOW (libc5; glibc since 2.1.1) If set to a nonempty string, causes the dynamic linker to resolve all symbols at program startup instead of deferring function call resolution to the point when they are first referenced. This is useful when using a debugger.
LD_WARN (ELF only)(glibc since 2.1.3) If set to a nonempty string, warn about unresolved symbols.
I think you can not statically link .so library. If you want to avoid load/run time errors you have to use all static libraries (.a). If you do not have static version of library and source then try to find some statifier. After googling I find few statifiers but do not know how do they work so leaving that part up to you.

Is it possible to symbolicate C++ code?

I have been running into trouble recently trying to symbolicate a crash log of an iOS app. For some reason the UUID of the dSYM was not indexed in Spotlight. After some manual search and a healthy dose of command line incantations, I managed to symbolicate partially the crash log.
At first I thought the dSYM might be incomplete or something like that, but then I realized that the method calls missing were the ones occurring in C++ code: this project is an Objective-C app that calls into C++ libraries (via Objective-C++) which call back to Objective-C code (again, via Objective-C++ code). The calls that I'm missing are, specifically, the ones that happen in C++ land.
So, my question is: is there some way that the symbolication process can resolve the function calls of C++ code? Which special options do I need to set, if any?
One useful program that comes with the apple sdk is atos (address to symbol). Basically, here's what you want to do:
atos -o myExecutable -arch armv7 0x(address here)
It should print out the name of the symbol at that address.
I'm not well versed in Objective-C, but I'd make sure that the C++ code is being compiled with symbols. Particularly, did you make sure to include -rdynamic and/or -g when compiling the C++ code?
try
dwarfdump --lookup=0xYOUR_ADRESS YOUR_DSYM_FILE
you will have to look up each adress manually ( or write a script to do this ) but if the symbols are ok ( your dSym file is bigger than say 20MB) this will do the job .

Linker issues in C++ / ObjC

I'm porting a sizeable codebase to iOS. The simplified version of my scenario is as follows:
I have a C++ library, built from the command line. I can run code from it from the iOS simulator, so I believe it's correctly built.
I have the skeleton iOS application created by Xcode
I want to add logging to the C++ library. I have a trace() method which takes fmt, .... I compile that .cpp using -x Objective-c++, the code is as follows:
void trace (const char* sFmt, ...)
{
va_list args;
va_start(args, sFmt);
NSString* sFmt2 = [ NSString stringWithUTF8String: sFmt ];
NSLogv(sFmt2, args);
va_end(args);
}
The library compiles just fine. However, when I try to link the app, I get a linker error:
".objc_class_name_NSString", referenced from: literal-pointer#__OBJC#__cls_refs#NSString in lib.a(trace.o)
This is strange because I can use NSString and NSLog from a .mm file in the project itself. The Foundation framework is linked. Moreover, just to test, instead of calling NSString from my library I added a helper foobar() to the .mm in the project, which does this
void foobar (const char* sFmt)
{
NSLog([NSString stringWithUTF8String:sFmt]);
}
When this is called from the library function above, it works!
Everything I read about this kind of error involves a "just updated my SDK" scenario, which is not my case. I started doing iOS stuff literally two days ago, I haven't changed the default project settings, etc.
My guess is that name mangling is failing at some point, because I know NSString is indeed linked, but it seems the name refrenced by the library is different to the linked one.
Any ideas?
Your linker output indicates that your command-line-built library is lib.a, which indicates to me that it's a static library. I'd guess that, not being a dylib, it doesn't know how to use the dyloader to find missing symbols at runtime. Relatedly, I suspect that the iOS project will link in these System libraries dynamically (even though non-OS developers can't create dynamic frameworks), whereas your static C++ library will expect those symbols to be resolved at link time.
I suspect that any of these three things would resolve the issue: (in descending order of attractiveness)
statically link against the right libraries when building the C++ library
make the C++ library a dylib instead of a static library (so it will expect to find missing symbols at runtime using the dyloader)
link your whole app statically (so the NSString class symbols are present at app link time) (This is a bad idea, if it's even possible at all, but would likely solve the problem.)
Hope this helps!
I was able to fix this by using libtool instead of ld, passing it -framework Foundation, and passing -fobjc-abi-version=2 to gcc.

Objective-C/C++ - Linker error/Method Signature issue

There is a static class Pipe, defined in C++ header that I'm including.
The static method I'm interested in calling (from Objective-c) is here:
static ERC SendUserGet(const UserId &_idUser,const GUID &_idStyle,const ZoneId &_idZone,const char *_pszMsg);
I have access to an objective-c data structure that appears to store a copy of userID, and zoneID -- it looks like:
#interface DataBlock : NSObject
{
GUID userID;
GUID zoneID;
}
Looked up the GUID def, and it's a struct with a bunch of overloaded operators for equality. UserId and ZoneId from the first function signature are #typedef GUID
Now when I try to call the method, no matter how I cast it (const UserId), (UserId), etc, I get the following linker error:
Ld build/Debug/Seeker.app/Contents/MacOS/Seeker normal i386
cd /Users/josh/Development/project/Mac/Seeker
setenv MACOSX_DEPLOYMENT_TARGET 10.5
/Developer/usr/bin/g++-4.2 -arch i386 -isysroot /Developer/SDKs/MacOSX10.5.sdk -L/Users/josh/Development/TS/Mac/Seeker/build/Debug -L/Users/josh/Development/TS/Mac/Seeker/../../../debug -L/Developer/Platforms/iPhoneOS.platform/Developer/usr/lib/gcc/i686-apple-darwin10/4.2.1 -F/Users/josh/Development/TS/Mac/Seeker/build/Debug -filelist /Users/josh/Development/TS/Mac/Seeker/build/Seeker.build/Debug/Seeker.build/Objects-normal/i386/Seeker.LinkFileList -mmacosx-version-min=10.5 -framework Cocoa -framework WebKit -lSAPI -lSPL -o /Users/josh/Development/TS/Mac/Seeker/build/Debug/Seeker.app/Contents/MacOS/Seeker
Undefined symbols:
"SocPipe::SendUserGet(_GUID const&, _GUID const&, _GUID const&, char const*)", referenced from:
-[PeoplePaneController clickGet:] in PeoplePaneController.o
ld: symbol(s) not found
collect2: ld returned 1 exit status
Is this a type/function signature error, or truly some sort of linker error? I have the headers where all these types and static classes are defined #imported -- I tried #include too, just in case, since I'm already stumbling :P
Forgive me, I come from a web tech background, so this c-style memory management and immutability stuff is super hazy.
Edit: Added full linker error text. Changed "function" to "method". Also I'll note that we're using a custom makefile to compile a few projects external to this one. SocPipe static methods are referenced elsewhere, though, in this xcode project and seems to compile fine.
(Eh, let's turn that comment into an answer.)
The method signature looks fine; that is, what you're calling matches what is declared in the header. If it was not, you would probably be getting a compilation error rather than a linker error.
The linker's problem is that it doesn't have any corresponding object code to connect this call to: the method is declared but never defined.
The latter should occur either in a C++ source file which your project can compile, or else in some precompiled library or framework that you can link to. Either way, that file needs to be included in your project so that it can be made available to the linker.
The object file containing Pipe::SendUserGet is not being built, or it is not being linked into your Xcode target. Whether or not other static methods in Pipe work correctly is not necessarily relevant if those methods are defined in the header file.
You mentioned that you use external makefiles to build parts of your project. In that case, it's not enough to run the makefile at compile time as a dependency — you also have to include the resulting products in your project.
For example, if you have a makefile that builds libLIBRARY.a, then drag libLIBRARY.a into your project and add it to your target.
This only works if the makefile is building a library. It won't work if the makefile builds a program. It also gets more complicated if the library is a dynamic library, as you'll also have to make sure that the dynamic library gets distributed with your application (often by putting it in the app bundle, if you're making an app bundle). It also gets more complicated if you want to build a universal binary. You could theoretically pass the right CFLAGS to make to build a universal library, but it may be easier to run make once for each architecture and combine the results using a script (which is what I do).