I am creating programs using C. However, I require to use a lot of libraries that have API's only for C++. So, is it possible that I can create a shared object in C++ and then access its functionality using C?
The only data I would be passing and returning would be C compatible data types.
Converting or migrating to cpp is not an option here.
If it is not possible to interface these codes, how do I get information from C++ code to C code?
I tried calling C++ functions from C, but I get errors during linking when I include <string>. So when I call C++ functions from C, should I only use that code which will be C compiler compatible?
C++ header cppfile.hpp
#ifndef CPPFILE_H
#define CPPFILE_H
#ifdef __cplusplus
extern "C" {
#endif
extern int myfunction(const char *filename);
#ifdef __cplusplus
}
#endif
#endif
C++ file cppfile.cpp
#include "cppfile.hpp"
#include <string>
int myfunction(const char *filename) {
String S(filename);
return 0;
}
C file cmain.c
#include "cppfile.hpp"
int main(int argc, char **argv)
{
int i = myfunction(argv[1]);
printf("%d\n", i);
return 0;
}
Compiling:
gcc -c cmain.c
g++ -fPIC -shared -o cppfile.so cppfile.cpp
You want something more like this (and here I will use a slightly more meaningful example):
C/C++ header - animal.h
#ifndef ANIMAL_H
#define ANIMAL_H
#ifdef __cplusplus
class Animal {
public:
Animal() : age(0), height(0) {}
Animal(int age, float height) : age(age), height(height) {}
virtual ~Animal() {}
int getAge();
void setAge(int new_age);
float getHeight();
void setHeight(float new_height);
private:
int age;
float height; // in metres!
};
#endif /* __cplusplus */
#ifdef __cplusplus
extern "C" {
#endif
struct animal; // a nice opaque type
struct animal *animal_create();
struct animal *animal_create_init(int age, float height);
void animal_destroy(struct animal *a);
void animal_setage(struct animal *a, int new_age);
void animal_setheight(struct animal *a, float new_height);
int animal_getage(struct animal *a);
float animal_getheight(struct animal *a);
#ifdef __cplusplus
}
#endif
#endif /* ANIMAL_H */
C++ animal implementation file - animal.cpp
#include "animal.h"
#define TO_CPP(a) (reinterpret_cast<Animal*>(a))
#define TO_C(a) (reinterpret_cast<animal*>(a))
void Animal::setAge(int new_age) { this->age = new_age; }
int Animal::getAge() { return this->age; }
void Animal::setHeight(float new_height) { this->height = new_height; }
float Animal::getHeight() { return this->height; }
animal *animal_create() {
animal *a = TO_C(new Animal);
return a;
}
animal *animal_create_init(int age, float height) {
animal *a = TO_C(new Animal(age, height));
return a;
}
void animal_destroy(animal *a) {
delete TO_CPP(a);
}
void animal_setage(animal *a, int new_age) {
TO_CPP(a)->setAge(new_age);
}
void animal_setheight(animal *a, float new_height) {
TO_CPP(a)->setHeight(new_height);
}
int animal_getage(animal *a) {
TO_CPP(a)->getAge();
}
float animal_getheight(animal *a) {
TO_CPP(a)->getHeight();
}
C client code - main.c
#include "animal.h"
#include <stdio.h>
int main()
{
// 6'0" 25yo (perhaps a human? :P)
struct animal *a = animal_create(25, 1.83);
animal_setage(a, 26); // birthday
printf("Age: %d\nHeight: %f", animal_getage(a), animal_getheight(a));
animal_destroy(a);
return 0;
}
C++ client code - main.cpp
#include "animal.h"
#include <iostream>
int main()
{
// 6'0" 25yo (perhaps a human? :P)
Animal* a = new Animal(25, 1.83);
a->setAge(26); // birthday
std::cout << "Age: " << a->getAge() << std::endl;
std::cout << "Height: " << a->getHeight();
delete a;
return 0;
}
So when you compile the library, you compile animal.cpp with a C++ compiler. You can then link to it with C code, and use the animal_xxx functions.
Note the use of struct animal and Animal. Animal is a normal C++ type. It's exactly what it looks like. struct animal, on the other hand, is an "opaque" type. That means that your C program can see it's there, and can have one, but it doesn't know what is inside it. All it knows is that it has a function that takes a struct animal*.
In a real library you will want to have customisation points for memory allocation. So assuming this is the library libjungle, you probably want at least jungle_setmalloc and jungle_setfree with sensible defaults. You can then set up the global new and delete in libjungle's C++ code to use these user-defined functions.
This is entirely possible. Here is how, quickly:
1.) You have a header.h with a C API that doesn't include any Cplusiness.
#ifndef MIXEDCCPP_H
#define MIXEDCCPP_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h> // Any C-compatible headers will go here.
// C API goes here. C Functions can't contain any CPPiness.
void myclass_setName( void *pClassObj, const char *pName, int nameLen );
#ifdef __cplusplus
}
#endif
#ifdef __cplusplus
// Stuff that is only compatible with CPP goes here
// __cplusplus section won't get processed while compiling C files.
#include <vector> // CPP headers.
class MyClass {
// Classes etc.
};
#endif // #ifdef __cplusplus
#endif // MIXEDCCPP_H
Then in the .cpp, you simply create some C-API functions that can even include CPP right in them:
#include "mixedccpp.h"
extern "C" {
// C API goes here. C Functions can't contain any CPPiness in their prototypes.
void myclass_setName( void *pClassObj, const char *pName, int nameLen )
{
// But CPP knowledge can go inside the function - no problem, since this is a CPP file.
MyClass *pMyClass = static_cast<MyClass *>(pClassObj);
pMyClass->setName( pName, nameLen );
}
} // #extern "C"
// CPP Stuff goes here... or vice-versa.
In your case, you don't actually need any CPP code declared in your header since you are calling external libraries. But you need to create C-compatible functions in your CPP file which can call out to CPP libraries. Use extern "C" for those functions that need to be called from C files, and then use C-structs instead of classes and, if classes are needed, use void * to point to them and then cast them back to their class from the C function any time you need to access them. A standard makefile should be able to compile this just fine, assuming it compiles .cpp files as .cpp and understands extern "C" {}
Your C code cannot use the C++ header <string>. You have to ensure that the functions in the C++ API that are to be called from C are declared extern "C" (as you have), and use only types recognized by a C compiler (as you have).
You also need to link with the C++ compiler if any of your code is in C++. You can do it otherwise if you're prepared to spend a lot of energy getting the loader options right, but it is far simpler just to use the C++ compiler:
gcc -c cmain.c
g++ -fPIC -shared -o cppfile.so cppfile.cpp
g++ -o cmain cmain.o cppfile.so
Of course, you need to:
Add #include <stdio.h> in cmain.c.
Use std::string S(filename); in cppfile.cpp.
Also, if the program is invoked without arguments, you get:
$ ./cmain
terminate called throwing an exceptionAbort trap: 6
$ ./cmain x3
0
$
You need to protect against misuse, even in test programs.
Related
I'm doing functional testing on c code. Have include .c file in test .cpp file so far, everything works well. But I need to include the same .c file in another .cpp file where I do other unit tests. Then I get problems that is already defined. Because I already include it in the first file cpp.
If merge all the test methods into one cpp file then it works well. If keep all unit test in one file get to big handle so I need to split up diffrent files in same project it also create help functions for secure that functions get in capsules.
This not a normal LNK2005 because I can not declare the variable and functions in .h: as extern BOOL MyBool; and then assign to it in a .c or .cpp file. Because need include c file as I do unit test this function. Also I can't or should avoid do any changes .c.
I looking way to keep include of .c local not effect other files in same project.
source.h
#ifndef SOURCE_H_
#define SOURCE_H_
#include "../car.h"
enum INITIALMODE {
INITIALMODE_NOT_POSITIONING, // 0
INITIALMODE_NO_DRIVER_INPUT, // 1
INITIALMODE_POSITION_LOW_POSITION, // 2
INITIALMODE_POSITION_STANDARD_POSITION, // 3
INITIALMODE_POSITION_HIGH_POSITION // 4
};
void initMotor(void);
#endif
source.c
/* Compiler include files */
#pragma once
#include "positioning.h"
#include "api.h"
#include "drive.h"
#include "types.h"
static void updateTarget(void);
static SWord getMax(UWord Limit, UWord Aux);
static DWord getHeight(void);
static Bool isMode(void);
static Bool isExiting(void);
#define cMaxHeight 100 * Profile.s.Max /* m -> mm */
void initMotor(void)
{
// do something
}
static void updatePositioning(void)
{
// do something
}
Test files look like this, however, this is very scaled for making exemple small.
UnitTest.cpp and UnitTest2.cpp
#include "CppUnitTest.h"
#ifndef UNIT_TEST
#define UNIT_TEST
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
namespace Test
{
extern "C" {
#include "../../Test/source.h"
#include "../../Test/source.c"
}
TEST_CLASS(UnitTest_1)
{
public:
TEST_METHOD(Test_1)
{
// Verify that the initial state is as expected.
initTest();
//Expected value
UWord Expected = 500
//Trigger to execute.
UWord Test = updatePositioning();
// Verify that the results are as expected.
Assert::AreEqual(Expected, Test);
}
};
}
#endif
You should never include a .C or .CPP file.
However, you can compile C code in C++. Here's an example based on the information you gave in your initial post.
YourCCode.h
#ifndef YourCCode_H
#define YourCCode_H
int FunctionToTest(int SomeParams);
int TestStaticFunctions(int SomeParam1, int SomeParam2);
#endif // YourCCode_H
YourCCode.c
#include "YourCCode.h"
static int SomeStaticFunction(int Param1, int Param2)
{
return Param1 + Param2; // that needs extensive testing, obviously.
}
int FunctionToTest(int SomeParams)
{
return SomeStaticFunction(SomeParams, 1);
}
int TestStaticFunctions(int SomeParam1, int SomeParam2)
{
return SomeStaticFunction(SomeParam1, SomeParam2);
}
UnitTest1.cpp
extern "C" {
#include "YourCCode.h"
}
bool TestFunction(int Value)
{
return (FunctionToTest(Value) == Value+1);
}
UnitTest2.cpp
extern "C" {
#include "YourCCode.h"
}
void AnotherTestFunction(int Val, int Val2)
{
int newValue = TestStaticFunctions(Val, Val2);
ASSERT(newValue == Val+Val2);
}
Then compile your CPP and C file.
After you clarified your intent, I realized you're trying to test static functions from another unit. Static function, by definition, are only available to other functions in the same translation unit. This is mostly use as a protection to prevent programmers to call some functions without knowing how to validate their inputs, know the call order, etc...
My best bet here is either you choose that your functions are not static and you can test them from outside your translation unit, or you implement the test functions inside the translation unit containing those static functions. I would recommend the latter as a translation unit should know (architecturally speaking) how to test their own features.
As a third solution, if you don't have any control over the content of the C file (but since you have that C file, I doubt it), you could have a proxy CPP file that includes the C file, and create a proxy call for each static call.
That is a ugly hack, though, and could break very easily if the C file ever gets updated, so I'm advising against it.
Here's a quick example :
YourCCode.h
#ifndef YourCCode_H
#define YourCCode_H
void SomeFunction(void);
#endif // YourCCode_H
YourCCode.c
#include "YourCCode.h"
static int AddSomething(int Param1, int Param2)
{
return Param1 + Param2;
}
static int SubtractSomething(int Param1, int Param2)
{
return Param1 - Param2;
}
void SomeFunction(void)
{
// code meant to be called externally.
}
ProxyTestCode.hpp
bool TestAddSomething(void);
bool TestSubtractSomething(void);
ProxyTestCode.cpp
extern "C" {
#include "YourCCode.h"
#include "YourCCode.c"
}
bool TestAddSomething(void)
{
return (AddSomething(2,2) == 4);
}
bool TestSubtractSomething(void)
{
return (AddSomething(2,2) == 0);
}
UnitTest1.cpp
#include "ProxyTestCode.hpp"
void TestAdd(void)
{
ASSERT(TestAddSomething());
}
UnitTest2.cpp
#include "ProxyTestCode.hpp"
void TestSubtract(void)
{
ASSERT(TestSubtractSomething());
}
If you do that, don't compile your C file in your project.
Let say I've decleared this within MyTools.h
#ifndef _MYTOOLS_
#define _MYTOOLS_
typedef struct {
// const
double LN20;
double LN40;
// methods
double NoteToFrequency(int noteNumber);
} Tool;
extern const Tool tool;
#endif // !_MYTOOLS_
For every compilation unit, there is only a global/const/unique instance of Tool. Exactly what I want.
But now: how can I define it? In the .h i've only declared it. How can I define it in .cpp? Tried somethings like:
tool.LN20 = 1.34;
But of course it doesn't works. And the method's definition?
extern doesn't define any variable it just declares it. What you wan't to achieve can be done as below:
The link Global const object shared between compilation units explains how to do it with extern const
t.h file
#ifndef _MYTOOLS_
#define _MYTOOLS_
struct Tool {
// const
double LN20;
double LN40;
double NoteToFrequency(int noteNumber);
} ;
extern const Tool tool ;
#endif // !_MYTOOLS_
t1.cpp
#include "t.h"
#include <stdio.h>
void use_tool()
{
printf("%f\n",tool.LN20);
printf("%f\n",tool.LN40);
return;
}
t2.cpp
#include "t.h"
#include <stdio.h>
const Tool tool = {.LN20 = 20.0, .LN40 = 30.2};
double Tool::NoteToFrequency(int noteNumber)
{
return 12.0;
}
void use1_tool()
{
printf("%f\n",tool.LN20);
printf("%f\n",tool.LN40);
return;
}
int main()
{
void use_tool();
use_tool();
use1_tool();
return 0;
}
Hope this helps.
I'm trying to call a function defined in a C file from my CPP code and I think I am having issues getting the correct namespace. When compiling I get the error: "Undefined reference to 'Get'".
My C header:
// c.h
#ifndef C_H
#define C_H
#ifdef __cplusplus
extern "C" {
#endif
typedef enum
{
VAL_A1,
VAL_A2
} TYPE_A;
typedef enum
{
VAL_B1,
VAL_B2
} TYPE_B;
typedef enum
{
VAL_C1,
VAL_C2
} TYPE_C;
typedef struct
{
TYPE_B b;
TYPE_C c;
} TYPE_D;
TYPE_A Get(TYPE_B b, TYPE_D *d);
#ifdef __cplusplus
}
#endif
#endif
And my CPP file:
// main.cpp
...
extern "C" {
#include "c.h"
}
...
namespace MyNamespace
{
...
MyClass::MyFunc()
{
TYPE_D d;
// None of these calls will compile
// Get(VAL_B1, &d);
// ::Get(VAL_B1, &d);
}
...
}
I have tried calling without namespace reference and also with the "root" namespace using "::" with no luck. Any help is appreciated. I've read through this which seems to clarify it but I don't really understand it:
using C++ with namespace in C
"Undefined reference" means that the function has been declared (in the header), but not defined. You'll need to define the function in a source file somewhere (presumably the C file you refer to), and make sure that is linked when you build the program.
First, let's note what that error means. An undefined reference at the linker stage means that the compiler is unable to find the instance of something. In this case, the implementation of a function.
Let's look at your code.. There are a few things missing that we need to add to make it compilable:
A definition for Get().
main()
The class definition for MyClass.
Once we added those three fixes, the code compiles without error.
extern "C" { extern "C" {
typedef enum {
VAL_A1,
VAL_A2
} TYPE_A;
typedef enum {
VAL_B1,
VAL_B2
} TYPE_B;
typedef enum {
VAL_C1,
VAL_C2
} TYPE_C;
typedef struct {
TYPE_B b;
TYPE_C c;
} TYPE_D;
TYPE_A Get(TYPE_B b, TYPE_D *d) {
return VAL_A1;
}
}}
namespace MyNamespace {
struct MyClass {
void MyFunc();
};
void MyClass::MyFunc() {
TYPE_D d;
Get(VAL_B1, &d);
::Get(VAL_B1, &d);
}
}
int main() {}
The definition of Get (not shown in the question) also needs to be enclosed in extern "C".
The main difference between C and C++ functions, in practice, is the way they are named in the executable format. C++ functions get "name mangling" treatment by the linker but C functions do not. The linker will see the C++ definition of Get and it will have no idea of its relation to the C declaration, even if they have the same signature.
I have this pieces of code:
class DLL_API MyClassWrapper
{
private:
MyClass * m_myClass;
public:
MyClassWrapper(SIZE inputSize);
~MyClassWrapper();
inline int OutputSize();
}
typedef std::shared_ptr<MyClassWrapper> MyClassWrapperPtr;
extern "C"
{
DLL_API MyClassWrapperPtr CreatreMyClassWrapper(SIZE inputSize)
{
return std::make_shared<MyClassWrapper>(inputSize);
}
}
But it doesn't work, with error:
Error 1 error C2526: CreatreMyClassWrapper: C linkage function cannot return C++ class 'std::shared_ptr<_Ty>'
I understand the problem, but how can I fix it?
The options that I can see are:
1- Don't pass a shared pointer. which means that DLL user should delete the pointer after they used it.
2- Don't use extern "C" : which means that I must use mangled names.
Is there any other solution?
Straight to the point, to return C++ object from C function - just returns it via output arguments:
extern "C"
{
DLL_API void CreatreMyClassWrapper(SIZE inputSize, SomeClass* outputPtr)
{
*outputPtr = SomeClass(....);
}
}
In your example SomeClass == MyClassWrapperPtr, so:
extern "C"
{
DLL_API void CreatreMyClassWrapper(SIZE inputSize, MyClassWrapperPtr* outputPtr)
{
*outputPtr = make_shared<MyClassWrapper>(inputSize);
}
}
Consider however to change your interface a little, because in current shape you need to be sure that your applications and DLLs shall use the same compiler, linker, settings, libraries...*
You might want to export Create and Delete from your DLL to be sure memory management will occur in your DLL (this is based on this answer:
DLL
extern "C"
{
DLL_API MyClassWrapper* CreateMyClassWrapper(SIZE inputSize)
{
return new MyClassWrapper(inputSize);
}
DLL_API void DeleteMyClassWrapper(MyClassWrapper* wrapper)
{
delete wrapper;
}
}
Application
shared_ptr<MyClassWrapper> myClassWrapper(CreateMyClassWrapper(inputSize),
DeleteMyClassWrapper);
Using Eclpse on Linux I have defined a C++ class, named ABC (ABC.hpp):
#ifndef ABC_HPP_
#define ABC_HPP_
#include <stdio.h>
// namespace my { <---- COMMENTED OUT
class ABC {
private:
int m_number;
public:
ABC(int p_number);
void doSomething();
virtual ~ABC();
};
// } /* namespace my */ <---- COMMENTED OUT
#endif /* ABC_HPP_ */
and its implementation is (ABC.cpp):
#include "ABC.hpp"
// using namespace my; <---- COMMENTED OUT
ABC::ABC(int p_number) {
this->m_number = p_number;
}
ABC::~ABC() {
this->m_number = -1;
}
void ABC::doSomething() {
printf("doing something (%d)\n", this->m_number);
}
To use this class in C programs, I have created a layer containing these methods (ABCwrapper.h):
typedef void CABC;
#ifdef __cplusplus
extern "C" {
#endif
CABC* create_abc();
void call_abc_methods(const CABC *p_abc);
void destroy_abc(CABC *p_abc);
#ifdef __cplusplus
} // extern "C"
#endif
and
#include "ABC.hpp"
#include "ABCWrapper.h"
extern "C" {
CABC* create_abc() {
ABC* abc = new ABC();
return (ABC*)abc;
}
void call_abc_methods(const CABC *p_abc) {
ABC* abc = (ABC*)p_abc;
abc->doSomething();
}
void destroy_abc(CABC *p_abc) {
ABC* abc = (ABC*)p_abc;
delete abc;
}
}
That's fine and I can use the ABC class instance. But what about the define the ABC class in a name space, let's say "my"? If I remove the comment signs from all name space lines the IDE complains saying that the "Type 'ABC' could not be resolved".
If I want to extend my C++ library I have to use name space for my classes but then I don't know how to use in wrappers. Please, help me to solve this mystery.
Thank you.
SK
Some mostly minor nitpicks about the code. You've already got the details of the solution with an active namespace, but there are various minor issues that should be addressed.
You would be better off introducing an incomplete type, typedef struct CABC CABC; (in place of typedef void CABC;), so that you get some type safety in the C code. This would prevent you passing a random FILE *, for example, to the C interface functions, which using void won't.
When you use the incomplete type, you should use reinterpret_cast<ABC *>(abc) in the C wrapper functions instead of C-style casts. The compiler then shows up a problem with const-ness in the call_abc_methods() function; the argument should not be const (but the C-style cast hid the problem).
Additionally, your ABC.hpp header shows a common (minor) mistake; it includes an extraneous header (#include <stdio.h>) that is not needed to use the header safely. That line should only appear in the implementation file, ABC.cpp, where the code uses the services of <stdio.h>. Most headers should #include only those other headers necessary to make the header usable on its own. They should not include random other headers.
Here's a complete working program — which has a lot of files. There are 3 headers:
ABC.hpp — declaring class ABC.
ABCwrapper.h — declaring the C interface to class ABC.
ABCprogram.h — bilingual header declaring other functions.
There is 1 C file:
ABCuser.c — there must be some C code that needs to use the C interface to class ABC to make the whole exercise worthwhile, and this is it.
There are 3 C++ files:
ABC.cpp — defining class ABC.
ABCwrapper.cpp — defining the C interface to class ABC.
ABCmain.cpp — the main program in a bilingual system should normally be written in C++.
And there's a makefile.
ABC.hpp
#ifndef ABC_HPP_INCLUDED
#define ABC_HPP_INCLUDED
namespace abc_library {
class ABC {
private:
int m_number;
public:
ABC(int p_number);
void doSomething();
virtual ~ABC();
};
} /* namespace abc_library */
#endif /* ABC_HPP_INCLUDED */
ABCwrapper.h
#ifndef ABCWRAPPER_H_INCLUDED
#define ABCWRAPPER_H_INCLUDED
typedef struct CABC CABC; // Pointer to this ncomplete type used in C code
#ifdef __cplusplus
extern "C" {
#endif
CABC *create_abc(int val);
void call_abc_methods(CABC *p_abc);
void destroy_abc(CABC *p_abc);
#ifdef __cplusplus
}
#endif
#endif /* ABCWRAPPER_H_INCLUDED */
ABCprogram.h
#ifndef ABCPROGRAM_H_INCLUDED
#define ABCPROGRAM_H_INCLUDED
#if defined(__cplusplus)
extern "C" {
#endif
extern int c_code_function(int init);
#if defined(__cplusplus)
}
#endif
#endif /* ABCPROGRAM_H_INCLUDED */
ABCuser.c
#include "ABCwrapper.h"
#include "ABCprogram.h"
int c_code_function(int init)
{
CABC *abc = create_abc(init);
call_abc_methods(abc);
destroy_abc(abc);
return 0;
}
ABC.cpp
#include "ABC.hpp"
#include <stdio.h>
using namespace abc_library;
ABC::ABC(int p_number) {
this->m_number = p_number;
}
ABC::~ABC() {
this->m_number = -1;
}
void ABC::doSomething() {
printf("doing something (%d)\n", this->m_number);
}
ABCwrapper.cpp
#include "ABC.hpp"
#include "ABCwrapper.h"
using namespace abc_library;
extern "C" {
CABC *create_abc(int val) {
ABC* abc = new ABC(val);
return reinterpret_cast<CABC*>(abc);
}
void call_abc_methods(CABC *p_abc) {
ABC *abc = reinterpret_cast<ABC *>(p_abc);
abc->doSomething();
}
void destroy_abc(CABC *p_abc) {
ABC* abc = reinterpret_cast<ABC *>(p_abc);
delete abc;
}
}
ABCmain.cpp
#include "ABCprogram.h"
int main()
{
return c_code_function(39);
}
makefile
CC = gcc # /usr/bin/gcc
CXX = g++
RM_FR = rm -fr --
WFLAGS = -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition
SFLAGS = -std=c99
OFLAGS = -g -O3
UFLAGS = # Set on make command line only
OXXFLAGS = -g -O3
SXXFLAGS = -std=c++11
WXXFLAGS = -Wall -Wextra
UXXFLAGS = # Set on make command line only
LDFLAGS =
LDLIBS =
CFLAGS = ${OFLAGS} ${SFLAGS} ${WFLAGS} ${UFLAGS}
CXXFLAGS = ${OXXFLAGS} ${SXXFLAGS} ${WXXFLAGS} ${UXXFLAGS}
PROGRAM = abc
FILES.cpp = \
ABC.cpp \
ABCmain.cpp \
ABCwrapper.cpp
FILES.c = \
ABCuser.c
FILES.h = \
ABCprogram.h \
ABCwrapper.h
FILES.o = ${FILES.cpp:.cpp=.o} ${FILES.c:.c=.o}
all: ${PROGRAM}
${PROGRAM}: ${FILES.o}
${CXX} -o $# ${CXXFLAGS} ${FILES.o} ${LDFLAGS} ${LDLIBS}
clean:
${RM_FR} *.o *.dSYM core a.out
depend:
mkdep ${FILES.cpp} ${FILES.c}
# DO NOT DELETE THIS LINE or the blank line after it -- make depend uses them.
ABC.o: ABC.cpp
ABC.o: ABC.hpp
ABCmain.o: ABCmain.cpp
ABCmain.o: ABCprogram.h
ABCuser.o: ABCprogram.h
ABCuser.o: ABCuser.c
ABCuser.o: ABCwrapper.h
ABCwrapper.o: ABC.hpp
ABCwrapper.o: ABCwrapper.cpp
ABCwrapper.o: ABCwrapper.h
In ABCWrapper.cpp, above the extern "C" { line, add:
using my::ABC;
or
using namespace my;
john's suggestion (replace all instances of ABC with my::ABC in ABCWrapper.cpp) also works.
You have to set the scope for your ABC class. So replace all the ABC class as my::ABC except in the class declaration.
extern "C" {
CABC* create_abc() {
my::ABC* abc = new my::ABC();
return (my::ABC*)abc;
}
void call_abc_methods(const CABC *p_abc) {
my::ABC* abc = (my::ABC*)p_abc;
abc->doSomething();
}
void destroy_abc(CABC *p_abc) {
my::ABC* abc = (my::ABC*)p_abc;
delete abc;
}
}