4

I am working on a school project which requires to work with sheepdog. Sheepdog provides a c api which enables you to connect to a sheepdog server. First i create c source file(test.c) with the following content :

#include "sheepdog/sheepdog.h"
#include <stdio.h>
int main()
{
struct sd_cluster *c = sd_connect("192.168.1.104:7000");
if (!c) {
    fprintf(stderr, "failed to connect %m\n");
    return -1;
}else{
    fprintf(stderr, "connected successfully %m\n");
}
    return 0;
}

then i compile with no error using the following command

gcc -o test test.c -lsheepdog -lpthread

But what i need is to use it with c++ project so i created a cpp file(test.cpp) with the following content :

extern "C"{
#include "sheepdog/sheepdog.h"
}
#include <stdio.h>
int main()
{
    struct sd_cluster *c = sd_connect("192.168.1.104:7000");
    if (!c) {
       fprintf(stderr, "failed to connect %m\n");
       return -1;
    }else{
       fprintf(stderr, "connected successfully %m\n");
    }
    return 0;
}

now, when i compiled using the following command :

g++ -o test test.cpp -lsheepdog -lpthread

I got this error : compilation error message

dkg
  • 1,775
  • 14
  • 34
  • Try with g++ -o test test.cpp -L/Absolut/PATH/TO/sheepdog -lpthread – Phiber Aug 19 '16 at 14:28
  • @Phiber having the same problem – Ilyas Lahmer Aug 19 '16 at 14:41
  • Just for grins, did you try it without the `extern "C"` first? Is [this file](https://github.com/sheepdog/sheepdog/blob/8772904509ce6b10c5edca4f497022686aecc18f/lib/shared/sheepdog.h) the `sheepdog/sheepdog.h`? (I don't see a `sheepdog/sheepdog.h` under `include/` in GitHub.) – cxw Aug 19 '16 at 14:49
  • it seems also you have problem with include headers, try with: g++ -I /sheepdog/headers OR set CPLUS_INCLUDE_PATH env variable – Phiber Aug 19 '16 at 14:52
  • @cxw yes i tried and the same error happened – Ilyas Lahmer Aug 19 '16 at 15:14

3 Answers3

6

You can't just wrap extern "C" around a header and expect it to compile in a C++ program. For example, the header sheepdog_proto.h uses an argument named new; that's a keyword in C++, so there's no way that will compile as C++. The library was not designed to be called from C++.

Pete Becker
  • 74,985
  • 8
  • 76
  • 165
1

I agree with @PeteBecker. From a quick look around Google, I am not sure there is an easy solution. Sheepdog is using C features and names that don't port well to C++. You might need to hack sheepdog fairly extensively. For example:

  • move the inline functions out of sheepdog_proto.h into a new C file, leaving prototypes in their place. This should take care of the offsetof errors, e.g., discussed in this answer.
  • #define new not_a_keyword_new in sheepdog/sheepdog.h

and whatever other specific changes you have to make to get it to compile. More advice from the experts here.

Community
  • 1
  • 1
cxw
  • 16,685
  • 2
  • 45
  • 81
  • @PeteBecker if i create .so library in c using this library which provide me the functions that i need in my c++ program then link it with my c++ program .will this work – Ilyas Lahmer Aug 19 '16 at 15:19
  • `#define new ...` produces undefined behavior. – Pete Becker Aug 19 '16 at 16:34
  • @PeteBecker in this situation? For sheepdog, I would think `new` would just be an identifier susceptible to redefinition like any other identifier. Sheepdog has no calls to `operator new`, so the compiler wouldn't have a reason to treat something called `foo_new` specially. Am I missing something? --- I also found [this answer](http://stackoverflow.com/a/1365402/2877364) to a vaguely-related question :) . – cxw Aug 19 '16 at 16:38
  • @cxw - redefining any C++ keyword with a macro produces undefined behavior. It might be that that turns out to be harmless, but that doesn't change what it is. – Pete Becker Aug 19 '16 at 16:41
  • For future readers of this post - [more about `#define new` and friends](http://stackoverflow.com/a/9110053/2877364) – cxw Aug 19 '16 at 19:09
0

As sheepdog was not designed to be useable from C++ you should build a tiny wrapper in C language to call the functions from sheepdog and only call the wrapper from your c++ code. Some hints to write such a wrapper:

  • void * is great to pass opaque pointers
  • extractors can help to access badly named members. If a struct has a member called new (of type T), you could write:

    T getNew(void *otherstruct); // declaration in .h
    

    and

    T getNew(void *otherstruct) {        // implementation in a c file
        return ((ActualStruct *) otherstruct)->new;
    }
    

Depending on the complexity of sheepdog (I do not know it) and the part you want to use, it may or not be an acceptable solution. But it is the way I would try facing such a problem.

Anyway, the linker allows mixing modules compiled in C and in C++, either in static linking or dynamic linking.

Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252