Reimplimenting a DLL method variable with C++ in visual studio at ABI level - class

I have a third party DLL in C++ that I'd like to replace with one I've made myself...
This is a clean room type exercise just for learning purposes ; and I am hoping to make a replacement DLL that can be used with programs linked against the original DLL -- without recompiling the applications.
I am using the same visual studio compiler version (9) used to make the original DLL, but I do not have the original source code for the DLL.
The DLL consists of a C++ class, and some extern "C" functions to handle constructor/destructors, so that all memory management is isolated to the DLL.
I used dependency walker to inspect the original DLL, and demangle/undecorate the linker symbols -- and have attempted to write prototypes for the class and methods ; and then I wrote a python script to take the object code compiled from my class -- and make a .def file that chooses the closest mangled symbols from MY obj code compared against the original DLL exports; ( Allows some qualifier variations, but not name variations ) and then I build a DLL from my obj code using that .def file to have an identical ABI ordering in the DLL.
I am at the stage where dependency walker can not tell the difference between my DLL and the original when it comes to listing the types -- although there are small differences in several of the mangled names that I would like to resolve...
One member is very troublesome to figure out as it is not a function, but supposedly member data eg: a decorated ?pzSambaAddress#HWInterface##2PBDB shows up as:
char const * const HWInterface::pzSambaAddress ; // in dependency walker
And I'm not sure if dependency walker is decoding the mangling wrong or not, because
I can't figure out how to implement anything even remotely like this in my header file which would export a symbol to an .obj file, let alone to a DLL.
What kinds of definitions could create something like that?
If I type it in (as shown above) to my header file, it's a constant string -- therefore I'm thinking it has to be initialized in the constructor methods, something like this:
HWInterface::HWInterface(HWInterface const & iface) : pzSambaAddress("dummy") {
std :: cout << this -> pzSambaAddress; // access it, to force compiler
}
But when I compile that, pzSambaAddress, does not show up in the obj file at all.
Obviously because it's not an allocated memory location prior to class instantiation.
eg: dumpbin /SYMBOLS HWInterface.obj | grep "pzSam" finds nothing.
I could add the static keyword to the definition of pzSambaAddress and initialize it exactly once for the whole class.
char const * const HWInterface::pzSambaAddress="a samba name constant.";
The name then mangles to: ?pzSambaAddress#HWInterface##2QBDB
But dependency walker doesn't say it's static... Nor is mangled ##2QBDB quite ##2PBDB... and that will also mean that I can also no longer initialize individual instances with constructors.
HWInterface.cpp(25) : error C2438: 'pzSambaAddress' : cannot initialize static class data via constructor
So Q1: Is a static constant the cause of the exported symbol, and dependency walker just doesn't say "static" -- or are there other ways it could be generated / initialized ?
Secondly:
Is there anything better at demangling, and giving information on esoteric qualifiers?
When I run dumpbin on an object file, I get all kinds of qualifiers that dependency walker doesn't show (on other symbols, not the example we've been talking about).
dumpbin.exe /symbols myOwnFile.obj
But as I don't have the obj file for the original DLL, nor the .lib, that switch doesn't work. Running dumpbin.exe /symbols on the DLL gives me nothing.
Running dumpbin.exe /exports on the DLL merely gives me the mangled names.
There is also a VC++ console application "undname.exe", but often it doesn't undecorate the name passed on the command line at all, but gives most of the name back still mangled.
I looked around a lot on the web, but am finding only partially accurate/incomplete information, which wasn't enough to solve the problem I just showed.
Wikipedia on mangling names
Any ideas of where to find a more verbose/accurate demangler program for visual C++ ?

class HWInterface {
public:
__declspec(dllexport)
static char const * pzSambaAddress;
};
char const* HWInterface::pzSambaAddress = "hello";
Then:
C:\temp>cl /LD test.cpp
...
C:\temp>dumpbin /exports test.dll
...
Dump of file test.dll
...
ordinal hint RVA name
1 0 00008000 ?pzSambaAddress#HWInterface##2PBDB
You can use the undname utility included with MSVC to decode mangled names:
C:\temp>undname ?pzSambaAddress#HWInterface##2PBDB
Microsoft (R) C++ Name Undecorator
Copyright (C) Microsoft Corporation. All rights reserved.
Undecoration of :- "?pzSambaAddress#HWInterface##2PBDB"
is :- "public: static char const * const HWInterface::pzSambaAddress"
However, you'll note that undname says that there should be an extra const in there. As you saw, adding that extra const gets you a slightly different mangled name (with a 'Q' instead of a 'P' near the end:
Using static char const * const instead of static char const * produces ?pzSambaAddress#HWInterface##2QBDB
undname imports a function from the C runtime, _unDNameEx, that I assume is used to demangle names (and I assume that Dependency Walker uses it, too - apparently via an interface in DBGHELP.DLL). Looks like there's a bug in the demangler.
The GNU tools have a similar utility, c++filt, to decode g++ mangled names.

Related

C++ does not import class methods from DLL while importing functions works fine

I am trying to import a DLL to my program. I am using the __declspec( dllimport ) attribute. The problem is I get the linker error "LNK2019: unresolved external symbol ...". This question has already been around here several times. But my problem is different.
I believe I have all the things set up correctly (header provided, lib-file with the exports linked in ...). When I try call a classic function (with or without extern "C" block) from that DLL, all works fine. The problem are just the classes.
All the method are exported within the DLL - I verified this by using the Dependency Walker.
Can there be some mismatch between the mangled exported names and the ones the linker tries to find? Or some other naming based problem? It seems there is no similar problem documented over the internet.
EDIT
The dependency walker sees the method
?LoadFile#CTxtFileHelper##QAE_NPAVCWrapperFile##I#Z
which is unmangled
bool CTxtFileHelper::LoadFile(class CWrapperFile *,unsigned int)
while the linker is trying to load the
?LoadFile#CTxtFileHelper##QAE_NPAVCWrapperFile#io#mylib##I#Z
which represents according to linker error message
__declspec(dllimport) public: bool __thiscall CTxtFileHelper::LoadFile(class mylib::io::CWrapperFile *,unsigned int)
The only difference is the namespace. Can it be the problem?
Thanks

Reference collapsing under C++03

I need to create a predicate from bound member function, so I wrapped it in a boost::function<bool(SomeObject const &)>. That seems to be fine and everything, but I also needed to negate it in one case. However
boost::function<bool(SomeObject const &)> pred;
std::not1(pred);
does not compile under MSVC++ 9.0 (Visual Studio 2008), complaining that reference to reference is invalid:
C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\include\functional(213) : warning C4181: qualifier applied to reference type; ignored
C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\include\functional(213) : error C2529: '_Left' : reference to reference is illegal
The problem is that boost::function defines the argument_type as SomeObject const & and the std::unary_negate<_Fn1> instantiated by std::not1 internally tries to use const typename _Fn1::argument_type& and compiler rejects it because T::argument_type is already a reference. I am certain that that should compile under C++11, but this is old compiler that is C++03 only. So I'd like to know who's fault it is:
the compiler's, because it should collapse the reference (apparently not),
the standard library's, because it should be prepared to handle functors taking references (apparently not, because the specification defines unary_negate with const typename Predicate::argument_type& x argument),
boost's, because argument_type shouldn't be reference even when the actual argument is or
mine, because boost::function shouldn't be used with reference arguments?
The fault is certainly not Boost's; boost::function is basically just std::function, with all the same semantics. And boost::functions with reference parameters work fine, too. You just can't use them with std::not1 or the rest of the <functional> stuff.
C++11's reference-collapsing makes std::not1 work the way you would think it ought to. The way std::not1 was specified in C++03 couldn't possibly work without reference-collapsing — except in implementations where the implementors did a little bit of creative interpretation rather than slavishly following the letter of the Standard.
It's possible to make std::not1 work in C++03 by adding a specialization of std::unary_negate for predicates with reference argument_types, but neither libc++ nor libstdc++ has done so.
But you know who has? Boost! If you just change your code to use boost::not1 everywhere you currently use std::not1, everything will work fine. Basically, think of the boost namespace as if it were a C++11-compliant version of std; anything that works in C++11's std namespace probably works in C++03's boost namespace.
Caveat, hopefully off-topic: The Clang compiler on my Macbook (Apple LLVM version 4.2 (clang-425.0.28) (based on LLVM 3.2svn)) silently collapses references even in -std=c++03 mode, so that
typedef const int& ref;
typedef const ref& ref2;
produces no error. When you test your C++03 code, make sure you're not using a compiler with this misfeature.

How do you call a C function from C++ code in the iPhone?

I added the line extern "C" void perlinTest(void); to a C++ header along with the include of the c header file hoping that was all I needed but the compiler complains:
Undefined symbols for architecture i386:
"perlinTest()", referenced from:
CreateRenderer3(IResourceManager*) in Renderer.o
Your C++ code needs to be aware that the function is a C function. To do so, you need to declare it this way:
extern "C" [prototype];
A realistic example for your situation would be:
extern "C" void perlinTest();
The reason for this is that C++ function names are mangled to something that tells about the types of the parameters. At the lowest level, this is what allows overloading: it never really is legal to have two visible symbols that share the same name, so C++ allows them by embedding markers that indicate the types of the parameters in the function names. For instance, void perlinTest() gets mangled as _Z10perlinTestv on my Lion box with g++ (and probably clang++), though this is ABI-specific and will not necessarily be the same on other platforms.
However, C doesn't support overloading, and functions aren't subject to name mangling, so when your C++ code tries to call one, it needs to know that it must not use a mangled name. This is what extern "C" tells the compiler.
If your header files need to be readable from both C and C++, the common practice is to wrap them in an extern "C" block (extern "C" { /* declarations */ }) itself wrapped in an #ifdef __cplusplus preprocessor directive (so the C code doesn't see the extern "C" code).
#ifdef __cplusplus
extern "C" {
#endif
/* header body */
#ifdef __cplusplus
}
#endif
If it is not a library, you do not need any extern C. Iwould be turning to the .c file extensions and how your compiler is configured to recognize it (looks like not as .c code)
Have you actually implemented void perlinTest(void) anywhere?
Initially, you'll likely be able to merely declare the function without actually having to implement it. If none of your other classes/objects actually call perlinTest(), Xcode will gladly build and run your app, and not issue any errors. Since perlinTest() isn't actually referenced from anywhere, it doesn't care that the function isn't actually implemented.
As soon as you attempt to call perlinTest() from one of your other classes (like from CreateRenderer3(IResourceManager*) in Renderer.o), the linker will want to make sure that symbol can be resolved, and if you haven't actually implemented a barebones definition of it (see below), then you'll likely get an error like the one you got.
A minimal implementation like the following should prevent the linking error:
void perlinTest(void) {
}
One trick you can use to debug this is to introduce an intentional error in your perlinTest() function. Then build your app and see if the compiler reports the error. If the app compiles anyway, then your problem is that the file that has this function is not part of the target you are building.
Also note that the error that you pasted is for a i386 architecture, so it can't be iPhone. You are probably building for the iPhone simulator instead.
Edit: next step would be to check that the link command issued by Xcode includes the .o that has the C function. If it does, then you should dump the contents of the .o file with the nm utility, to see what the function name looks like in the .o.

Need clarification on what's going on when linking libraries in iOS

This is probably a totally noob question but I have missing links in my mind when thinking about linking libraries in iOS. I usually just add a new library that's been cross compiled and set the build and linker paths without really know what I'm doing. I'm hoping someone can help me fill in some gaps.
Let's take the OpenCV library for instance. I have this totally working btw because of a really well written tutorial( http://niw.at/articles/2009/03/14/using-opencv-on-iphone/en ), but I'm just wanting to know what is exactly going on.
What I'm thinking is happening is that when I build OpenCV for iOS is that your creating object code that gets placed in the .a files. This object code is just the implementation files( .m ) compiled. One reason you would want to do this is to make it hard to see the source code and so that you don't have to compile that source code every time.
The .h files won't be put in the library ( .a ). You include the .h in your source files and these header files communicate with the object code library ( .a ) in some way.
You also have to include the header files for your library in the Build Path and the Library itself in the Linker Path.
So, is the way I view linking libraries correct? If , not can someone correct me on this ?
Basically, you are correct.
Compiling the source code of a library produces one object file for each of the source files (in more than one, if compiled multiply times against different architectures). Then all the object files are archived (or packaged) into one .a file (or .lib on Windows). The code is not yet linked at this stage.
The .h files provide an interface for the functionality exposed by the library. They contain constants, function prototypes, possibly global declarations (e.g. extern int bad_global;), etc. -- basically, everything that is required to compile the code which is using the library.
.h files do not 'communicate' with object code in any way. They simply provide clues for the compiler. Consider this header file:
// library.h
extern int bad_global;
int public_func(int, const void*);
By including this file in your own code, you're simply telling the compiler to copy and paste these declarations into your source file. You could have written declarations for OpenCV library and not use the headers provided with it. In other words, you're asking the compiler to not issue errors about undefined symbols, saying "I have those symbols elsewhere, ok? Here are their declarations, now leave me alone!".
The header files need to be included in the search path in order for compiler to find them. You could simply include them via the full path, e.g. #include "path/to/file.h", or supply an -I option for your compiler, telling him where to look for additional headers, and use #include <file.h> instead.
When your code is compiled, the declarations in header files serve as an indication that symbols your code is using are defined somewhere. Note the difference between the words declaration and definition. Header files contain only declarations most of the time.
Now, when your code is compiled, it must be linked in order to produce the final executable. This is where the actual object code stored in the library comes into play. The linker will look at each symbol, function call, etc. in your object code and then try to find the corresponding definition for each such symbol. If it doesn't find one in the object code of your program, it will look the standard library and any other library you've provided it with.
Thus, it is important to understand that compilation and linkage are two separate stages. You could write any function prototypes at all and use them in your code, it will compile cleanly. However, when it comes to the linking stage, you have to provide implementation for symbols used in your code, or you won't get your executable.
Hope that makes sense!
The .a is the compiled version of the code.
The header files provided with a library are its public interface. They show what classes, methods, properties are available. They do not "communicate" with the binary code.
The compiler needs the headers to know that a symbol (a method name for example) is defined somewhere else. They are associated with the right "piece of code" in the library binary later during the "link" step.

Objective-C categories in static library

Can you guide me how to properly link static library to iPhone project. I use static library project added to app project as direct dependency (target -> general -> direct dependencies) and all works OK, but categories. A category defined in static library is not working in app.
So my question is how to add static library with some categories into other project?
And in general, what is best practice to use in app project code from other projects?
Solution: As of Xcode 4.2, you only need to go to the application that is linking against the library (not the library itself) and click the project in the Project Navigator, click your app's target, then build settings, then search for "Other Linker Flags", click the + button, and add '-ObjC'. '-all_load' and '-force_load' are no longer needed.
Details:
I found some answers on various forums, blogs and apple docs. Now I try make short summary of my searches and experiments.
Problem was caused by (citation from apple Technical Q&A QA1490 https://developer.apple.com/library/content/qa/qa1490/_index.html):
Objective-C does not define linker
symbols for each function (or method,
in Objective-C) - instead, linker
symbols are only generated for each
class. If you extend a pre-existing
class with categories, the linker does
not know to associate the object code
of the core class implementation and
the category implementation. This
prevents objects created in the
resulting application from responding
to a selector that is defined in the
category.
And their solution:
To resolve this issue, the static
library should pass the -ObjC option
to the linker. This flag causes the
linker to load every object file in
the library that defines an
Objective-C class or category. While
this option will typically result in a
larger executable (due to additional
object code loaded into the
application), it will allow the
successful creation of effective
Objective-C static libraries that
contain categories on existing
classes.
and there is also recommendation in iPhone Development FAQ:
How do I link all the Objective-C
classes in a static library? Set the
Other Linker Flags build setting to
-ObjC.
and flags descriptions:
-all_load Loads all members of static archive libraries.
-ObjC Loads all members of static archive libraries that implement an
Objective-C class or category.
-force_load (path_to_archive) Loads all members of the specified static
archive library. Note: -all_load
forces all members of all archives to
be loaded. This option allows you to
target a specific archive.
*we can use force_load to reduce app binary size and to avoid conflicts which all_load can cause in some cases.
Yes, it works with *.a files added to the project.
Yet I had troubles with lib project added as direct dependency. But later I found that it was my fault - direct dependency project possibly was not added properly. When I remove it and add again with steps:
Drag&drop lib project file in app project (or add it with Project->Add to project…).
Click on arrow at lib project icon - mylib.a file name shown, drag this mylib.a file and drop it into Target -> Link Binary With Library group.
Open target info in fist page (General) and add my lib to dependencies list
after that all works OK. "-ObjC" flag was enough in my case.
I also was interested with idea from http://iphonedevelopmentexperiences.blogspot.com/2010/03/categories-in-static-library.html blog. Author say he can use category from lib without setting -all_load or -ObjC flag. He just add to category h/m files empty dummy class interface/implementation to force linker use this file. And yes, this trick do the job.
But author also said he even not instantiated dummy object. Mm… As I've found we should explicitly call some "real" code from category file. So at least class function should be called.
And we even need not dummy class. Single c function do the same.
So if we write lib files as:
// mylib.h
void useMyLib();
#interface NSObject (Logger)
-(void)logSelf;
#end
// mylib.m
void useMyLib(){
NSLog(#"do nothing, just for make mylib linked");
}
#implementation NSObject (Logger)
-(void)logSelf{
NSLog(#"self is:%#", [self description]);
}
#end
and if we call useMyLib(); anywhere in App project
then in any class we can use logSelf category method;
[self logSelf];
And more blogs on theme:
http://t-machine.org/index.php/2009/10/13/how-to-make-an-iphone-static-library-part-1/
http://blog.costan.us/2009/12/fat-iphone-static-libraries-device-and.html
The answer from Vladimir is actually pretty good, however, I'd like to give some more background knowledge here. Maybe one day somebody finds my reply and may find it helpful.
The compiler transforms source files (.c, .cc, .cpp, .m) into object files (.o). There is one object file per source file. Object files contain symbols, code and data. Object files are not directly usable by the operating system.
Now when building a dynamic library (.dylib), a framework, a loadable bundle (.bundle) or an executable binary, these object files are linked together by the linker to produce something the operating system considers "usable", e.g. something it can directly load to a specific memory address.
However when building a static library, all these object files are simply added to a big archive file, hence the extension of static libraries (.a for archive). So an .a file is nothing than an archive of object (.o) files. Think of a TAR archive or a ZIP archive without compression. It's just easier to copy a single .a file around than a whole bunch of .o files (similar to Java, where you pack .class files into a .jar archive for easy distribution).
When linking a binary to a static library (= archive), the linker will get a table of all symbols in the archive and check which of these symbols are referenced by the binaries. Only the object files containing referenced symbols are actually loaded by the linker and are considered by the linking process. E.g. if your archive has 50 object files, but only 20 contain symbols used by the binary, only those 20 are loaded by the linker, the other 30 are entirely ignored in the linking process.
This works quite well for C and C++ code, as these languages try to do as much as possible at compile time (though C++ also has some runtime-only features). Obj-C, however, is a different kind of language. Obj-C heavily depends on runtime features and many Obj-C features are actually runtime-only features. Obj-C classes actually have symbols comparable to C functions or global C variables (at least in current Obj-C runtime). A linker can see if a class is referenced or not, so it can determine a class being in use or not. If you use a class from an object file in a static library, this object file will be loaded by the linker because the linker sees a symbol being in use. Categories are a runtime-only feature, categories aren't symbols like classes or functions and that also means a linker cannot determine if a category is in use or not.
If the linker loads an object file containing Obj-C code, all Obj-C parts of it are always part of the linking stage. So if an object file containing categories is loaded because any symbol from it is considered "in use" (be it a class, be it a function, be it a global variable), the categories are loaded as well and will be available at runtime. Yet if the object file itself is not loaded, the categories in it will not be available at runtime. An object file containing only categories is never loaded because it contains no symbols the linker would ever consider "in use". And this is the whole problem here.
Several solutions have been proposed and now that you know how all this plays together, let's have another look on the proposed solution:
One solution is to add -all_load to the linker call. What will that linker flag actually do? Actually it tells the linker the following "Load all object files of all archives regardless if you see any symbol in use or not'. Of course, that will work; but it may also produce rather big binaries.
Another solution is to add -force_load to the linker call including the path to the archive. This flag works exactly like -all_load, but only for the specified archive. Of course this will work as well.
The most popular solution is to add -ObjC to the linker call. What will that linker flag actually do? This flag tells the linker "Load all object files from all archives if you see that they contain any Obj-C code". And "any Obj-C code" includes categories. This will work as well and it will not force loading of object files containing no Obj-C code (these are still only loaded on demand).
Another solution is the rather new Xcode build setting Perform Single-Object Prelink. What will this setting do? If enabled, all the object files (remember, there is one per source file) are merged together into a single object file (that is not real linking, hence the name PreLink) and this single object file (sometimes also called a "master object file") is then added to the archive. If now any symbol of the master object file is considered in use, the whole master object file is considered in use and thus all Objective-C parts of it are always loaded. And since classes are normal symbols, it's enough to use a single class from such a static library to also get all the categories.
The final solution is the trick Vladimir added at the very end of his answer. Place a "fake symbol" into any source file declaring only categories. If you want to use any of the categories at runtime, make sure you somehow reference the fake symbol at compile time, as this causes the object file to be loaded by the linker and thus also all Obj-C code in it. E.g. it could be a function with an empty function body (which will do nothing when being called) or it could be a global variable accessed (e.g. a global int once read or once written, this is sufficient). Unlike all other solutions above, this solution shifts control about which categories are available at runtime to the compiled code (if it wants them to be linked and available, it accesses the symbol, otherwise it doesn't access the symbol and the linker will ignore it).
That's all folks.
Oh, wait, there's one more thing:
The linker has an option named -dead_strip. What does this option do? If the linker decided to load an object file, all symbols of the object file become part of the linked binary, whether they are used or not. E.g. an object file contains 100 functions, but only one of them is used by the binary, all 100 functions are still added to the binary because object files are either added as a whole or they are not added at all. Adding an object file partially is usually not supported by linkers.
However, if you tell the linker to "dead strip", the linker will first add all the object files to the binary, resolve all the references and finally scan the binary for symbols not in use (or only in use by other symbols not in use). All the symbols found to be not in use are then removed as part of the optimization stage. In the example above, the 99 unused functions are removed again. This is very useful if you use options like -load_all, -force_load or Perform Single-Object Prelink because these options can easily blow up binary sizes dramatically in some cases and the dead stripping will remove unused code and data again.
Dead stripping works very well for C code (e.g. unused functions, variables and constants are removed as expected) and it also works quite good for C++ (e.g. unused classes are removed). It is not perfect, in some cases some symbols are not removed even though it would be okay to remove them, but in most cases it works quite well for these languages.
What about Obj-C? Forget about it! There is no dead stripping for Obj-C. As Obj-C is a runtime-feature language, the compiler cannot say at compile time whether a symbol is really in use or not. E.g. an Obj-C class is not in use if there is no code directly referencing it, correct? Wrong! You can dynamically build a string containing a class name, request a class pointer for that name and dynamically allocate the class. E.g. instead of
MyCoolClass * mcc = [[MyCoolClass alloc] init];
I could also write
NSString * cname = #"CoolClass";
NSString * cnameFull = [NSString stringWithFormat:#"My%#", cname];
Class mmcClass = NSClassFromString(cnameFull);
id mmc = [[mmcClass alloc] init];
In both cases mmc is a reference to an object of the class "MyCoolClass", but there is no direct reference to this class in the second code sample (not even the class name as a static string). Everything happens only at runtime. And that's even though classes are actually real symbols. It's even worse for categories, as they are not even real symbols.
So if you have a static library with hundreds of objects, yet most of your binaries only need a few of them, you may prefer not to use the solutions (1) to (4) above. Otherwise you end up with very big binaries containing all these classes, even though most of them are never used. For classes you usually don't need any special solution at all since classes have real symbols and as long as you reference them directly (not as in the second code sample), the linker will identify their usage pretty well on its own. For categories, though, consider solution (5), as it makes it possible to only include the categories you really need.
E.g. if you want a category for NSData, e.g. adding a compression/decompression method to it, you'd create a header file:
// NSData+Compress.h
#interface NSData (Compression)
- (NSData *)compressedData;
- (NSData *)decompressedData;
#end
void import_NSData_Compression ( );
and an implementation file
// NSData+Compress
#implementation NSData (Compression)
- (NSData *)compressedData
{
// ... magic ...
}
- (NSData *)decompressedData
{
// ... magic ...
}
#end
void import_NSData_Compression ( ) { }
Now just make sure that anywhere in your code import_NSData_Compression() is called. It doesn't matter where it is called or how often it is called. Actually it doesn't really have to be called at all, it's enough if the linker thinks so. E.g. you could put the following code anywhere in your project:
__attribute__((used)) static void importCategories ()
{
import_NSData_Compression();
// add more import calls here
}
You don't have to ever call importCategories() in your code, the attribute will make the compiler and linker believe that it is called, even in case it is not.
And a final tip:
If you add -whyload to the final link call, the linker will print in the build log which object file from which library it did load because of which symbol in use. It will only print the first symbol considered in use, but that is not necessarily the only symbol in use of that object file.
This issue has been fixed in LLVM. The fix ships as part of LLVM 2.9 The first Xcode version to contain the fix is Xcode 4.2 shipping with LLVM 3.0. The usage of -all_load or -force_load is no longer needed when working with XCode 4.2 -ObjC is still needed.
Here's what you need to do to resolve this problem completely when compiling your static library:
Either go to Xcode Build Settings and set Perform Single-Object Prelink to YES or
GENERATE_MASTER_OBJECT_FILE = YES in your build configuration file.
By default,the linker generates an .o file for each .m file. So categories gets different .o files. When the linker looks at a static library .o files, it doesn't create an index of all symbols per class (Runtime will, doesn't matter what).
This directive will ask the linker to pack all objects together into one big .o file and by this it forces the linker that process the static library to get index all class categories.
Hope that clarifies it.
One factor that is rarely mentioned whenever the static library linking discussion comes up is the fact that you must also include the categories themselves in the build phases->copy files and compile sources of the static library itself.
Apple also doesn't emphasize this fact in their recently published Using Static Libraries in iOS either.
I spent a whole day trying all sorts of variations of -objC and -all_load etc.. but nothing came out of it.. this question brought that issue to my attention. (don't get me wrong.. you still have to do the -objC stuff.. but it's more than just that).
also another action that has always helped me is that I always build the included static library first on its own.. then i build the enclosing application..
You probably need to have the category in you're static library's "public" header: #import "MyStaticLib.h"