comp.lang.ada
 help / color / mirror / Atom feed
* A suggestion about interfacing with C
@ 2016-05-02 16:45 mockturtle
  2016-05-02 18:46 ` Simon Wright
                   ` (4 more replies)
  0 siblings, 5 replies; 6+ messages in thread
From: mockturtle @ 2016-05-02 16:45 UTC (permalink / raw)


Dear all,
I need to interface with a C library (libnl, for using Netlink in Linux).  The library provides a "socket" represented by a struct nl_sock, but the user (the library user, that is, myself) sees only a pointer to nl_sock, since the library provides constructors, destructors and everything is needed to manipulate the socket. In a sense, the user can consider the pointer just as an "opaque handler" rather than a pointer. (I must say that my first impression of the API is definitively positive). 

In Ada I would like to provide a slightly thick package that hides the C type behind a, say, Netlink_Socket type that could be a record holding the pointer to nl_sock. Note that since libnl uses said pointer as an opaque handle, I just need to store the "bitstring" representing its value, in order to pass it to the C library.

I was wandering about the best way to implement the Ada "view"  of the pointer to nl_sock.  

* I could use Interfaces.C.Pointers, but it seems me an overkill since I do not need to do pointer arithmetic.  Moreover, I would need to define a record equivalento to struct nl_sock (although maybe in my case a null record could suffice)

* I could convert it in C to a char* and then using Interfaces.C.Strings.  (A bit dirty, but not too much...)

* I could convert it to an integer... (no, definitively too dirty)

* others? 

What would you suggest?

Keep in mind that the software will run on Linux only (Netlink is specific to Linux, as long as I know) and at 99.99% only on x86 and similar.

Thank you in advance for your help

Riccardo


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: A suggestion about interfacing with C
  2016-05-02 16:45 A suggestion about interfacing with C mockturtle
@ 2016-05-02 18:46 ` Simon Wright
  2016-05-02 19:07 ` Jeffrey R. Carter
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Simon Wright @ 2016-05-02 18:46 UTC (permalink / raw)


mockturtle <framefritti@gmail.com> writes:

> I was wandering about the best way to implement the Ada "view" of the
> pointer to nl_sock.

I think you should implement it as a pointer, because you need to make
sure the size is right; here (OS X), a pointer is 64-bits, whereas an
integer is 32-bits.

But noone else needs to know!

   type Nl_Sock (<>) is private;
   --  the constraint means that users can't create uninitialized
   --  instances

private

   type Nl_Sock is access all Integer;


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: A suggestion about interfacing with C
  2016-05-02 16:45 A suggestion about interfacing with C mockturtle
  2016-05-02 18:46 ` Simon Wright
@ 2016-05-02 19:07 ` Jeffrey R. Carter
  2016-05-02 19:40 ` Per Sandberg
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Jeffrey R. Carter @ 2016-05-02 19:07 UTC (permalink / raw)


On 05/02/2016 09:45 AM, mockturtle wrote:
>
> I need to interface with a C library (libnl, for using Netlink in Linux).  The library provides a "socket" represented by a struct nl_sock, but the user (the library user, that is, myself) sees only a pointer to nl_sock, since the library provides constructors, destructors and everything is needed to manipulate the socket. In a sense, the user can consider the pointer just as an "opaque handler" rather than a pointer. (I must say that my first impression of the API is definitively positive).
>
> In Ada I would like to provide a slightly thick package that hides the C type behind a, say, Netlink_Socket type that could be a record holding the pointer to nl_sock. Note that since libnl uses said pointer as an opaque handle, I just need to store the "bitstring" representing its value, in order to pass it to the C library.

The 1st question is, "How many objects of this type are there in a typical 
application?" Very often in C, you find a type like this even though it makes no 
sense to have more than one of them, because the language lacks modules. If this 
is one of those cases where there will only be one of them, then the Ada 
implementation would be a pkg providing only operations, with the C pointer 
hidden in the body.

This doesn't address your low-level question, which is

> I was wandering about the best way to implement the Ada "view"  of the pointer to nl_sock.
>
> * I could use Interfaces.C.Pointers, but it seems me an overkill since I do not need to do pointer arithmetic.  Moreover, I would need to define a record equivalento to struct nl_sock (although maybe in my case a null record could suffice)
>
> * I could convert it in C to a char* and then using Interfaces.C.Strings.  (A bit dirty, but not too much...)
>
> * I could convert it to an integer... (no, definitively too dirty)
>
> * others?

This kind of opaque pointer is very common in C libraries. Some use "void*" to 
further hide the implementation details. I think you're over thinking things 
here. I usually do something like

type C_Socket is null record;
pragma Convention (C, C_Socket);

type Socket_Ptr is access all C_Socket;
pragma Convention (C, Socket_Ptr);

If you're hiding this in the pkg body, then you're done. If you're exposing the 
type, then these would be in the private part and you'll have

type Socket [(...)] is limited private;

in the public part. Also in the private part you'd have

type Socket [(...)] is limited record
    Ptr : Socket_Ptr;
end record;

or maybe even

function New_Socket [(...)] return Socket_Ptr;
pragma Import (C, New_Socket, ...);

type Socket [(...)] is limited record
    Ptr : Socket_Ptr := New_Socket [(...)];
end record;

Of course, if finalization is needed, this becomes a little more complex, as 
does initialization that needs parameters that can't be discriminants.

-- 
Jeff Carter
"When Roman engineers built a bridge, they had to stand under it
while the first legion marched across. If programmers today
worked under similar ground rules, they might well find
themselves getting much more interested in Ada!"
Robert Dewar
62


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: A suggestion about interfacing with C
  2016-05-02 16:45 A suggestion about interfacing with C mockturtle
  2016-05-02 18:46 ` Simon Wright
  2016-05-02 19:07 ` Jeffrey R. Carter
@ 2016-05-02 19:40 ` Per Sandberg
  2016-05-02 20:14 ` Maciej Sobczak
  2016-05-03 21:53 ` mockturtle
  4 siblings, 0 replies; 6+ messages in thread
From: Per Sandberg @ 2016-05-02 19:40 UTC (permalink / raw)


Well
I would have done it in two steps
1) generate a full low-level interface using -fdump-ada-spec
2) Do the high level interface using the generated specs in the private 
part.
I usually use a script like the following:
##################################################################################
#!/bin/bash
mkdir -p .gen
rm -rf src/gen
mkdir -p src/gen

(cd /usr/include/ ; find libnl3/ -type f -name "*.h")  | \
		grep -v -e qdisc/hfsc.h  \
				-e netlink/hashtable.h \
				-e route/link/info-api.h \
				-e route/link/sit.h \
				-e route/tc-api.h \
				-e route/link/api.h \
				-e route/link/ip6tnl.h \
				-e netlink/cache-api.h | sed -e "s-^-#include <-" -e "s-\$->-" | 
while read i ; do
	echo $i >.gen/gen.cpp
	(cd .gen; gcc -I /usr/include/libnl3/ -c -fdump-ada-spec gen.cpp)
done

# patch up all standard stuff (size_t, int32, uint32, ...)
# Get rid of dependencies to bits_*.h ctype.h ans alike.
sed -f sed sed/all.sed .gen/*.ads -i

# And file specific patches.
for i in sed/*.sed ; do
	name=$(basename $i .sed).ads
	echo .gen/$name
	if [[ -e ${name} ]] ; then
		sed -f $i -i ${name}
	fi
done

cp .gen/libnl3_* src/gen
##################################################################################

Den 2016-05-02 kl. 18:45, skrev mockturtle:
> Dear all,
> I need to interface with a C library (libnl, for using Netlink in Linux).  The library provides a "socket" represented by a struct nl_sock, but the user (the library user, that is, myself) sees only a pointer to nl_sock, since the library provides constructors, destructors and everything is needed to manipulate the socket. In a sense, the user can consider the pointer just as an "opaque handler" rather than a pointer. (I must say that my first impression of the API is definitively positive).
>
> In Ada I would like to provide a slightly thick package that hides the C type behind a, say, Netlink_Socket type that could be a record holding the pointer to nl_sock. Note that since libnl uses said pointer as an opaque handle, I just need to store the "bitstring" representing its value, in order to pass it to the C library.
>
> I was wandering about the best way to implement the Ada "view"  of the pointer to nl_sock.
>
> * I could use Interfaces.C.Pointers, but it seems me an overkill since I do not need to do pointer arithmetic.  Moreover, I would need to define a record equivalento to struct nl_sock (although maybe in my case a null record could suffice)
>
> * I could convert it in C to a char* and then using Interfaces.C.Strings.  (A bit dirty, but not too much...)
>
> * I could convert it to an integer... (no, definitively too dirty)
>
> * others?
>
> What would you suggest?
>
> Keep in mind that the software will run on Linux only (Netlink is specific to Linux, as long as I know) and at 99.99% only on x86 and similar.
>
> Thank you in advance for your help
>
> Riccardo
>

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: A suggestion about interfacing with C
  2016-05-02 16:45 A suggestion about interfacing with C mockturtle
                   ` (2 preceding siblings ...)
  2016-05-02 19:40 ` Per Sandberg
@ 2016-05-02 20:14 ` Maciej Sobczak
  2016-05-03 21:53 ` mockturtle
  4 siblings, 0 replies; 6+ messages in thread
From: Maciej Sobczak @ 2016-05-02 20:14 UTC (permalink / raw)



> * others?
> 
> What would you suggest?

Apart from the suggestions that you have got already, I would like to expand a bit on the "others" category.

Note that in the case of this library (and many others, because the pattern is popular) it is not necessary to pass the pointer to Ada, even if it is opaque, as Ada will not operate on it. The only purpose of passing it to Ada is to pass it back to C, where the actual operations will take place, in which case you might as well not pass it at all and just keep it at the C side. Really, you do not need this value (no matter how mangled) at the Ada level. And this observation opens the idea to pass some token instead (if there can be many objects identified this way), which might be of some more Ada-friendly type, even (or maybe in particular) the integer. That is, you can use 32-bit Integer on the Ada side, as a descriptor for the 64-bit pointer at the C side, and there is no need to pass the pointer around.

You will need some additional, very thin layer of C to map one to another (note that I used the word "map" instead of "convert"), but such a thin layer could prove useful anyway, in order to flatten and "sanitize" anything else that might need to be passed between domains. If there are any structs or #defines used in the C API, then you will find such a thin wrapper very valuable (how about checking whether the Ada descriptor is still valid, before doing anything with the pointer?). The target is a C API that uses *only* those types that are trivial to handle at the Ada level, where you can stack up higher-level APIs if necessary.
I have used this approach to create bindings for both C and C++ libraries.

-- 
Maciej Sobczak * http://www.inspirel.com


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: A suggestion about interfacing with C
  2016-05-02 16:45 A suggestion about interfacing with C mockturtle
                   ` (3 preceding siblings ...)
  2016-05-02 20:14 ` Maciej Sobczak
@ 2016-05-03 21:53 ` mockturtle
  4 siblings, 0 replies; 6+ messages in thread
From: mockturtle @ 2016-05-03 21:53 UTC (permalink / raw)


Thank you everyone for your replies.

In the end, I decided to go for the "token" approach (suggested by Maciej) that I already used in some other case.  The reason to use this approach is that the "send" functions of the library require the message header and payload to be stored inside a special struct, whose definition is unknown (at least, very difficult to find :-) and that the user manipulates using some library functions.  It turns out that it is simpler to build the payload on the Ada side, then convert it to a "C string" that is moved to the C side where the final assembling -- before transmission -- is done.

Thank you again.

Riccardo

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2016-05-03 21:53 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-05-02 16:45 A suggestion about interfacing with C mockturtle
2016-05-02 18:46 ` Simon Wright
2016-05-02 19:07 ` Jeffrey R. Carter
2016-05-02 19:40 ` Per Sandberg
2016-05-02 20:14 ` Maciej Sobczak
2016-05-03 21:53 ` mockturtle

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