To teach myself a little C++, I decided to write a little Program to write text to my Saitek X52 Pro joystick display.
I wanted to use Eduards C-library
http://plasma.hasenleithner.at/x52pro/
I know I have to place an "extern C" around the methods if I want to use them in my C++ program. But that means changing the Header file of the library - and then it wouldn't build anymore.
What would be the correct approach in this case?
EDIT: the suggested method worked partially.
Comm.cpp:
...
extern "C"{
#include <x52pro.h>
}
using namespace std;
int main ( int argc, char *argv[] ) {
cout<<"entered main"<<endl;
char *String;
strcpy(String,"testing");
struct x52 *hdl = x52_init();
x52_settext(hdl, 0,String , 7);
x52_close(hdl);
return EXIT_SUCCESS;
}
Error Message:
Comm.o: In function `main':
Comm.cpp|38| undefined reference to `x52_init'
Comm.cpp|39| undefined reference to `x52_settext'
Comm.cpp|40| undefined reference to `x52_close'
which are all methods defined in x52pro.h
To use extern "C" in C header files, wrap it so
#ifdef __cplusplus
extern "C" {
#endif
...
#ifdef __cplusplus
}
#endif
or you can wrap the #includes with extern "C"
extern "C" {
#include <chdr1.h>
#include <chdr2.h>
}
When linking your application, you must tell the linker what library to use and where the library is. From your link, you must add libusb as well. This looks roughly like this
g++ -o app_name Comm.o -L /path/to/library -lx52pro -lusb
When the library is installed in the system lib directory, you can omit the -L /path/... part. If you use a Makefile, you define this in some variables, usually
LDFLAGS = -L /path/to/library
LDLIBS = -lx52pro -lusb
See also Compiling and Linking and Wikipedia - Linker (computing)
In your C++ code, you can surround the included header file with extern "C" like this:
extern "C" {
#include "c_header_file.h"
}
Then, you would not need to modify the header file of the third party library.
#ifdef __cplusplus
extern C {
#endif
...
#ifdef __cplusplus
}
#endif
Related
I'd like to make a tool that automatically wraps C libraries in:
#ifdef __cplusplus
extern "C" {
#endif
But I'm confused by what exactly needs to be wrapped with extern "C", and what needn't be. Only functions? What about any (shock-horror) global variables? Anything else?
If I write a script that just finds all functions and wraps them with extern "C", is that enough?
And finally: if the library already wrapped its functions with extern "C" and then they're wrapped again, can I trust that nothing bad happens and it'll still work fine, or do I need to explicitly check for this?
It does not matter, because anything that does not need it (such as macros and comments) will be unaffected by it, so you can just wrap the entire header content - and that hardly requires a a "tool".
Also not this is not "modifying the library", just modifying the header.
Nested wrapping is benign - applying C linkage to something that already has it has no effect.
What extern "C" does is tell the C++ compiler not to apply name mangling to the specified symbol because it has C linkage and the corresponding name in the library has C linkage and is not name-mangled.
Name-mangling is the means by which C++ applies meta-data to a symbols in order to provide type information and parameter counts in order to support C++ features that require this information such as function overloading.
See this answer here which is partially related.
You'll basically just want to either:
Autowrap an include, i.e. extern "C" { #include <foo.h> }
Autowrap the C header files being included by the include (so, at the start of "foo.h" as opposed to the include statement itself)
As far as doubly-wrapped extern "C"s, I tested it with these files:
lib.h:
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
void printHWorld(void);
#ifdef __cplusplus
}
#endif
lib.c:
#include <stdlio.h>
#include <lib.h>
void printHWorld(void) {
printf("Hello, world!\n");
}
main.cpp:
#ifdef __cplusplus
extern "C" {
#endif
#include <lib.h>
#ifdef __cplusplus
}
#endif
int main(void) {
printHWorld();
return 0;
}
I then built it with the following commands:
gcc -Wall -O2 -I. -o lib.o -c lib.c
g++ -Wall -O2 -I. -o main.o -c main.cpp
g++ -o test main.o lib.o
And that worked just fine, so I don't think you need to worry about the double extern "C"
Within extern "C" { } the macro __cplusplus is still defined. When I want to include the C version of mpi.h in the header of my library which is dynamically load this will not work as mpi.h still finds __cplusplus and will still load like it was opened by C++.
#undef __cplusplus works with gcc. But I do not want to rely on this.
So how to write a C++ program that
- uses the C++ version of mpi and
- is linked against a C-library that uses the C-Version of mpi (where #include <mpi.h> appears already in the header?
Example code:
library.h:
#ifdef __cplusplus
extern "C" {
#endif
#include <mpi.h>
void library_do(MPI_Comm comm);
#ifdef __cplusplus
}
#endif
program.cpp:
#include <library.h>
#include <mpi.h>
int main() {
MPI::Init();
// do some mpi C++ calls...
library_do(MPI::COMM_WORLD);
MPI::Finalize();
}
In case somebody wants to play the example here the library.c:
#include <stdio.h>
#include "library.h"
void library_do(MPI_Comm comm)
{
int rank;
MPI_Comm_rank(comm, &rank);
printf("MPI Rank: %d", rank);
}
And to compile everything I try with
mpicc -shared library.c -o lib.so
mpicxx program.cpp -l lib.so
__cplusplus will always be defined by the compiler if the compiler is a C++ compiler. extern "C" {} only gives you C linkage so the code inside plays nice with a C compiler.
The point of using
#ifdef __cplusplus
extern "C" {
#endif
...
#ifdef __cplusplus
}
#endif
is to prevent the name mangling that C++ does. We are basically saying dont use the name mangling like a traditional C++ function call instead leave it undecorated.
This link could be useful Name mangling
It is used to make C headers compatible with C++.
The flag __cplusplus is automatically defined in C++ compiler.
Because they are different things. extern "C" {} tells the compiler how to export symbols (see here), whereas __cplusplus tells you that you can use C++ code so your library can use different code paths inbetween #ifdefs.
The compiler outputs the following:
In file included from /usr/include/c++/4.8.2/bits/stl_algobase.h:61:0,
from /usr/include/c++/4.8.2/bits/stl_tree.h:61,
from /usr/include/c++/4.8.2/map:60,
from /usr/include/openmpi-x86_64/openmpi/ompi/mpi/cxx/mpicxx.h:38,
from /usr/include/openmpi-x86_64/mpi.h:2674,
from x1.cpp:6:
/usr/include/c++/4.8.2/bits/cpp_type_traits.h:72:3: error: template with C linkage
template<typename _Iterator, typename _Container>
^
/usr/include/c++/4.8.2/bits/cpp_type_traits.h:85:3: error: template with C linkage
template<bool>
^
...
The mpi.h header detects that it's being compiled as C++ and so includes C++ specific features. However templates (among other things) don't work with C linkage (i.e. if the header is within an extern "C" block).
Move the include above extern "C":
#include <mpi.h>
#ifdef __cplusplus
extern "C" {
#endif
void library_do(MPI_Comm comm);
#ifdef __cplusplus
}
#endif
Of course it's defined. It's still a C++ compiler that compiled the code inside the extern "C" block. It doesn't stop treating the code as C++, only makes sure to use a C calling/naming convention.
If the header cannot be compiled by a C++ compiler, the only recourse is to create a C wrapper that exposes a C++ compatible API.
If you #include <mpi.h> from a C++ program, just don't put extern "C" around it. At least OpenMPI and Intel MPI do this for you in the header itself - if __cplusplus is defined.
You probably get into trouble because some MPI implementations still define the C++ interface in mpi.h that was deleted from the standard. This obviously breaks under extern "C". For instance with OpenMP you can skip this by setting OMPI_SKIP_MPICXX. Then the double extern "C" works, but I still wouldn't recommend it.
Update: In case you can't modify the library header, just #include <mpi.h> before #include <lib.h>.
That said, you should not use the C++ bindings for MPI. They were removed from the standard more than 6 years ago, after being for 3 years...
I tried to link a static library (compiled with gcc) to a c++ program and I got 'undefined reference'. I used gcc and g++ version 4.6.3 on a ubuntu 12.04 server machine. For example, here is the simple library file for factorial method:
mylib.h
#ifndef __MYLIB_H_
#define __MYLIB_H_
int factorial(int n);
#endif
mylib.c
#include "mylib.h"
int factorial(int n)
{
return ((n>=1)?(n*factorial(n-1)):1);
}
I created object for this mylib.c using gcc:
gcc -o mylib.o -c mylib.c
Again the static library was created from the object file using AR utility:
ar -cvq libfact.a mylib.o
I tested this library with a C program (test.c) and C++ program (test.cpp)
Both C and C++ program have the same body:
#include "mylib.h"
int main()
{
int fact = factorial(5);
return 0;
}
Assuming static library libfact.a is available in /home/test directory, I compiled my C program without any issues:
gcc test.c -L/home/test -lfact
However while testing C++ program, it threw a link error:
g++ test.cpp -L/home/test -lfact
test.cpp:(.text+0x2f): undefined reference to `factorial(int)'
collect2: ld returned 1 exit status
I even tried adding extern command in test.cpp:
extern int factorial(int n) //added just before the main () function
Still the same error.
Can someone tell me what I am wrong here?
Is there anything I missed while creating the static library?
Do I have to add anything in my test.cpp to make it work?
The problem is that you haven't told your C++ program that factorial is written in C. You need to change your test.h header file. Like this
#ifndef __MYLIB_H_
#define __MYLIB_H_
#ifdef __cplusplus
extern "C" {
#endif
int factorial(int n);
#ifdef __cplusplus
}
#endif
#endif
Now your header file should work for both C and C++ programs. See here for details.
BTW names containing a double underscore are reserved for the compliler (so are names starting with an underscore and a capital letter) so #ifndef __MYLIB_H_ is illegal strictly speaking. I would change to #ifndef MYLIB_H #define MYLIB_H
While the accepted answer is absolutely correct, I thought I'd just add an observation. Some editors have trouble with the open / close brace, and will indent the entire extern "C" scope in the header. If mylib.h is a key header for a library, you might consider:
#if defined (__cplusplus)
#define _MYLIB_INIT_DECL extern "C" {
#define _MYLIB_FINI_DECL }
#else
#define _MYLIB_INIT_DECL
#define _MYLIB_FINI_DECL
#endif
All other headers in mylib library, e.g., mylib_aux.h, can be of the form:
#ifndef _MYLIB_AUX_H
#define _MYLIB_AUX_H
#include <mylib.h>
_MYLIB_INIT_DECL
... header content ...
_MYLIB_FINI_DECL
#endif /* _MYLIB_AUX_H */
Obviously, the names I'm using are arbitrary, but for multiple library headers, this approach has been useful to me.
I have a problem. I wrote example code and I want to build it without the error:
main.cpp(.text+0x5): undefined reference to `test()'
Library
test1.c
#include <stdlib.h>
void test()
{
puts("DziaĆa");
}
test1.h
#ifndef TEST1_H
#define TEST1_H
extern void test();
#endif
makefile
all:
gcc -c ./src/test1.c -o ./lib/test1.o
ar rcs ./lib/libtest1.a ./lib/test1.o
Program
main.cpp
#include <test1.h>
int main()
{
test();
return 0;
}
makefile
all:
g++ -static -I../test1/include -L../test1/lib ./src/main.cpp -o ./build/MyApp -ltest1
What am I doing wrong?
You are compiling a C code function, but you are expecting to link a C++ function.
Because of 'type safe linkage', the function you provide is not the function that the C++ code calls.
Either in test1.h use:
#ifdef __cplusplus
extern "C" {
#endif
extern void test1(void);
#ifdef __cplusplus
}
#endif
Or:
Compile the function with the C++ compiler.
The C++ compiler will mangle the symbol names to provide type-safe linkage (a term which you should be able to search for via your preferred search engine).
The 'compiler' - actually the linker - is looking for a function with a C++ mangled name representing the C++ function with the signature 'void test1(void);'.
For example (but remember - different compilers deliberately mangle things differently), G++ 4.2.1 on MacOS X 10.6.2 generates a symbol '__Z5test1v' for the function; GCC generates a symbol '_test1'. Clearly, when the linker is looking for '__Z5test1v', the symbol '_test1' is not going to be used - it is not spelled the same. This is a good thing.
You can use 'nm -g' on the object file for the main program to see what it is looking for, and on the object file in the library to see what it is providing. And, given that the spellings are different, that is why the loader does not pick up the library function - it is looking for something with a different name.
You are calling a C function from a C++ function. The naming between the two is different (C++ mangles names to include parameter information).
Change the header file to look like this:
#ifdef __cplusplus
extern "C" {
#endif
extern void test();
#ifdef __cplusplus
}
#endif
This will tell the compiler that the function follows the C naming/calling convention.
I am trying to figure out why when I convert my main.m file to a main.mm file, it no longer will link properly.
I have reduces the problem to the following example code:
#import <Foundation/Foundation.h>
#import <AppKit/AppKit.h>
int main( int argc, const char ** argv ) {
return NSApplicationMain( argc, argv);
}
I am using gnustep and linux. I enter the following commands and everything works as expected:
g++ -g -c main.m -I/usr/GNUstep/Local/Library/Headers -I/usr/GNUstep/System/Library/Headers
g++ -g -o test main.o -L/usr/GNUstep/Local/Library/Libraries -L/usr/GNUstep/System/Library/Libraries -lgnustep-base -lgnustep-gui
Now if I rename main.m to main.mm and use these two commands ( same exept main.m now main.mm):
g++ -g -c main.mm -I/usr/GNUstep/Local/Library/Headers -I/usr/GNUstep/System/Library/Headers
g++ -g -o test main.o -L/usr/GNUstep/Local/Library/Libraries -L/usr/GNUstep/System/Library/Libraries -lgnustep-base -lgnustep-gui
I get the following error:
main.mm:7: undefined reference to `NSApplicationMain(int, char const**)'
Can someone please find what I am doing wrong? I do not see why it is now failing to link.
I am trying to add some C++ classes to an objective c program and this is preventing me from continuing.
Thank you for any help you can provide.
The problem is that when you compile it as C++, the compiler mangles the name of the symbol NSApplicationMain, so it can't find it, since it's looking for something like __Z17NSApplicationMainiPPKc. You can use the nm program (from binutils) to see what symbols the object files are referencing:
$ # When compiled as Objective-C:
$ nm main.o | grep NSApplicationMain
U NSApplicationMain
$ # When compiled as Objective-C++:
$ nm main.o | grep NSApplicationMain
U _Z17NSApplicationMainiPPKc
In order to avoid this problem, C functions need to be declared with an extern "C" modifier in order to tell the compiler not to mangle the name. Looking into <AppKit/NSApplication.h>, the header file where NSApplicationMain is declared, I see this:
APPKIT_EXPORT int
NSApplicationMain(int argc, const char **argv);
Alas, APPKIT_EXPORT is defined to be one of extern, __declspec(dllexport), extern __declspec(dllexport), or nothing in <AppKit/AppKitDefines.h>. Since it's also used for global variable declarations, we can't get around this by redefining it to extern "C" (which would be extremely hacky and kludgy anyways). The AppKit header files do not seem to contain any extern "C" declarations at all, although I do see them in various header files under Foundation/ and GNUStepBase/.
So what can you do? The solution is to wrap your includes with an extern "C":
extern "C"
{
#import <Foundation/Foundation.h>
#import <AppKit/AppKit.h>
}
int main( int argc, const char ** argv ) {
return NSApplicationMain( argc, argv);
}
This will give the functions defined in those header files the proper linkage, and it will all work out. But you shouldn't have to do this -- I would file a bug report with GNUstep, telling them to add proper extern "C" declarations to their header files.
The problem is the name mangling c++ compilers typically use to enable function overloading at the link stage.
C++ defines a extern "C" directive that forces it to use a C compatible name for a function.
You can use it in a C++ file like so :-
// this makes func use a C compatible linkage
extern "C" void func(int a)
{
In a header file that is included by C and C++ it is necessary to protect the extern "C" declaration from C, and the C compiler does not under stand it.
#ifndef EXTERN_C
#ifdef __cplusplus
#define EXTERN_C extern "C"
#else
#define EXTERN_C
#endif
#endif
// Use it like this to declare a Function with C linkage
EXTERN_C void func(int a);
// If you have a lot of functions and declarations that need to be C compatible
#ifdef __cplusplus
extern "C" {
#endif
//functions with C linkage
void func(int a);
...
#ifdef __cplusplus
}
#endif
Now, how does this help your problem? Well, main.mm means the Foundation.h and AppKit.h files are being compiled as C++. Why Apple have not protected NSApplicationMain with a extern "C" directive I cannot guess, but it clearly isn't guarded.
A simple, if brutal, fix would be to alter your #imports like follows:
extern "C" {
// All declarations inside this block will use C linkage
#import <Foundation/Foundation.h>
#import <AppKit/AppKit.h>
}
int main( int argc, const char ** argv ) {
return NSApplicationMain( argc, argv);
}