Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Example Ada calling Gnu Scientific Library (GSL)

359 views
Skip to first unread message

Leo Brewin

unread,
Mar 28, 2017, 9:29:22 PM3/28/17
to
Hi Folks,

I've been following the discussion about the thin bindings to the GSL library (and thanks to all for the useful information).

I decided to follow the suggestion by Per Sandberg (Mar 19) to use gcc to create the header files. After a small amount of fiddling I got things working. And I'm very impressed with just how painless the whole process was. So here is a short summary of what I did.

1. Created a simple C-file, "integral.c"

#include <gsl/gsl_integration.h>
int main (void) {}

2. Run "gcc -fdump-ada-spec integral.c"
3. Replace "limited with" by "with" on line 6 of gsl_gsl_integration_h.ads
4. Used the generated headers to glean the required Ada syntax to create the
thin binding needed for a simple GSL example. Here is the main program

with Ada.Text_IO; use Ada.Text_IO;
with Interfaces.C; use Interfaces.C;

with gsl_gsl_math_h;
with gsl_gsl_integration_h;
with sys_utypes_usize_t_h;

with fun; -- function to integerate, must be in a separate pacakge

procedure GSL_Test is

a,b : Interfaces.C.double;
epsabs : Interfaces.C.double;
epsrel : Interfaces.C.double;
abserr : aliased Interfaces.C.double;
result : aliased Interfaces.C.double;
limit : sys_utypes_usize_t_h.size_t;
key : Interfaces.C.int;
return_code : Interfaces.C.int;

integrand : aliased gsl_gsl_math_h.gsl_function;
alpha : Interfaces.C.double := 4.0;

workspace : access gsl_gsl_integration_h.gsl_integration_workspace;
size : aliased sys_utypes_usize_t_h.size_t;
level : access sys_utypes_usize_t_h.size_t;

begin

a := 0.0; -- lower limit
b := 1.0; -- upper limit

epsabs := 1.0e-25; -- target actual error
epsrel := 1.0e-13; -- target relative error, 1.0e-14 gives a GSL error
limit := 1000; -- maximum number of sub-intervals
key := 5; -- which integration method to use, range from 1 to 6

integrand.c_function := fun.f'access; -- the function to integrate
integrand.params := alpha'address; -- parameters for the function

workspace := gsl_gsl_integration_h.gsl_integration_workspace_alloc (limit);

return_code := gsl_gsl_integration_h.gsl_integration_qag
(integrand'access,a,b,epsabs,epsrel,limit,key,workspace,result'access,abserr'access);

put ("Intgeral (qag) = ");
put (Interfaces.C.double'Image(result));
new_line;

return_code := gsl_gsl_integration_h.gsl_integration_qags
(integrand'access,a,b,epsabs,epsrel,limit,workspace,result'access,abserr'access);

put ("Intgeral (qags) = ");
put (Interfaces.C.double'Image(result));
new_line;

size := workspace.size;
level := workspace.level;

put ("Workspace size = ");
put (sys_utypes_usize_t_h.size_t'Image(size));
new_line;

put ("Workspace level = ");
put (sys_utypes_usize_t_h.size_t'Image(level.all));
new_line;

gsl_gsl_integration_h.gsl_integration_workspace_free (workspace);

end GSL_Test;

5. The integrand is in a separate package, here is the spec file (fun.ads)

with Interfaces.C; use Interfaces.C;
with System;

package fun is

function f (x : Interfaces.C.double; params : System.Address) return Interfaces.C.double;
pragma Convention (C, f);

end fun;

6. And here is the body, fun.adb

with Ada.Numerics.Generic_Elementary_Functions;

package body fun is

package GSL_Maths is new Ada.Numerics.Generic_Elementary_Functions (Interfaces.C.double); use GSL_Maths;

function f (x : Interfaces.C.double; params : System.Address) return Interfaces.C.double is
alpha : Interfaces.C.double;
for alpha'address use params;
begin
return log(alpha*x) / sqrt(x);
end f;

end fun;

7. The code can be compiled using the "-lgsl" linker option (assuming GSL has been installed
in the standard locations. I used "homebrew" on my macOS, "brew install gsl").

8. The output from the above code was

Intgeral (qag) = -1.22741127776022E+00
Intgeral (qags) = -1.22741127776022E+00
Workspace size = 12
Workspace level = 11

I hope this helps (sorry for the long code listing).

But I do have a question. If I chose the target relative error (epsrel) to be 1.0e-14 the GSL code fails to meet that accuracy and the Ada code crashes with a PROGRAM_ERROR. I tried to catch this with an exception block (around the call to the gsl code) but that didn't work. The exception is raised within the GSL library -- is there any way I can catch this? The GSL documentation states that even when the code fails, it returns the best answer. So I'd rather have an answer even if it didn't meet my too stringent error request.

One further note. On experiments with the GSL Bessel library I found that the GSL code uses the case sensitive nature of C to provide different versions of the Bessel functions. This is a problem for Ada which is cases insenstive. The solution is to add some unique descriptor to selected function names in the Ada headers to avoid the ambiguities.

Cheers,
Leo

gautier...@hotmail.com

unread,
Mar 29, 2017, 3:01:54 AM3/29/17
to
For things such as Bessel functions, wouldn't it easier after all build a library in plain Ada ? You would spare these headaches with bindings and pointers...
Usually you can translate easily the C code, or if you are lucky, you have Pascal code that you can translate via p2ada. Some stuff is available in my Mathpaqs library (link below).
_________________________
Gautier's Ada programming
http://sf.net/users/gdemont/

hreba

unread,
Mar 29, 2017, 3:19:09 AM3/29/17
to
On 03/29/2017 03:29 AM, Leo Brewin wrote:
> Hi Folks,
>
> I've been following the discussion about the thin bindings to the GSL library (and thanks to all for the useful information).
>

Thanks for the example. Nevertheless, I think it is only a first step,
because I would prefer an interface to the C library where the client
does not have to use the type Interfaces.C.double, or even import
Interfaces.

--
Frank Hrebabetzky +49 / 6355 / 989 5070

Dmitry A. Kazakov

unread,
Mar 29, 2017, 3:23:38 AM3/29/17
to
On 29/03/2017 09:01, gautier...@hotmail.com wrote:
> For things such as Bessel functions, wouldn't it easier after all
> build a library in plain Ada ?

To me it would be far more difficult because of higher Ada code standards.

I mean that when writing approximations in Ada the natural goal would be
to have the accurate result within the interval of two adjacent machine
numbers and also to have generic version for all real types. This is
really hard.

When using binding you basically wash your hands and do not care about
quality anymore.

--
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de

Randy Brukardt

unread,
Mar 29, 2017, 4:07:24 PM3/29/17
to
"hreba" <f_h...@yahoo.com.br> wrote in message
news:ek15fa...@mid.individual.net...
Surely. But the point is that you can use these steps to relatively easily
make a working thin binding. You then write your intended interface (the
thick binding) by directly using the thin binding in Ada. That should work
without stressing the Ada compiler and causing weird failures. (That's how
the best Ada bindings are built; you have a direct thin binding and then a
thicker binding that makes the thin binding more appropriate for Ada by
introducing exceptions, generics, default parameters, sensible Ada naming
(no camel case!), and so on.)

Randy.


gautier...@hotmail.com

unread,
Mar 30, 2017, 8:39:27 AM3/30/17
to
> To me it would be far more difficult because of higher Ada code standards.
>
> I mean that when writing approximations in Ada the natural goal would be
> to have the accurate result within the interval of two adjacent machine
> numbers and also to have generic version for all real types. This is
> really hard.

Well... why not having a minimum precision requirement ? something like this:
generic
type Real is digits <>;

package Special_functions is
...
end Special_functions;

package body Special_functions is
...
begin
... [raise an exception here if precision is not enough]
end Special_functions;


> When using binding you basically wash your hands and do not care about
> quality anymore.

Agreed - some Ada programmers have a double standard, and accept a much lower one for the C code used for binding. Sometimes they would complain about formatting of comments in Ada code and and just ignore the mess of some old "1980's home-computing-like" +/- equivalent C code...
_________________________
Gautier's Ada programming
http://gautiersblog.blogspot.com/search/label/Ada
NB: follow the above link for a valid e-mail address

Dmitry A. Kazakov

unread,
Mar 30, 2017, 10:22:27 AM3/30/17
to
On 30/03/2017 14:39, gautier...@hotmail.com wrote:
>> To me it would be far more difficult because of higher Ada code standards.
>>
>> I mean that when writing approximations in Ada the natural goal would be
>> to have the accurate result within the interval of two adjacent machine
>> numbers and also to have generic version for all real types. This is
>> really hard.
>
> Well... why not having a minimum precision requirement ? something like this:
> generic
> type Real is digits <>;
>
> package Special_functions is
> ...
> end Special_functions;
>
> package body Special_functions is
> ...
> begin
> ... [raise an exception here if precision is not enough]
> end Special_functions;

I would suggest an interval result instead of exceptions. The exact
result is guaranteed in the returned interval.

One problem with generics is that numerical algorithms usually require
computations performed with the precision higher than of the arguments
and the result. It is unclear how to do this with generics or when the
actual type is the biggest machine type already.

Another problem is the type range. Most mathematical functions are
defined on some narrow and/or strange subsets. The accuracy of
algorithms greatly depends on the range.

Preconditions may help, do we have formal generic pre-/post-conditions?

Randy Brukardt

unread,
Mar 30, 2017, 4:44:08 PM3/30/17
to
"Dmitry A. Kazakov" <mai...@dmitry-kazakov.de> wrote in message
news:obj4b1$dus$1...@gioia.aioe.org...
...
> Preconditions may help, do we have formal generic pre-/post-conditions?

Preconditions can be given on any non-instance subprogram, including those
in (or that are) a generic. For preconditions on a generic formal package,
you'd probably have to use assertions.

Randy.


G.B.

unread,
Mar 31, 2017, 2:31:16 PM3/31/17
to
On 30.03.17 16:22, Dmitry A. Kazakov wrote:
> Preconditions may help, do we have formal generic pre-/post-conditions?

As a hint to a user of generic package, it seems
possible to announce aspects of FP Types required:

generic
type Fractional is digits <>;
package R is
type T is new Fractional
with
Dynamic_Predicate => (Fractional'Digits >= 8
and T in -4.0 .. +4.0);

function Algo (X : T) return T;
end R;

Dmitry A. Kazakov

unread,
Mar 31, 2017, 2:50:05 PM3/31/17
to
This is of course different from specifying it in the formal part. The
only reason for generics ever exist is static substitution and static
checks. With dynamic checks in place a class-based model is as efficient
as generic expansion.

BTW, there are two kinds of constraints:

1. That certain values are included
2. That certain values are excluded

with uncounted variations of, e.g. that the range includes zero and is
symmetric around zero etc.

hreba

unread,
Apr 4, 2017, 5:25:50 PM4/4/17
to
Ok, I did this and now I am struggling with the project files. The first
one handles the thin binding:

library project GSL_Raw is
for Source_Dirs use ("src");
for Library_Dir use ".";
for Library_Name use "gsl_raw";
for Library_Kind use "static";
for Externally_Built use "true";
end GSL_Raw;

Directory src contains the output from g++ -c -fdump-ada-spec -C...
There is another directory, obj, which holds the result from
gcc -c -gnat05 ../src/*.ads.

Then there is the project of the thick binding in another directory:

with "GSL_Raw/gsl_raw";
library project GSL is
for Source_Dirs use ("src");
for Library_Name use "gsl";
for Library_Dir use ".";
for Object_Dir use "obj";
for Library_Interface use ("gsl");
for Library_Kind use "static";
for externally_built use "false";
package Compiler is
for Default_Switches ("Ada") use ("-g", "-gnat05");
end Compiler;
end GSL;

Now when a 3. project, for an executable program, imports project GSL I get:
error: "gsl_gsl_integration_h.ali" not found,
"gsl_gsl_integration_h.ads" must be compiled

The missing file is present in the directory obj mentioned above, but
how/where do I specify this?

I included the line

for Object_Dir use "obj";

in the GSL_Raw project, but to no avail.

Simon Wright

unread,
Apr 5, 2017, 1:31:59 PM4/5/17
to
hreba <f_h...@yahoo.com.br> writes:

> Ok, I did this and now I am struggling with the project files. The
> first one handles the thin binding:
>
> library project GSL_Raw is
> for Source_Dirs use ("src");
> for Library_Dir use ".";
> for Library_Name use "gsl_raw";
> for Library_Kind use "static";
> for Externally_Built use "true";
> end GSL_Raw;
>
> Directory src contains the output from g++ -c -fdump-ada-spec -C...
> There is another directory, obj, which holds the result from
> gcc -c -gnat05 ../src/*.ads.

Try

library project GSL_Raw is
for Source_Dirs use ("src");
for Library_Dir use "lib"; -- keeps .ali, libgsl_raw.a out of the way
for Object_Dir use "obj"; -- for .ali, .o intermediate products
for Library_Name use "gsl_raw";
for Library_Kind use "static";
for Externally_Built use "false"; -- you need to build it
end GSL_Raw;

and build with "gprbuild -p -P gsl_raw" - "-p" creates necessary
directories. Result is .ali, libgsl_raw.a in lib/. Don't use
"externally_built" at this early stage.

> Then there is the project of the thick binding in another directory:
>
> with "GSL_Raw/gsl_raw";
> library project GSL is
> for Source_Dirs use ("src");
> for Library_Name use "gsl";
> for Library_Dir use ".";

again, I'd use "lib"

hreba

unread,
Apr 5, 2017, 4:22:00 PM4/5/17
to
On 04/05/2017 06:29 PM, Simon Wright wrote:
>
> Try
>
> library project GSL_Raw is
> for Source_Dirs use ("src");
> for Library_Dir use "lib"; -- keeps .ali, libgsl_raw.a out of the way
> for Object_Dir use "obj"; -- for .ali, .o intermediate products
> for Library_Name use "gsl_raw";
> for Library_Kind use "static";
> for Externally_Built use "false"; -- you need to build it
> end GSL_Raw;
>
> and build with "gprbuild -p -P gsl_raw" - "-p" creates necessary
> directories. Result is .ali, libgsl_raw.a in lib/. Don't use
> "externally_built" at this early stage.
>
>> Then there is the project of the thick binding in another directory:
>>
>> with "GSL_Raw/gsl_raw";
>> library project GSL is
>> for Source_Dirs use ("src");
>> for Library_Name use "gsl";
>> for Library_Dir use ".";
>
> again, I'd use "lib"
>
Did as you suggested. gprbuild on gsl_raw worked fine. But when I tried
to build the test program with:

with "../../gsl.gpr";
with "../../../Gen/gen.gpr";

project Test_Integration is
for Source_Dirs use (".");
for Object_Dir use "../obj";
for Exec_Dir use ".";
for Main use ("test_integration.adb");
package Compiler is
for Default_Switches ("ada") use ("-g", "-gnat05");
end Compiler;
end Test_Integration;

the output was:

gprlib gsl.lexch
gnatbind -n -o b__gsl.adb -Lgsl -a /home/frank/Lib/Ada/Num/obj/gsl.ali
gcc -c -x ada -gnatA -gnatws b__gsl.adb -o b__gsl.o ...
gcc -nostdlib -Wl,-r -o p__gsl_0.o ...
ar cr /home/frank/Lib/Ada/Num/lib/libgsl.a p__gsl_0.o
ranlib libgsl.a
gprbind test_integration.bexch
gnatbind test_integration.ali
gcc -c b__test_integration.adb
gcc test_integration.o -o test_integration
/home/frank/Lib/Ada/Num/Tests/obj/integ_aux.o: In function
`integ_aux__gsl_test__integration_qng':
/home/frank/Lib/Ada/Num/src/gsl.adb:54: undefined reference to
`gsl_integration_qng'
collect2: error: ld returned 1 exit status
gprbuild: link of test_integration.adb failed

But in GSL_Raw/src/gsl_gsl_integration_h.ads the procedure
gsl_integration_qng _is_ declared.

Where might it have gone lost?

Simon Wright

unread,
Apr 6, 2017, 3:30:01 AM4/6/17
to
hreba <f_h...@yahoo.com.br> writes:

> gcc test_integration.o -o test_integration
> /home/frank/Lib/Ada/Num/Tests/obj/integ_aux.o: In function
> `integ_aux__gsl_test__integration_qng':
> /home/frank/Lib/Ada/Num/src/gsl.adb:54: undefined reference to
> `gsl_integration_qng'
> collect2: error: ld returned 1 exit status
> gprbuild: link of test_integration.adb failed
>
> But in GSL_Raw/src/gsl_gsl_integration_h.ads the procedure
> gsl_integration_qng _is_ declared.
>
> Where might it have gone lost?

Hard to say, but running nm on gsl_gsl_integration_h.o might give a
clue. Most likely, I guess, is that that file contains the corresponding
symbol but decorated with a prefix derived from the package name? e.g.
gsl_gsl_integration_h__gsl_integration_qng

hreba

unread,
Apr 7, 2017, 2:45:23 PM4/7/17
to
Nothing similar:

frank@pc-frank ~/Lib/Ada/Num/GSL_Raw/obj $ nm gsl_gsl_integration_h.o
0000000000000000 D gsl_gsl_integration_h_E
0000000000000124 T gsl_gsl_integration_h__gsl_integration_cquad_ivalIP
000000000000012e T gsl_gsl_integration_h__gsl_integration_cquad_workspaceIP
00000000000000d2 T gsl_gsl_integration_h__gsl_integration_glfixed_tableIP
0000000000000020 R gsl_gsl_integration_h__gsl_integration_qawo_enumN
0000000000000000 R gsl_gsl_integration_h__gsl_integration_qawo_enumS
00000000000000bc T gsl_gsl_integration_h__gsl_integration_qawo_tableIP
00000000000000b2 T gsl_gsl_integration_h__gsl_integration_qaws_tableIP
0000000000000000 T gsl_gsl_integration_h__gsl_integration_workspaceIP
00000000000000f4 T
gsl_gsl_integration_h__Tgsl_integration_cquad_ival_c_arrayBIP
000000000000010c T
gsl_gsl_integration_h__Tgsl_integration_cquad_ival_fx_arrayBIP
0000000000000082 T
gsl_gsl_integration_h__Tgsl_integration_qaws_table_rg_arrayBIP
000000000000009a T
gsl_gsl_integration_h__Tgsl_integration_qaws_table_rh_arrayBIP
0000000000000052 T
gsl_gsl_integration_h__Tgsl_integration_qaws_table_ri_arrayBIP
000000000000006a T
gsl_gsl_integration_h__Tgsl_integration_qaws_table_rj_arrayBIP

The missing function is declared in src/gsl_gsl_integration_h.ads as

function gsl_integration_qng
(f : access constant gsl_gsl_math_h.gsl_function;
a : double;
b : double;
epsabs : double;
epsrel : double;
result : access double;
abserr : access double;
neval : access stddef_h.size_t) return int;
pragma Import (C, gsl_integration_qng, "gsl_integration_qng");

So what would be the next search step?

Simon Wright

unread,
Apr 8, 2017, 4:28:13 AM4/8/17
to
hreba <f_h...@yahoo.com.br> writes:

> The missing function is declared in src/gsl_gsl_integration_h.ads as
>
> function gsl_integration_qng
> (f : access constant gsl_gsl_math_h.gsl_function;
> a : double;
> b : double;
> epsabs : double;
> epsrel : double;
> result : access double;
> abserr : access double;
> neval : access stddef_h.size_t) return int;
> pragma Import (C, gsl_integration_qng, "gsl_integration_qng");

What the pragma Import says is that gsl_integration_qng is imported from
some place else, presumably the C library you've asked gcc to generate a
skinny binding to.

Here, gsl 2.3, the symbol is in libgsl.

nm -Aa libgl.a | grep gsl_integration_qng

says

libgsl.a:qng.o: 00000000000000c0 T _gsl_integration_qng

I don't think the leading underscore is your problem, GNAT knows when
the platform (macOS here) needs the leading underscore.

I hate to ask this, but have you actually linked with -lgsl?

hreba

unread,
Apr 9, 2017, 6:57:27 AM4/9/17
to
My directory structure is

└── Num <-- thick bindings
├── gsl.gpr
├── GSL_Raw <-- thin bindings
│ ├── gsl_raw.gpr
│ ├── lib
│ │ ├── alloca_h.ali
│ │ ├── gsl_gsl_integration_h.ali
...
│ ├── obj
│ │ ├── alloca_h.ali
│ │ ├── alloca_h.o
...
│ ├── readme.txt
│ └── src
│ ├── alloca_h.ads
│ ├── gsl_gsl_integration_h.ads
...
├── lib
│ ├── gsl.ali
│ └── libgsl.a
├── num.gpr
├── obj
│ ├── auto.cgpr
│ ├── b__gsl.adb
...
├── src
│ ├── gsl.adb
│ ├── gsl.ads
│ ├── numfunc.adb
│ └── numfunc.ads
...

So, sitting in directory Num:

nm -Aa GSL_Raw/lib/libgsl_raw.a | grep gsl_integration_qng
says nothing.
nm -Aa lib/libgsl.a | grep gsl_integration_qng
says nothing
nm -Aa /usr/lib/libgsl.a | grep gsl_integration_qng
says /usr/lib/libgsl.a:qng.o:0000000000000000 T gsl_integration_qng

> I hate to ask this, but have you actually linked with -lgsl?
>
Where, how? I have 3 project files now:
1. in Num/GSL_Raw for the thin binding
2. in Num for the thick binding
3. in the directory of my test program
To the first one using your suggestion on 04/05/2017, I added:

package Builder is
for Default_Switches ("C") use ("-lgsl");
end Builder;

but it didn't help. (Sigh)

Simon Wright

unread,
Apr 9, 2017, 11:17:49 AM4/9/17
to
hreba <f_h...@yahoo.com.br> writes:

> package Builder is
> for Default_Switches ("C") use ("-lgsl");
> end Builder;

Try

package Linker is
for Default_Switches ("ada") use ("-lgsl");
end Linker;

hreba

unread,
Apr 10, 2017, 4:53:30 AM4/10/17
to
I put this in all my 3 project files, called gprbuild with the -f option
with all 3 project files - nothing new.

Is there no example with another thick binding to a library with C
interface (and which is less huge than GtkAda)?

Dmitry A. Kazakov

unread,
Apr 10, 2017, 5:47:18 AM4/10/17
to
On 10/04/2017 10:53, hreba wrote:

> I put this in all my 3 project files, called gprbuild with the -f option
> with all 3 project files - nothing new.

Because it has nothing to do with the linker package. Packages do not
cross project boundary. See Linker_Options if you want to pass library
switches.

> Is there no example with another thick binding to a library with C
> interface (and which is less huge than GtkAda)?

library project GSL is
for Externally_Built use "true";
for Source_Files use ();
for Library_Dir use "/usr/lib"; -- Or as appropriate
for Library_Name use "gsl";
for Library_Kind use "relocatable"; -- Assuming gsl.so or gsl.dll
end GSL;

with "gsl.gpr";
library project GSL_Thin_Bindings is
...

You also seem confuse project to build and project to use a library.
They are not same! For a bindings library you need both.

hreba

unread,
Apr 10, 2017, 11:39:21 AM4/10/17
to
On 04/10/2017 11:47 AM, Dmitry A. Kazakov wrote:
>
> You also seem confuse project to build and project to use a library.
> They are not same! For a bindings library you need both.
>

I don't understand that. From the discussions here on the list I thought:

1. Thin binding is just an interface module which allows to call the C
library functions from an Ada program, using all the parameters of the C
prototype and some types from Interfaces.C.
Library project.

2. Thick binding: Specification and implementation of Ada subprograms
which call subprograms of the thin binding. Interfaces.C types can be
avoided in the specifications. Specification of exported subprograms
usually differ from corresponding imported C prototypes, because this is
what you want from thick bindings.
Library project, because there is no executable.

3. Application calls subprograms from the thick binding and defines
executable(s) (Main).
Non-library project because executables are generated.

What is wrong here, why do i need both types of projects for a bindings
library?

And is that documented anywhere?

Simon Wright

unread,
Apr 10, 2017, 11:44:22 AM4/10/17
to
Oops, thanks Dmitry: I should have said

package Linker is
for Linker_Options use ("-lgsl");
end Linker;

(in your lowest-level GPR, gsl_raw I think?)

Dmitry A. Kazakov

unread,
Apr 10, 2017, 1:16:41 PM4/10/17
to
On 2017-04-10 17:39, hreba wrote:
> On 04/10/2017 11:47 AM, Dmitry A. Kazakov wrote:
>>
>> You also seem confuse project to build and project to use a library.
>> They are not same! For a bindings library you need both.
>>
>
> I don't understand that. From the discussions here on the list I thought:
>
> 1. Thin binding is just an interface module which allows to call the C
> library functions from an Ada program, using all the parameters of the C
> prototype and some types from Interfaces.C.
> Library project.

Yes, plus conversion of some elementary types. It is considered thin to
convert char * to String and int!=0 to Boolean.

> 2. Thick binding: Specification and implementation of Ada subprograms
> which call subprograms of the thin binding. Interfaces.C types can be
> avoided in the specifications. Specification of exported subprograms
> usually differ from corresponding imported C prototypes, because this is
> what you want from thick bindings.
> Library project, because there is no executable.

Yes.

> 3. Application calls subprograms from the thick binding and defines
> executable(s) (Main).
> Non-library project because executables are generated.

AFAIK relocatable library counts as executable, but yes.

> What is wrong here, why do i need both types of projects for a bindings
> library?

It is how gprbuild works. I am not happy with that design but it is how
it is.

You need:

1. C library project [or package Linker / Library_Options]

2.a. Ada thin bindings library build project that with-es #1
2.b. Ada thin bindings library use project that with-es #1

3.a. Ada think bindings library build project that with-es #2.b
3.b. Ada think bindings library use project that with-es #2.b

4. Application build project that with-es #3.b

You can ditch #1 and then:

for #2.a you use package Linker to link to C library
for #2.b you use Linker_Options to instruct future users of the library
that they also must link to the C library

To summarize: for building application or library you use different
options from when you use already built library in another project.

Of course, 2 and 3 are normally merged together. There is little reason
to keep them in separate libraries.

> And is that documented anywhere?

Sure, you can find hints in:

https://docs.adacore.com/gprbuild-docs/html/gprbuild_ug/gnat_project_manager.html

P.S. For an example of thin and thick bindings smaller than GtkAda you
can look at ODBC bindings:

http://www.dmitry-kazakov.de/ada/components.htm#ODBC_Bindings

Simon Wright

unread,
Apr 10, 2017, 1:43:24 PM4/10/17
to
hreba <f_h...@yahoo.com.br> writes:

> On 04/10/2017 11:47 AM, Dmitry A. Kazakov wrote:
>>
>> You also seem confuse project to build and project to use a library.
>> They are not same! For a bindings library you need both.
>>
>
> I don't understand that.

If you're building a library project, you have to specify all sorts of
things - particularly the compiler options, but you might for example
have multiple source directories.

Once the project has been built, this sort of thing isn't needed, you
can use a different GPR to present just what's needed to use the
library. Indeed, you can write an externally-built library GPR for a
completely external library.

If you're going to install the built library, the tool gprinstall knows
what to do and will generate the necessary externally-built library GPR
for you.

But if you don't want to install the built library, your projects can
just use the GPR you used for building it.

I'm not quite sure what to do when using a two-layer library like your
GSL binding!

You can see a Makefile and GPR (complicated, I know) at
https://sourceforge.net/p/gnatutil/code/ci/default/tree/ . The resulting
installed GPR is

gnat_util.gpr

hreba

unread,
Apr 11, 2017, 1:31:39 PM4/11/17
to
On 04/10/2017 05:44 PM, Simon Wright wrote:
> Oops, thanks Dmitry: I should have said
>
> package Linker is
> for Linker_Options use ("-lgsl");
> end Linker;
>
> (in your lowest-level GPR, gsl_raw I think?)
>

FINALLY!

I had to add "-L/usr/lib"!. This provoked a series of other link errors
showing that "-lgslcblas" is needed too. Now for completeness and
perhaps as help for others, my 3 project files are:

1. Thin binding:

library project GSL_Raw is
for Source_Dirs use ("src");
for Library_Dir use "lib";
for Object_Dir use "obj";
for Library_Name use "gsl_raw";
for Library_Kind use "static";
for Externally_Built use "false";
end GSL_Raw;

2. Thick binding:

with "GSL_Raw/gsl_raw";

library project GSL is
for Source_Dirs use ("src");
for Library_Name use "gsl";
for Library_Dir use "lib";
for Object_Dir use "obj";
for Library_Interface use ("gsl");
for library_kind use "static";
for externally_built use "false";

package Compiler is
for Default_Switches ("Ada") use ("-g", "-gnat05");
end Compiler;

package Linker is
for Linker_Options use ("-L/usr/lib", "-lgslcblas", "-lgsl");
end Linker;
end GSL;

3. Test program

with "../../gsl.gpr";
with "../../../Gen/gen.gpr"; --<-- a libray I use in my program

project Test_Integration is

for Source_Dirs use (".");
for Object_Dir use "../obj";
for Exec_Dir use ".";
for Main use ("test_integration.adb");

package Compiler is
for Default_Switches ("ada") use ("-g", "-gnat05");
end Compiler;

end Test_Integration;

Thanks to all for your help, and specially to Simon for his patience.

Simon Wright

unread,
Apr 11, 2017, 2:45:16 PM4/11/17
to
hreba <f_h...@yahoo.com.br> writes:

> FINALLY!
>
> I had to add "-L/usr/lib"!. This provoked a series of other link
> errors showing that "-lgslcblas" is needed too.
[...]
> Thanks to all for your help, and specially to Simon for his patience.

You're welcome! Glad it's come good.

[to be ignored in the interests of getting on with the job...] I still
think the required libraries could be specified in gsl_raw. And
shouldn't /usr/lib be the default, not needing to be specified?

Dmitry A. Kazakov

unread,
Apr 11, 2017, 3:46:33 PM4/11/17
to
No, under Debian it is actually

/usr/lib/${DEB_HOST_MULTIARCH}

Under Fedora there is a predefined project Directories which must be
with-ed and then it is simply

Directories.Libdir

This is why having a project for external library might work better than
using direct linker switches.
0 new messages