Compiling C and C++ - c++

I have a program written in C and I need to use KDIS libraries which are written in C++. I compile my C program with automake&friends in KDevelop. How can I compile everything together?? Because I want to call some KDIS functions inside my C program.
Thank you in advance.

If you need to call C++ functions which are not declated extern "C", then you have to do so from a C++ program yourself. You can create one single C++ file in your project which wraps all the library functions you need in extern "C" functions to be used by the rest of your project. You'll have to tell autotools that you're using both C and C++. The file extensions should be enough to decide which is which.
To give you an example, consider the following mymagic.cc creating bindings for some libmagic written in C++:
#include <libmagic/magic.hh>
extern "C" {
int doMagic() {
magic::Wizard w("foo", 42);
magic::Result res = w.doMagic();
return res.getResultCode();
}
}
To the rest of your application, doMagic() would appear as just another C function. But the inside is C++, so it can use any C++ constructs you want. When you need to pass stuff from your library around, you should use pointers to opaque types. So in the header mymagic.h which is also used by your C code, you can write
struct magicValue;
int doMagic(void);
struct magicValue* createMagic(void);
void destroyMagic(struct magicValue*);
And in the mymagic.cc you'd then be more explicit:
struct magicValue {
magic::value v;
magicValue(magic::value val) : v(val) { }
};
magicValue* createMagic() {
return new magicValue(magic::value("foo"));
}
void destroyMagic(magicValue*) {
delete magicValue;
}

This link may help you understand how to mix C and C++ code in your application.
Also, look at this Stack Overflow question, I believe that's what you need.

Related

Use C++ class in a c file

I need to use the mbed api but limited to using C. How can I use for example a SPI class in a c file. From looking online to use C++ classes you should create a wrapper function in C++ but as stated I can't use C++, is their another way around this?
How can I use for example a SPI class in a c file.
You cannot use a class† in C.
From looking online to use C++ classes you should create a wrapper function in C++
This is correct.
is their another way around this?
No.
but as stated I can't use C++
Then you're out of options (as far as the standards are concerned). A C++ API (with classes and everything) cannot be used in C. It is possible to create a wrapper interface that uses only features shared by both languages (which excludes all OOP stuff).
That wrapper interface can only be implemented in C++, because it has to interact with the interface that it is wrapping. If the wrapper could be implemented in C, then there would be no need for it. Once that wrapper interface is implemented, it can be used from C.
Some other points:
If a library uses C++, then main must be implemented in C++. That main can also be a trivial wrapper for a C function, which can be called from C++ without fuss.
You must link the dependencies of the C++ library, which may include the C++ standard library
Example:
C++ API
// interface.hpp
class C {
public:
std::string str;
};
C wrapper for the API
// wrapper.h
struct C;
struct C* makeC();
void freeC(struct C*);
void setStr(struct C*, char*);
conts char* getStr(struct C*);
Implementation of the wrapper (in C++)
extern "C" {
#include "wrapper.h"
}
#include "interface.hpp"
C* makeC() { return new C; }
void freeC(C* c) { delete c; }
void setStr(C* c, char* str) { c->str = str; }
const char* getStr(C* c) { return c->str.c_str(); }
Usage in C
struct C* c = makeC();
setStr(c, "test");
puts(getStr(c));
freeC(c);
†Except when the class definition and all of its sub objects use no C++ features whatsoever. Then it is compatible with an identical C struct.
The mbed HAL is written in C, so you can use that without the C++ wrappers. E.g. here is hal/spi_api.h.
Answer is simply - using mbed involves using C++.
If you have to program in C forget about mbed and write your own SPI library or use one of the many available libraries (frameworks) for your target hardware.
There is no other way
If you are limited to use C... just use C and compile it as a C++ file. Most code shall be compatible.

Initialisation of C++ structures from C

I'm trying to use opencv C++ library with another lib in C. So I've defined a structure in an .hpp file which I've added to the .h of the C library
typedef struct {
cv::FileStorage fs;
cv::Mat mat;
} myCPPStruct;
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
myCPPStruct * mycppstruct;
} myCStruct;
void initialize_myCPPStruct(myCPPStruct * mycppstruct);
#ifdef __cplusplus
}
#endif
In the .c files the initializer for myCStruct calls initialize_myCPPStruct which is defined in a .cpp file somewhat as:
void initialize_myCPPStruct(myCPPStruct * mycppstruct){
mycppstruct = {};
mycppstruct->fs = cv::FileStorage( "file.txt", cv::FileStorage::READ );
mycppstruct->mat = cv::Mat(3,3,CV_8UC3);
}
But once it tries to allocate a value to mycppstruct->fs, it gets a segmentation fault. I assume this is because there is no memory allocation in C, but I've tried
std::memset(stitcher->fs,0,sizeof(cv::FileStorage));
which also doesn't work as it can't parse cv:FileStorage as void *.
Will I have to use the deprecated C OpenCV library to make this work?
EDIT - More details about the compilation.
For the C lib, I recompile (without linking ie with the -c option)all the .c files where I've added C++ functions or structures using g++ while making sure I add the __cplusplus guards in the .h files. All the .c files without C++ code already have .o files compiled with gcc. I then compile the whole program with g++ while making sure to include the relevant library files. There are no compiler errors.
It seems the structure itself has not been created.
You might try this (or something similar):
myCPPStruct* initialize_myCPPStruct()
{
myCPPStruct* result;
result = new myCPPStruct();
result->fs = cv::FileStorage( "file.txt", cv::FileStorage::READ );
result->mat = cv::Mat(3,3,CV_8UC3);
return (result);
}
You need to allocate the memory for your structure:
myCPPStruct = malloc(sizeof(myCPPStruct));
Use the above line instead of:
mycppstruct = {};
Also,since your function is passing in the pointer and allocating the memory internally you need to pass a pointer to the pointer or the allocation will not be passed back:
void initialize_myCPPStruct(myCPPStruct** mycppstruct){
if ( mycppstruct == NULL ) {
//Abort as no address of the pointer to allocate passed
return;
}
*myCPPStruct = malloc(sizeof(myCPPStruct));
(*mycppstruct)->fs = cv::FileStorage( "file.txt", cv::FileStorage::READ );
(*mycppstruct)->mat = cv::Mat(3,3,CV_8UC3);
}
Or you could just change the above to:
myCPPStruct* initialize_myCPPStruct(void) {
myCPPStruct* ptr = malloc(sizeof(myCPPStruct));
ptr->fs = cv::FileStorage( "file.txt", cv::FileStorage::READ );
ptr->mat = cv::Mat(3,3,CV_8UC3);
return ptr;
}
First, let me point out the sentence which confuse me.
there is no memory allocation in C
Yes, there is. Have a look to malloc function.
char *my_allocated_string = malloc(sizeof(char) * 42);
Here you are, you've allocated an array of character of size 42.
Now, have a look to : mycppstruct = {};
That's not how you allocate a structure in C. You have to call... malloc() !
my_struct *s = malloc(sizeof(my_struct));
s->fs = 42;
Ok. Done. Feels better.
Well, first of all, you have to create a wrapper around your C++ code. Why ? Because C++ allows multiple definition of a given function (also call symbol) :
int my_func(int);
int my_func(char);
This is valid in C++. But, think about it, how is the compiler able to let two functions with the same name exist ? Well it's not. It uses a technique named mangling when evaluating the functions to create 2 different names. Mangling is use on everything function and method. Event on single functions.
C is not able (and willing) to create several functions with the same name. Otherwise, you will experience a kind of function-already-implemented error. When you declare :
int my_func(int);
the C compiler will create the symbol : my_func. No mangling.
To make both language interact, you need to reference to a symbol understandable by the C compiler. If you call my_func from a C source file, the C compiler will look for my_func symbol. Bu since C++ will modify its my_func symbol into something like _ZN9myfuncE, the linkage will fail. That's why you have to says to the C++ compiler to not use mangling on the function you expose to C. That's why you need extern "C" { }.
Feeww, so far so good...
Now you have to embed you C API into an extern "C" block :
In my_c_api.h :
void my_func(int);
void my_func(char);
In my_c_api.cpp :
#include "my_c_api.h"
extern "C" void my_func_i(int i) { my_func(i); }
extern "C" void my_func_c(char c) { my_func(c); }
You compile it to create your C++ library.
In your C compilation pipeline, you link against your new C++ library and header files. Then :
#include "<path_to_my_c_api.h>"
void c(int i,char s)
{
my_func_i(i);
my_func_c(c);
}
You cannot compile C++ code with C compiler. You have to compile te C++ code independently.
More on ISO CPP.

error when using extern "C" to include a header in c++ program

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

C++/Ada Link Errors

I am not familiar with link errors at all so I was hoping someone could shed some light on these errors...
I am working with a Legacy Ada program. I am developing a C++ Extension in which the Ada will use a proxy to call the C++ functions. The C++ compiles cleanly without any warnings. However I am getting the following Undefined Symbol errors:
__nw__FUi
__walkback
__dl__FPv
The code base is as follows:
#include "cppProxy.h"
extern classHandler *classPtr;
void processData(void* ioBuffer)
{
classPtr->processData(ioBuffer);
}
Header File:
#include "classHandler.h"
extern "C" void processData(void* ioBuffer);
classHandler.cpp
extern "C"
{
classHandler* create()
{
return new classHandler;
}
void destroy(classHandler *p)
{
delete p;
}
}
void processData(*ioBuffer)
{
int idx;
data = static_cast<int*>(ioBuffer);
idx = (data[0] >> 16);
returnData[idx] = data;
}
classHandler.h
class classHandler
{
public:
classHandler();
~classHandler();
void processData(void* ioBuffer);
};
typedef classHandler classPtr;
typedef void destroy_t(classHandler*);
Now the objective is to have the C++ keep track of the object so I was trying to create a singleton that would then be called. Looking at the current state of the code I am trying to figure out where this is since I have done multiple changes trying to fix the linker error.
Overall I am wondering if this is truly a linking error or an issue with my class implementation. I am leaning towards the latter but still uncertain on how to resolve the issue.
Once again the design I am going for is as follows:
Implemented:
Ada calls the C++ to process data.
C++ parses the data and stores it locally.
Not Implemented:
Ada calls the C++ to retrieve the data.
C++ does a lookup and returns data array.
Any help would be appreciated on this since I am lost in my own code at the moment. Thanks!
EDIT1:
The Ada code is too robust but I know with certainty that that side is correct. As for the compiler, I am using Concurrent ANSI C/C++ compiler (PowerPC) – 5.4 (005). I CANNOT change compilers. The first two fragments are the proxy layer of the code. This is what the Ada portion uses to interface into the C++ code.

Calling C++ (not C) from Common Lisp?

I am wondering if there is some way to call C++ code from Common Lisp (preferably portably, and if not, preferably in SBCL, and if not, well, then Clozure, CLisp or ECL).
The C++ would be called inside loops for numeric computation, so it would be nice if calls were fast.
CFFI seems to not support this:
"The concept can be generalized to
other languages; at the time of
writing, only CFFI's C support is
fairly complete, but C++ support is
being worked on."
(chapter 4 of the manual)
SBCL's manual doesn't mention C++ either; it actually says
This chapter describes SBCL's
interface to C programs and libraries
(and, since C interfaces are a sort of
lingua franca of the Unix world, to other programs and libraries in
general.)
The C++ code uses OO and operator overloading, so it really needs to be compiled with g++.
And as far as I know, I can have a C++ main() function and write wrappers for C functions, but not the other way around -- is that true?
Anyway... Is there some way to do this?
Thank you!
After compiling, most C++ functions actually boil down to regular C function calls. Due to function overloading and other features, C++ compilers use name mangling to distinguish between similarly named functions. Given an object dump utility and sufficient knowledge about your C++ compiler, you can call C++ code directly from the outside world.
Having said that though, you may find it easier to write a C-compatible layer between Lisp and your C++ code. You would do that using extern "C" like this:
extern "C" Foo *new_Foo(int x)
{
return new Foo(x);
}
This makes the new_Foo() function follow the C calling convention so that you can call it from external sources.
The main difference in calling C++ functions instead of C functions apart from the name mangling are the 'hidden' features like this pointers that are implicitly passed to member functions. The C runtime layer doesn't know anything about these, implicit type conversions and other fun C++ features, so if you intend to call C++ through a C interface, you might have to fake these features if necessary.
Assuming that you can hold at least a void * to the object you intend to call and the data it requires, you can degrade the following C++ call
matrix->multiply(avector);
to a C call if you create a C wrapper function:
extern "C"
void matrix_multiply(void *cpp_matrix, void *cpp_vector) {
reinterpret_cast<matrix_type *>(cpp_matrix)->multiply(reinterpret_cast<vector_type *>(cpp_vector);
}
Obviously the function matrix_multiply would sit in the C++ source code and compiled as such but it does expose a C interface to the outside world. As long as you can interact with the opaque pointers, you're OK with the translation shims above.
Admittedly this is not necessarily the most elegant solution for a problem like this but I've used it in the past in situations like yours.
The other option would be to make the C++ calls directly by treating them as C calls with additional parameters and supplying all the required information yourself, but that does move you into the realm of compiler-specific code very quickly. Basically, you would still be holding the opaque pointers to C++ objects, but you'd have to work out the mangled name of the function you want to call. Once you've got that function name, you'll have to supply the this pointer (which is implicit in C++ and semi-implicit in the example above) and the correct parameters and then call the function. It can be done but as mentioned, puts you deeply in to the realm of compiler and even compiler-version specific behaviour.
Oh, wait!
It seems that there is a trick I can use!
I write a wrapper in C++, declaring wrapper functions extern "C":
#include "lib.h"
extern "C" int lib_operate (int i, double *x) {
...
}
The header file lib.h, which can be called from both C and C++, is:
#if __cplusplus
extern "C" {
#endif
int lib_operate (int i, double *x);
#if __cplusplus
}
#endif
Then compile with:
g++ -c lib.cpp
gcc -c prog.c
gcc lib.o prog.o -lstdc++ -o prog
Seems to work for a toy example! :-)
So, in Common Lisp I'd call the wrapper after loading libstdc++.
Anyway, thank you for your answers!
Update 2021:CL-CXX-JIT which handles most of the work on the lisp side.
Example:
(ql:quickload :cxx-jit)
(in-package cxx-jit)
(from '("<cmath>") 'import '("static_cast<double(*)(double)>(std::sin)" . "cpp-sin"))
(cpp-sin 0d0)
(from nil 'import "struct C{ auto hi(){return \"Hello, World\\n\";} auto bye(){return \"Bye\";} };" '("&C::bye" . "bye") '("&C::hi" . "hi") '("[](){static C x; return x;}" . "cc"))
(cc)
(hi *)
(bye **)
You can use cl-cxx which is like writing pybind11 for python.
example in c++ 'std >= c++14', compiled as shared lib:
#include <string>
#include "clcxx/clcxx.hpp"
class xx {
public:
xx(int xx, int yy) : y(yy), x(xx) {}
std::string greet() { return "Hello, World"; }
int y;
int x;
};
std::string greet() { return "Hello, World"; }
int Int(int x) { return x + 100; }
float Float(float y) { return y + 100.34; }
auto gr(std::complex<float> x) { return x; }
std::string hi(char* s) { return std::string("hi, " + std::string(s)); }
void ref_class(xx& x) { x.y = 1000000; }
CLCXX_PACKAGE TEST(clcxx::Package& pack) {
pack.defun("hi", F_PTR(&hi));
pack.defun("test-int", F_PTR(&Int));
pack.defun("greet", F_PTR(&greet));
pack.defun("test-float", F_PTR(&Float));
pack.defun("test-complex", F_PTR(&gr));
pack.defun("ref-class", F_PTR(&ref_class));
pack.defclass<xx, false>("xx")
.member("y", &xx::y)
.defmethod("greet-from-class", F_PTR(&xx::greet))
.constructor<int, int>();
}
usage in lisp:
(cffi:use-foreign-library my-lib)
(cxx:init)
(cxx:add-package "TEST" "TEST")
(test:greet)
(setf my-class (test:create-xx2 10 20))
(test:y.get myclass)
That would take care of all conversions, extern "C", ... for you.
Depending on your C++ ABI, your wrapper (lib_operate above) might need to somehow handle any C++ exceptions that might occur. If your ABI does table-drive exception handling, unhandled exceptions will simply crash the (Lisp) process. If it instead does dynamic registration, you might not even notice that anything went wrong. Either way, it's bad.
Or, if you've got the no-throw guarantee for the wrapped code, you can ignore all this.