Static library with ARC support linked to non-ARC project causing linker errors - objective-c

I have a non-ARC project that uses an ARC-enabled static library. This is a supported scenario, so that everything works fine. That is, until I run the code on a 4.x device, including the Simulator. In that case the code blows up with the following linker error:
dyld: lazy symbol binding failed: Symbol not found: _objc_storeStrong
Referenced from: /Users/zoul/Library/Application Support/iPhone Simulator/4.3.2/Applications/…/Demo.app/Demo
Expected in: /Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator4.3.sdk/System/Library/Frameworks/Foundation.framework/Foundation
This happens as soon as some of the ARC-enabled code attempts to call _objc_storeStrong function, like in an init method (self = [super init]). Converting the main project to ARC solves the problem, but I’d like to know if there are other solutions.

I assumed that the toolchain may have added the necessary libraries to link to, in order for ARC to work properly. So the linker transcript may contain this piece of information. If the project of the app itself is not ARC-enabled, you may not get these by default, but you could still link to them by defining them explicitly.
Looking at the build transcript you can indeed find the appropriate linker flag there: it’s called -fobjc-arc (just as the related compiler flag). When you add this setting to Other Linker Flags, the linker will include the ARC library with the main build product and the code should run fine.

I'm adding a new answer to this as the previous accepted solution no longer appears to work with Xcode 4.3.2. I can only assume that the -fobjc-arc linker flag was never supposed to be exposed and has now been removed.
This appears to be a known issue although the only thread I can find on this with somebody from Apple commenting on the devforums dates back to mid-2011. From that thread, it is suggested that manually linking the following file solves the issue:
${DEVROOT}/Platforms/iPhoneOS.platform/Developer/usr/lib/arc/libarclite_iphoneos.a
This requires you to be compiling using the latest compiler/SDK though. I'm submitting this answer without testing, please upvote if it works, downvote if it doesn't!

Related

How to deal with undefined symbols when loading Mono libraries in Linux

I'm porting my Windows Mono application to Linux, one step at a time, first to WSL Linux under Windows 10, then hopefully to Real Ubuntu. Everything described here behaves identically under both WSL and Ubuntu 20.04.
My application loads the /usr/lib/libmono-2.0.so shared library, but in doing so the loader throws an exception: undefined symbol: _ZTIPi. Some research showed that this symbol was defined in libstdc++.so, so I "pre-loaded" that as well. That had no effect.
Meanwhile, I found this code fragment perusing the mono code base. It would be in mono\mini\mini-llvm.c: (https://github.com/mono/mono/blob/main/mono/mini/mini-llvm.c)
/* Add a reference to the c++ exception we throw/catch */
{
LLVMTypeRef exc = LLVMPointerType (LLVMInt8Type (), 0);
module->sentinel_exception = LLVMAddGlobal (module->lmodule, exc, "_ZTIPi");
LLVMSetLinkage (module->sentinel_exception, LLVMExternalLinkage);
mono_llvm_set_is_constant (module->sentinel_exception);
}
What exactly is happening here? What do I need to know and understand to successfully load this library?
Solution so far was to build and install Mono outside of the default release.
See https://www.mono-project.com/docs/compiling-mono/linux/
then One Stop Shop Build Script (Debian)
If you follow the instructions, your alternate Mono installation would be in /usr/local
This would suggest that the Mono release was somehow incorrectly compiled.
So, having found this after having the same issue, thank you for the information in the question and answer, it helped me figure out how to solve it. However, your solution doesn't answer your "What exactly is happening here?", which I shall try to explain.
Let's start with the _ZTIPi symbol, which when run through c++filt comes out as: typeinfo for int*
Which is indeed a part of the C++ standard library. It is listed as undefined in the default install of libmono, but not listed at all in the one I compiled from source.
You can check this with something like:
$ readelf --all /usr/lib/libmono-2.0.so | grep _ZTIPi
However, libstdc++.so isn't listed as needed library in either case.
You can check this with something like:
$ readelf --all /usr/lib/libmono-2.0.so | grep NEEDED
This all means that when you try to load in libmono the dynamic linker will try to resolve the _ZTIPi symbol by looking in the libraries listed by libmono (where it can't find it), and in the global symbol table for the process, which may or may not have it.
If you link against libmono at compile-time the solution would be to also link against libstdc++ at that time. This way, your executable will list libstdc++ as needed library, causing the dynamic linker to load its symbols into the global symbol table. When loading libmono the dynamic linker can then find the symbol fine.
If you load libmono dynamically at runtime, you'll have to load in libstdc++ first, using something like this:
void * cxxlib = dlopen("libstdc++.so.6", RTLD_LAZY | RTLD_GLOBAL);
Key thing here is the RTLD_GLOBAL flag, which will add all symbols to the global table, so they can be found when you're trying to load libmono.
And alternative is of course to build mono yourself, which should end you up with a libmono that isn't subtly broken. In that case, make sure to throw in a call to mono_set_dirs, like this:
mono_set_dirs("/opt/mono/lib", "/opt/mono/etc");

Reference to ' ' is ambigous error in Xcode

I was working with a custom iOS framework project in Xcode.There I am getting a lot of errors mentioning "Reference to ' ' is ambigous".I am attaching the screenshot of errors.Please help me correcting this.
Adding more information to Jason's answer.
The error message makes me think you have two declarations of the same library functions. All of those references are from UIKit
mostly this can be occurring because of the header files. As you can see all the errors indicates that it is quoting the enum values. Enum values will always be in the .h files. Normally the reference headers(.h files) will be present inside the frameworks. It is a common mistake that sometimes these header files will be buried some where in our code by any third party frameworks. So kindly check your third party libraries.
I did face this issue once and after searching everywhere i could not able to find the solution. The only thing solved my issue was
Opening a fresh project and importing my files into that project. Actually it really took me less than 10 minutes to move to a new project and immediately my xcode was happy. This is definitely worth a try.
Actually This error was cleared when I shift from iOS SDK 6.1 to 7.1(or any version higher that 6.1)
The error message makes me think you have two declarations of the same library functions. All of those references are from UIKit. Check to make sure only one version of UIKit is referenced in your project (check the frameworks), and make sure any libraries you have included are linking the same UIKit version as the rest of the app.
Steps to fix from here:
Clean the project
Delete everything inside
'~/Library/Developer/Xcode/DerivedData/ModuleCache/' (the button
inside the organizer window did not work for me)
Clean once more
Build project
from here: Reference to 'X' is ambiguous
Clean your project and rebuild again.If it don't work then create a new project
Set value of Enable Module (C and objective-c) to No

iOS framework with dependencies

I have created two iOS .frameworks
they both compile perfectly
my structure is as follows:
iPadProject
- framework1
- framework2
So Framework2 is included in framework1 and framework1 is included in the actual iPad Project
So my problem is, if I add both framework1 and framework2 into my iPadProject it won't compile because its whining about duplicate symbols from framework2 ( that's logical because it was already included in framework1)
But if i only include framework1 into my iPadProject when i access a method from framework1 that in his turn access a method from framework2 it crashes the application with "signal SIGABRT"
Do not nest static libraries, including iOS frameworks. As you've seen, it leads to major problems (it leads to even more problems when two frameworks each have their own version of the third). The final link step should link all libraries required; static libraries should never link other static libraries. There is no really good way to automate this; it just has to be part of the documentation for the framework.
You shouldn't be getting runtime exceptions, though, for failing to link a framework. You should be getting link-time failures that indicate that the symbol isn't defined. If you're getting a crash, that suggests you're doing something strange in your linking.
the problem is that because it is nested right now, the linker links f2 into f1 -- BUT only the parts of f2 that are needed by f1.
like
f2 has 5 symbols (f2_1 - 5)
f1 uses f2_1 and f2_2 but NOT 3,4,5
=> the linker throws it away
now the app needs f2_3, f2_4 and f2_5 but they aren't there... but nobody knows that at compile time.
now you try to resolve it by linking the app with f2 again but as before nobody at compile time the linker optimized out f2_3 - 5 and they are assumed to be in f1 and so are duplicates!
the way to solve this Rob Napier already mentioned. Don't nest Frameworks (mainly not static ones / 3rd part ones)
a workaround is to pass -all_load to the linker when f1 links in f2!

Xcode debugger in submodule

Working on an iOS App I'm using an static library integrated as a submodule. No problem, but when I want to step into a method of this submodule while debugging the debugger just step over that method call.
I guess it's related to the Build settings but I don't have any idea.
Thanks for your help!
kober
You cannot step into the library code unless you have source code for it.
This is the purpose of libs, if you make your own you may want to prevent others to look how its built. If you want to check library function correctness you have two ways:
Get the source code - which is in most cases impossible unless you get it from the author
Do unit testing. Check if library function's arguments give correct results.
If you do have the source code for the lib you have to set its build to debug mode, so you can provide symbols for Xcode to get through library's methods.

Getting: "Compilation exited with code 134" when attempting to use "LLVM Optimizing Compiler" switch

I'm getting a "Compilation exited with code 134" when attempting to use the "LLVM Optimizing Compiler" switch for release iPhone builds, using MonoTouch 4.0.1.
I don't get much information from build output window at all - just:
"Compilation exited with code 134, command:"
MONO_PATH=(snip)/bin/iPhone/Release/LSiOS.app /Developer/MonoTouch/usr/bin/arm-darwin-mono --llvm --aot=mtriple=armv7-darwin,nimt-trampolines=2048,full,static,asmonly,nodebug,llvm-path=/Developer/MonoTouch/LLVM/bin/,outfile=/var/folders/03/033pAAGuHgGkIy4CorbVV++++TI/-Tmp-/tmp38107451.tmp/Newtonsoft.Json.MonoTouch.dll.7.s "(snip)/bin/iPhone/Release/LSiOS.app/Newtonsoft.Json.MonoTouch.dll"
Mono Ahead of Time compiler - compiling assembly (snip)/mscorlib.dll
What is odd is that in earlier command lines, there is a correlation between the DLL mentioned in the arm-darwin-mono command line and what is the compiling, but in this case it says "mscorlib.dll".
Any thoughts?
I have found a few cases (googling and from bugzilla.xamarin.com) where the error code 134 is related to Mono.Linker being too aggressive (removing something that's needed).
This is easy to confirm by turning off the linker, i.e. "Don't link" in Linker Options. If the build works then you can try isolating the assembly where the linker makes a mistake.
E.g. add a "--linkskip=mscorlib" to the mtouch extra parameters and re-enable linking. This will link everything (Link All) or all SDK (Link SDK assemblies) except the assembly you selected (mscorlib in the example). That's only a workaround and a bug report should be filled so the issue can be fixed properly (and get you all the linker advantages).
However be warned that there are other issues sharing the same error code, like:
http://ios.xamarin.com/Documentation/Troubleshoot#Error_134.3a_mtouch_failed_with_the_following_message.3a
YMMV
mtouch does its native builds in parallel so the logs can be confusing, e.g. you can see a bit of assembly X output followed by some assembly Y output.
Reading the full log might help you (or us) to pinpoint the issue.
I was having the exact same problem Scolestock. My app would build fine until I enabled llvm, then it was "Compilation exited with code 134, command" when trying to build the 7s for the app itself.
I'm elated to say that after 2 days of painstakingly whittling my app down to the core problem, I was able to isolate the issue to the usage of embedded dictionaries such as:
Dictionary<enum, Dictionary<enum, value>>
I was able to fix this by defining a class for the embedded dictionary and using that instead:
public class MyDefinition : Dictionary<enum, value>
{
}
...
public Dictionary<enum, MyDefinition>
Not sure if this will help you, but hopefully it'll help some poor soul who decides to use embedded dictionaries and runs into my same problem.