IOS platform Cocos2d-x Project access third-party SDK (is the problem of static library access)
Solution:
-Force_load path/to/your/libWeiboSDK. a instead of the-ObjC and-all_load provided by him. The following describes in detail
Here is a special example path. For example, you have imported XXX in the project. put a in a group file named aaa, and the path is aaa/xxx. a, or you can use the full path and click the corresponding xxx. static library a will show the path of the file on the right side of Xcode. copy it and you will be able
My Development Environment
- Mac OS X 10.10.1Xcode 6.1.1 (6A2008a) Cocos2d-x 3.2 Sina Weibo SDK for iOS January 5, 2015 problems encountered from githubclone versions
After the project is connected according to the documents attached to the Sina Weibo SDK, The project runs on the simulator and crashes when the registration method is called. Registration Method Code:
1 |
[WeiboSDK registerApp: @ "xxxxxxxx"]; |
The crash information is printed as follows:
1 |
[_ NSDictionaryM weibosdk_WBSDKJSONString]: unrecognized selector sent to instance 0x170255780 |
Obstacles to solving the problem
The document attached to the Sina Weibo SDK contains the following description:
After a static library is introduced in the project, you need to add the-ObjC compilation option during compilation to avoid program crash due to incomplete class loading in the static library. Method: Add-ObjC to the Other Linker Flags item under the Target program> Buid Settings> Linking.
People who encounter the same crash error on the Internet mentioned that adding the-all_load compilation option during compilation can also solve the problem. You can also add-all_load to the Other Linker Flags item under Target-> Buid Settings-> Linking.
Coincidentally, when I opened the Demo project attached to the Sina Weibo SDK, I found that the compilation option for this project is-all_load rather than-ObjC as prompted in its own document. And in the same development environment, my cocos2d-x project will crash, but Sina Weibo SDK with Demo can work normally, presumably the above two solutions should be a positive solution
However, after you add the compilation option to your cocos2d-x project, an error occurs when you re-compile the program. The error message is as follows:
1 2 3 4 5 6 7 8 |
Undefined symbols for architecture i386: "_ GCControllerDidConnectNotification", referenced from:-[GCControllerConnectionEventHandler observerConnection: disconnection:] in libcocos2dx iOS. a (CCController-iOS.o) "_ GCControllerDidDisconnectNotification", referenced from:-[GCControllerConnectionEventHandler observerConnection: disconnection:] in libcocos2dx iOS. a (CCController-iOS.o) "_ OBJC_CLASS _ $ _ GCController", referenced from: objc-class-ref in libcocos2dx iOS. a (CCController-iOS.o) (maybe you meant: _ OBJC_CLASS _ $ _ GCControllerConnectionEventHandler) |
No matter whether it is set to-ObjC or-all_load, the compilation will fail and the above Link error cannot be found.
Correct Solution
Here we will first provide a correct solution and then discuss why we should do so. The correct method is to set the Other Linker Flags compilation option, but you do not need to use-ObjC or-all_load. Instead, you must use-force_load path/to/your/libWeiboSDK. a. the exact location of the static Link Library of Sina Weibo SDK is followed.
Why?
Starting from the compilation Link
I don't want to introduce compilation links too much here, but I strongly recommend a book "programmer's self-cultivation". if you look at the title, you may worry that this is a book with no "serious" content. At least I thought it was the first time I saw the title, but I was wrong, the subtitle of this book is links, loads, and libraries. Believe me, after reading this book N times, you will have a very thorough understanding of the principle and process of linking the program from source code compilation to the binary program generation, more importantly, after reading this book N times, you will go up to several levels.
To put it bluntly, the source code of a project is eventually converted into a binary executable program, a dynamic link library, or a static Link Library. The process is as follows:
1 |
Source code = [compiler] =, assembly code = [assembler] =, object file = [linker] =, executable programs, dynamic link libraries, or static Link Libraries |
What is a symbol?
In general, the global variable name, function name, or class name written in the source code is called a symbol in the generated *. o object file, and there is a place called a symbol table.
For example, in. in the c file, write a function named foo (), and then in main. the foo () function is called in the c file, and. o The symbol table in the object file stores the foo () function symbol, which can be used to locate. o file specific implementation code for the foo () method.
The linker will find main when the link generates the final binary program. the o object file references the symbol foo (), while the foo () symbol is not in main. o file, so it does not exist with main. o object file symbol table, the linker starts to check other object files. o file defines the symbol foo (), so. o object file link. This ensures that the foo () method implemented in a. c can be normally called in main. c.
What is in the libWeiboSDK. a static Link Library?
There is nothing mysterious about the Unix static Link Library. It is a compressed package. It is the same as a common zip or rar compressed package, but people use a compression tool named ar to compress the data. So let's decompress it and see what's in it. Since ar is used for compression, the tool ar is also used for decompression. Run the following command on the command line:
An error is returned:
1 2 |
Ar: libWeiboSDK. a is a fat file (use libtool (1) or lipo (1) and ar (1) on it) ar: libWeiboSDK. a: Inappropriate file type or format |
Here we will explain why it is so fat ). During iOS development, we all know that we can use simulators and real machines to test our projects. However, the architecture of these two platforms is different. The simulators are in the i386 x86_64 architecture, our devices are in the armv7 arm64 architecture. When creating a static Link Library, two static link libraries for the real machine and simulator should be created for different architectures, when we want to use a static link library in our own project, if we want to run it on the simulator, we need to use a static library version for the simulator, it is very troublesome to switch to the static Link Library for the real machine when testing with the real machine device.
As mentioned above, the static Link Library is a compressed package, can we compress these two static link libraries into a static link library so that we can support both the simulator and the real machine equipment architecture? The answer is yes. For example, if we have two architecture versions of a static Link Library: libXXX. i1__x86_64.a and libXXX. armv7_arm64.a, we can use the following command to generate a unified static Link Library:
1 |
Lipo-create libXXX. i1__x86_64.a libXXX. armv7_arm64.a-output libXXX. |
In this way, we get a Unified Version of the static library libXXX. a. Its advantage is that it supports both the simulator architecture and the real machine equipment architecture. Its disadvantage is that it has become larger, that is, it is very fat ).
While libWeiboSDK. a is such a static library after the combination, we can still verify this through the command:
This command will output:
1 |
Ubuntures in the fat file: libWeiboSDK. a are: armv7 arm64 i386 x86_64 |
Since it is a fat man, we need to slim down it before decompression. We randomly extract a static Link Library of the Architecture from it. The slimming command is:
1 |
Lipo-thin i386 libWeiboSDK. a-output libWeiboSDK. i386.a |
In this way, we can extract the static Link Library of Sina Weibo sdk for the i386 platform. We call it libWeiboSDK. i386.a. Now we can decompress it with the ar command to see what is in it.
1 |
Ar-x libWeibo O. i386.a |
After decompression, you will see a lot. o. The object files at the end recall the compilation link process we just talked about. These object files are used to generate a static Link Library for the linker. Because there are too many files, I will only list the following:
1 2 3 4 5 6 7 8 9 |
-Rw-r -- 1 leenjewel staweff 13 K Jan 8 NSData + WBSDKBase64.o-rw-r -- 1 leenjewel staff 42 K Jan 8 UIImage + WBSDKResize. o-rw-r -- 1 leenjewel staff 12 K Jan 8 UIImage + WBSDKStretch. o-rw-r -- 1 leenjewel staweff 74 K Jan 8 UIView + WBSDKSizes. o-rw-r -- 1 leenjewel staff 58 K Jan 8 WBAidManager. o-rw-r -- 1 leenjewel staff 15 K Jan 8 WBAuthorizeRequest. o-rw-r -- 1 leenjewel staff 16 K Jan 8 WBAuthorizeResponse. o-rw-r -- 1 leenjewel staff 19 K Jan 8 WBBaseMediaObject. o-rw-r -- 1 leenjewel staff 265 K Jan 8 WBSDKJSONKit. o |
Why does it crash during running?
When we introduce the static Link Library of Sina Weibo SDK into our own project, and Build our own project to run on the simulator or real machine device, it is actually a process of compiling the link, finally, the project Build generates an App that can be run on a simulator or on a real machine device. In this process, the processing method for the static Link Library of Sina Weibo SDK is as follows: we just split libWeiboSDK. a's process is similar:
- Set libweibo SDK. a Based on the current platform architecture (simulator or real machine device) to reduce the size of the static library, decompress the package, and link the used object files to the project. The crash problem we encounter is that the link of the used object files is used to enter the project.
The developer website of Apple has an article to address this issue. Let's refer to the content:
The dynamic nature of Objective-C complicates things slightly. Because the code that implements a method is not determined until the method is actually called,
This sentence explains that Objective-C has runtime, and the code to be executed by a method is determined at runtime, rather than at link. If you want to learn more about Objective-C runtime, please refer to the following link:
Objective-C does not define linker symbols for methods. Linker symbols are only defined for classes.
In Objective-C, the execution of a method is only determined at runtime. Therefore, when linking, the linker only links the Class symbol and does not link the method symbol.
For example, if main. m parameters des the code [[FooClass alloc] initWithBar: nil]; then main. o will contain an undefined symbol for FooClass, but no linker symbols for the-initWithBar: method will be in main. o
Finally, an example is given: when you are in main. the m file initializes an object of the FooClass class, and then calls an object method initWithBar of the FooClass class. main. o object file, the object file does not have the defined symbol FooClass, so it will go to other. o search for the definition of the FooClass symbol in the object file. As for the definition of the method symbol initWithBar, the linker does not care about it, because the execution of initWithBar is the responsibility of the runtime, And the linker does not care.
Now the problem is coming. Let's repeat this sentence:
1 |
The execution of methods in Objective-C is determined by the actual running time. Therefore, the linker only links the symbols of classes and does not link the symbols of methods. |
Let's look back at the crash error message:
1 |
[_ NSDictionaryM weibosdk_WBSDKJSONString]: unrecognized selector sent to instance 0x170255780 |
The cause of the crash is that the definition of this method is not found when the weibosdk_WBSDKJSONString method of the _ NSDictionaryM class object is called at runtime. It is not hard to see that _ NSDictionaryM is a class in the Foundation Framework, and weibosdk_WBSDKJSONString is a method defined by Sina Weibo SDK. Sina uses the classification technology to expand the behavior of the _ NSDictionaryM class. Let's verify this:
We have decompressed all. o object files in libWeiboSDK. a. We use the nm command to export the symbols in all object files:
1 |
Nm *. o> libWeiboSDK.symbols.txt |
Then, open libweibosdk.symbols.txt with a personal editor to search for weibosdk_WBSDKJSONString. We can find the following results:
1 2 3 4 |
WBSDKJSONKit. o: 20177ba0 t-[NSArray (arrays) encoding] 4107de8 t-[NSDictionary (WBSDKJSONKitSerializing) encoding] 10979cd t-[NSString (WBSDKJSONKitSerializing) encoding] |
This shows that the Sina Weibo SDK actually uses the classification technology to extend the class behavior under the three Foundation frameworks: NSArray, NSDictionary, and NSString. Well, now we can see the truth:
- During the link, the linker finds that the WBSDKJSONKit. o object file lacks the class symbols NSArray, NSDictionary, and NSString. The linker finds the symbolic definition of the class from the Foundation Framework, and links the object files related to the Foundation Framework. Because the linker does not link the method symbol, therefore, the method symbols such as weibosdk_WBSDKJSONString are completely ignored. Because the definition of Class symbols is defined in the Foundation Farmework, The WBSDKJSONKit. o object file does not have a symbol to be referenced, and the linker does not link the object file. When running the weibosdk_WBSDKJSONString method, the WBSDKJSONKit defined by this method exists because this method does not exist in the Foundation Framework. o The object file is not linked by the linker, so it crashes. Why can the compilation option be added to solve the problem?
We will continue to reference the content in Apple's developer website's remarks on this issue:
Passing the-ObjC option to the linker causes it to load all members of static libraries that implement any Objective-C class or category. this will pickup any category method implementations. but it can make the resulting executable larger, and may pickup unnecessary objects. for this reason it is not on by default.
After the-ObjC option is added, the linker links all object files of the Objective-C class and category, and all method symbols are linked in after all links, the crash problem is solved naturally.
The-all_load option is more thorough. This option will allow the linker to link all object files. Of course, the cost is that the size of the constructed APP will increase.
Why can't the cocos2d-x be compiled with the compilation option?
In fact, the correct statement is that the compilation can be successful, and the linker returns an error. Let's review the error message of the linker after the-ObjC or-all_load link option is added:
1 2 3 4 5 6 7 8 |
Undefined symbols for architecture i386: "_ GCControllerDidConnectNotification", referenced from:-[GCControllerConnectionEventHandler observerConnection: disconnection:] in libcocos2dx iOS. a (CCController-iOS.o) "_ GCControllerDidDisconnectNotification", referenced from:-[GCControllerConnectionEventHandler observerConnection: disconnection:] in libcocos2dx iOS. a (CCController-iOS.o) "_ OBJC_CLASS _ $ _ GCController", referenced from: objc-class-ref in libcocos2dx iOS. a (CCController-iOS.o) (maybe you meant: _ OBJC_CLASS _ $ _ GCControllerConnectionEventHandler) |
According to the error information we can understand that the error is caused by a file named CCController-iOS.o object, and the source code corresponding to this file is CCController-iOS.mm, by reading the source code we found that, this file defines an Objective-C Class GCControllerConnectionEventHandler. The methods in this class reference the GCControllerDidConnectNotification and GCControllerDidDisconnectNotification classes, which are actually defined in the GameController Framework.
By default, the project generated by the cocos2d-x does not introduce the GameController Framework for us. Therefore, an error is reported because the linker cannot find the symbolic definition of the corresponding class during the link. If you go to Xcode> Target> Buid Phases> and add the GameController Framework to the Link Binary With Libraries item, the solution is not clean.
Correct posture
-Force_load path/to/your/libWeiboSDK. the a link option is actually the same as-ObjC and-all_load, but it is more targeted. It only allows the linker to link all the object files in your specified static Link Library, this is more refreshing.