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/
Related
I'm using a C library in my C++ project, which uses Cmake. In that project, I'm building a plugin from that library. During the development of the project, I used to add files like this to my plugin library in cmake:
add_library(plugin SHARED
impl.cpp
Interface.h
${LIBBTC_REPO}/src/base58.c
${LIBBTC_REPO}/src/bip32.c
${LIBBTC_REPO}/src/block.c
${LIBBTC_REPO}/src/ripemd160.c
...
)
And everything was going fine. But after using the function ripemd160(), my shared library started giving an undefined symbol error:
plugin.so: undefined symbol: _Z9ripemd160PKhjPh
When studying the contents of the plugin with nm -g plugin.so | grep -i ripe, I got:
000000000002e1cb T ripemd160
U _Z9ripemd160PKhjPh
which shows that the original C function is not mangled and is not available, but C++ is expecting a mangled function name. That I don't understand.
What surprises me is that I also call other functions in other files. For example the function utils_hex_to_bin(), but I don't get that undefined symbol error there.
Why is C++ expecting this function to specifically be mangled, while all other C functions not? Is there a better way to do what I'm doing? Am I linking this incorrectly?
Btw, that file, ripemd160.c is the only file in the library that has the header file beside it, instead of being in the include directory. I don't know if that makes a difference.
I also tried creating another module for that library in CMake, but that doesn't help.
Please advise.
EDIT:
Just to be clear, I never decalred any of the functions in the library. I just include headers from that library and that takes care of declarations. That's why I never mentioned extern "C".
Solved: Wrapping the include with extern "C" solved the problem. Apparently the library dev forgot to do that.
Try to declare the ripemd160() function with extern "C". Or you can do this simply by
extern "C" { #include "ripemd160.h" }
I am using an open source hydrodynamics code written in C. They have a lot of functions for reading and writing Input/Output parallely. I am writing a program to do post analysis of outputs in C++, and I want to use these functions in my code by including their header file. Problems such as printf etc are taken care of when I include the header file (a.h) within
extern "C" {
#include "a.h"
}.
But when I try to compile it an error shows up saying
/Src/Parallel/al_io.c:234:5: error: invalid conversion from ‘void*’ to ‘char*’ [-fpermissive]
a = (void *)va;
Which means it is not allowing this in spite of the extern keyword. Is this normal? If so is there another way to allow these functions to work. Editing each of them by hand is not possible as there are about thousands of them.
Thanks!!
Is this normal?
Yes. extern "C" changes the linkage. The program is still compiled as a C++ program.
In the implementation of a extern "C" function, you have access to all the features of C++. The flip side of it is that it is compiled just like a regular C++ function. All the syntactic constraints of a C++ program apply to such a function.
If so is there another way to allow these functions to work.
You can use static_cast<char*>(...).
/Src/Parallel/al_io.c:234:5: error: invalid conversion from
‘void*’ to ‘char*’ [-fpermissive] a = (void *)va;
You need to compile this third-party C library as C, not as C++.
As you have discovered, wrapping the third-party library's headers in extern "C" does not do that. (You do still need to do this, or the program as a whole will fail to link, but it doesn't fix your immediate problem.)
What does do that is using the correct "compiler driver" to compile each source file. You didn't tell us which compiler you're using, or anything at all about how you are building the program, so I can't be terribly specific about that, but: make sure you are using a program named something like "cc", "gcc", or "clang" to compile all files named whatever.c, not a program named something like "c++", "g++", "clang++". Compilers with "++" in their name should only be used to compile source files that actually contain C++ code.
When it comes time to link all the .o files together into a complete program, you will either need to use the compiler with "++" in its name to do that, or you will need to name the C++ runtime library explicitly on the command line (e.g. gcc foo.o bar.o baz.o -lstdc++). The name of the C++ runtime library can vary and can be difficult to discover, so I recommend the former approach.
I have a bunch of arm assembly, C and C++ files. gcc is trying to link them, but these are for an embedded project.
I am not using any external libraries, all code that is being used was written by me. An error seems to happen because I have a function called int kernel_main(void) defined in main.c that is trying to call set_LED(int value) defined in mailbox.cpp which includes the header mailbox.h (I did include the header in the main.c file).
The exact error is:
undefined reference to `__aeabi_unwind_cpp_pr1'
The way I am making my project is:
-compile all source files (.s, .c, .cpp) into object files (.o) without linking (-c), then link them all together with the use of a custom linker script.
Edit: I am going to add some information to make things more clear.
First changing all files so that all of them are C files (no cpp extensions) yields:
undefined reference to `set_LED'
It is unlikely that the issue itself is name mangling an it probably has nothing to do with CPP and C differences.
The problem is very likely to be a linker issue
This is the build process:
Compile c files, Example:
arm-none-eabi-g++ -O0 -march=armv8-a source/MainFiles/mailbox.cpp -nostartfiles -c -o objects/MainFiles/mailbox.o
(Compiling a C++ file would be identical except for the use of g++ instead of gcc)
Link everything:
arm-none-eabi-ld object1 object2... -o build/kernel.elf -T ./source/kernel.ld -I include_directory_1 -I include_directory_2 -L include_directory_1 -L indlude_directory_2
Include directories are all directories under the current one
Edit:
The error came back. Ignore the parts of this question relevant to name mangling. The error I need to fix is:
./objects/Hardware/mailbox.o:(.ARM.exidx+0x18): undefined reference to `__aeabi_unwind_cpp_pr1'
So far all I know is that this has something to do with unwinding the stack and exceptions. It seems the function is defined in libgcc. However I have used -nostdlib, I have omitted it, and in both cases the error persists. I have tried changing file extensions to .c whenever possible and to .cpp whenever possible, alas the error is always there.
It got fixed only as long as I had exactly 1 cpp file and the rest of my files were C files (this is no longer true, I tried). What triggered the error again was that I was refactoring the code and I wanted to move a couple of functions to new files.
In other words, without deleting a single file, declaring a function named wait(uint32_t time) in mailbox.cpp works, declaring it in a file called time.c (or cpp) with it's respective header declaration and including the header in mailbox.cpp breaks things. Note I don't delete the files when moving the function I simply delete the function declaration inside each file.
Adding a stub like this:
void __aeabi_unwind_cpp_pr1()
{
}
Fixes the problem and the code works. But I don't like this solution. I don't want a useless stub being called mysteriously in my code. I don't need nor want this function in my current implementation, how can I tell the compiler or the linker that they are to omit whatever they are doing that requires this function?
The solution is very simple. As it turns out exceptions are enabled by default (which is what generates the code that calls __eabi_unwind_cpp_pr1). To disable them all that is needed is to pass:
-fno-exceptions as an argument to the gcc/g++ compiler and the problem is solved.
You have a reference to this function that belongs to the C++ runtime of GCC. It's part of the exception handling. Whatever you are doing, sounds a little crazy, but anyway you can do this if you really know what you are doing. You must link against the C++ runtime libraries. That's it. Link against "libstdc++".
About the set_LED I also believe it's just about the C++ mangling, just as Justin J mentioned in the other answer.
I have seen this when mixing C and C++. Because of name mangling, the symbols will have different names internally depending on the type of the source file.
If the source for 'set_LED'is a c file, use the following in the header around the prototype and see if it helps.
#ifdef __cplusplus
extern "C" {
#endif
// function prototypes here
#ifdef __cplusplus
}
#endif
Please also add prefix "-shared" without quotes to -fno-exceptions. I am using ARM GCC version
I have a small program that I can compile with GCC and ICC without any difficulties, but I would also like the code to work with G++ and ICPC. I tried to add this:
#ifdef __cplusplus
extern "C" {
#endif
at the beginning and this:
#ifdef __cplusplus
}
#endif
at the end of all the header files, but I still get several `undefined reference to "..."' errors.
I think you're getting it wrong... The extern C is for disabling the function mangling; so if you do it just for the header files, when you try to link your mangled object code, the declared function names won't match with the function names in the object file.
Anyway, the extern C won't add any portability if the whole application is being compiled and linked with the same C++ compiler, it's intended for mixing C libraries with C++ code.
If your code is in the common subset of C and C++, you should be already able to compile it with either compiler, but I cannot see the reason to do that (besides working on the principle of least surprise, as C++ is more strict with some things).
You get undefined references because the declaration and the definition are not matching if you put extern "C", which prevents name mangling from happening: but in this case this is happening only in your header files.
If one of the undefined references is gxx_personality, then I'd say the post by "fortran" is correct.
See my response to this earlier question: When to use extern "C" in simple words?
It should hopefully make it clear how to mix C and C++ code.
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.