Linking error when trying to use self-written Framework in Library of an App - objective-c

I've build a Framework for an Objective-C App. I've tested it on minimalistic Programs where it worked. I was trying to use it in a real App now. Unfortunately the linker can't find the definition of my classes. =(
When I try to run it, I get the following Error Message:
Undefined symbols for architecture x86_64:
"_OBJC_CLASS_$_ClassInMyFramework", referenced from:
objc-class-ref in libMyLib.a(MyLib.o)
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
The Dependency:
App -> libMyLib.a -> MyFramework.framework
The usual suggestion for this error message is to add the framework into the "Link Binary with Library" Build Phase... I can assure you that this has happened ;)
My first thought is that something might be wrong with the Build Settings which results in this linking error.
On second thought It may have to do with the Project-Setup. Is it possible to statically link a framework into an '.a' library file?
Update:
I've linked the Framework into the App and now it's working. But I don't consider this a clean solution. Help still appriciated. =)

The short answer is no, you can't link the framework statically into your .a file. See this discussion.
The reason is, the static library doesn't include the object code (the definition) of classes from the dynamic framework. The static library links to object code in the framework the same way the app links to the framework code: at run-time.
From Apple's Framework Programming Guide: "Dynamic shared libraries have characteristics that set them apart from static linked shared libraries. For static linked shared libraries, the symbols in the library are checked at link time to make sure they exist. If they don’t exist, link errors occur. With dynamic shared libraries, the binding of undefined symbols is delayed until the execution of the program."
It depends on what you want to be able to do with your code. You could add a static "target" for your framework project, so your framework project outputs both a framework and a static library. You could include this static library into apps.
But, one benefit of frameworks is that you can include nibs, images, headers, etc. So, linking your framework into your apps directly is not a bad way to go. Otherwise, you need to include these assets directly into your project. If you want this framework to be distributed with your app, you'll need to package it inside the app wrapper.
It looks like some people create a "static framework" for inclusion into an iOS project, but this looks a bit hacky to me.
As an interesting exercise, you can explore the symbols in your object code. Let's say you are using a ClassInMyFramework (from your framework) somewhere in your static library, like:
ClassInMyFramework *myFramework = [[ClassInMyFramework alloc] init];
The static library will then include the _OBJC_CLASS_$_ClassInMyFramework symbol. You can see the list of symbols in your static library file at the command line:
$ nm /path/to/libMyLib.a
This will output a list of symbols, which will show that _OBJC_CLASS_$_ClassInMyFramework is undefined (note, the "U" designates that the class is undefined):
U _OBJC_CLASS_$_ClassInMyFramework
Whereas, if you were do to the nm command on your framework:
$ nm /path/to/MyFramework.framework/Versions/A/MyFramework
Your output would show that the symbol is defined in your framework (though the definition will still only linked at run-time), which would look something like this, showing an address of the definition:
0000000000001100 S _OBJC_CLASS_$_ClassInMyFramework

Related

Linking mingw libs with cmake

Long story short, I rewrote the Godot build system to cmake (only windows part), mostly because I wanted to learn it, but I have trouble compiling Godot with mingw. When I'm trying to compile it, at first everything goes fine, up until the point of linking final exe, where I get a lot of "undefined reference to" errors. It looks like main libraries (core/scene/editor/..) can't see functions from each other. MSVC build is working fine, and scons version is also compiling under mingw, so I clearly just missed something in my cmake version.. I tried to remove some compile/linking options throughout my cmake scripts as a test, but nothing changed. I don't really know how even debug this problem, so if someone could kick me in the right direction I would be really glad for it.
Ok, I finally got time to came back to this.
The problem
So basically the problem was in circular dependency on godot libs. I didn't thought this was the problem because I'm spoiled by MSVC (which doesn't depend on link order). Also, I tried to replicate circular dependency in mingw on a test project with much smaller scale. The project was a 30 libs with two functions in each, first function printing string, and another calling all first functions from all 30 libs, so there is 30 libs of circular dependency. Strangely enough, the project linked no problems, and printed 30^2 strings..
The solution
The solution is to use -Wl,--start-group/-Wl,--end-group linking flags around all libraries. There is two ways you can do it.
First way, is to add all your libraries to the some list of sorts. This could be global property, or property on some target (not just a simple variable), so it could be accessed from other subdirectories. After you formed your list of libraries you simply link it to the executable as follows
# getting all your libs from the global property..
get_property(__LIBS_LIST GLOBAL PROPERTY EXE_LIBS_LIST)
# linking all libraries to the exe..
target_link_libraries(my-exe PRIVATE -Wl,--start-group ${__LIBS_LIST} -Wl,--end-group)
This is the easiest solution, but be cautious about dependencies on libraries which you link to your exe, because it seems that when CMake creates link line for your exe, it first lists all libraries which are linked directly to your exe, and only after it places libraries which came from dependencies of libraries linked directly. Basically if your target dependency tree looks something like this:
exe // your main exe file
- lib_A // lib A linked directly to the main exe
- lib_AA // lib AA linked to the lib_A
- lib_AAA // lib AAA linked to the lib_AA
- lib_B // lib B linked directly to the main exe
- lib_BB // lib BB linked to the lib_B
- lib_BBB // lib BBB linked to the lib_BB
your link order for the exe will look something like this:
// first libs linked directly to the exe
lib_A
lib_B
// only after recursively initial libs dependencies
lib_AA
lib_AAA
lib_BB
lib_BBB
That's meen, that if you will link your libs like target_link_libraries(my-exe PRIVATE -Wl,--start-group ${__LIBS_LIST} -Wl,--end-group), --start-group and --end-group will guard only the libraries linked directly to your exe. I didn't found this described in documentation, but I found SO question which talks pretty much about same behaviour (CMake library linking order). Also, as I tested this on mingw, it didn't mattered how exactly libs lib_AA/lib_AAA/lib_BB/lib_BBB were linked, via PRIVATE or via INTERFACE, the results were the same.
Second way, is to exploit recursivity of link expanding for dependencies of libraries linked directly to the exe. From my example you can see, that dependencies of lib_A (lib_AA/lib_AAA) weren't mixed with dependencies of lib_B (lib_BB/lib_BBB). So basiacaly what we can do, is to create INTERFACE library and connect to it -Wl,--start-group immediately after that. Then add any number of libraries to it's interface and link global-libs to your exe (order does not matter). And in very end, close the group in your global-libs library
add_library(global-libs INTERFACE)
target_link_libraries(global-libs INTERFACE -Wl,--start-group)
# ...
# linking another libs, and linking global-libs to exe
# ...
target_link_libraries(global-libs INTERFACE -Wl,--end-group)
This will ensure, that all libraries connected to global-libs will be surrounded by -Wl,--start-group/-Wl,--end-group.
Now, theoretically, CMake should handle circular dependency by itself, by placing libraries in link line multiple times (how many times controlled by LINK_INTERFACE_MULTIPLICITY). But this method didn't worked for me (mb I just missed something..). Plus, you need declare dependencies between cmake targets, and with -Wl,--start-group/-Wl,--end-group you can just set one specific interface library as a holder for all libs with circular dependencies..

CodenameOne "Undefined symbols" error when adding native library

I am trying to add the Honeywell Captuvo iOS library to my CodenameOne project as a native library. I have been through the "Generate Native Access" process and placed the .a library in the native/ios directory. However when I send the app to be built it comes back with the error:
Undefined symbols for architecture arm64:
"_OBJC_CLASS_$_EAAccessoryManager", referenced from:
objc-class-ref in libCaptuvoSDK.a(CaptuvoReal.o)
Many thanks
Rereading the error message it seems I missed a key detail. You need to add the ExternalAccessory.framework to your project. To do this you need to define the build hint: ios.add_libs=ExternalAccessory.framework
Original answer below:
Is the name of the .a library preceded with the lower case word lib and does it actually end with a .a. If not make sure to rename it so it abides by these constraints.
Assuming both are OK you will need to verify the library actually has the required architecture in this case arm64.
This is explained in this question: How to check if a static library is built for 64-bit?
I would just use the second suggestion: file libFileName.a
It should include arm64 among the list of supported architectures.

Objective C Linker Error: Undefined Symbols

What does it mean to have undefined symbols?
There are no errors in the code files themselves and I am NOT using any external libraries.
I DID add a typedef NS_ENUM prior to this linker error occurring.
Where do I add this -v to see invocation?
Here is the error message:
Undefined symbols for architecture x86_64:
"_OBJC_IVAR_$_UIViewController._parentViewController", referenced from:
-[PEPI_LessonController setParentViewController:] in PEPI_LessonController.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
"Undefined Symbols"
Building source code files to an executable file consist of at least two steps:
Compile the source code files to intermediate binary files (often called xyz.o).
Link the intermediate binary files to the final executable file.
The error message "undefined symbols" is a linker message. It may appear even though the compilation process was successful without notice. The linker organizes final memory address relations and it replaces symbols that the compiler had to assume they would be valid later, if all parts of the code would be available. Without this, no modularization would be possible at all.
-v to see invocation
If you build your application in Xcode, then Xcode calls all the compile and link commands for you (CompileC, Ln, Clang ...). But remember that a typical IDE runs only the commands you could run by yourself in the shell. Theoretically, you could develop big applications only in a text editor and a shell. So I suggest take some time and try to copy paste some commands listed in the Xcode build report to a shell :-) You'll learn a lot about the backgrounds. Therefore, in my opinion, -v to see invocation is used while invoking the command in the shell - or in the build settings, if you wish permanently more information.
"External libraries"
Finally, try to clarify "external libraries". To look at the most simple example: even if you write a simple C program and you want to know something trivial like the length of a string, you'll include <glibc.h>. Now this is an external library. It's external to your program code. Are you sure you haven't included external libraries?
Solving linker problems
Linker errors are often confusing and somehow difficult, because details of the linked modules tend to be out of sight. You may find many hints if you enter the error message in a search engine. For example, have a look at here:
Undefined symbols for architecture armv7: "_SCNetworkReachabilityCreateWithAddress"
Even if all components are found for linking, all paths are known etc, they may have the wrong version or else.
It means it can't find the property parentViewController and method setParentViewController when linking your object files files. The most common cause for these types of errors is not linking a library or framework in your projects target. UIViewController is part of UIKit so I'd be surprised if it's not already linked. Is this an OSX project and your trying to use UIViewcontroller instead of NSViewController?
In my case I had forgotten to add the .m file to all the same targets as the .h and that's what caused this issue. In case it helps anyone thought I'd mention here... double check your target memberships!

Unit test unresolved symbol when using Objective-C++

I am trying to create unit tests to my project, I have workspace with several projects with tens of static libraries and apps. So, I created a new project for static library in this workspace and added Cocoa Touch UnitTest bundle to it. Then I added a test for one of the functions in one of the libraries in this workspace, lets say library X, I also added link dependency to my unit test bundle to lib X. But when I run unit tests (Cmd + U). I get linker error:
Undefined symbols for architecture i386:"_OSVersion", referencedfrom:-[MyUnitTest testMethodFromLibX] in MyUnitTestTest.o "_methodFromLibX", referenced symbol(s) not found for architecture i386
Why test bundle is not linking with library X? I can see libX.a and MyUnitTests.octet in build folder.
Ok, thanks all, I found cause of the problem - my libX was Objective-C++ library, so linker mangled all names, but my Unit-Tests were Objective-C library, so when it was linking it obviously couldn't find method or class by name, since linkage was different. So, I convert unit-tests into Objective-C++ library(just changed *.m -> *.mm) and everything works!
Unit tests run in the simulator, and so every library need to have a x386 version. You can use the command line to examine each - i believe "file lib.a" does this but a quick google search will turn up the name.

Xcode linker flag -force_load for static library which is built in project [duplicate]

Some libraries require the -all_load linker flag when linking to an Xcode project. However, this leads to a linker error if there are symbol conflicts among libraries. The solution is to use -force_load, which effectively lets you use -all_load on some libraries, but not on others.
However, this in turn leads to a new problem, at least for me. Whenever I use -force_load with a relative path to a library, the linker always finds symbol conflicts between the library and itself. It appears that the linker thinks that the library with its absolute path and the library with its relative path are different libraries, and therefore finds conflicts between the library and itself.
I can avoid this by using an absolute path with the flag. But this is not a wonderful solution, as it is convenient to keep source code for libraries within my documents directory. But the path to the documents directory will be different on other machines.
Question: Can anyone get force_load to work with a relative path to the library?
EDIT: for background information, see this question
With Xcode 4, if you include the library project into your app project, then you can add this to the Other Linker Flags:
-force_load $(BUILT_PRODUCTS_DIR)/<library_name.a>
You still need the dependency, and you need to add the library in the Link Phase list of frameworks and libraries too.
EDIT: Apple now says as of some Xcode 4 release that you can simply use this linker flag: "-ObjC" to get libraries with categories to properly load. That flag is working just fine for me in Xcode 5. People are still up voting this answer, but I suspect that the -ObjC flag is the best solution now.
This worked for me. Like the above answers you still need to include the library in the project.
-force_load $(SRCROOT)/pathToLibraryFromProject/libname.a
For the path it's just the folders in your project that lead to where you put your library, for example BaseFoler/Subfolder/libName.a.