Page 1 of 2
C++ OOP library and Interface
Posted: Tue Sep 27, 2016 4:43 am
by StarBootics
Hello everyone,
I'm currently looking to use C++ OOP libraries directly in PureBasic using the Interface/EndInterface feature but I can't find a working example.
I have take a look at
this topic and also few others but nothing seems to work at least under Linux.
The best will be a complete tutorial explaining everything from the C++ source code, compiling it into a *.so library to Import it Into PureBasic and finally using it in an actual program.
Thanks in advance for any advices.
Best regards
StarBootics
Re: C++ OOP library and Interface
Posted: Wed Sep 28, 2016 4:59 am
by StarBootics
More than 100 view, no answer yet ...
A small C++ class source code, the header file (time.h) :
Code: Select all
#ifndef TIME_H
#define TIME_H
class Time
{
public:
Time();
void Update(int, int ,int);
void SetHour(int);
void SetMinute(int);
void SetSecond(int);
int GetHour() const;
int GetMinute() const;
int GetSecond() const;
~Time();
private:
int hour;
int minute;
int second;
};
#endif // TIME_H
The corresponding time.cpp file :
Code: Select all
#include <iostream>
#include "time.h"
Time::Time()
{
hour = minute = second = 0;
}
void Time::Update(int h, int m, int s)
{
hour = ( h >=0 && h < 24 ) ? h : 0;
minute = ( m >=0 && m < 60 ) ? m : 0;
second = ( s >=0 && s < 60 ) ? s : 0;
}
void Time::SetHour(int h)
{
hour = ( h >= 0 && h < 24 ) ? h : 0;
}
void Time::SetMinute(int m)
{
minute = ( m >= 0 && m < 60 ) ? m : 0;
}
void Time::SetSecond(int s)
{
second = ( s >= 0 && s < 60 ) ? s : 0;
}
int Time::GetHour() const
{
return hour;
}
int Time::GetMinute() const
{
return minute;
}
int Time::GetSecond() const
{
return second;
}
Time::~Time()
{
hour = minute = second = 0; // Maybe over kill in this case
}
So the question how to make a *.so file out of this to be imported into PureBasic later on ?
Any modifications to the original code ?
Thanks
StarBootics
Re: C++ OOP library and Interface
Posted: Wed Sep 28, 2016 3:07 pm
by Shield
My answer after having done that many years ago: don't do it.
If you want to use the functions in PB, either code them in a procedural style or wrap your objects in functions.
You will have a hard time getting this right because of the way compilers allocate / optimize the class layout.
If you insist on doing it: create a separate create_time_object() function that returns "new Time()",
add a release method that calls "delete this", and mark all methods as "virtual" (this is probably
the most important step, because without the keyword virtual, the method calls are just syntactical sugar
and nothing is actually being written into the virtual table that is required for interfaces to work).
You then might have some luck getting it to work, but you probably have to fiddle around with correct layouting
and call methods (e.g. mark them as __stdcall).
Re: C++ OOP library and Interface
Posted: Wed Sep 28, 2016 4:21 pm
by StarBootics
Shield wrote:My answer after having done that many years ago: don't do it.
If you want to use the functions in PB, either code them in a procedural style or wrap your objects in functions.
The problem is this : I would like to use Open Cascade in PureBasic and Open Cascade is not something I will code my self.
Even if it's possible to recode an entire geometry kernel in PureBasic, I don't want to do that. And if I need to re-code something complex in C, it will probably better to Switch to C++ all together.
Thanks anyway.
StarBootics
Re: C++ OOP library and Interface
Posted: Wed Sep 28, 2016 9:05 pm
by idle
As far as I remember you can only use C++ libs that have exported their classes functions as pure virtual functions
or wrapped in com.
The calling convention is different between x86 and x64
x86 windows uses thiscall where the object pointer is passed in ecx as first parameter, so you would need a patch or macro to do it
x86 linux uses fastcall, so it should work via interfaces unchanged
and x64 windows and linux both use fastcall
try user_russian's patch for windows x86
http://www.purebasic.fr/english/viewtop ... 12&t=54604
Re: C++ OOP library and Interface
Posted: Thu Sep 29, 2016 2:02 am
by StarBootics
Mainly I'm under Linux x64 so ...
Anyway I will be in training for the next two day, I will make some test next Saturday.
Thanks
StarBootics
Re: C++ OOP library and Interface
Posted: Sat Oct 01, 2016 7:32 pm
by StarBootics
Hello everyone,
I'm trying to compile a library but it's not working since I'm not as good at C++ as I'm with PureBasic so I'm asking for help.
This the modified header file (time.h) :
Code: Select all
#ifndef TIME_H
#define TIME_H
class Time
{
public:
Time();
virtual void Update(int, int , int);
virtual void SetHour(int);
virtual void SetMinute(int);
virtual void SetSecond(int);
virtual int GetHour() const;
virtual int GetMinute() const;
virtual int GetSecond() const;
virtual ~Time();
private:
int hour;
int minute;
int second;
};
#endif // TIME_H
The time.cpp :
Code: Select all
#include "time.h"
Time::Time()
{
hour = minute = second = 0;
}
void Time::Update(int h, int m, int s)
{
hour = ( h >=0 && h < 24 ) ? h : 0;
minute = ( m >=0 && m < 60 ) ? m : 0;
second = ( s >=0 && s < 60 ) ? s : 0;
}
void Time::SetHour(int h)
{
hour = ( h >= 0 && h < 24 ) ? h : 0;
}
void Time::SetMinute(int m)
{
minute = ( m >= 0 && m < 60 ) ? m : 0;
}
void Time::SetSecond(int s)
{
second = ( s >= 0 && s < 60 ) ? s : 0;
}
int Time::GetHour() const
{
return hour;
}
int Time::GetMinute() const
{
return minute;
}
int Time::GetSecond() const
{
return second;
}
Time::~Time()
{
hour = minute = second = 0; // Maybe over kill in this case
}
The library main file :
Code: Select all
#include "time.h"
extern "C"
{
Time* CreateTimeInterface()
{
return new Time;
}
}
I'm under Linux (Ubuntu Gnome16.04 x64), I'm using Code::Blocks 16.01 x64 with gcc/g++ compiler.
This is the build log
-------------- Build: Debug in time (compiler: GNU GCC Compiler)---------------
g++ -shared obj/Debug/main.o obj/Debug/time.o -o bin/Debug/libtime.so
/usr/bin/ld: obj/Debug/main.o: relocalisation de R_X86_64_32 en vertu de «__gxx_personality_v0» ne peut être utilisée lors de la création d'un objet partagé; recompiler avec -fPIC
obj/Debug/main.o : erreur lors de l'ajout de symboles : Mauvaise valeur
collect2: error: ld returned 1 exit status
Process terminated with status 1 (0 minute(s), 0 second(s))
1 error(s), 0 warning(s) (0 minute(s), 0 second(s))
I'm stuck there, any help will be welcome.
Best regards
StarBootics
Re: C++ OOP library and Interface
Posted: Sat Oct 01, 2016 8:46 pm
by Shield
An error message in a language I understand would be helpful.
Try to use make instead of CodeBlocks so you have more control over what the compiler is doing.
I used your time.h and time.cpp, but put the CreateTimeInterface directly into time.cpp.
Using the following make code, it compiled fine as a static library. I didn't test it, though, because
I don't have PB installed and it's 3:45am
Code: Select all
all: libtime.a
time.o: time.cpp
gcc -c time.cpp -o time.o
libtime.a: time.o
ar rcs libtime.a time.o
Time::~Time()
{
hour = minute = second = 0; // Maybe over kill in this case
}
It's not only overkill, it's completely useless. No need for a destructor.
Deletion of the object by the caller should be done with a Release() function.
Re: C++ OOP library and Interface
Posted: Sat Oct 01, 2016 11:16 pm
by StarBootics
Shield wrote:An error message in a language I understand would be helpful.
relocalisation de R_X86_64_32 en vertu de «__gxx_personality_v0» ne peut être utilisée lors de la création d'un objet partagé; recompiler avec -fPIC
Translation : relocation of R_X86_64_32 under «__gxx_personality_v0» can't be used during the creation of a shared object; recompile with -fPIC
obj/Debug/main.o : erreur lors de l'ajout de symboles : Mauvaise valeur
Translation : obj/Debug/main.o : error when adding symbols : Bad value
About the Destructor, ok for the provided example but what will happen if the "Class" allocate dynamic stuff being freed by the destructor ? My guess, we will end up with a memory leak if we don't use the class destructor. So I prefer to have the most general example as possible and include a class Destructor even if it's not needed.
Best regards
StarBootics
Re: C++ OOP library and Interface
Posted: Sat Oct 01, 2016 11:55 pm
by idle
did you try adding -fPic to your command line to gcc it's needed to make a shared object
Re: C++ OOP library and Interface
Posted: Sun Oct 02, 2016 12:25 am
by StarBootics
idle wrote:did you try adding -fPic to your command line to gcc it's needed to make a shared object
I have finally find where to add this directive to the compiler and it work. This test was successful for the "Debug" version of the lib. For the release version, even if I add -fPIC flag I still have the same error telling about -fPIC flag.
As soon as I have it working out I will take time to create a complete tutorial explaining everything how to do it.
@Shield : Can you be more specific about the Release function.
EDIT : Finally I got it to work for both "Debug" and "Release"
Best regards
StarBootics
Re: C++ OOP library and Interface
Posted: Sun Oct 02, 2016 3:43 am
by Shield
StarBootics wrote:
@Shield : Can you be more specific about the Release function.
You need something like this:
Code: Select all
void Time::Release()
{
delete this;
}
Be careful about that though, as this only works with objects allocated with plain "new".
Ensure that nothing touches the object after running this function.
StarBootics wrote:
About the Destructor, ok for the provided example but what will happen if the "Class" allocate dynamic stuff being freed by the destructor ? My guess, we will end up with a memory leak if we don't use the class destructor. So I prefer to have the most general example as possible and include a class Destructor even if it's not needed.
Don't include a destructor if it's not needed, just like you're not including random empty functions in your program.
You only need to specify a destructor if you have allocated resources that will not be freed automatically (such as raw
pointers to the heap or things like file handles, for example). But sure, for the purpose of demonstration it's fine.
Also, the destructor should not be virtual here because that will result in another entry in the virtual table.
(However, it might be possible to include the destructor as the first virtual function instead of a Release function,
but this working is just all as fuzzy as the rest we're trying to do here).
I'd still recommend you wrap the member functions you want access to into regular C functions.
Doing so will get rid of all the hassle and ensures that your program will run correctly, independent of platform and compiler.
Re: C++ OOP library and Interface
Posted: Sun Oct 02, 2016 5:28 am
by StarBootics
Hello everyone,
This is an example about how to Interface with a C++ Class. I'm using Code::Blocks V16.01 with gcc compiler under Ubuntu Gnome 16.04 x64.
At this point I can't tell if this will work under x86 Linux or under other operating system, you will have to make some test for that.
https://www.dropbox.com/s/2ry3xi4pighlk ... e.zip?dl=0
The provided package contain the C++ library source code, the Code::Blocks project file and a PureBasic example of use.
If everything work as expected you should see this in the PureBasic debugger output when you try the provided example :
Code: Select all
21
6
30
The Time Object is invalid !
Thanks to all programmers who have provided help, it's greatly appreciated.
Best regards
StarBootics
Re: C++ OOP library and Interface
Posted: Sun Oct 02, 2016 6:09 am
by Shield
Great that you got it working.
One thing I saw while quickly looking over it was that you now have a Release function and a destructor.
That doesn't quite work, because upon calling Release(), the destructor will also be called (and thus needlessly zeroing out the values twice).
I recommend not to include a destructor at all and instead free your resources in Release().
The destructor cannot be called directly from PB anyway.

Re: C++ OOP library and Interface
Posted: Sun Oct 02, 2016 1:14 pm
by StarBootics
Shield wrote:Great that you got it working.
One thing I saw while quickly looking over it was that you now have a Release function and a destructor.
That doesn't quite work, because upon calling Release(), the destructor will also be called (and thus needlessly zeroing out the values twice).
I recommend not to include a destructor at all and instead free your resources in Release().
The destructor cannot be called directly from PB anyway.

I think I got it with a Virtual Destructor and without a Release() method inside the class it self. The class it's self without a Virtual Destructor give me a warning about Polymorphic stuff. So the library main file look like this instead :
Code: Select all
// The functions contained in this file are pretty dummy
// and are included only as a placeholder. Nevertheless,
// they *will* get included in the shared library if you
// don't remove them :)
//
// Obviously, you 'll have to write yourself the super-duper
// functions to include in the resulting library...
// Also, it's not necessary to write every function in this file.
// Feel free to add more files in this project. They will be
// included in the resulting library.
#include "time.h"
extern "C"
{
Time* CreateTimeInterface()
{
return new Time;
}
int DeleteTimeInterface(const Time * ToBeDeleted)
{
delete ToBeDeleted;
return 0;
}
}
That way, no warning during the compilation of the library and working in PureBasic flawlessly.
This is the second version of the demonstration :
https://www.dropbox.com/s/uh5hdcipudpe9 ... 2.zip?dl=0
Best regards
StarBootics