"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 (towith
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.