From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00 autolearn=ham autolearn_force=no version=3.4.4 X-Google-Thread: a07f3367d7,d8e3cd3d8dbaa4fb X-Google-Attributes: gida07f3367d7,public,usenet X-Google-NewGroupId: yes X-Google-Language: ENGLISH,ASCII-7-bit Received: by 10.180.106.199 with SMTP id gw7mr1300603wib.0.1343313139964; Thu, 26 Jul 2012 07:32:19 -0700 (PDT) Path: ge7ni75591628wib.0!nntp.google.com!volia.net!news2.volia.net!feed-A.news.volia.net!border1.nntp.ams2.giganews.com!border2.nntp.ams2.giganews.com!border4.nntp.ams.giganews.com!border2.nntp.ams.giganews.com!nntp.giganews.com!newsfeed.straub-nv.de!news-1.dfn.de!news.dfn.de!lrz.de!news-peer.in.tum.de!weretis.net!feeder4.news.weretis.net!eternal-september.org!feeder.eternal-september.org!mx04.eternal-september.org!.POSTED!not-for-mail From: Brian Drummond Newsgroups: comp.lang.ada Subject: Re: Ada "library only" compiler ? Date: Sun, 22 Jul 2012 17:54:02 +0000 (UTC) Organization: A noiseless patient Spider Message-ID: References: <2879c45e-f8e0-4434-9f82-968c585a4539@googlegroups.com> <4ec072e1-853f-4210-82aa-9aab335ab0ba@googlegroups.com> <98bd035c-3da7-4c9b-b483-051399dc5b57@googlegroups.com> Mime-Version: 1.0 Injection-Date: Sun, 22 Jul 2012 17:54:02 +0000 (UTC) Injection-Info: mx04.eternal-september.org; posting-host="0e44dd4a3c4e0a6e83a86f947fb780ae"; logging-data="29306"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1/qOPqw+6Tg5jIe2f9rY7plRf9nFJixG3Y=" User-Agent: Pan/0.135 (Tomorrow I'll Wake Up and Scald Myself with Tea; GIT 30dc37b master) Cancel-Lock: sha1:yTqEuudbLcj2Eb0iAPX0Iisp+jM= Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Date: 2012-07-22T17:54:02+00:00 List-Id: 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 ---------------------------------------------------