Skip to main content
  1. About
  2. For Teams
Asked
Viewed 4k times
4

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
4
  • 6
    __cplusplus is defined when you are compiling translation unit as C++ code. extern "C" { } does not make code inside compile as C
    user7860670
    –  user7860670
    2019-07-10 09:57:23 +00:00
    Commented Jul 10, 2019 at 9:57
  • __cplusplus is a macro. It is defined and used by the preprocessor. The preprocessor has no idea about curly braces or C++ keywords. So whatever you expect of __cplusplus is fundamentally impossible.
    n. m. could be an AI
    –  n. m. could be an AI
    2019-07-10 10:02:44 +00:00
    Commented Jul 10, 2019 at 10:02
  • 3
    The question is a prime example of an XY-Problem. You didn't include any code or error message - now you got four correct answers addressing your question, but probably not your problem. Please edit your question to make it more useful and to avoid that for any further questions.
    Zulan
    –  Zulan
    2019-07-10 10:27:15 +00:00
    Commented Jul 10, 2019 at 10:27
  • 1
    this will not work as mpi.h still finds __cplusplus and will still load like it was opened by C++. If __cplusplus was defined at compile time, and you didn't improperly define it yourself in C code, the library is being opened by C++ code. #undef __cplusplus is Easter egging - you are blindly changing things you don't understand trying to fix something.
    Andrew Henle
    –  Andrew Henle
    2019-07-10 10:47:45 +00:00
    Commented Jul 10, 2019 at 10:47

6 Answers 6

9

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

Sign up to request clarification or add additional context in comments.

3 Comments

Do you play nice with a C compiler?
@Bathsheba Only on sundays.
I don't think that it is important that it is a C++ compiler but whether it is C++ compiling (i.e. a .cpp file).
4

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.

Comments

3

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.

Comments

2

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

2 Comments

The problem still persists in the real world program which loads a cpp library that again depends on the C library using mpi. The error is libbla_plugin.so: undefined symbol: _ZN3MPI3Win4FreeEv
Finally found the error for this too: I linked against the C version of MPI lib in the cpp library in cmake.
2

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.

2 Comments

Can I wrap you up inside extern "ST" ?
StoryTeller - Unslander Monica
@SombreroChicken - ST linkage results in UB.
1

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

Comments

Your Answer

Post as a guest

Required, but never shown

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.

Morty Proxy This is a proxified and sanitized view of the page, visit original site.