comp.lang.ada
 help / color / mirror / Atom feed
From: Brian Drummond <brian@shapes.demon.co.uk>
Subject: Re: Ada  "library only" compiler ?
Date: Sun, 22 Jul 2012 17:54:02 +0000 (UTC)
Date: 2012-07-22T17:54:02+00:00	[thread overview]
Message-ID: <juhenq$sjq$1@dont-email.me> (raw)
In-Reply-To: 98bd035c-3da7-4c9b-b483-051399dc5b57@googlegroups.com

On Sat, 21 Jul 2012 20:25:48 -0700, Patrick wrote:

> Hi Brian
> 
> Thanks for your feedback Yes, thankfully with the help of people on the
> list I can work in both directions with C and Ada now and as such could
> write code in Ada and export it as C for use with other languages like
> Lua.

I can now call Lua from Ada. 
Calling Ada from Lua ought to work, but I haven't tried it yet.

I downloaded Lua 5.21 today and tried this (c) example
http://lua-users.org/wiki/SimpleLuaApiExample

I needed to modify the compile process a little (linking with -ldl) to 
overcome missing "dlopen" etc functions; after that, it worked as 
expected. Then I made a basic port of the example to Ada.

This port uses a "thin binding", which can be (mostly) auto-generated by 
GCC, using the -fdump-ada-spec[-slim] option. (This assumes gcc4.6.1 or 
later)

gcc -fdump-ada-spec ../lua-5.2.1/install/include/lua.h
gcc -fdump-ada-spec ../lua-5.2.1/install/include/lauxlib.h
gcc -fdump-ada-spec ../lua-5.2.1/install/include/lualib.h

This builds package spec files (lua_h.ads, etc) for these header files. 
Without -slim, actually the transitive closure of all the headers they 
include, which can get VERY large. (This is not a problem with the tools, 
just a reflection of the disastrous character of C's #include mechanism)

It is probably better to use -slim, and collect the (few) missing 
dependencies into one small additional package. But for Lua, the closure 
only generated 11 files, so I didn't try for this experiment.

Now there are a few problems with this binding; two trivial, one large, 
because -fdump-ada-spec cannot parse everything in every header file.
I am detailing these below in case you want to reproduce the result.

Small problems (minimising the dependencies would eliminate these): 
(1) compiling lauxlib_h.ads reports 
"lauxlib_h.ads:289:25: "FILE" not declared in "stdio_h"
Workaround : comment out the problematic declaration (type luaL_Stream) 
in lauxlib_h.ads. (I can't see the problem)
(2) compiling libio_h.ads reports
libio_h.ads:49:28: "anon652_anon676_array" is undefined
libio_h.ads:58:27: "anon652_anon679_array" is undefined
which turns out to be missing declarations for fields in a record

   type u_IO_FILE is record
...
      u_shortbuf : aliased anon652_anon676_array;  
...
      u_unused2 : aliased anon652_anon679_array;  
   end record;

Considering that one of these fields is declared in C as
--------------------------------------------------------
  /* Make sure we don't get into trouble again.  */
  char _unused2[15 * sizeof (int) - 4 * sizeof (void *) 
	- sizeof (size_t)];
--------------------------------------------------------
I can't blame -fdump-ada-spec for failing to translate it!

Workaround : add subtype declarations ahead of the record decln in 
libio_h.ads, as follows... (size was experimentally determined)
subtype anon652_anon676_array is Interfaces.C.char_array (0 .. 0);
subtype anon652_anon679_array is Interfaces.C.char_array (0 .. 39);
   type u_IO_FILE is record ...

Bigger problem : -fdump-ada-spec can't translate macros; they just don't 
have enough context to define their meaning.

I have resolved this by adding a new package, lua_macros (below), to 
define constants, procedures and functions to replace the missing macros. 
(There are probably 150 missing macros; I have only replaced enough to 
run this example, but the remainder are mostly boilerplate)

Then a straight port of the test program (below) works as expected.
I have left all the gory details explicit in the source; a few "use" 
clauses would make it much more readable.

A better approach would be a thick binding, another package which uses 
these, but hides all the C interface details internally and provides a 
clean Ada interface to application code.

-------- output --------------------------------------------------
./test
The table the script received from the Ada main has:
1	2
2	4
3	6
4	8
5	10
Returning data back to Ada
Script returned: 3.00000E+01
Success

--------- source ---------------------------------------------------

with Interfaces.C.Strings; use Interfaces.C;

with lua_h;
with lauxlib_h;
with lua_macros;
with lualib_h; -- why didn't the C version need to #include lualib.h?

with Ada.Text_Io; use Ada.Text_Io;

-- http://lua-users.org/wiki/SimpleLuaApiExample

procedure test is
    status, result 	: Interfaces.C.int;
    sum 		: Interfaces.C.double;
    L	 		: lua_macros.lua_State_Ptr;

begin

    L := lauxlib_h.luaL_newstate;

    lualib_h.luaL_openlibs(L); -- /* Load Lua libraries */

    status := lua_macros.luaL_loadfile(L, 
				Strings.New_String("script.lua"));
    if status /= 0 then 
        -- If something went wrong, error is at the top of the stack 
        Put_Line("Couldn't load file: " & 
		Strings.Value(lua_macros.lua_tostring(L, -1)));
        raise Program_Error;
    end if;

    lua_macros.lua_newtable(L);

    for i in 1 .. 5 loop
        lua_h.lua_pushnumber(L, double(i));   	-- /* Push the table 
index */
        lua_h.lua_pushnumber(L, double(i*2)); 	-- /* Push the cell value 
*/
        lua_h.lua_rawset(L, -3);      		-- /* Stores the pair in 
the table */
    end loop;

    -- /* By what name is the script going to reference our table? */
    lua_h.lua_setglobal(L, Strings.New_String("foo"));

    -- /* Ask Lua to run our little script */
    result := lua_macros.lua_pcall(L, 0, lua_macros.LUA_MULTRET, 0);
    if result /= 0 then
        Put_Line("Failed to run script: "& 
		Strings.Value(lua_macros.lua_tostring(L, -1)));
        raise Program_Error;
    end if;

    -- /* Get the returned value at the top of the stack (index -1) */
    sum := lua_macros.lua_tonumber(L, -1);

    Put_Line("Script returned:"  & float'image(float(sum)));

    lua_macros.lua_pop(L, 1);  	-- /* Take returned value off stack */
    lua_h.lua_close(L);   	-- /* Cya, Lua */

    Put_Line("Success");

end test;

--------- macro spec ---------------------------------------------------
with lua_h;
with System;
with Interfaces.C.Strings;
use Interfaces.C;

package lua_macros is

-- missing macros from lua_h

   --  skipped empty struct lua_State ... lua.h
   subtype lua_State_Ptr is System.Address;

   -- /* option for multiple returns in 'lua_pcall' and 'lua_call' */
   -- #define LUA_MULTRET	(-1)
   LUA_MULTRET : constant Interfaces.C.Int := -1;

   -- #define lua_pcall(L,n,r,f) lua_pcallk(L, (n), (r), (f), 0, NULL)
   function lua_pcall (	L : lua_State_Ptr; 
			n : Interfaces.C.int;
			r : Interfaces.C.int;
			f : Interfaces.C.int ) 
   			return Interfaces.C.int;

   -- #define lua_pop(L,n)		lua_settop(L, -(n)-1)
   procedure lua_pop (L : lua_State_Ptr; n : Interfaces.C.int); 

   -- #define lua_tonumber(L,i)	lua_tonumberx(L,i,NULL)
   function lua_tonumber (L : lua_State_Ptr; i : Interfaces.C.int) 
	return lua_h.lua_Number; 

   -- #define lua_newtable(L)	lua_createtable(L, 0, 0)
   procedure lua_newtable (L : lua_State_Ptr);

   -- #define lua_tostring(L,i)	lua_tolstring(L, (i), NULL)
   function lua_tostring
     (L : lua_State_Ptr;
      i : Interfaces.C.int) return Interfaces.C.Strings.chars_ptr; 

-- missing macros from lauxlib_h

   -- #define luaL_loadfile(L,f)	luaL_loadfilex(L,f,NULL)
   function luaL_loadfile
     (L : lua_State_Ptr;
      f : Interfaces.C.Strings.chars_ptr ) return Interfaces.C.int;

end lua_macros;
--------- macro body ---------------------------------------------------
with lauxlib_h;
with lua_h;
with System;
with Interfaces.C;

package body lua_macros is

   function lua_pcall (	L : lua_State_Ptr; 
			n : Interfaces.C.int;
			r : Interfaces.C.int;
			f : Interfaces.C.int ) 
   			return Interfaces.C.int is
   begin
      return lua_h.lua_pcallk(L, n, r, f, 0, NULL);
   end lua_pcall;

   procedure lua_pop (L : lua_State_Ptr; n : Interfaces.C.int) is
   begin
      lua_h.lua_settop(L, -(n)-1);
   end lua_pop;

   function lua_tonumber (L : lua_State_Ptr; i : Interfaces.C.int) 
	return lua_h.lua_Number is
   begin
      return lua_h.lua_tonumberx(L, i, NULL);
   end lua_tonumber;

   procedure lua_newtable (L : lua_State_Ptr) is
   begin
      lua_h.lua_createtable(L, 0, 0);
   end lua_newtable;

   function lua_tostring
     (L : lua_State_Ptr;
      i : Interfaces.C.int) return Interfaces.C.Strings.chars_ptr is
   begin
      return lua_h.lua_tolstring(L, (i), NULL);
   end lua_tostring;

   function luaL_loadfile
     (L : lua_State_Ptr;
      f : Interfaces.C.Strings.chars_ptr ) return Interfaces.C.int is
   begin
   	return lauxlib_h.luaL_loadfilex
(L,f,Interfaces.C.Strings.Null_Ptr);
   end luaL_loadfile;

end lua_macros;
--------- end        ---------------------------------------------------




  reply	other threads:[~2012-07-26 14:32 UTC|newest]

Thread overview: 41+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-07-20 20:05 Ada "library only" compiler ? Patrick
2012-07-20 21:11 ` Niklas Holsti
2012-07-20 21:47   ` Ludovic Brenta
2012-07-20 22:25   ` Peter C. Chapin
2012-07-20 22:51     ` Ludovic Brenta
2012-07-21  0:32       ` Randy Brukardt
2012-07-21 12:39         ` Pascal Obry
2012-07-22  4:59           ` Shark8
2012-07-22  7:04             ` Pascal Obry
2012-07-22 10:17           ` Florian Weimer
2012-07-24  1:54           ` Randy Brukardt
2012-07-24 16:50             ` Pascal Obry
2012-07-24 18:01               ` Vasiliy Molostov
2012-07-24 21:30                 ` Pascal Obry
2012-07-25  6:33                   ` Vasiliy Molostov
2012-07-25 23:44                   ` sbelmont700
2012-07-25 23:34               ` Randy Brukardt
2012-07-21 11:05     ` Niklas Holsti
2012-07-20 23:30   ` Patrick
2012-07-21 16:47     ` Niklas Holsti
2012-07-21 17:47       ` Patrick
2012-07-21 19:22         ` Simon Wright
2012-07-21 19:38           ` Patrick
2012-07-21 22:53         ` Brian Drummond
2012-07-22  3:25           ` Patrick
2012-07-22 17:54             ` Brian Drummond [this message]
2012-07-22 17:59               ` Brian Drummond
2012-07-22 18:44                 ` Patrick
2012-07-22 21:03                   ` Brian Drummond
2012-07-25 19:10                   ` J-P. Rosen
     [not found]               ` <m2a9yrsbf5.fsf@nidhoggr.home>
     [not found]                 ` <jui36a$hs0$1@dont-email.me>
2012-07-23 10:10                   ` Simon Wright
2012-07-24 10:55                     ` Brian Drummond
2012-07-22 21:25             ` Niklas Holsti
2012-07-22 22:00               ` Patrick
2012-07-22 21:18         ` Niklas Holsti
     [not found]   ` <olpj085ii9fpifpligh6jerghoaieiim1d@invalid.netcom.com>
2012-07-20 23:38     ` Patrick
2012-07-21 13:12     ` Niklas Holsti
2012-07-21  0:27   ` Randy Brukardt
2012-07-21  7:36     ` Dmitry A. Kazakov
2012-07-21 13:31     ` Niklas Holsti
2012-07-23  5:02 ` Miles Bader
replies disabled

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