Reputation: 99
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
Upvotes: 4
Views: 3798
Reputation: 22670
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...
Upvotes: 1
Reputation: 224387
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
Upvotes: 2
Reputation: 652
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.
Upvotes: 4
Reputation: 170153
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.
Upvotes: 2
Reputation: 10301
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 #ifdef
s.
Upvotes: 3
Reputation: 36503
__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.
Upvotes: 9