Using C/C++ static libraries from iPhone ObjectiveC Apps - c++

Is it possible to have a C static library API, which uses C++ internally and hide this from users of the library?
I have writen a portable C++ library I wish to statically link to an iPhone application.
I have created an Xcode project using the Max OS X 'static library' template, and copied the source across, as well as writing a C wapper (to deal with exceptions) using (extern "C").
I am trying to use the generated library (.a file) in another Cocoa iPhone application.
Everything works well if the I use (.mm) extentions on the calling ObjectiveC file and (.cpp) on the implementation class in the library.
But I get unresolved symbols on linking when I try and change the wrapper file to a (.c) extention, even though all the wrapper function files are only C functions.
Just becuase C++ is used internally in a library, does it mean that externally it still must be treated as a C++ program. Is there not anyway to enforce this abstraction?
Edit: Thanks for the replies,
I had been using extern "C", I was just unsure about what configurations where needed in the calling project. ie. if the calling projected would require to know if it used C++ or could be ignorant and think its a purely C library.
It would seem I cannot, and I must use (.mm) files on my ObjectiveC classes.

It's too hard to do this in comments, so I'm just going to demonstrate for you quickly what the linking issues are that you're having. When Xcode encounters files, it uses build rules based on the suffix to decide which compiler to use. By default, gcc links the files to the standard C library, but does not link with the standard C++ library. Archive files (static libraries) have no linking resolution done at all. They are basically an archive of object files which need to be linked. Since you have no .mm or .cpp files in your project, g++ is never called and your files are never linked to the standard libraries. To correct this, just add the standard C++ libraries to your other linker flags in your Xcode project, or just simply add them to the pre-defined other flags option as -l (e.g., -lstdc++).
Here is a quick demonstration:
stw.h:
#ifdef __cplusplus
extern "C"
#endif
void show_the_world(void);
stw.cpp:
#include <iostream>
#include "stw.h"
using namespace std;
extern "C" void show_the_world() {
cout << "Hello, world!\n";
}
Build the library:
$ g++ -c stw.cpp -o stw.cpp -O0 -g
$ ar rcs stw.a stw.o
Using the library from a C application:
myapp.c:
#include "stw.h"
int main() {
show_the_world();
return 0;
}
Building the C application:
$ gcc -o myapp myapp.c stw.a -lstdc++ -g -O0
$ ./myapp
Hello, world!
$
If you try to compile without the -lstdc++ you will get all the unresolved issues because the C compiler has absolutely NO idea that it should link to the C++ runtime (and why would it, right!?!?) so you have to add this manually. The other option you have is to change the build rule for your project... instead of having Xcode use gcc to build .c and .m files, tell it to use g++ and your issues will be resolved.

You should declare the functions you want to be visible extern "C". Their signatures need to be C-compatible, but the contents do not (you may access C++ objects, for instance, but you cannot pass them directly; pointers are okay). The symbols will then be visible to any C-compatible environment.
EDIT: And compile it as a C++ source file, C doesn't have the notion of language linkage. There are a couple other gotchas with language linkage (like the fact that all extern "C" functions with the same name are the same function, regardless of namespace).
EDIT2: In the header, you can check for the macro __cplusplus, and use that to set for C++ and other languages, respectively (because C++ will require extern "C" declarations, and other languages will probably complain about them).

Basically when you compile the C functions with a C++ compiler it mangles the function names and uses the C++ ABI.
When you use the *.cpp or *.mm extension you are using the C++ compiler.
What you want to do is force the compiler to generate C functions with un-mangles names and using the C ABI.
You can do this by either:
Compile with the C compiler.
Compile with the C++ compiler but make sure that you prefix the function declarations with extern "C"
A favorite way to set up the header file, so that the same file can be included from both C and C++ source files is:
#ifndef HEADER_GUARD_1_H
#define HEADER_GUARD_1_H
#ifdef __cplusplus
extern "C" {
#endif
// Declare C function interface here.
int myFunc(int x,char*);
#ifdef __cplusplus
}
#endif
#endif

thanks, for such good discussion.
what I did is:
1) I created a static lib using cocaotouch static lib option. In that i have c/c++/obj-c all mix. however, my exports are only obj-c classes.
Infact i used objc- to c to C++.
2) then I creatd iphone app in X-code proj.
I added the otherlink flags my lib name ( -lxyz ) //my lib name is libxyz.a
I added lib search path, header search path
3) then I compiled. I got errors.
saying oeprator new, operator delete not found.
3) then apart my appdelegate, view controller, I added
dummy cpp(.h, .cpp)...
atestdummy.h atestdummy.cpp
4) then I build again...
thats it worked.
So - I whatever suggestions they gave earlier workedfor me.
basic reason, unless u r app sees a .cpp file .mm file with cpp code,
linked will not use g++.
Thanks all.
I have read the above and ssolved my problem.
u guys are good to share.

Related

Mixing C/C++ code yields "undefined symbol" with shared library

This problem has perplexed me for a week now so I thought it might finally be time to ask you guys for help. Here is the story in a nutshell:
We are developing an embedded server in-house using Qt/C++. It is a very simple server that processes client requests and loads the proper function through dlopen()/dlsym() calls to do something vendor specific. This means the vendor would simply provide us a .so file in C with their function (which is transparent to us) the way we define. This would be written in C because of a lot of low level things it would need to do, and our server is in Qt because we plan on eventually having a frontend for it.
Here is some pseudocode:
In our main.cpp file (this is written in C fashion but uses the g++ compiler as is defined in the Qt mkspec, compiled using -ldl and -rdynamic to export all symbols):
dlopen() vendor.so file (tried with both RTLD_NOW and RTLD_LAZY)
dlsym() vendor.so init() method (this will call the vendor's init method, which will set up the name/properties of this "vendor plugin" through setter methods inside our code, call this plugin_set_name(args...))
In the shared header file (shared.h) (both code bases would use this; ours would have complete definitions of the structs, vendors would simply have prototypes of setters/getters):
extern "C" int plugin_set_name(args...)
In the vendor main.c file (compiled using gcc, -fPIC, and -shared)
Implementation of init() function as mentioned above
So essentially, what is happening is that the C++ code will use the dl calls to load the init() function from the C .so library, and then the C .so library will call a function that is defined in the C++ code (in this case, plugin_set_name). Is this even possible? Neither is linked against each other since they are compiled independently of each other and with different compilers (gcc vs g++).
The error I am getting is on runtime: "undefined symbol: plugin_set_name" (so it finds and gets inside the library's init() method just fine). It works flawlessly when I use gcc and straight C code to do everything so I know it's not the code but something with mixing C/C++. I also understand the use of extern "C" to prevent name mangling and have used nm / readelf to determine that there is no mangling of any kind. Any ideas? What is the best way to go about this?
Somehow, this just magically works today. I can't explain it. I simply have extern "C" declarations around the shared header, so in shared.h:
#ifdef __cplusplus
extern "C" {
#endif
plugin_set_name(args...)
other_shared_functions
#ifdef __cplusplus
}
#endif
I've always had this however. In either case, it works now with vendor plugins being compiled in C and server being compiled in Qt and C++. I think the problem was a combination of where to place all the externs as well as g++ linking flags (where rdynamic is crucial). Thanks. Just putting this here in case anyone else runs into the same issue.

is extern "C" required in C files ? (to solve odd Eclipse behaviour)

I am relatively new to Mixed C/C++ applications using the gcc and g++ tools.
To get the hand of it I have downloaded the iperf source code and built it with success using Eclipse.
There is one oddity: If I look into the file "Thread.c" using Eclipse it thinks there is a syntax error and underlines almost the whole file as if the code is flawed, which it is absolutely not.
This is the piece of code that triggers it:
#ifdef __cplusplus
extern "C"
{
#endif
I know what extern "C" is used for in C++ but Eclipse has problems with it when present in .c files. It happily accepts it in .cpp and .h files though.
I have checked out how the Make utility builds the iperf application and I see it always uses gcc to compile c files and g++ to compile cpp files which makes me wonder if extern "C" is actually required. It most definitely does not hurt because the gcc compiler happily deals with it but if it is not strictly required I could omit it and get better readability in Eclipse.
I have also looked at a possible solution for Eclipse's behaviour but have not really found one, if anybody can point out how to solve it that would be equally good.
If you are using Eclipse, what you seeing in editor has to do with Eclipse internal indexer/parser. Your mixed C/C++ project may compile and build with no issues, but when you open a source file which has
#ifdef __cplusplus
extern "C" {
#endif
you may see a syntax error marked on the extern "C" line. This means that "__cplusplus" symbol is defined for your C compiler in your project settings.
In order to get rid of that syntax error in the Eclipse editor, go to project Properties -> C/C++ General -> Paths and Symbols -> # Symbols tab, and select "GNU C" (or whatever C compiler you use) under "Languages" column. Scroll through Symbol/Value list on the right, find the "__cplusplus" symbol and delete it. Make sure you do that only for C compiler.
Click OK to close the project Properties window and the syntax error warning will be gone in Eclipse editor.
that piece of code is normally found in headers, and should be always be written to header files that belong to c-files. (with the corresponding closing bracket at the end of the header)
reason is, that c uses a different scheme how the functions are internally called (--> name mangeling). while the compiler can distinguish a c++ code file from c code file by its extension it can not distinguish between a c-header and a c++ header that is included from a cpp file. so it does not know if it has to mangle the name of the declared functions or not (by default it does).
then the linker tries to match the used symbols (reference to function from cpp) with the created one (defined by the c-file) it does not find the symbol if the compiler was not told not to mangle the declaration.
extern "C" is only legal in C++ and ensures that the specified function(s) have C linkage. This means that the function parameters are not mangled into the binary function name.
To ensure that the header file compiles in C we include the #ifdef __cplusplus __cplusplus is defined by a C++ compiler and not a C compiler. This use used to protect C code from the C++ only extern "C" directive.
IDE's so not use compilers for code intelligence and therefore may get things wrong.
probably just a silly workaround for your issue.
what i found is that, while using c functions in cpp file, theoretically extern is required.
But i found that in eclipse oxygen version, we do not have to specify extern c, we can directly use c functions and printf statements too in cpp file and it just works fine.
Havent tried in older versions of eclipse.
My solution may not be very helpful, but you could give it a try. It worked for me.

Link a static library on a .cpp file

I'm trying to compile some code that use a function implemented in a static library named staticlib.a. I also have the header named staticlib.h which contain the declaration of that function. My main, that is contained in the main.c file wich include staticlib.h, only calls that function and no else. So I compile with
gcc main.c staticlib.a
and everything work fine. I need some feature of c++ but if I properly change main.c in main.cpp and compile same way
gcc main.cpp staticlib.a
an undefined reference to my function occured. How can I make this works? And why this problem occurred? I cannot really find an explanation in any site i visited...
Thank you for all trhe answers.
you have to define the function in the library as a 'C' function, not a C++ function - do this in your main.cpp
extern "C"
{
#include "staticlib.h"
}
C and C++ compile differently, C++ uses name mangling (embedding C++ type information in the object file). To stop this behaviour so that you can link to C code from C++, you can use the extern C syntax in C++ when including the C header file.
Please see here
http://www.cplusplus.com/forum/general/1143/

How do you compile C++ source code that includes C source file?

I'm attempting to use SQLite in a c++ program. My knowledge of C/C++ is limited as I've mostly used Java to this point. I had some classes in college but its been a while and we never covered anything like this. SQLite is written in C. When compiling the program how would you do this? (I have MinGW installed on my windows platform so gcc and g++ are what i use to compile.)
You protect the C headers in your C++ code by
extern "C" {
// your includes here
}
and that should be all---g++ should happily link code from both gcc and g++. The extern "C" ... trick is also used in C++ system headers and many libraries, just look at the headers that came with your g++ installation or some suitable Open Source projects. Here is a Boost example:
edd#max:~$ grep 'extern "C"' /usr/include/boost/date_time/*
/usr/include/boost/date_time/filetime_functions.hpp: extern "C" {
/usr/include/boost/date_time/filetime_functions.hpp: } // extern "C"
edd#max:~$
Edit: Thanks to delnan for an attentive comment---this is from the sqlite3.h header itself:
/*
** Make sure we can call this stuff from C++.
*/
#ifdef __cplusplus
extern "C" {
#endif
so this is of course already taken care of.
C++ achieves compatibility with C through the use of extern "C" declarations. There are some good explanations of what extern "C" means and why it is needed at this SO question: Why do we need extern ā€œCā€{ #include } in C++?. Virtually all C-based libraries, including sqlite, provide for automatic C++ compatibility by including extern "C" in their header files.
Therefore, SQLite will work without any special handling on your part (other than including the header and the library as you normally would for a C or a C++ library)...
/* my_sqlite_program.cpp */
#include <sqlite3.h>
int main()
{
...call sqlite functions...
}
compile with
g++ -Wall -Werror my_sqlite_program.cpp -lsqlite3 -o my_sqlite_program
For SQLite in specific, there's nothing really complicated about it.
If you're using a dynamic or static library, you just include their headers and link against the proper lib files.
If you're including SQLite fully inside your app, you'll need to include all the source files in your project and build them as well, and include the headers as needed (using it as a static/dynamic library might be nicer though).
If you need to use C code in files compiled as C++, Dirk's answer is correct, but that's not needed for SQLite.
How can you call C programs from C++ source code?
By using a facility called as linkage specification provided by the compilers. The specification tells the compiler how to link the source code.
Linkage specification is of the format
extern "Language_Type"
{
}
In your case you can wrap your SQLlite C functions like
extern "C"
{
//SQLite function declarations
}
This should enable you to get it working but Since you are trying to call SQlite c functions from C++, SQLite already provides some wrappers for achieving what you are trying to achieve. Check more details on SQLite website. Also, some open source projects also provide what you want. Check CppSQLite
Hope this helps!

How do I resolve link errors that appear in Objective-C++ but not Objective-C?

I'm converting my App Delegate file from .m to .mm (Objective-C to Objective-C++) so that I can access a third-party library written in Objective-C++. In Objective-C, my app delegate builds and runs fine. But when I change the extension, the project builds and I get link errors, all of which are missing symbols from a static library written in C that I use. The errors are classic link errors with the following format:
"MyFunction(arguments)", referenced from:
-[MyAppDelegate myMethod] in MyAppDelegate.o
Symbol(s) not found
All of the problems are in the app delegate object. I know that I'm all set to compile Objective-C++ because my ViewController file is .mm. So my question has a few parts to it.
First, are these symbols truly not there in the sense that I can't use them? In other words, is it not possible to access plain old C functions from an Objective-C++ file? If this is true, that's pretty unfortunate. I thought that almost all Objective-C code, and certainly all Objective-C code that at least builds as .mm, was valid Objective-C++. Am I wrong?
If not, any idea how I can prevent these errors? Are there header rules that are different in Objective-C++ that I don't know about?
Thanks for any and all help.
Link errors with mixed C++/C or C++/Objective-C programs are usually due to C++ name mangling. Make sure you have extern "C" attached to all the appropriate declarations, and also that all of your code agrees on the linkage. That is, make sure that the function definition as well as the places where it is used can all see the extern "C" or extern "C++".
In your particular situation, it looks like MyFunction() is getting compiled with C++ linkage and having its name mangled, but that your myMethod Objective-C file is trying to link against the unmangled name.
Here is a link to the wikipedia article about name mangling.
Surround your header include with extern C.
This tells the linker that the function names in the library do not get C++ name mangling.
E.g.:
extern "C" {
#include "my-lib.h"
}