comp.lang.ada
 help / color / mirror / Atom feed
From: Tarek Ghaleb <invalid@invalid.org>
Subject: C++/Ada dispatching
Date: Wed, 31 Jul 2013 18:30:50 +0000 (UTC)
Date: 2013-07-31T18:30:50+00:00	[thread overview]
Message-ID: <ktbl4o$2tta$1@adenine.netfront.net> (raw)

Hi everyone,

Here is the problem: given a C++ class Fl_Widget and a derived class
Fl_Window, I'd like to write a thick binding that wraps the C++ type
into an Ada Type and offers only a subset of the available operations,
plus do type conversions, etc. before calling the C++ operations. So
the basic idea is that an Ada Widget is in the form of,

   type Fl_Widget is abstract tagged limited record
      Base_Widget : access Class_Fl_Widget.Fl_Widget'Class;
   end record;

And here is an example: 

(Apologies for including so much code, I tried to strip it down as
much as possible but still give a complete example).

header file fl_widget.hpp:

  class Fl_Widget {
    int _width;
    int _height;
  public:
    void show();
    virtual void some_operation() { };
  protected:
    Fl_Widget();
    Fl_Widget(int width, int height);
  };

header file fl_window.hpp:

  #include "fl_widget.hpp"

  class Fl_Window : public Fl_Widget {
  public:
    Fl_Window();
    Fl_Window(int width, int height);
    void fullscreen();
    void some_operation();
  };

C++ file fl_widget.cpp:

  #include "fl_widget.hpp"
  #include <cstdio>

  Fl_Widget::Fl_Widget() {}

  Fl_Widget::Fl_Widget(int width, int height) {
    _width  = width;
    _height = height;
  }

  void Fl_Widget::show() {
    std::puts("view called");
  }

C++ file fl_window.cpp:

  #include "fl_window.hpp"
  #include <cstdio>

  Fl_Window::Fl_Window() {}

  Fl_Window::Fl_Window(int width, int height) : Fl_Widget(width, height)
  {
    std::puts("initialized window");
  }

  void Fl_Window::fullscreen() {
    std::puts("fullscreen called");
  }

  void Fl_Window::some_operation() {
    // empty
  }

generated Ada thin binding fl_widget_hpp.ads:

  pragma Ada_2005;
  pragma Style_Checks (Off);

  with Interfaces.C; use Interfaces.C;

  package fl_widget_hpp is

     package Class_Fl_Widget is
	type Fl_Widget is tagged limited record
	   u_width  : aliased int;
	   u_height : aliased int;
	end record;
	pragma Import (CPP, Fl_Widget);

	procedure show (this : access Fl_Widget'Class);  
	pragma Import (CPP, show, "_ZN9Fl_Widget4showEv");

	procedure some_operation (this : access Fl_Widget);
	pragma Import 
          (CPP, some_operation, "_ZN9Fl_Widget14some_operationEv");

	function New_Fl_Widget return Fl_Widget;
	pragma CPP_Constructor (New_Fl_Widget, "_ZN9Fl_WidgetC1Ev");

	function New_Fl_Widget 
	   (width : int; height : int) return Fl_Widget;
	pragma CPP_Constructor (New_Fl_Widget, "_ZN9Fl_WidgetC1Eii");


     end;
     use Class_Fl_Widget;
  end fl_widget_hpp;

generated Ada thin binding fl_window_hpp.ads:

  pragma Ada_2005;
  pragma Style_Checks (Off);

  with Interfaces.C; use Interfaces.C;
  with fl_widget_hpp;

  package fl_window_hpp is

     package Class_Fl_Window is
	type Fl_Window is limited new
	fl_widget_hpp.Class_Fl_Widget.Fl_Widget with record
	   null;
	end record;
	pragma Import (CPP, Fl_Window);

	function New_Fl_Window return Fl_Window;
	pragma CPP_Constructor (New_Fl_Window, "_ZN9Fl_WindowC1Ev");

	function New_Fl_Window 
	  (width : int; height : int) return Fl_Window;
	pragma CPP_Constructor (New_Fl_Window, "_ZN9Fl_WindowC1Eii");

	procedure fullscreen (this : access Fl_Window'Class);
	pragma Import (CPP, fullscreen, "_ZN9Fl_Window10fullscreenEv");

	procedure some_operation (this : access Fl_Window);
	pragma Import 
          (CPP, some_operation, "_ZN9Fl_Window14some_operationEv");
     end;
     use Class_Fl_Window;
  end fl_window_hpp;

and the Ada file widget.ads:

  with fl_widget_hpp;

  package Widget is

     type Fl_Widget is abstract tagged limited record
	Base_Widget : access 
          fl_widget_hpp.Class_Fl_Widget.Fl_Widget'Class;
     end record;

     procedure Show (Object : Fl_Widget);

  end Widget;

with body in widget.adb:

  package body Widget is

     procedure Show (Object : Fl_Widget) is
     begin
	Object.Base_Widget.show;
     end Show;

  end Widget;

and window.ads:

with Widget;

package Window is

   type Fl_Window is new Widget.Fl_Widget with null record;

   procedure Init (Object : in out Fl_Window);

   procedure Fullscreen (Object : Fl_Window);

end Window;

and body in window.adb:

  with fl_window_hpp; use fl_window_hpp;

  package body Window is

     type Base_Window_Access is access all Class_Fl_Window.Fl_Window;

     procedure Init (Object : in out Fl_Window) is
	Win : constant Base_Window_Access :=
	  new Class_Fl_Window.Fl_Window'(
					 Class_Fl_Window.New_Fl_Window
					   (width  => 500,
					    height => 500));
	--  Is there a better way to do this?
     begin
	Object.Base_Widget := Win;
     end Init;

     procedure Fullscreen (Object : Fl_Window) is
     begin
	Base_Window_Access (Object.Base_Widget).fullscreen;
	--  This fails with
	--  raised CONSTRAINT_ERROR : window.adb:36 tag check failed
     end Fullscreen;

  end Window;

and finally a driver to test this code:

  with Window;

  procedure Main is
     Win : Window.Fl_Window;
  begin
     Win.Init;
     --  Curiously, commenting this line out, no errors are raised and
     --  fullscreen() is called. (Although, Base_Widget is
     --  uninitialized/null here!)

     Win.Show;
     Win.Fullscreen;
  end Main;


I'm getting raised CONSTRAINT_ERROR : window.adb:36 tag check failed,
the line

	Base_Window_Access (Object.Base_Widget).fullscreen;

Also, I'm looking for related reading material. So far I've only found
a couple of GEM's on AdaCore and a section in the GNAT manual, and a
Green Hills `Mixing Ada and C++' report. Any recommendations?

Another question: when importing overloaded C++ functions, the
generated code with `g++ -fdump-ada-spec` fails to compile as it
imports the function twice, for example:

     function align 
       (this : access constant Fl_Widget'Class) 
        return FL_Enumerations_H.Fl_Align;
      pragma Import (CPP, align, "_ZNK9Fl_Widget5alignEv");

      procedure align 
        (this : access Fl_Widget'Class; 
         alignment : FL_Enumerations_H.Fl_Align);
      pragma Import (CPP, align, "_ZN9Fl_Widget5alignEj");

how should overloaded C++ functions be imported?

Tarek. 

-- 
Injustice anywhere is a threat to justice everywhere. -- Martin Luther
King, Jr.

--- news://freenews.netfront.net/ - complaints: news@netfront.net ---


                 reply	other threads:[~2013-07-31 18:30 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed
replies disabled

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox