0

I have a class in C++ which I want to make a shared library from it and use in C or other languages. this is the class that I want to make a library from it:

getinfo.h

#ifndef GETINFO_H
#define GETINFO_H
#include "info.h"

char* getMaximumSpeedCpu();
char* getCoreNumbers();
#endif

getinfo.cpp:

#include <iostream>
#include "getinfo.h"
using namespace Morsa::Prd::SMC::SL;
char* getMaximumSpeedCpu()
{
    info *inf = new info;
    std::string str = inf->maximumSpeedCpu();
    char* maxspeed = new char[str.length()+1];
    strcpy(maxspeed, str.c_str());
    free(inf);
    return maxspeed;
}
char* getCoreNumbers()
{
    info *inf = new info;
    std::string corenum = inf->coreNumbers();
    char* num = new char[corenum.length()+1];
    strcpy(num, corenum.c_str());
    free(inf);
    return num;
}

and this is my wrapper class (smc.h):

#ifndef SMC_H
#define SMC_H
#include "getinfo.h"

#ifdef __cplusplus
extern "C"
{
#endif
//void smc_destroy(ctestsmc *a);
char* smc_getMaximumSpeedCpu();
char* smc_getCoreNumbers();

#ifdef __cplusplus
}

#endif
#endif // SMC_H

smc.cpp:

#include "smc.h"

char *smc_getMaximumSpeedCpu()
{
   char* c = getMaximumSpeedCpu();
   return c;
}

char *smc_getCoreNumbers()
{
    char* c = getCoreNumbers();
    return c;
}

I made a shared library from smc.cpp, now I want to use my library in for example a C code.

How am I supposed to do it without including any header file? Whenever I include header file of smc, my C code doesn't know libraries that I had used in getinfo.h, like fstream.
EDIT:
info.h:

#ifndef INFO_H
#define INFO_H
#include <stdlib.h>
#include <cstring>
#include <sys/statvfs.h>
#include <libssh/libssh.h>

class info
{
private:
    std::ifstream ifile;
    std::ofstream ofile;
    std::vector<std::string> lists;
    std::string str;
    ssh_session my_ssh_session ;

public:
    info();
    info(const void *ip, const char* pw, const void *hostName);
    ~info();
    std::string maximumSpeedCpu();
    std::string coreNumbers();
    const void* _hostName;
    const void* _ip;
    const char* _password;

info.cpp:

#include "info.h"
info::info(const void *ip, const char* pw, const void *hostName)
{
    int a;
    _ip = ip;
    _password = pw;
    _hostName = hostName;
    my_ssh_session = ssh_new();
}
info::info()
{
}
info::~info()
{
    ssh_disconnect(my_ssh_session);
    ssh_free(my_ssh_session);
}

std::string info::maximumSpeedCpu()
{
    //maximum speed of cpu
    getSSHState();
    std::string cpuSpeed;
    cpuSpeed = exec_ssh_command(my_ssh_session, "dmesg | grep 'MHz processor' | awk '{print $5}'" );
    return cpuSpeed;
}

std::string info::coreNumbers()
{
    //number of processors
    getSSHState();
    std::string coresNumber;
    coresNumber = exec_ssh_command(my_ssh_session, "cat /proc/cpuinfo | grep processor | wc -l");
    return coresNumber;
}
fa7eme
  • 73
  • 10
  • Comments are not for extended discussion; this conversation has been [moved to chat](https://chat.stackoverflow.com/rooms/219156/discussion-on-question-by-fa7eme-include-a-header-file-built-in-c-using-extern). – Samuel Liew Aug 04 '20 at 04:23

2 Answers2

2

Theory

You can only access functions written in C from the world of C. Whenever calling C++ code from C, you must go through a wrapper function, in your case smc_* functions.

Now, note that the declaration of the wrapper functions, which is in the wrapper's header file smc.h does not need to include getinfo.hpp. This is the key insight. The wrapper's header merely tells any C program that includes it, the type of arguments and return values of the smc_* functions. The header must stick to C.

For example, see the image below. The functions foo and bar are declared in the wrapper.h file which only includes other C headers. The wrapper.cpp file which actually implements the wrapper, and uses other stuff from the C++ world (like the STL, or other classes) includes the C++ headers it needs.

In your case, smc.cpp will include getinfo.hpp, not smc.h.

enter image description here

However, the definitions of these wrapper functions needs to know the types of the C++ functions it is wrapping. Therefore, smc.cpp will include getinfo.h. Further, because this file will be compiled by a C++ compiler, it will understand any references to C++ STL in included headers.

EDIT: Code example

Suppose I want to wrap the class cppworld.

cppworld.hpp:

class cppworld {
public:
    cppworld();
    int one();
};

cppworld.cpp:

#include <iostream>
#include "cppworld.hpp"

cppworld::cppworld() {}

int cppworld::one() {
    return 1;
}

I write a wrapper with wrapper.h and wrapper.cpp.

wrapper.h:

#ifdef __cplusplus
extern "C"
{
#endif

int get_one();

#ifdef __cplusplus
}
#endif

wrapper.cpp:

#include "wrapper.h"
#include "cppworld.hpp"

int get_one() {
    cppworld obj = cppworld();

    return obj.one();
}

I can compile wrapper.cpp and cppworld.cpp into a shared library. Then, to use the library from C, I create the C program below.

cworld.c

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

int main() {
    printf("Calling one() returns: %d\n", get_one());
}
TSG
  • 877
  • 1
  • 6
  • 23
  • thanks in advance for your great explanation. about the last part that you said :` because this file will be compiled by a C++ compiler, it will be understand any references to C++ STL in included headers.` do you mean that if I include `info.hpp` in my `smc.cpp`, i don't need to use another extra wrappers for any stl or iostream usages? – fa7eme Aug 03 '20 at 21:02
  • Exactly. You are using two layers of wrapping (smc->getinfo->info) to use `info.hpp` functions. You only need one. `smc.cpp` can directly include `info.hpp` and use the `class info` and other C++ stuff. Just take care to use the `extern C` wrappers carefully. – TSG Aug 04 '20 at 08:55
  • @fa7eme For you, `wrapper.cpp` is `smc.cpp` and `cppworld.cpp` is `info.cpp`. `getinfo` is not needed. – TSG Aug 04 '20 at 09:25
  • is there any way to not to including header file of wrapper in c program?or using of wrapper's functions without including its header? – fa7eme Aug 04 '20 at 10:19
  • I found my answer here : https://rosettacode.org/wiki/Call_a_function_in_a_shared_library – fa7eme Aug 04 '20 at 10:35
1

Whenever I include header file of smc, my C code doesn't know libraries that I had used in getinfo.h, like fstream.

Yeah, you need to give C the declarations (not the definition) of the functions you need, and those declarations cannot use C++ features (directly).

For instance, you cannot give C things like references, templates or overloaded functions. You cannot directly use arbitrary class objects either, like an std::string, but you can pass them around as opaque pointers since for C they are just pointers.

Regardless of how you do it, you need C to see only what appear to be C functions on the surface.

Acorn
  • 24,970
  • 5
  • 40
  • 69
  • thanks in advance. you mean that I should use wrapper for using `fstream` or `std::string` , like in `extern "C"`? how should I do that?is there any example you can give me? – fa7eme Aug 03 '20 at 20:01
  • 1
    @fa7eme Yes, either you pass an opaque pointer to them (like a `void *`, for instance), or you avoid having them as parameters/return types. See for instance [How to call C++ function from C?](https://stackoverflow.com/questions/2744181/how-to-call-c-function-from-c) – Acorn Aug 04 '20 at 01:36