Search code examples
cgoogletestada

Passing a C-styled integer array to an Ada function to retrieve the first element in the array


I am running an experiment in trying to link google test to ada95 for unit testing. I know ada has aunit and ahven, but this is just to see if this is possible and is outside of the scope of my question. I have successfully been able to do simple functions and procedures with the basic data types. The next thing I would like to try to do is similar to the following:

Here is the main.cpp file:

#include <stdio.h>
#include <gtest/gtest.h>

extern "C" {
  int firstElement(int buffer[]);
}

TEST(tryTest, checkBuffer){
   int buffer[10] = {10,1,6,4,3,2,1,3,4,6};
   ASSERT_EQ(buffer[0],firstElement(buffer));
}

int main(int argc, char ** argv) {
  testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}

for simplicity I will just put the ads file:

Lib_test.ads

with Interfaces.C;
with Interfaces.C.Pointers;
package Lib_Test is

  function FirstElement(a: Interfaces.C.Pointers) return Interfaces.C.Int;
  pragma Export(C,FirstElement,"firstElement");
end Lib_Test;

I know in c you are passing in the pointer to the first element not the entire array for the function. That is why I tried to use Interfaces.C.Pointers for the data type but I got the following error

subtype mark required in this context
found "Pointers" declared at i-cpoint.ads:44

I have not found a good example of using other array types besides char arrays. Can someone show me how I can use Interfaces.C.Pointers for an integer array or even how I can fix this, I believe it is just my data type in the parameter of the function. I want to be able to access the c integer array in the ada function.

Thank you all!


Solution

  • According to RM B.3 (70):

    An Ada parameter of an array type with component type T, of any mode, is passed as a t* argument to a C function, where t is the C type corresponding to the Ada type T.

    Hence, there's no need to use package Interfaces.C.Pointers. You can just use an Ada array type. A small example:

    main.cpp

    #include <stdio.h>
    #include <gtest/gtest.h>
    
    extern "C" {
      void testinit();
      void testfinal();
      int firstElement(int *buffer);
    }
    
    class MyTest : public ::testing::Test {
    protected:
    
      MyTest() {
        testinit();          // Initialize the Ada library
      }
    
      ~MyTest() override {
        testfinal();         // Finalize the Ada library
      }
    };
    
    TEST_F(MyTest, CheckBuffer) {
      int buffer[10] = {10,1,6,4,3,2,1,3,4,6};
      ASSERT_EQ(buffer[0], firstElement(buffer));
    }
    
    int main(int argc, char **argv) {
      ::testing::InitGoogleTest(&argc, argv);
      return RUN_ALL_TESTS();
    }
    

    test.gpr

    with "libtest";
    
    project Test is
    
       for Source_Dirs use ("src");
       for Object_Dir use "obj";
       for Main use ("main.cpp");
       for Languages use ("C++");
    
       package Compiler is
          for Switches ("c++") use ("-I/usr/src/googletest/googletest/include");
       end Compiler;
    
       package Linker is
          for Switches ("c++") use ("-lgtest", "-lgtest_main", "-pthread", "-ltest");
       end Linker;
    
    end Test;
    

    lib_test.ads

    with Interfaces.C;
    
    package Lib_Test is
    
       package C renames Interfaces.C;
       
       type Seq is array (0 .. 9) of C.Int;
          
       function First_Element (A : Seq) return C.Int;
       pragma Export (C, First_Element, "firstElement");
       
    end Lib_Test;
    

    lib_test.adb

    package body Lib_Test is
       
       -------------------
       -- First_Element --
       -------------------
       
       function First_Element (A : Seq) return C.Int is
       begin
          return A (A'First);
       end First_Element;
    
    end Lib_Test;
    

    libtest.gpr

    library project Libtest is
       for Library_Kind use "dynamic";
       for Library_Name use "test";
       for Library_Interface use ("lib_test");
       for Library_Auto_Init use "False";
       for Library_Dir use "lib";
       for Object_Dir use "obj";
       for Source_Dirs use ("src");   
    end Libtest;
    

    output

    $ ./obj/main 
    [==========] Running 1 test from 1 test case.
    [----------] Global test environment set-up.
    [----------] 1 test from MyTest
    [ RUN      ] MyTest.CheckBuffer
    [       OK ] MyTest.CheckBuffer (0 ms)
    [----------] 1 test from MyTest (0 ms total)
    
    [----------] Global test environment tear-down
    [==========] 1 test from 1 test case ran. (0 ms total)
    [  PASSED  ] 1 test.