Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>Yes!</p> <p>In fact, any language that can be called from C can be used from Perl using XS. Here's a solution to how to do it with an Ada module and ExtUtils::MakeMaker.</p> <h2>Setting things up</h2> <h3>Module tree</h3> <p>Let's start by creating a module tree using <code>h2xs</code>:</p> <pre><code>$ h2xs -A -n MyAdaModule </code></pre> <p>Then let's create a subdirectory to hold our Ada files:</p> <pre><code>$ cd MyAdaModule $ mkdir src </code></pre> <p>Here is the module's specification: <strong>src/hello.ads</strong></p> <pre><code>procedure hello; </code></pre> <p>... and the body: <strong>src/hello.adb</strong></p> <pre><code>with Ada.Text_IO; use Ada.Text_IO; procedure hello is begin Put_Line("Hi from Ada!"); end; </code></pre> <p>Don't forget to update the MANIFEST.</p> <h3>Writing the XS file</h3> <p>Let's write the body of MyAdaModule.xs now. It's pretty much like using a function from a C library:</p> <pre><code>#define PERL_NO_GET_CONTEXT #include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include "ppport.h" extern void adainit(); extern void adafinal(); MODULE = MyAdaModule PACKAGE = MyAdaModule void say_hello() CODE: adainit(); hello(); adafinal(); </code></pre> <p>From the <a href="http://gcc.gnu.org/onlinedocs/gnat_ugn_unw/Interfacing-to-C.html" rel="noreferrer">gnat documentation</a> we know that we need to call <code>adainit()</code> and <code>adafinal()</code> to initialise and then clean up. These calls surround <code>hello()</code> here but they would probably be in a better place in some other function in your XS file. They would then be called from a BEGIN and END block in your Perl module.</p> <h2>Time to compile!</h2> <h3>Ada library</h3> <p>First, we don't want to delegate all the magic linking and binding to MakeMaker so let's create a makefile in the src/ directory that will compile our Ada code into a static library.</p> <p>To make this library, <code>hello.a</code>, we just have to follow the gnat documentation:</p> <ul> <li>use <code>gnatmake -c</code> to generate a <code>hello.ali</code> and a <code>hello.o</code>;</li> <li>use <code>hello.ali</code> with <code>gnatbind</code> with the <code>-n</code> switch. This will generate <code>b~hello.adb</code> and <code>b~hello.ads</code> which contain binding code;</li> <li>compile <code>b~hello.adb</code> into an object file: <code>b~hello.o</code>.</li> <li>group <code>hello.o</code> and <code>b~hello.o</code> together into an archive with <code>ar</code></li> </ul> <p>So, in short, we will use this makefile:</p> <pre><code>all: hello.a hello.a: hello.o b~hello.o ar rcs $@ $^ hello.o: hello.adb hello.ads gnatmake -c -o $@ $&lt; b~hello.o: b~hello.adb b~hello.ads gnatmake -c -o $@ $&lt; b~hello.adb: hello.ali gnatbind -n $&lt; hello.ali: hello.o clean: rm -rf *.o *.ali *.a b~* </code></pre> <p>Don't forget to update the MANIFEST.</p> <h3>Makefile.PL</h3> <p>Finally, the MakeFile.PL file needs some editing. It has to call the above makefile to build our library and then use it in the final linking phase. This is done by setting <code>MYEXTLIB</code> to <code>src/hello.a</code> and by adding a rule in the <code>postamble</code> section.</p> <p>In our case, we also need to link with libgnat (for <code>Ada.Text_IO</code>) which should reside somewhere on your system. This is done by editing <code>LIBS</code>. In this example the path is hardcoded but you should probably figure out a more portable way to find libgnat.</p> <pre><code>use 5.018001; use ExtUtils::MakeMaker; # See lib/ExtUtils/MakeMaker.pm for details of how to influence # the contents of the Makefile that is written. WriteMakefile( NAME =&gt; 'MyAdaModule', VERSION_FROM =&gt; 'lib/MyAdaModule.pm', # finds $VERSION PREREQ_PM =&gt; {}, # e.g., Module::Name =&gt; 1.1 ($] &gt;= 5.005 ? # Add these new keywords supported since 5.005 (ABSTRACT_FROM =&gt; 'lib/MyAdaModule.pm', # retrieve abstract from module AUTHOR =&gt; 'A. U. Thor &lt;author@nonet&gt;') : ()), DEFINE =&gt; '', # e.g., '-DHAVE_SOMETHING' INC =&gt; '-I.', # e.g., '-I. -I/usr/include/other' LIBS =&gt; ['-L/usr/lib/gcc/i686-pc-linux-gnu/4.8.2/adalib/ -lgnat'], MYEXTLIB =&gt; 'src/hello.a', ); sub MY::postamble { join("\n", "\$(MYEXTLIB)::", "\tmake -C src/", "", "clean::", "\tmake -C src/ clean", ); } </code></pre> <p>Now try </p> <pre><code>$ perl Makefile.PL $ make $ make test </code></pre> <p>And surprise: the test doesn't pass! The <code>hello()</code> symbol doesn't exist. Inspecting the <code>MyAdaLib.so</code> generated by make with the <code>nm</code> tool reveals that some symbols have been renamed. In my case, they were prefixed with <code>_ada_</code>. So I'd have to call <code>_ada_hello()</code> instead of <code>hello()</code>. This can be corrected in <code>src/ada.ads</code> using the <code>Export</code> pragma:</p> <pre><code>pragma Export (Convention =&gt; C, Entity =&gt; hello, External_Name =&gt; "hello" ); </code></pre> <p>From what I understood, this should be done for all public symbols as it ensures the representation of types, records, etc, is understood from a C program.</p> <p>Now, you should be able to call <code>hello()</code> from the XSUB. Enjoy!</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload