1

I want to call some C++ functions from C code. There are three files in my project: main.c, cgal_kernel.cpp and cgal_kernel.h.

I get compilation errors when I try to compile them.

Here are the three files.

cgal_kernel.h

typedef enum{
  LEFT_TURN,
  COLLINEAR,
  RIGHT_TURN
} Orientation;

/* Given points p,q,r determine if the link p-q-r is a left turn, right-turn or collinear
*/
extern Orientation orientation_2 (double px, double py, double qx, double qy, double rx, double ry);  

cgal_kernel.cpp

#include "cgal_kernel.h"

extern "C" Orientation orientation_2 (double px, double py, double qx, double qy, double rx, double ry)  
{
  return LEFT_TURN ;

}

main.c

#include <stdio.h>
#include "cgal_kernel.h"

int main(void)
{
  double px = 0.0;
  double py = 0.0;

  double qx = 0.0;
  double qy = 1.0;

  double rx = 1.0;
  double ry = 1.0;

  Orientation test= orientation_2 ( px,  py,  qx,  qy,  rx,  ry);

  printf("Answer is %d\n", test);
  return 0;
}

I want cgal_kernel.cpp to be compiled to a shared library file to be used from other languages via their Foreign function interfaces.

My compilation steps, stored inside a bash script are

export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH 
set -ex # Display compilation process.

rm  -f  *~  *.o  *.so
g++ -c -Wall  -Werror -fPIC cgal_kernel.cpp  # Convert to object file
g++ -shared   cgal_kernel.o -o libcgal_kernel.so      
gcc -g -Wall  main.c -o main -I. -L. -lcgal_kernel

I get the following compilation errors, after running the above build script.

+ rm -f *~ *.o *.so
+ g++ -c -Wall -Werror -fPIC cgal_kernel.cpp
In file included from cgal_kernel.cpp:1:0:
cgal_kernel.h: In function ‘Orientation orientation_2(double, double, double, double, double, double)’:
cgal_kernel.h:17:20: error: previous declaration of ‘Orientation orientation_2(double, double, double, double, double, double)’ with ‘C++’ linkage
 extern Orientation orientation_2 (double px, double py, double qx, double qy, double rx, double ry);  
                    ^
cgal_kernel.cpp:3:103: error: conflicts with new declaration with ‘C’ linkage
 extern "C" Orientation orientation_2 (double px, double py, double qx, double qy, double rx, double ry)  

Where am I going wrong here? I tried removing the "C" from the cgal_kernel.cpp file, in the function signature, then I get the error

+ rm -f *~ cgal_kernel.o libcgal_kernel.so
+ g++ -c -Wall -Werror -fPIC cgal_kernel.cpp
+ g++ -shared cgal_kernel.o -o libcgal_kernel.so
+ gcc -g -Wall main.c -o main -I. -L. -lcgal_kernel
/tmp/cclw7kGD.o: In function `main':
/home/gaurish/Dropbox/MyWiki/research_projects/MiCha/main.c:15: undefined reference to `orientation_2'
collect2: error: ld returned 1 exit status

It seems I am making some elementary mistake, about how C++ functions get called from C code, but I can't seem to figure it out!


EDIT: If I add the extern "C" to the function signature in both cgal_kernel.h and cgal_kernel.cpp files I get the following error:

+ rm -f *~ cgal_kernel.o libcgal_kernel.so
+ g++ -c -Wall -Werror -fPIC cgal_kernel.cpp
+ g++ -shared cgal_kernel.o -o libcgal_kernel.so
+ gcc -g -Wall main.c -o main -I. -L. -lcgal_kernel
In file included from main.c:2:0:
cgal_kernel.h:17:8: error: expected identifier or ‘(’ before string constant
 extern "C" Orientation orientation_2 (double px, double py, double qx, double qy, double rx, double ry);  
        ^
main.c: In function ‘main’:
main.c:15:3: warning: implicit declaration of function ‘orientation_2’ [-Wimplicit-function-declaration]
   Orientation test= orientation_2 ( px,  py,  qx,  qy,  rx,  ry);
   ^
smilingbuddha
  • 14,334
  • 33
  • 112
  • 189
  • 5
    The extern "C" needs to be in the declaration, not the definition (I think it can be in both) – Justin Apr 06 '17 at 22:25
  • 2
    @Justin and you'll need some `#if` or macro to make sure it only applies in the C++ environment since C doesn't have `extern "C"`. – Mark Ransom Apr 06 '17 at 22:32
  • @Justin Please see edit. I still get errors by adding `extern "C"` to the header file – smilingbuddha Apr 06 '17 at 22:34
  • There is a working example here which may be useful: https://stackoverflow.com/questions/31903005/how-to-mix-c-and-c-correctly/31903685#31903685 – Galik Apr 06 '17 at 22:42

2 Answers2

1

The easiest way to call C++ code from C is to write a valid C/C++ header file of this form:

// header guard
#ifdef __cplusplus
extern "C" {
// alternatively, you could have separate C and C++ headers and have
// the extern "C" before each function in your C++ header
#endif

// Valid C header

#ifdef __cplusplus
}
#endif

And proceed to just use it from C. In C++, define the functions exactly the same way you normally would.

For your example:

cgal_kernel.h

#ifdef __cplusplus
extern "C" {
#endif

typedef enum{
  LEFT_TURN,
  COLLINEAR,
  RIGHT_TURN
} Orientation;

/* Given points p,q,r determine if the link p-q-r is a left turn, right-turn or collinear
*/
Orientation orientation_2 (double px, double py, double qx, double qy, double rx, double ry);

#ifdef __cplusplus
}
#endif

cgal_kernel.cpp

#include "cgal_kernel.h"

Orientation orientation_2(double px, double py, double qx, double qy, double rx, double ry)  
{
  return LEFT_TURN ;
}

Note that your main file should be a C++ file, as we can read from How to mix C and C++

Justin
  • 24,288
  • 12
  • 92
  • 142
1

when mixing C and C++ code, remember that the extern "C" needs to be on the C++ end but is INVALID SYNTAX on the C end. So generally I use a macro when mixing code:

#ifdef __cplusplus
#define EXTERN_C extern "C"
#else
#define EXTERN_C
#endif

then use EXTERN_C on all declarations of any function that must be mutually accessible. That way, it is invisible to the C compiler but avoids name-mangling by the C++ compiler.

Gold Dragon
  • 480
  • 2
  • 9