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.
Related
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..
I'm creating a framework that links against a static library using the linker flags -pagezero_size and -image_base
The library is LuaJIT compiled for 64 bits on Mac OS X, and my framework is just an ObjC wrapper for LuaJit plus a bridge to load other frameworks and passing classes and instance objects back and forth.
Everything works fine, but now I want to start writing tests for my framework before I start making some modifications, but the problem is that Xcode complains that pagezero_size is only for the main executable. i.e. adding the flags to the test target throws the error:
ld: -pagezero_size option can only be used when linking a main executable
Any ideas how to run tests for a static library that needs to be linked using -pagezero_size and -image_base?
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!
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
In my Cocoa Touch static library project, I have a target set apart for unit testing with OCUnit. When I build the project, I have several unit tests that are supposed to automatically run, but when I actually build the project, I get this linker errors:
"_OBJC_CLASS_$_ObjectIntTreeMap_ObjectEntry", referenced from:
objc-class-ref-to-ObjectIntTreeMap_ObjectEntry in libMyLib.a(ObjectIntTreeMap.o)
ld: symbol(s) not found
collect2: ld returned 1 exit status
As far as I know, I am linking the libraries properly (in targets / Tests / Link Binary With Libraries, I have the main project listed there).
Thanks
I figured it out...
My problem was that I had not the class ObjectIntTreeMap_ObjectEntry, and a global variable, and that was what caused my error.
Hope this helps others with the same problem
P.S. I am using GHUnit now