On Thursday 26 January 2006 20:14, Florian Klaempfl wrote:
> Christian Iversen wrote:
> > On Thursday 26 January 2006 12:55, Felipe Monteiro de Carvalho wrote:
> >>Hello,
> >>
> >>Attached is a patch that changes the current Qt interface into a Qt4
> >>interface.
> >>
> >>The following widgets work: TApplication, TCustomForm, TCustomButton,
> >>TCustomMemo
> >>
> >>It uses Jen Dean qt4 wrapper, which is basically a 800kb .so file that
> >>needs to be on the library path for lcl-qt4 programs to work.
> >
> > I'll bet the farm that the 800kb file is not needed!
> >
> > All you need to do is change the header file slightly. I ported the
> > modplug (module player) header code to linux. Now, modplug is C++, so of
> > course this was a bit of a challenge. However, I managed to use the
> > following style:
> >
> > Procedure SoundFile_FreeSample(p: Pointer); CDecl; External {$IFDEF
> > DYNLINK}libmodplugname{$ENDIF} Name '_ZN10CSoundFile10FreeSampleEPv';
> >
> > Function  SoundFile_ReadS3M (Obj : Pointer; lpStream : Pointer;
> > dwMemLength: dword): Bool; CDecl; External {$IFDEF
> > DYNLINK}libmodplugname{$ENDIF} Name '_ZN10CSoundFile7ReadS3MEPKhm';
> >
> > and so on.
>
> How do you handle e.g. virtual calls :) ?

I've been quite busy with my final exams, but I managed to find a little time 
to make sample of this.

It's attached here. To run it, do this:

$ gcc -c test.cpp               (creates test.o)
$ fpc -Mdelphi virtest.pas && ./virtest

It should print out something like the following:

Free Pascal Compiler version 2.1.1 [2005/12/15] for i386
Copyright (c) 1993-2005 by Florian Klaempfl
Target OS: Linux for i386
Compiling virtest.pas
Linking virtest
94 Lines compiled, 0.3 sec
I got the number 42 as an argument
Reading back a variable: 42
Got 3
I got the number 17 as an argument
Reading back a variable: 17

Please notice that all code except for "Reading back a variable" is entirely 
in C++!

Also, the memory maps in the header file is currently made in such a way as to 
save typing for me. If it were auto-generated, it would be HUGELY simpler to 
access a low-level property of a high-level object (i.e no 
object.vmt.parent.parent.parent.parent... )

This is _only_ a proof-of-concept, but it goes to show that it's quite doable 
to link in C++ code. Please once again keep in mind that the access method 
will look much nicer in a possible real version.

-- 
Regards,
Christian Iversen
#include <stdio.h>

class foo {
  private:
  public:
  int foo;
  virtual void frob(int x) {
    foo = x;
  }
  virtual void nicate() {
    printf("I got the number %d as an argument\n", foo);
  }
};

class bar : public foo {
  virtual void frobnicate(int x) {
    printf("Got %d\n", x);
  }
};

foo* new_foo() {
  return new foo();
}

bar* new_bar() {
  return new bar();
}


program test;

{$LINK 'test.o'}
{$LINKLIB 'c'}

uses
  LibC, sysutils;

type
  tfrobber = procedure(obj: pointer; x: integer); stdcall;
  tnicater = procedure(obj: pointer); stdcall;

  // VMTs for Foo and Bar

  tfoovmt =
    record
      frob: procedure(obj: pointer; x: integer); stdcall;
      nicate: procedure(obj: pointer); stdcall;
    end;
  pfoovmt = ^tfoovmt;

  tbarvmt =
    record
      parent: tfoovmt;
      frobnicate: procedure(obj: pointer; x: integer); stdcall;
    end;
  pbarvmt = ^tbarvmt;

  // Memory maps for Foo and Bar

  tfoovars =
    record
      x: integer;
    end;

  tbarvars =
    record
      parent: tfoovars;
    end;

  // Class maps for Foo and Bar

  tfooclass =
    record
      vmt: pfoovmt;
      vars: tfoovars;
    end;
  pfooclass = ^tfooclass;

  tbarclass =
    record
      vmt: pbarvmt;
      vars: tbarvars;
    end;
  pbarclass = ^tbarclass;

  // Custom constructors

function new_foo(): pfooclass; external name '_Z7new_foov';
function new_bar(): pbarclass external name '_Z7new_barv';

function new_integer(x: integer): pointer;
begin
  result := malloc(x);
end;

procedure dummy();
begin
end;

// Quiesce the linker - g++ needs this to be defined

exports
  dummy name '__gxx_personality_v0',
  dummy name '_ZTVN10__cxxabiv117__class_type_infoE',
  dummy name '_ZTVN10__cxxabiv120__si_class_type_infoE',
  new_integer name '_Znwj';

var
  x: pfooclass;
  y: pbarclass;
begin
  x := new_foo();
  y := new_bar();
 
  x.vmt.frob(x, 42);
  x.vmt.nicate(x);
  writeln('Reading back a variable: ', x.vars.x);

  y.vmt.frobnicate(y, 3);

  y.vmt.parent.frob(y, 17);
  y.vmt.parent.nicate(y);
  writeln('Reading back a variable: ', y.vars.parent.x);
end.

Reply via email to