IOS Platform Cocos2d-x Project access to Sina Weibo SDK pit
Recently in an IOS Cocos2d-x project to access the Sina Weibo SDK when the "pit", and finally successfully resolved. Found that many people on the Internet have encountered the same problem, but can find a limited number of solutions written in detail, it is difficult to understand, I would like to write in depth.
My development environment
Problems encountered
Following the documentation Access project included with the Sina Weibo SDK, a crash occurred while invoking the registration method when the emulator was running the project. Registration Method Code:
1 |
[WeiboSDK registerApp: @"xxxxxxxx"];
|
The crash information is printed as follows:
1 |
[__NSDictionaryM weibosdk_WBSDKJSONString] : unrecognized selector sent to instance 0x170255780
|
Resolve problems encountered by the obstacles
There is a note in the documentation included with the Sina Weibo SDK:
After a static library is introduced into the project, you need to add the –OBJC compilation option at compile time to avoid a program crash due to incomplete class loading in the static library. Method: Program Target->buid settings->linking under other Linker Flags item added-OBJC
People who have encountered the same crash on the web have mentioned that adding compilation options at compile time -all_load
can also solve the problem. The method is also added under Target->buid settings->linking other Linker Flags item -all_load
.
Coincidentally, when I opened the Demo project that came with the Sina Weibo SDK, I found that the compilation options for this project were also -all_load
not prompted -ObjC
by its own documentation. And in the same development environment, my cocos2d-x project will crash, but the Sina Weibo SDK comes with the Demo can work properly, presumably the two solutions should be positive solution
However, after adding the compile option to your Cocos2d-x project, an error occurred while compiling the run again, with the following error message:
12345678 |
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)
|
Both the set- -ObjC
up -all_load
and compile-time failures will report link errors that cannot be found for the symbol above.
The right solution
Here's the right solution to talk about why. The right thing to do is to set the other Linker Flags as a compile option, -ObjC
but -all_load
not to use, but to -force_load path/to/your/libWeiboSDK.a
use, followed by the Sina Weibo SDK The exact location of the static link library.
Why is all this? From the compile link.
Here is not going to be too much about compiling links related to just, but strongly recommend a book "self-cultivation of programmers", you may be worried about this is a book with no "serious" content, at least when I first saw the title, that's what I thought, but I was wrong, the subtitle of the book is a link , loading and libraries . Believe me, after reading this book n times you will have a very thorough understanding of the principles and processes of the program from source code compilation to the generation binaries, and more importantly, you will rise several levels after reading the book n Times.
To get to the bottom, a project's source code eventually becomes a binary executable, a dynamic link library, or a static link library that goes through several processes:
1 |
源代码 ==[编译器]==》 汇编码 ==[汇编器]==》 对象文件 ==[链接器]==》 可执行程序、动态链接库或静态链接库
|
What's the sign, anyway?
Popularly speaking, we write in the source code, 全局变量名
函数名
or 类名
in the generated *.o
object files are called symbols, there is a place called 符号表
.
For example: We a.c
wrote a function called in the file, foo()
and then main.c
called the function in the file, the source code compiled in the object file in the object file in foo()
a.o
the symbol table holds the foo()
function symbol, and through the symbol can be positioned to a.o
foo()
The specific implementation code for the method in the file.
The linker will find that the symbol is referenced in the object file when it is delivered to the final binary, and the symbol main.o
foo()
foo()
is not defined in the main.o
file, so there is no main.o
symbol table with the object file, so the linker begins to examine the other object files. When a.o
a symbol is defined in the file foo()
, the a.o
object file is linked in. This ensures that the main.c
method implemented in the normal call can be made in a.c
foo()
.
LIBWEIBOSDK.A what is in the static link library?
Unix Static link library Nothing mysterious, it is a compressed package , peace is more common zip or rar, such as the compression package, but others are using a compression tool called AR compression. So let's unzip it and see what's inside it. Since it is used AR compression, extract the natural also need to use AR this tool. Execute at the command line:
The result is an error:
12 |
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
|
Let's explain why it's so fat (fat). In IOS development we all know that we can test our projects with simulators and real machines, but the architecture of these two platforms is different, the simulator is I386 x86_64 architecture, and our device is ARMV7 arm64 architecture. When making a static link library, we also make two static link libraries for the real machine and simulator for different architectures, and when we want to use the static link library in our own project, if we run the static library version for the simulator on the emulator, It is very troublesome to switch to a static link library for a real machine when testing with a real machine device.
As I said before, the static link library is a compressed package , so we can compress the two static link libraries into a static link library so that we can support both the simulator and the two architectures of the real machine device? The answer is yes. For example, we have two schema versions of the static link library on hand: libXXX.i386_x86_64.a
and libXXX.armv7_arm64.a
, we can generate a unified static link library by the following command:
1 |
lipo -create libXXX.i386_x86_64.a libXXX.armv7_arm64.a -output libXXX.a
|
This gives us a unified version of the static library, which has libXXX.a
the advantage of supporting both the emulator architecture and the real machine architecture, with the drawback that it's getting bigger, which means it's fat.
And libWeiboSDK.a
It is such a static library, we can still use the command to verify this:
1 |
lipo -info libWeiboSDK.a
|
This command will output:
1 |
Architectures in the fat file: libWeiboSDK.a are: armv7 arm64 i386 x86_64
|
Since it's a fat man, we'll have to thin it before we can decompress it. Let's just pull out a static link library of the schema from the inside, the Slimming command is:
1 |
lipo -thin i386 libWeiboSDK.a -output libWeiboSDK.i386.a
|
This allows us to pull out the static link library for the Sina Weibo SDK for the i386 platform, and we call it libWeiboSDK.i386.a
, and now we use the ar
command to extract it and see what's inside.
After the decompression is done you will see a lot .o
of end of the object file, memory recall just we talked about the compilation link process, these object files are to 链接器
the final generation of static link library used in the file, because too much, I only list the few we want to talk about:
123456789 |
-rw-r--r-- 1 leenjewel staff 13K Jan 8 15:47 NSData+WBSDKBase64.o-rw-r--r-- 1 leenjewel staff 42K Jan 8 15:47 UIImage+WBSDKResize.o-rw-r--r-- 1 leenjewel staff 12K Jan 8 15:47 UIImage+WBSDKStretch.o-rw-r--r-- 1 leenjewel staff 74K Jan 8 15:47 UIView+WBSDKSizes.o-rw-r--r-- 1 leenjewel staff 58K Jan 8 15:47 WBAidManager.o-rw-r--r-- 1 leenjewel staff 15K Jan 8 15:47 WBAuthorizeRequest.o-rw-r--r-- 1 leenjewel staff 16K Jan 8 15:47 WBAuthorizeResponse.o-rw-r--r-- 1 leenjewel staff 19K Jan 8 15:47 WBBaseMediaObject.o-rw-r--r-- 1 leenjewel staff 265K Jan 8 15:47 WBSDKJSONKit.o
|
Why does it crash in the run?
When we introduce the static link library of the Sina Weibo SDK into our own project, and build our own project to run on the simulator or the real machine, it is also a process of compiling the link, and finally build the APP from the project build that can run on the emulator or the real machine, and in the process of Sina Weibo The static link library of the SDK is handled in the same way as the process we just opened up libWeiboSDK.a
:
LIBWEIBSDK.A based on the platform architecture currently being built (simulator or real device)
Extract the thin static library and unpack the package
Use the object file link to enter the project
And the crash problem that we're having is just the 将用到的对象文件链接进入项目
one step.
Apple's developer site has a description of the issue, so let's quote the content:
The dynamic nature of objective-c complicates things slightly. Because the code that implements a method was not determined until the method is actually called,
This statement explains that Objective-c is run-time (runtime), and that a method executes what code is determined at run time, not at the time of the link. To learn more about OBJECTIVE-C runtime knowledge, you can look at this
OBJECTIVE-C does not define linker symbols for methods. Linker symbols is only defined for classes.
Because in objective-c, the execution of a method is determined at run time, so when linking, the linker only links the symbol of the class and does not link the symbol of the method.
For example, if MAIN.M includes the code [[Fooclass alloc] initwithbar:nil]; Then MAIN.O would contain an undefined symbol for FOOCLASS, but no linker symbols for The-initwithbar:method would be is in M ain.o
Finally, an example is given: when you main.m
initialize a class object in a file, FooClass
and then call FooClass
an object method of the class, when the initWithBar
linker parses the main.m
object file generated by the compilation main.o
, it finds that the object file does not have a symbol FooClass
defined So we go to other .o
object files to find FooClass
the definition of the symbol, and the definition of the method symbol initWithBar
where the linker is not concerned, because initWithBar
the execution is the responsibility of the runtime, the linker regardless.
Well, now that's the problem, let's repeat this:
1 |
Objective-C 中方法的执行实在运行时决定的,所以链接器只链接类的符号,不链接方法的符号
|
Let's look back at the crash error message:
1 |
[__NSDictionaryM weibosdk_WBSDKJSONString] : unrecognized selector sent to instance 0x170255780
|
This indicates that the reason for the crash is that the method __NSDictionaryM
weibosdk_WBSDKJSONString
's definition was not found when invoking the method of the class object at run time. It is not difficult to see the __NSDictionaryM
Foundation Framework
class is in, and the method weibosdk_WBSDKJSONString
is the Sina Weibo SDK own definition of the method, Sina here using the classification technology to expand the __NSDictionaryM
behavior of the class. Let's verify this:
We have extracted libWeiboSDK.a
all the .o
object files in, and we use nm
the command to export the symbols in all the object files:
1 |
nm *.o >> libWeiboSDK.symbols.txt
|
Then we use a text editor to open libWeiboSDK.symbols.txt
weibosdk_WBSDKJSONString
The search, we can find the following results:
1234 |
WBSDKJSONKit.o:00007ba0 t -[NSArray(WBSDKJSONKitSerializing) weibosdk_WBSDKJSONString]00007de8 t -[NSDictionary(WBSDKJSONKitSerializing) weibosdk_WBSDKJSONString]000079cd t -[NSString(WBSDKJSONKitSerializing) weibosdk_WBSDKJSONString]
|
This means that the Sina Weibo SDK does use classification techniques to extend the NSArray
NSDictionary
NSString
behavior of classes under the three Foundation Framework. OK, now it's time to reveal the truth:
When linking, the linker discovers that the WBSDKJSONKit.o
class symbol, and the, are missing from the object file NSArray
NSDictionary
NSString
.
The linker Foundation Framework
found the symbolic definition of the class from, which links the Foundation Framework
relevant object file in
Because the linker does not link method symbols, weibosdk_WBSDKJSONString
Such method symbols are completely ignored.
Because the definition of a class symbol is Foundation Farmework
defined in, WBSDKJSONKit.o
there is no symbol referenced in the object file, and the linker does not link the object file.
Runtime to the weibosdk_WBSDKJSONString
method, because there Foundation Framework
is no definition of the method, and the existence of the method definition of the WBSDKJSONKit.o
object file is not linked by the linker, so crashed.
Why is adding compilation options to solve the problem?
We continue to cite Apple's developer website for a description of this issue in the article:
Passing THE-OBJC option to the linker causes it-load all members of static libraries this implement any OBJECTIVE-C cl or category. This would pickup any category method implementations. But it can make the resulting executable larger, and may pickup unnecessary objects. For this reason it was not on by default.
After adding the -ObjC
option, regardless of whether or not it is referenced, the linker will link all the object files of Objective-c class and classification, all links after the method symbols are all linked in, the problem of collapse is solved naturally.
and -all_load
the option is more thorough, this option will let the linker to all the object files are linked in, of course, the price is to build the APP volume will become larger.
Why does the cocos2d-x compile option not compile and pass?
In fact, the accurate statement is that the compilation can be successful, the linker to perform the error. Let -ObjC
-all_load
's review the error message of the linker after adding or linking options:
12345678 |
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: (maybe meant: _objc_class_$_gccontrollerconnectioneventhandler) |
According to the error message we can learn that the error is CCController-iOS.o
caused by a named object file, and this file corresponds to the source code is CCController-iOS.mm
, through the reading source we found that the file defines a objective-c class GCControllerConnectionEventHandler
, the method in this class refers to GCControllerDidConnectNotification
and GCControllerDidDisconnectNotification
two classes, and these two classes are actually GameController Framework
defined.
The project generated by Cocos2d-x is not introduced to us by default GameController Framework
, so it will be error-free because the linker cannot find the symbolic definition of the corresponding class at the time of the link. If you go to Xcode->target->buid phases->, the Link Binary with Libraries adds to GameController Framework
solve the problem, but the solution is not clean .
The right Posture
-force_load path/to/your/libWeiboSDK.a
The link option is actually doing the -ObjC
-all_load
same thing, but it's more specific, it just lets the linker link all the object files in the static link library you specify, which is more refreshing.
I hope my explanation is deep enough.
:–)
IOS Platform Cocos2d-x Project access to Sina Weibo SDK pit