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;
}
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.
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());
}
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.
Related
I want to give a c++ function a custom symbol name (without mangling) so that a can call it from c directly without redirection. For example: If I have the following class in c++:
class Foo {
public:
Foo();
void some_method(int);
int a_;
};
I want to give Foo::some_method a custom name like Foo_some_method so that I can call it from c code directly without need for redirection from another function inside extern "C", is that possible?
No, to enable a C conpatible calling convention and symbol name you need to produce an extern "C" normal function (in theory, an extern "C" function pointer could also work).
So write your glue code.
It is plausible with reflection you'll be able to automate that. But that is not yet standardized, and covid 19 may delay it past 2023.
I tested this using g++ and gcc and it worked! I used asm labels to give the symbol a custom name.
product.h
#ifndef BCC702_PRODUTO_H
#define BCC702_PRODUTO_H
#include <string>
#include <ostream>
class product {
public:
/// Create product
product(int id, double price, char* name);
/// Print product
void print() asm("Asm_product_print");
void set_name(char* name) asm("Asm_product_set_name") ;
private:
int id_;
double price_;
char* name_;
};
#endif //BCC702_PRODUTO_H
product.cpp compiled to object using g++
#include "product.h"
#include <iostream>
void product::print() {
std::cout << name_ << std::endl;
}
product::product(int id_, double price_, char* _name_) :
id_(id_), price_(price_), name_(_name_) {}
void product::set_name (char* _name_) {
product::name_ = _name_;
}
main.c compiled with gcc
typedef struct{
int id_;
double price_;
char* name_;
} product;
void Asm_product_set_name(product* p, char* string);
void Asm_product_print(product* p);
char* example = "hello world!";
int main(){
product p;
Asm_product_set_name(&p, example);
Asm_product_print(&p);
return 0;
}
Finally, link objects using g++. And the test result is:
Hello world!
However, I'm not sure whether it will work with other c++ compilers.
In my project I would like to use C++ and STL containers but have a problem that I have to include hw vendor headers (and link vendor lib and use some vendor C sources that also include the vendor headers) written in ANSI C, that contain C++ reserved keywords, for example:
vendor.h:
// Vendor header (read only)
struct Vendor_Export_Struct {
unsigned char* data;
};
struct Vendor_Export_Struct export; // <<< compilation error under C++
union Vendor_Union {
struct Vendor_Export_Struct export; // <<< compilation error under C++
};
What included into C++ will cause errors during compile: expected unqualified id before ‘export’. So I'm forced to use pure C and thinking if it would be possible simply wrap STL vector to kind of C API like this (with C++ implementation behind):
cvect.h :
typedef void* Vect_Type;
typedef void** Vect_Iterator_Type;
typedef void* Vect_Data_Type;
Vect_Type Vect_New();
void Vect_PushBack(Vect_Type v, Vect_Data_Type d);
Vect_Iterator_Type Vect_Begin(Vect_Type v);
Vect_Iterator_Type Vect_End(Vect_Type v);
Vect_Iterator_Type Vect_Next(Vect_Type v, Vect_Iterator_Type it);
But problem is how to pass on the vector and iterator. I think I would be forced to use reinterpret_cast when casting from std::vector<> -> void* -> std::vector<> on the C++ code side and still thinking how to cast/pass std::vector<>::iterator.
c_vect.cpp :
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <vector>
#include <algorithm>
#include "c_vect.h"
typedef std::vector<void*> Vect_Container_Type;
Vect_Type Vect_New()
{
return static_cast<Vect_Type>(new Vect_Container_Type);
}
void Vect_PushBack(Vect_Type v, Vect_Data_Type d)
{
Vect_Container_Type& vref = *reinterpret_cast<Vect_Container_Type*>(v);
vref.push_back(d);
}
Vect_Iterator_Type Vect_Begin(Vect_Type v)
{
Vect_Container_Type& vref = *reinterpret_cast<Vect_Container_Type*>(v);
return &*vref.begin();
}
Vect_Iterator_Type Vect_End(Vect_Type v)
{
Vect_Container_Type& vref = *reinterpret_cast<Vect_Container_Type*>(v);
return &*vref.end();
}
Vect_Iterator_Type Vect_Next(Vect_Type v, Vect_Iterator_Type it)
{
Vect_Container_Type& vref = *reinterpret_cast<Vect_Container_Type*>(v);
Vect_Container_Type::iterator it_ = static_cast<Vect_Container_Type::iterator>(it); //<<<< ugly and not portable
if (it_ != vref.end())
{
++it_;
return &*it_;
}
return NULL;
}
main.c :
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "c_vect.h"
#include "vendor.h"
typedef struct S_Connection {
size_t id;
char* name;
union Vendor_Union u;
Vect_Type sessions; // Another vector
} T_Connection;
typedef T_Connection* T_ConnectionPtr;
static void* makeConn(size_t id, const char* name)
{
T_ConnectionPtr ptr = (T_ConnectionPtr)malloc(sizeof(T_Connection));
ptr->id = id;
ptr->name = (char*)malloc(strlen(name) + 1);
strcpy(ptr->name, name);
return ptr;
}
int main(int argc, char* argv[])
{
Vect_Type conns = Vect_New();
Vect_Iterator_Type it;
unsigned i;
for (i = 0; i < 10; ++i) {
char name[20];
sprintf(name, "conn_%03d", i);
Vect_PushBack(conns, makeConn(i + 1, name));
}
// Iterate vector and access stored data
for (it = Vect_Begin(conns);
it != Vect_End(conns);
it = Vect_Next(conns, it)) {
T_ConnectionPtr cd = (T_ConnectionPtr)*it;
}
return 0;
}
So I'm not sure if all this is a good idea, probably not from several reasons. I just would like to avoid another redundant C vector implementation, take profit from STL iterators. The final code should be portable. Has someone been solving a similar problem like this? Or do you have a better idea how to cope with this?
There are methods now to access the raw data array of the Vector:
value_type* data() noexcept;
const value_type* data() const noexcept;
These extensions were added in C++11 exactly for your case, to interface third party libraries that only take the raw data array. Pass the returned pointer to C as an array that is also a pointer in C. You will likely need add vector.size() as another parameter.
Do not manipulate the vector while using the returned pointer.
I am by no means an expert in this topic, but I've run into this problem before, and I've found that there are two options that seem to work:
You can write a vector library in C yourself. I've often found that this isn't really as hard as it may seem, and then you don't have code that is reliant upon the C++ STL, which won't be supported in a lot of the places one may want to use C, like in embedded systems, for example.
You will have to make a header in the following form:
#ifdef __cplusplus
extern "C" {
#endif
/* Define all your C wrapper functions here */
/* For example: */
void VectorWrapper_Add(struct VectorWrapper *vector_wrapper, const struct VectorWrapper_DataType *data_to_add);
#ifdef __cplusplus
}
#endif
And then in the implementation file, you can put something like this:
#include "my_c_wrapper.h"
#include <vector>
/* Do something similar for all your functions... */
void VectorWrapper_Add(struct VectorWrapper *vector_wrapper, const struct VectorWrapper_DataType *data_to_add)
{
/* Your implementation might look something like this for such a function: */
vector_wrapper->_stl_vector->push_back(*data_to_add);
}
Most the time, what I end up doing is just creating my own libraries to manage these sorts of data structures; but again, the choice is yours.
I hope my answer helps you.
I'm developing a C++ library for export as a DLL in Visual Studio 2013 (C++ 11), and I'm running into a challenge where the library, once imported as an external dependency by another program, contains the classes that I wanted, but none of the functions of the classes are included.
View of classes within external dependency
I have included one particular class that is supposed to be part of this DLL export.
Here is my RegressionTrainer class header file:
#ifndef REGRESSION_TRAINER_H
#define REGRESSION_TRAINER_H
#include "MachineLearning.h"
#pragma once
#ifndef DLL_EXPORT
#define DLL_EXPORT __declspec(dllexport)
#endif
using namespace MachineLearning;
namespace MachineLearningTraining{
public class RegressionTrainer{
public:
DLL_EXPORT RegressionTrainer();
virtual DLL_EXPORT ~RegressionTrainer();
std::vector<sample_type> DLL_EXPORT getInputData();
std::vector<double> DLL_EXPORT getAugmentedOutputs();
std::vector<double> DLL_EXPORT getNonAugmentedOutputs();
protected:
pugi::xml_parse_result DLL_EXPORT setDataFile(pugi::xml_document &doc, char* file_name);
void DLL_EXPORT setDataFolder(char* folder_name);
std::vector<char*> DLL_EXPORT findDataFiles();
char* data_folder;
std::vector<char*> file_names;
std::vector<sample_type> input_data;
/*
sample_type m;
m(0, 0) = 14.86;
m(1, 0) = 0.24;
*/
std::vector<double> augmented_outputs;
std::vector<double> non_augmented_outputs;
pugi::xml_parse_result result;
void DLL_EXPORT setInputData();
void DLL_EXPORT setAugmentedOutputs();
void DLL_EXPORT setNonAugmentedOutputs();
virtual int DLL_EXPORT trainAugmentedModel();
virtual int DLL_EXPORT trainNonAugmentedModel();
};
}
#endif
Here are the contents of MachineLearning.h:
#include <vector>
#include <iostream>
#include <exception>
#include <fstream>
#include <string>
#include <dlib/svm.h>
#include "pugixml.hpp"
namespace MachineLearning{
// Here we declare that our samples will be 2 dimensional column vectors.
typedef dlib::matrix<double, 3, 1> sample_type;
// Now we are making a typedef for the kind of kernel we want to use. I picked the
// radial basis kernel because it only has one parameter and generally gives good
// results without much fiddling.
typedef dlib::radial_basis_kernel<sample_type> kernel_type;
}
And here is my RegressionTrainer.cpp file:
#include "Stdafx.h"
#include "RegressionTrainer.h"
#include "dirent.h"
using namespace std;
using namespace dlib;
using namespace MachineLearning;
namespace MachineLearningTraining{
RegressionTrainer::RegressionTrainer(){
file_names = findDataFiles();
}
RegressionTrainer::~RegressionTrainer(){
}
pugi::xml_parse_result RegressionTrainer::setDataFile(pugi::xml_document &doc, char *file_name){
return doc.load_file(file_name);
}
void RegressionTrainer::setDataFolder(char *folder_name){
data_folder = folder_name;
}
std::vector<char*> RegressionTrainer::findDataFiles(){
DIR *dir;
struct dirent *ent;
std::vector<char*> file_names;
if ((dir = opendir(data_folder)) != NULL) {
/* print all the files and directories within directory */
while ((ent = readdir(dir)) != NULL) {
file_names.push_back(ent->d_name);
}
closedir(dir);
}
else {
/* could not open directory */
perror("Could not open directory");
}
return file_names;
}
std::vector<sample_type> RegressionTrainer::getInputData(){
return input_data;
}
std::vector<double> RegressionTrainer::getAugmentedOutputs(){
return augmented_outputs;
}
std::vector<double> RegressionTrainer::getNonAugmentedOutputs(){
return non_augmented_outputs;
}
void RegressionTrainer::setInputData(){
pugi::xml_document doc;
for (unsigned i = 0; i < file_names.size(); i++){
setDataFile(doc, file_names[i]);
std::cout << "Load result: " << result.description() << endl;
pugi::xml_node measures = doc.child("case").child("measures");
sample_type m;
int count = 0;
for (pugi::xml_node measure = measures.first_child(); measure; measure = measure.next_sibling()){
m(count, 0) = measure.text().as_double();
count++;
}
input_data.push_back(m);
}
}
void RegressionTrainer::setAugmentedOutputs(){
pugi::xml_document doc;
for (unsigned i = 0; i < file_names.size(); i++){
setDataFile(doc, file_names[i]);
std::cout << "Load result: " << result.description() << endl;
pugi::xml_node output = doc.child("case").child("studyresults").child("averageangledeviation");
augmented_outputs.push_back(output.text().as_double());
}
}
void RegressionTrainer::setNonAugmentedOutputs(){
pugi::xml_document doc;
for (unsigned i = 0; i < file_names.size(); i++){
setDataFile(doc, file_names[i]);
std::cout << "Load result: " << result.description() << endl;
pugi::xml_node output = doc.child("case").child("studyresults").child("averageangledeviationAR");
augmented_outputs.push_back(output.text().as_double());
}
}
int RegressionTrainer::trainAugmentedModel(){
return 0;
}
int RegressionTrainer::trainNonAugmentedModel(){
return 0;
}
}
Would welcome any thoughts!
Your code is confusing:
public class RegressionTrainer
Is this C++ or C#? Some other part of your code clearly shows it is C++. Therefore you must always put exact (or syntactically same) code.
Back to your problem, you cannot export members of a class. You must export entire class from a DLL.
Then issues start to begin. For one, you must expose (export or not, doesn't matter) all types the class uses (pugi::xml_parse_result for example). Then, you need to take care of different compilers versions (Even VC2015, various versions, debug/release, compiler settings etc). For example a vector on VC2015 debug build would be different from a release version. Service pack would complicate the problem.
In short: Don't export entire class having data-members. Even if entire data is private, you will need to export entire class, so that client (consumer of DLL) can compile and link (to code) properly.
So, what's the solution?
Well, just export a helper class:
class DLL_EXPORT RegressionTrainerHelper
{
RegressionTrainer* pCoreClass;
};
Expose (export) all required methods (for the client) from this class. You'd just need to forward the calls from helper to real class.
Now, you might wonder, you will need to export the underlying type RegressionTrainer, and you are back to same problem.
Well, yes and no. If this helper class is being compiled within DLL, RegressionTrainer would be real thing. If not, just:
typedef int RegressionTrainer;
Pointer of anytype is of same size (32-bit or 64-bit). Hence the size of entire exported class would always match the size in DLL and in EXE.
EDIT
For example, there is a XML parser class, ParseXML, but it uses comlpex data members, you have a method Parse.
class ParseXML
{
// complex data members
// some private OR public datamembers and functions, you dont want/need to export
public:
void Parse(const char*); // or something different
};
You would want to export only Parse, through helper class.
class DLL_EXPORT Exported_ParseXML
{
private:
ParseXML* pCoreXMLInstance;
public:
Exported_ParseXML()
{
// implementation in CPP
pCoreXMLInstance = new ParseXML();
}
// The function!
void Parse(const char* pData)
{
// FORWARD
pCoreXMLInstance->Parse(pData);
}
The client will simply use the exported class:
Exported_ParseXML parser;
parser.Parse("XML-data");
The server compiler (DLL) would see ParseXML as real class type. But the client (EXE, or other DLL), would need see ParseXML as int. You got to figure out this!
Is there any solution to run a function/macro that name is created by concatenation of two strings?
I just want to do something like that:
template <char *A, char *B, int C>
int function_that_run_other_function(void){
// Here is the main point
char function_name[80];
strcpy (function_name, "function");
strcat (function_name, A);
strcat (function_name, B);
return function_name(C);
}
I can do this using macro:
#define macro_that_run_function(A,B,C) \
function_##A##B##(C);
But I don't want to use macro because of many problems with macros.
Is it possible to do in C++ without any additional libraries?
I got curious and after a little while I ended up with this ungodly mess and general mainentace nightmare:
main.cpp:
#include <map>
#include <iostream>
#include <sstream>
#include <functional>
#include <cstring>
typedef std::function<void(int)> func;
typedef std::map<std::string, func> FuncMap;
template <char* A, char* B, int C>
void runner(FuncMap funcs){
std::stringstream ss;
ss <<A <<B;
return funcs[ss.str()](C);
}
void ABC(int val) {
std::cout <<"Woo: " <<val <<"\n";
}
extern char a[]; //due to external linkage requirement
extern char b[];
int main(...) {
FuncMap funcs;
strcpy(a, "A");
strcpy(b, "B");
funcs["AB"] = std::bind(&ABC, std::placeholders::_1);
runner<a, b, 0>(funcs);
return 0;
}
vars.cpp:
char a[5] = {""};
char b[5] = {""};
So yes with enough force you can make c++ do something along the lines of what you want, but I really wouldn't recommend it.
No, C++ does not allow the compile or run time manipulation or inspection of symbol names (barring the implementation specified type info stuff).
Dynamic libraries often export names (mangled for C++, almost unmangled for `extern "C"``), and libraries for loading them usually (always?) allow them to be loaded by string value.
I have these two files table.cpp and table.h in my program code apart from the main.cpp. The files are described as below
table.cpp
#include <iostream>
#include "table.h"
using namespace std;
// accessor function for Name
char* PeriodicTable::Name()
{
return Name;
}
// accessor function for Symbol
char* PeriodicTable::Symbol()
{
return Symbol;
}
table.h
#ifndef TABLE_H
#define TABLE_H
class PeriodicTable
{
char Name[15], Symbol[3], GroupName[20], Block, State[25], Colour[15], Classification[20];
int GroupNo, AtomicNo, PeriodNo;
float Weight;
public:
char* Name();
char* Symbol();
};
#endif
but the problem is that the IntelliSense(since I am using Visual C++ Express 2010) shows a red curved underline below the name and symbol in the accessor function in table.cpp. I can't understand why???
Your member functions and member variables have the same name. This is not possible in C++. That's why various conventions exist for naming member variables, e.g. m_name, name_ etc. (NB: When dealing with underscores in identifiers make sure you don't use a reserved name by accident.)
You might wonder why and how that could possibly go wrong. In your example there clearly is no way to invoke operator() on char[15], but the problem is that the compiler only knows that after performing semantic analysis. There could also be cases where it is impossible to disambiguate. For example:
struct Func {
void operator()() { };
};
struct C {
Func f;
void f() {}
};
int main() {
C c;
c.f(); // which one?
}