comp.lang.ada
 help / color / mirror / Atom feed
From: Maurizio Tomasi <ziotom78@gmail.com>
Subject: Re: Thick bindings to a C library and gnattest: suggestions?
Date: Mon, 1 Jul 2013 04:11:55 -0700 (PDT)
Date: 2013-07-01T04:11:55-07:00	[thread overview]
Message-ID: <40bf5a31-b09a-4106-a57a-7ac3dd5f951e@googlegroups.com> (raw)
In-Reply-To: <1fxsf70zl2ckq.aysy7d9c8jkl$.dlg@40tude.net>

Hi Dmitry,

  Many thanks for your suggestions. You gave me a lot of things to think about.  I have a few questions about what you wrote.

> > First question: the vectors used by the CFITSIO library are sometimes
> > huge (millions of elements), sometimes very small (~ 10 elements).
> > I decided to always allocate them on the heap, using declarations like
> > these:
> 
> Why should bindings care about that?

Shouldn't they care? Perhaps I am missing something regarding the Ada language, in fact C++ does not care about whether an array is allocated on the stack or on the heap. But if I declare a function like the following:

function Read_Double_Array_From_FITS (File_Name : String) return Double_Array;

and I implement it in the following way:

--  Call the C functions that returns the number of rows in the file
Num_Of_Elements := Get_Number_Of_Elements(FITS_File);
declare
  Vector_To_Return : Double_Array (1 .. Num_Of_Elements);
begin
  --  Call the C function that fills Vector_To_Return
  ...
  return Vector_To_Return;
end;

then every time I read some huge array I will get a STORAGE_ERROR near the declaration of "Vector_To_Return". This is the reason why I declared the return type of "Read_Data_From_FITS" as a Double_Array_Ptr instead of a Double_Array, and implemented it as:

Num_Of_Elements := Get_Number_Of_Elements(FITS_File);
declare
  Vector_To_Return : Double_Array_Ptr;
begin
  Vector_To_Return := new Double_Array (1 .. Num_Of_Elements);
  --  Call the C function that fills Vector_To_Return
  ...
  return Vector_To_Return;
end;

Your answer makes me think there is a smarter way of avoiding the distinction between Double_Array_Ptr and Double_Array. (This would in fact make Ada much more like C++, where this distinction does not exist.) Is this the reason why in your example you declared Double_Array an array of *aliased* doubles? Or was your point just to use the address of its first member?

> Using unconstrained arrays could be troublesome because they contain
> bounds. You may consider the package B.3.2
> 
>    Interfaces.C.Pointers
> 
> But normally you do not need array pointers in bindings except for the
> cases when the C library stores the pointer to keep it after returning from
> the subprogram.

I need the C library only in those cases where I need to save/retrieve arrays of data from disk in binary format. But 100% of the calculations on the values stored in these arrays will be done using Ada code (e.g., loops...). The point of rewriting my C++ program in Ada is because my codes need to work with very large arrays (I am part of a large astrophysics project), and I find Ada arrays much more appealing than C++ vectors. The fact that Ada arrays can have arbitrary bounds whom they carry is one of the things that made me interested towards Ada at the beginning. Why did you say this might be "troublesome"?

Given this context, is your suggestion of using Interfaces.C.Pointers still valid?

> Why don't you simply pass the array down to the C subprogram? You can do
> something like:
> 
>    type Double_Array is array (Positive range <>)
>       of aliased Interfaces.C.double;
>    pragma Convention (C, Double_Array);
>    procedure Foo (A : Double_Array);
> 
> Implementation:
> 
>    type Double_Ptr is access all Interfaces.C.double;
>    pragma Convention (C, Double_Ptr);
> 
>    procedure Foo (A : Double_Array) is
>    --
>    -- Assuming foo's signature in C:
>    --
>    --    foo (double * a, unsigned n);
>    --
>       procedure Internal (A : Double_Ptr; N : Interfaces.C.unsigned);
>       pragma Import (C, Internal, "foo");
>    begin
>       Internal (A (A'First)'Access, A'Length);
>    end Foo;

But what if A'Length is so large that the array does not fit into the stack? Increasing the stack to a good value would be better than allocating objects on the heap? I would have problems in determining what size to use, as my code should work on a variety of systems (my laptop, supercomputing facilities...) and the amount of data it needs to load depends on the context.

> > I am sure there is some clever way to solve these two minor points,
> > but so far I have not been able to find it. I tried e.g. to put
> > "-lcfitsio" in the project file of the AdaFITS library, but with no
> > success.
> 
> Make a library project file for cfitsio instead. "with" it from your
> project. GNAT knows how to handle it and will add appropriate linker
> switches to any project using it directly or indirectly. A library project
> file could look like:
> 
> project cfitsio is
>    for Externally_Built use "true"; -- Do not bother to compile me
>    for Source_Files use (); -- No sources
>    for Library_Dir use ".";   -- Where .llb, .a, .dll, .so are
>    for Library_Name use "cfitsio"; -- Without "lib" prefix!
>    for Library_Kind use "dynamic"; -- A DLL
> end cfitsio;

This is really a good idea, I did not think about this! There are only two problems with this approach:

1. The CFITSIO library is often compiled using ad-hoc flags in supercomputing facilities, in order to make it work better with the storage systems. I need to use the library provided by the system, not my own. But...

2. ...the system library is not always available as a dynamic .so file: in some cases I must statically link CFITSIO (the libcfitsio.so library is not available on every node of the cluster: when I discovered this, the system admin told me to link statically).

Is there no other option? I searched the "gnattest" documentation for some way to prevent it from overwriting some parts of the files, but with no success.

Again, many thanks for your answers.
  Maurizio.

  reply	other threads:[~2013-07-01 11:11 UTC|newest]

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-07-01  9:02 Thick bindings to a C library and gnattest: suggestions? ziotom78
2013-07-01  9:45 ` Dmitry A. Kazakov
2013-07-01 11:11   ` Maurizio Tomasi [this message]
2013-07-01 11:41     ` Simon Wright
2013-07-01 12:00       ` Maurizio Tomasi
2013-07-01 12:42         ` Dmitry A. Kazakov
2013-07-01 19:07           ` Simon Wright
2013-07-01 12:32     ` Dmitry A. Kazakov
2013-07-01 12:41       ` Maurizio Tomasi
2013-07-01 12:47       ` Simon Wright
2013-07-02  8:55     ` Georg Bauhaus
2013-07-02  8:33   ` Maurizio Tomasi
2013-07-02  8:58     ` Dmitry A. Kazakov
2013-07-02 16:58     ` Robert A Duff
2013-07-02 17:00     ` Jeffrey Carter
2013-07-01 17:16 ` Jeffrey Carter
2013-07-02  4:24   ` Randy Brukardt
2013-07-02  4:37     ` Shark8
2013-07-02  5:04     ` tmoran
2013-07-02 22:27       ` Randy Brukardt
2013-07-03 12:02   ` Jacob Sparre Andersen
2013-07-02  3:16 ` Jerry
2013-07-02  4:02   ` Shark8
replies disabled

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