"cannot generate code for file random.ads" when running a .adb program

I have some troubles with running a program in Ada. I have the three following project files (I use GPS) :

Types.ads

package types is
   subtype T_valeurind is Integer range 2..14;
   type T_couleur is (s, h, c, d);
   type t_carte is record
      valeur : T_valeurind;
      couleur : T_couleur;
   end record;

   type T_jeu is array (1..7) of t_carte;

   function trans(val: Character) return T_valeurind;

end types;

Trans.adb

with types;
use types;
WITH Text_Io , Ada.Integer_Text_Io;
USE Text_Io , Ada.Integer_Text_Io;


function trans(val : Character) 
   return T_valeurind is
   ret: Integer;
begin 
   case val is
     when '3' => ret:=3;
     when '4' => ret:=4;
     when '5' => ret:=5;
     when '6' => ret:=6;
     when '7' => ret:=7;
     when '8' => ret:=8;
     when '9' => ret:=9;
     when 'T' => ret:=10;
     when 'J' => ret:=11;
     when 'Q' => ret:=12;
     when 'K' => ret:=13;
     when 'A' => ret:=14;
     when others => null;
  end case;
  return ret;
end trans;

Test.adb

WITH Text_Io , Ada.Integer_Text_Io;
USE Text_Io , Ada.Integer_Text_Io;
with types;
use types;


procedure test is
begin
   put(T_valeurind'Image(trans('c')));
end test;

I'm just trying to execute test.adb just to check if my function "trans" works well. When I build the files in GPS, everything works just fine. But when I want to run them, I have the following message, and no execution :

cannot generate code for file types.ads (package spec)

gprbuild: *** compilation phase failed

[2018-12-02 02:01:39] process exited with status 4, 100% (2/2), elapsed time: 01.65s

But what is perturbing is that the first time I tried running the code, it worked. Without changing anything, it stopped working. I don't know what to do. I've seen that this message just tells me that .ads file is not compilable, but what I try to compile and run is an .adb file, so I don't get it.. Do you have an idea why it doesn't work ?

Thank you all in advance !

First, those aren't project files, which would have type .gpr; they're Ada source files in your project.

Your types.ads promises function trans, which means it needs a package body in types.adb,

package body types is
   function trans(val : Character) 
      return T_valeurind is
      ret: Integer;
   begin 
      case val is
        when '3' => ret:=3;
        when '4' => ret:=4;
        when '5' => ret:=5;
        when '6' => ret:=6;
        when '7' => ret:=7;
        when '8' => ret:=8;
        when '9' => ret:=9;
        when 'T' => ret:=10;
        when 'J' => ret:=11;
        when 'Q' => ret:=12;
        when 'K' => ret:=13;
        when 'A' => ret:=14;
        when others => null;
     end case;
     return ret;
   end trans;
end types;

(Hmm. If you pass in an invalid character, you'll return uninitialised data, and as like as not get a Constraint_Error; T_valeurind includes the value 2, shouldn’t you cover it?)

Your trans.adb specifies a library-level function instead.

When I build the files in GPS, everything works just fine. But when I want to run them, I have the following message, and no execution :

If a package spec (types.ads) requires a body (types.adb) and you don't provide it, the compiler will produce the message you report when you try to compile it. If you try to just compile test.adb it will be OK. If you try to build test.adb it will try to compile the package Types and will fail, regardless of whether you're trying to Build or Build & Run.

I have no idea how this could have worked first time!

It looks like you forgot to include your function Trans in the context of the test program. And if it isn't in the context, you can't use it.

Try to add:

with Trans;

To the context clause of procedure Test.

Your whole problem could have been avoided in the first place using powerful Ada enums capabilities (and some bad inputs handling strategy, like exceptions). Your trans procedure would be useless.

If you are interested in the order relation of your enum values, you can also use the Ada's 'First* (first enum literal), 'Last (last enum literal), 'Pos (position inside the enum), 'Succ (next enum literal), 'Pred (previous enum literal).

If you perform memory mapping for your variables, you could use 'Valid to check if the variable has a valid value and save the need of exception catch for constraint errors.

See example below:

with Ada.Text_IO; use Ada.Text_IO;
with Ada.Exceptions; use Ada.Exceptions;

procedure Hello is
    -- miwing chars and literal values in enum
    -- note that jack is 'J' and not the single source code character J
    type My_Awesome_Enum is ('1', '2', '3', 'J', Q, K, Ace);
    for My_Awesome_Enum use
       ('1' => -1,
       '2' => 2,
       '3' => 3,
       -- ...
       'J' => 11,
       Q => 12,
       K => 13,
       Ace => 14);
    temp : Integer;
    prev : My_Awesome_Enum;
    succ : My_Awesome_Enum;
    temp2 : My_Awesome_Enum;
begin
    -- ------------------------------------------
    -- Ada enum power
    declare
    begin
      for value in My_Awesome_Enum loop
        temp := My_Awesome_Enum'Enum_Rep(value);
        Put_Line("Enum litteral value: " & value'Image & " - memory representation: " & Integer'Image(temp));

        if value /= My_Awesome_Enum'First then
            prev := My_Awesome_Enum'Pred(value);
            Put_Line("Previous: " & prev'Image);
        else
            Put_Line("No previous");
        end if;
        if value /= My_Awesome_Enum'Last then
            succ := My_Awesome_Enum'Succ(value);
            Put_Line("Next: " & succ'Image);
        else
            Put_Line("No next");
        end if;
        Put_Line("");
      end loop;
    end;
    -- ------------------------------------------
    -- conversion from some input source
    Put_Line("");
    declare
        strInput : String := "Unknown user value";
    begin
        Put_Line("Handling of user input: " & strInput);
        temp2 := My_Awesome_Enum'Value (strInput);
    exception
    when E: others =>
        Put_Line("Exception catched: " & Exception_Information (E));
        Put_Line("Setting value to Ace instead");
        temp2 := Ace;
    end;
    Put_Line("tmp2 value: " & temp2'Image & " - memory representation: " & Integer'Image(My_Awesome_Enum'Enum_Rep(temp2)));
    -- ------------------------------------------
    -- mmemory mapping
    Put_Line("");
    declare
        my_int : Integer := -3;
        mapped_Enum : My_Awesome_Enum;
        for mapped_Enum'Address use my_int'Address;
        last_enum : My_Awesome_Enum := (My_Awesome_Enum'Last);
        stop_condition : Integer := (last_enum'Enum_Rep) + 2;
    begin
        while (my_int < stop_condition) loop
            if mapped_Enum'Valid then
                Put_Line("Enum with value: " & my_int'Image & " is valid.");
            else
                Put_Line("Memory mapping would result in invalid enum for value: " & my_int'Image);
            end if;
            my_int := my_int + 1;
        end loop;
    end;

end Hello;

This give sthe following output (https://www.tutorialspoint.com/compile_ada_online.php, with GNATMAKE v7.1.1):

Build:

$gnatmake -o hello *.adb
gcc -c hello.adb
gnatbind -x hello.ali
gnatlink hello.ali -o hello

Execute:

Enum litteral value: '1' - memory representation: -1
No previous
Next: '2'

Enum litteral value: '2' - memory representation:  2
Previous: '1'
Next: '3'

Enum litteral value: '3' - memory representation:  3
Previous: '2'
Next: 'J'

Enum litteral value: 'J' - memory representation:  11
Previous: '3'
Next: Q

Enum litteral value: Q - memory representation:  12
Previous: J
Next: K

Enum litteral value: K - memory representation:  13
Previous: Q
Next: ACE

Enum litteral value: ACE - memory representation:  14
Previous: K
No next

Handling of user input: Unknown user value
Exception catched: raised CONSTRAINT_ERROR : bad input for 'Value: "Unknown user value"

Setting value to Ace instead
tmp2 value: ACE - memory representation:  14

Memory mapping would result in invalid enum for value: -3
Memory mapping would result in invalid enum for value: -2
Enum with value: -1 is valid.
Memory mapping would result in invalid enum for value:  0
Memory mapping would result in invalid enum for value:  1
Enum with value:  2 is valid.
Enum with value:  3 is valid.
Memory mapping would result in invalid enum for value:  4
Memory mapping would result in invalid enum for value:  5
Memory mapping would result in invalid enum for value:  6
Memory mapping would result in invalid enum for value:  7
Memory mapping would result in invalid enum for value:  8
Memory mapping would result in invalid enum for value:  9
Memory mapping would result in invalid enum for value:  10
Enum with value:  11 is valid.
Enum with value:  12 is valid.
Enum with value:  13 is valid.
Enum with value:  14 is valid.
Memory mapping would result in invalid enum for value:  15

Comments
  • If I understood well, since you talk of types.ADB, I have to create this file to put your code, right ?
  • That's what I tried, and it looks like it works. I have other issues now, but this problem is solved. Thanks a lot !
  • Well I tried with adding with Trans; at the beginning of my test.adb file, but it sends me that trans.adb is not found. Yet trans.adb is in the same folder (src). I think I misunderstood something about functions and their declarations...
  • It probably means that trans.ads isn’t found (to with a unit, there has to be a spec, in .ads)
  • Well I'm new to Ada, so I do not understand all your code yet, but I keep it since I think it will be useful later. Thank you a lot for your time !
  • Basically, Ada provides features for enum conversion from/ to string and for enums memory representation. It saves the pain of writing and maintaining switch cases similar to the one you posted.
  • Note that if you don’t define a memory representation yourself, the compiler will define one itself.