tags:

views:

6388

answers:

5

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.

A: 

Does this library run on iPhone?

If not, how could you link against it?

Friedrich
The library source is standard C++ and hence will run on an iPhone. The trouble I have is compiling the library and linking it statically.
Akusete
If you are refering to the reason I used the 'Max OS X' template, it is becuase I only saw application templates existing under the iPhone selection in Xcode.
Akusete
Akusete, are you declaring your functions as extern "C"? Also, even tho your library is statically linked, it may have unresolved symbols which link to the STL and the C++ runtime... you will have to tell the linker about this if it is expecting to link a C file...
Jason Coco
Yes, I am using STL quite heavily. Although I have replicated this problem using a dummy library with only a single empty C++ class.
Akusete
arg, akusete, it's because you are not linking to the C++ runtime... add this to your Xcode project under other flags: -lstdc++ ... remember, archive files are NOT pre-linked like shared libraries. G++ links to the C++ library automatically, GCC does not.
Jason Coco
+1  A: 

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).

coppro
Thanks, 'compile it as a C++ source file' means that I will still need a (.mm) Objective C file to use it right?'C doesn't have the notion of language linkage' I guess that means if I have C++ anywhere inside a library the whole thing has to be compiled as C++.
Akusete
+1  A: 

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
Martin York
Thanks, I understand the use of extern "C", the library currently works for C/C++/C#(using pinvoke), on win32 windowsCE and linux platforms.Im not sure however if I needed to use (.mm) in the objectiveC code if my interface was C.
Akusete
The .mm just forces it to use the C++ compiler rather than the C compiler. Objective C is just a wrapper ontop of these languages (I don't mean literally).
Martin York
thanks for the tips!
William Denniss
+7  A: 

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.

Jason Coco
Thanks for your help, my appologies for being irritating. I am somewhat ignorant of how the C++ runtime operates, and previously had always been using g++ or VC++.
Akusete
ah, you're not irritating at all :) just doing everything in 300 character comments was...
Jason Coco
This saved my bacon when bringing in the FMOD Libraries into my straight Objective-C project. Have to include the -lstdc++ to get rid of link errors.
Batgar
A: 

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.

Nareshkumar