[fpc-devel] Linking to C++

Peter Popov ppopov at tamu.edu
Mon Jan 22 21:14:03 CET 2007


The simple answer is that you cannot reliably mix object oriented  
langugages without severe portability issues and without loosing basic  
functionality: polymorphism. You simply cannot extend the functionality of  
a class written in one language from another language.

ON THE LINKING PART: all that distinguishes a member function from a usual  
one is that a member function has an implicit first argument which is a  
pointer to the class instance. So, you can put all your member functions  
in a dll, and from an assembly level view point they are just regular  
function with an additional first argument (pointer to the class instence  
- *this in c++, self in o-pascal). How the calling language interprets  
them is a matter of the calling language.

The problem is the logical structure of a class. That is, the layout of  
the VMT, and stuff like this. Generally, the pointer to the first virtual  
method is at offset 0, so you can safely call virtual functions from a  
single inherited C++ class. However, everything else is different. For  
example, different versions of delphi place the automated methods at a  
different offset, etc. The simplest problem is the destrictor. All delphi  
classes have the destructor at offset -4. A C++ class CANNOT have a  
virtual destructor (the VMT is killed when you call delete, before the  
class' destructor is called). In fact, C++ classes need not have a VMT at  
all.

So if the function calls virtual methods, the dll that contains that  
function MUST use the internal representation of a class as the calling  
program (which supplies *this, e.g. Self). This will force you to use the  
same object model as C++. Since C++ does not support class functions for  
example, I don't see how you can mix a delphi function in a dll with  
C++ code. A C++ class need not have a VMT at all. If a C++ member function  
belongs to a Multiple Inheritance class then this class will have several  
VMTs, so the whole thing becomes pointless. You cannot ensure any code  
portability. So linking is not the problem.

If you want to use class libraries, you have to make this class library  
into a reasonable API with reasonable semantics, behavior and so on. An  
example is the way QT is interfaced with Kylix. It works, only because QT  
is reasonably well written, all the new/deletes of QT objects are  
explicitly wrapped in Kylix, and the published QT member functions don't  
do weird things. All QT functions are wrapped as normal function, by  
explictly specifying the Self pointer as the first argument. The last  
problem in this is the actual linking. In fact the unofficial QT patches  
(QT 3) does the same thing using object semantics on the Kylix side. It  
works, because QT is a reasonable API, and obviously, you cannot extend QT  
in any way.

I don't know what FPC does with member functions, but Delphi does not  
export them. You cannot put a member function in the export part of a  
library. You have to create a wrapper (normal function with Self as the  
first argument) and then export the wrapper. So, if you happen to have a  
good class API in Delphi, you have to manually type wrappers and export  
them. This can be changed in FPC by allowing TMyObject.MyFunction in the  
export part of a library.

Peter

On Mon, 22 Jan 2007 13:17:48 -0600, Felipe Monteiro de Carvalho  
<felipemonteiro.carvalho at gmail.com> wrote:

> Hello,
>
> I was studing how to write the system unit for Symbian OS, and
> everything on Symbian is C++, so you actually import lot´s of methods
> from classes, not procedures. So I decided to study the task of
> linking from Free Pascal to C++
>
> Maybe it´s easy to be implemented, and that would be very nice. Here is  
> my test:
>
> To start with I created a trivial C++ DLL:
>
> File: cpplib.cpp
>
> class User
> {
>   public:
>      __declspec(dllexport) int Sum(int a, int b);
> };
>
> int User::Sum(int a, int b)
> {
>     return a + b;
> }
>
> File: build.bat
>
> PATH=C:\Programas\Dev-Cpp\bin
> g++ -c cpplib.cpp -o cpplib.o
> dllwrap.exe --output-def cpplib.def --driver-name c++ --implib
> cpplib.a cpplib.o -L"c:/Programas/dev-cpp/lib" --no-export-all-symbols
> --add-stdcall-alias -o cpplib.dll
>
> Calling build.bat will of course produce cpplib.dll It also produces a
> cpplib.def
>
> Now, I utilized dllview software I created and saw that cpplib exports
> this function: _ZN4User3SumEii
>
> Then, I created a simple pascal software to call that function:
>
> program loadcpp;
>
> {$mode objfpc}{$H+}
>
> {$apptype console}
>
> uses
>   SysUtils, ctypes;
>
> function User_Sum(Self: Pointer; a, b: cint): cint; cdecl; external
> 'cpplib.dll' name '_ZN4User3SumEii';
>
> begin
>   WriteLn('7 + 8 = ' + IntToStr(User_Sum(nil, 7, 8)));
> end.
>
> And it works!
>
> So, basically, what I mean with this is: What is needed to add C++
> linking to Free Pascal? It seams to me that it should be easy, we just
> need to understand C++ name mangling and choose a sintax to implement
> it. Maybe something like this:
>
> type
>   User = class
>   public:
>     function Sum(a, b: cint): cint; cdecl; external 'cpplib.dll';
> cpp_name_mangling;
>   end;
>
> One possible problem is C++ multiple inheritance. I would propose
> that, to start with, just disconsider it.
>
> Disclaimer: I know very little on the subject, so feel free to correct  
> me =)
>
> thanks,

|***********************************************|



More information about the fpc-devel mailing list