GNAT is free software; you can redistribute it and/or modify it under terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNAT is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANT ABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNAT; see file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
The document serves as an introduction to some of the tools provided with the GNAT (GNU Ada 95) compilation system. This document does not replace the "official" GNAT User Guide, but rather selectively augments it with examples of tool use and some helpful hints. All these tools have many more options and flags than we can cover here; please refer to the GNAT User Guide for further details.
Overriding the GNAT default file-naming conventions
Using gdb to get a simple traceback
Using gnatf to get a cross reference
gnatmake is the GNAT tool that builds an executable program from a set of source files, typically an Ada main program and a set of library units like packages. gnatmake has many options, including compiler, binder, and linker options to be passed through to those tools, multidirectory compilation structures, and the like. Here we cover some of the most frequently-used options. Throughout, our annotations and explanations are in the typeface you are reading. Our command line input is shown like this:
sample command line
and the output is shown like this:
sample output line
Consider a program test_factorial.adb, a source file containing one nested subprogram, Factorial, which recursively computes the factorial of its positive input argument. We build an executable test_factorial with the command
gnatmake -v -g -gnatl test_factorial
We have used the three options
Here is the screen output from this command, with our annotations:
GNATMAKE 3.07 (960911) Copyright 1995 Free Software Foundation, Inc. "test_factorial.ali" being checked ... -> "test_factorial.adb" time stamp mismatch
test_factorial needs to be compiled; gnatmake invokes the compiler and displays the listing:
gcc -c -g -gnatl test_factorial.adb GNAT 3.07 (960911) Copyright 1991-1996 Free Software Foundation, Inc. Compiling: test_factorial.adb (source file time stamp: 1996-09-22 15:15:47) 1. with Ada.Text_IO; 2. with Ada.Integer_Text_IO; 3. procedure Test_Factorial is 4. ------------------------------------------------------------------ 5. --| Demonstrates the factorial function 6. --| Author: Michael B. Feldman, The George Washington University 7. --| Copyright 1996, Michael B. Feldman. All Rights Reserved. 8. --| Last Modified: August 1996 9. ------------------------------------------------------------------ 10. 11. Answer: Positive; 12. 13. function Factorial (N : IN Positive) return Positive is 14. 15. -- Computes the factorial of N (N!) recursively 16. -- Pre : N is defined 17. -- Post: returns N! 18. 19. Result : Positive; 20. 21. begin -- Factorial 22. 23. if N = 1 then 24. Result := 1; -- stopping case 25. else 26. Result := N * Factorial(N-1); -- recursion 27. end if; 28. 29. return Result; 30. end Factorial; 31. 32. begin -- Test_Factorial 33. 34. Answer := Factorial(4); 35. Ada.Text_IO.Put(Item => "The value of 4! is "); 36. Ada.Integer_Text_IO.Put(Item => Answer, Width => 11); 37. Ada.Text_IO.New_Line; 38. 39. end Test_Factorial; 39 lines: No errors
Successful compilation; gnatmake invokes the binder and linker.
gnatbind -x test_factorial.ali gnatlink -g test_factorial.ali
Having built the executable, we now run it from the command line:
test_factorial
The value of 4! is 24
If you want to save the listing in a file, say, in test_factorial.lst, just redirect the output:
gnatmake -v -g -gnatl test_factorial >test_factorial.lst
If your source file is in the Macintosh file system (as opposed to the MachTen Fast File System), and using Alpha or BBEdit to edit your file, when you save a modified file the modification is NOT noticed by gnatmake, so invoking gnatmake on such a file will produce an "up to date" message instead of a compilation. This is a minor inconsistency in the various tools' treatment of Mac file timestamps; it may get fixed in later releases. The workaround is to "touch" the modified file from the MachTen command line before invoking gnatmake, for example:
touch test_factorial.adb
GNAT requires that each source file contain only one compilation unit (see gnatchop in the GNAT Users Guide for details on how to split multi-unit files). GNAT prefers that each file name agree with the name of the unit in that file, e.g., Test_Factorial is in the file test_factorial.adb. Note that the file name is always in lower-case, and that the file extension should be .ads for a package spec and .adb otherwise.
These conventions are sometimes inconvenient, for example, when porting in Ada source code from another compiler with different conventions. It is possible to override these preferences, using a configuration file called gnat.adc. If this file is present in the current directory, gnatmake will use it to map the file names to the unit names. Let's look at a set of files making up a program to do rational-number arithmetic. Here is the contents of gnat.adc.
pragma Source_File_Name (Unit_Name => Rationals, Spec_File_Name => "prog21.ads"); pragma Source_File_Name (Unit_Name => Rationals, Body_File_Name => "prog22.adb"); pragma Source_File_Name (Unit_Name => Rationals.IO, Spec_File_Name => "prog23.ads"); pragma Source_File_Name (Unit_Name => Rationals.IO, Body_File_Name => "prog24.adb"); pragma Source_File_Name (Unit_Name => Test_Rationals_1, Body_File_Name => "prog25.adb");
Rationals provide a simple rational number package; Rationals.IO provides Get and Put operations for rationals, and Test_Rationals_1 is a simple demonstration of the package. To get a listing of the rationals spec, we type
gnatmake -gnats -gnatl prog21.ads
(the -gnats option does syntax checking only)
gcc -c -gnats -gnatl prog21.ads GNAT 3.07 (960911) Copyright 1991-1996 Free Software Foundation, Inc. Checking: prog21.ads (source file time stamp: 1996-09-22 14:14:00) 1. package Rationals is 2. ------------------------------------------------------------------ 3. --| 4. --| Specification of the abstract data type for representing 5. --| and manipulating rational numbers. 6. --| All rational quantities in this package are initialized 7. --| to 0/1. 8. --| 9. --| Author: Michael B. Feldman, The George Washington University 10. --| Copyright 1996, Michael B. Feldman. All Rights Reserved. 11. --| Last Modified: August 1996. 12. --| 13. ------------------------------------------------------------------ 14. 15. type Rational is private; 16. 17. ZeroDenominator: exception; 18. 19. function "/" (X : Integer; Y : Integer) return Rational; 20. -- constructor: 21. -- Pre : X and Y are defined 22. -- Post: returns a rational number 23. -- If Y > 0, returns Reduce(X,Y) 24. -- If Y < 0, returns Reduce(-X,-Y) 25. -- Raises: ZeroDenominator if Y = 0 26. 27. function "+"(R1 : Rational; R2 : Rational) return Rational; 28. -- dyadic arithmetic constructor: 29. -- Pre : R1 and R2 are defined 30. -- Post: returns the rational sum of R1 and R2 31. 32. private 33. -- A record of type Rational consists of a pair of Integer values 34. -- such that the first number represents the numerator of a rational 35. -- number and the second number represents the denominator. 36. 37. type Rational is record 38. Numerator : Integer := 0; 39. Denominator: Positive := 1; 40. end record; 41. end Rationals; 41 lines: No errors
and we do the same for the spec of the rational input/output package:
gnatmake -gnats -gnatl prog23.ads
gcc -c -gnats -gnatl prog23.ads GNAT 3.07 (960911) Copyright 1991-1996 Free Software Foundation, Inc. Checking: prog23.ads (source file time stamp: 1996-09-22 14:14:00) 1. with Ada.Text_IO; 2. package Rationals.IO is 3. ------------------------------------------------------------------ 4. --| Specification of the input/output child package for Rationals 5. --| 6. --| Author: Michael B. Feldman, The George Washington University 7. --| Copyright 1996, Michael B. Feldman. All Rights Reserved. 8. ------------------------------------------------------------------ 9. 10. procedure Get (Item : out Rational); 11. -- Pre : None 12. -- Post: The first integer number read is the numerator of Item; 13. -- the second integer number is the denominator of Item. 14. -- A "/" between the two numbers is optional. 15. -- The Rational constructor "/" is called 16. -- to produce a rational in reduced form. 17. 18. procedure Put (Item : in Rational); 19. -- Pre : Item is defined 20. -- Post: displays the numerator and denominator of Item. 21. 22. end Rationals.IO; 22 lines: No errors
Now we are ready to build Test_Rationals_1:
gnatmake -g -v -gnatl -f prog25.adb
GNATMAKE 3.05 (960607) Copyright 1995 Free Software Foundation, Inc. gcc -c -g -gnatl prog25.adb GNAT 3.07 (960911) Copyright 1991-1996 Free Software Foundation, Inc. Compiling: prog25.adb (source file time stamp: 1996-09-22 14:14:01) 1. with Ada.Text_IO; 2. with Rationals; use type Rationals.Rational; 3. with Rationals.IO; 4. procedure Test_Rationals_1 is 5. ------------------------------------------------------------------ 6. --| Very rudimentary test of package Rationals and Rationals.IO 7. --| 8. --| Author: Michael B. Feldman, The George Washington University 9. --| Copyright 1996, Michael B. Feldman. All Rights Reserved. 10. --| Last Modified: July 1995 11. ------------------------------------------------------------------ 12. 13. A: Rationals.Rational; 14. B: Rationals.Rational; 15. C: Rationals.Rational; 16. D: Rationals.Rational; 17. E: Rationals.Rational; 18. F: Rationals.Rational; 19. 20. begin -- Test_Rationals_1 21. 22. A := 1/3; 23. B := 2/(-4); 24. Ada.Text_IO.Put(Item => "A = "); 25. Rationals.IO.Put(Item => A); 26. Ada.Text_IO.New_Line; 27. Ada.Text_IO.Put(Item => "B = "); 28. Rationals.IO.Put(Item => B); 29. Ada.Text_IO.New_Line; 30. 31. -- Read in rational numbers C and D. 32. Ada.Text_IO.Put(Item => "Enter rational number C > "); 33. Rationals.IO.Get(Item => C); 34. Ada.Text_IO.Put(Item => "Enter rational number D > "); 35. Rationals.IO.Get(Item => D); 36. Ada.Text_IO.New_Line; 37. 38. E := A + B; 39. Ada.Text_IO.Put(Item => "E = A + B is "); 40. Rationals.IO.Put(Item => E); 41. Ada.Text_IO.New_Line; 42. 43. F := C + D; 44. Ada.Text_IO.Put(Item => "F = C + D is "); 45. Rationals.IO.Put(Item => F); 46. Ada.Text_IO.New_Line; 47. 48. Ada.Text_IO.Put(Item => "A + E + F is "); 49. Rationals.IO.Put(Item => A + E + F); 50. Ada.Text_IO.New_Line; 51. 52. end Test_Rationals_1; 52 lines: No errors gcc -c -g -gnatl prog22.adb
gnatmake has discovered that Rationals must be compiled (no .ali or .o file was present). Note that gnatmake goes directly to the rationals body; GNAT compiles its spec "on the fly" and produces no listing of the spec. That is why we did the earlier syntax-check steps, just to get the listings.
GNAT 3.07 (960911) Copyright 1991-1996 Free Software Foundation, Inc. Compiling: prog22.adb (source file time stamp: 1996-09-22 14:14:00) 1. package body Rationals is 2. 3. ------------------------------------------------------------------ 4. --| Body of the abstract data type for representing 5. --| and manipulating rational numbers. 6. --| 7. --| Author: Michael B. Feldman, The George Washington University 8. --| Copyright 1996, Michael B. Feldman 9. --| Last Modified: August 1996 10. ------------------------------------------------------------------ 11. 12. -- local function GCD, not provided to clients 13. 14. function GCD(M: Positive; N: Positive) return Positive is 15. -- finds the greatest common divisor of M and N 16. -- Pre: M and N are defined 17. -- Post: returns the GCD of M and N, by Euclid's Algorithm 18. 19. R : Natural; 20. TempM: Positive; 21. TempN: Positive; 22. 23. begin -- GCD 24. 25. TempM := M; 26. TempN := N; 27. 28. R := TempM rem TempN; 29. 30. while R /= 0 loop 31. TempM := TempN; 32. TempN := R; 33. R := TempM rem TempN; 34. end loop; 35. 36. return TempN; 37. 38. end GCD; 39. 40. -- exported operations 41. 42. function "/" (X : Integer; Y : Integer) return Rational is 43. G: Positive; 44. begin -- "/" 45. 46. if Y = 0 then 47. raise ZeroDenominator; 48. end if; 49. 50. if X = 0 then 51. return (Numerator => 0, Denominator => 1); 52. end if; 53. 54. G := GCD(abs X, abs Y); 55. if Y > 0 then 56. return (Numerator => X/G, Denominator => Y/G); 57. else 58. return (Numerator => (-X)/G, Denominator => (-Y)/G); 59. end if; 60. 61. end "/"; 62. 63. -- dyadic arithmetic operator 64. 65. function "+"(R1 : Rational; R2 : Rational) return Rational is 66. N: Integer; 67. D: Positive; 68. begin -- "+" 69. N := R1.Numerator * R2.Denominator + R2.Numerator * R1.Denominator; 70. D := R1.Denominator * R2.Denominator; 71. return N/D; -- compiler will use Rational constructor here! 72. end "+"; 73. 74. end Rationals; 74 lines: No errors
Similarly, gnatmake invokes a compilation for Rationals.IO.
gcc -c -g -gnatl prog24.adb GNAT 3.07 (960911) Copyright 1991-1996 Free Software Foundation, Inc. Compiling: prog24.adb (source file time stamp: 1996-09-22 14:14:00) 1. with Ada.Text_IO; 2. with Ada.Integer_Text_IO; 3. package body Rationals.IO is 4. ------------------------------------------------------------------ 5. --| Body of the input/output child package for Rationals 6. --| 7. --| Author: Michael B. Feldman, The George Washington University 8. --| Copyright 1996, Michael B. Feldman. All Rights Reserved 9. --| Last Modified: August 1996 10. ------------------------------------------------------------------ 11. 12. -- input procedure 13. 14. procedure Get (Item : out Rational) is 15. 16. N: Integer; 17. D: Integer; 18. Dummy: Character; -- dummy character to hold the "/" 19. 20. begin -- Get 21. 22. Ada.Integer_Text_IO.Get(Item => N); 23. Ada.Text_IO.Get (Item => Dummy); 24. Ada.Integer_Text_IO.Get(Item => D); 25. Item := N/D; 26. 27. end Get; 28. 29. -- output procedure 30. 31. procedure Put (Item : in Rational) is 32. 33. begin -- Put 34. 35. Ada.Integer_Text_IO.Put(Item => Item.Numerator, Width => 1); 36. Ada.Text_IO.Put(Item => '/'); 37. Ada.Integer_Text_IO.Put(Item => Item.Denominator, Width => 1); 38. 39. end Put; 40. 41. end Rationals.IO; 41 lines: No errors
Finally, gnatmake invokes the binder and linker.
gnatbind -x prog25.ali gnatlink -g prog25.ali
Now we execute the demonstration program several times:
prog25 A = 1/3 B = -1/2 Enter rational number C > 2/4 Enter rational number D > 9/6 E = A + B is -1/6 F = C + D is 2/1 A + E + F is 13/6 prog25 A = 1/3 B = -1/2 Enter rational number C > 0/1 Enter rational number D > 9/6 E = A + B is -1/6 F = C + D is 3/2 A + E + F is 5/3 prog25 A = 1/3 B = -1/2 Enter rational number C > 1/0 raised RATIONALS.ZERODENOMINATOR
Here we entered a zero for the denominator of a rational. This is not allowed mathematically, so the exception is raised (somewhere in the rationals package) and propagated out of the main program.
We can get a full traceback showing where the exception was raised and how it propagated, but we need gdb for that.
GNAT does not come with its own debugger, or even a built-in traceback facility. Instead, it depends upon the GNU debugger, gdb. Let's use gdb to get a traceback from our rationals demonstration. We type
gdb prog25
and we are placed in gdb's command processor. gdb's prompts are indicated by (gdb).
GDB is free software and you are welcome to distribute copies of it under certain conditions; type "show copying" to see the conditions. There is absolutely no warranty for GDB; type "show warranty" for details.
GDB 4.15.1.gnat.1.10
Copyright 1995 Free Software Foundation, Inc.
(gdb) break __gnat_unhandled_exception
We have indicated that we wish gdb to stop the program and accept more commands, if an unhandled exception is raised. The address of the breakpoint is given; this will, in general, vary from machine to machine and even execution to excution. The file a-raise.c is part of the GNAT runtime and not of concern to us here.
Breakpoint 1 at 0x17dec: file a-raise.c, line 65
Now we tell gdb to run the program. It will run normally, unless that breakpoint is reached.
(gdb) run
Starting program: prog25 Breakpoint 1 at 0x1fa328c: file a-raise.c, line 65. A = 1/3 B = -1/2 Enter rational number C > 1 0 Breakpoint 1, __gnat_unhandled_exception (except=0x36abb58) at a-raise.c:65 a-raise.c:65: No such file or directory.
Here we stop at the breakpoint, because we entered that zero denominator. Ignore the last line about a-raise.c. We request a traceback (which gdb calls a backtrace):
(gdb) backtrace #0 __gnat_unhandled_exception (except=0x36abb58) at a-raise.c:65 #1 0x1fa33c4 in __gnat_raise_nodefer_with_msg (except=0x36abb58) #2 0x1fa3438 in __gnat_raise_nodefer (except=0x36abb58) #3 0x1fa34cc in __gnat_raise (except=0x36abb58) #4 0x1fa2510 in rationals."/" (x=1, y=0) at prog22.adb:47 #5 0x1fa288c in rationals.io.get (item={numerator = 0, denominator = 1}) at prog24.adb:25 #6 0x1fa2b08 in test_rationals_1 () at prog25.adb:33 #7 0x1f8b64c in main (argc=1, argv=0x1f8a3ec, envp=0x1f8a3f4) at b_prog25.c:40 #8 0x1f8b4e8 in __start (=0x4186001c, =0x81620008, =0x1) #9 0x1f8b4a0 in __start (=0x1f8a59f, =0x1f8a5c6, =0x1f8a5d1)
Refer back to the listings above. The interesting part of the traceback, lines 4-6, shows that the exception was raised in the function "/" at line 22 of Rationals, which was called from the procedure Get at line 25 of Rationals.IO, which in turn was called from line 33 of Test_Rationals_1. The first four traceback lines, and the last 3 lines, give trace information from the GNAT runtime system. Normally you can ignore these lines.
(gdb) quit
The program is running. Quit anyway (and kill it)? (y or n) y
We can show some more gdb commands by returning to the program test_factorial. Here we will break not on an exception, but every time the Factorial function is called. Since Factorial is recursive, we will stop at every new level of recursion.
gdb test_factorial GDB is free software and you are welcome to distribute copies of it under certain conditions; type "show copying" to see the conditions. There is absolutely no warranty for GDB; type "show warranty" for details. GDB 4.15.1.gnat.1.10, Copyright 1995 Free Software Foundation, Inc.
First we stop at the first executable statement of the main program:
(gdb) break test_factorial Breakpoint 1 at 0x16ee4: file test_factorial.adb, line 34.
now we set a break for each time we call Factorial
(gdb) break factorial Breakpoint 2 at 0x16dd0: file test_factorial.adb, line 23. (gdb) run Starting program: test_factorial Breakpoint 1 at 0x2f6ef24: file test_factorial.adb, line 34. Breakpoint 2 at 0x2f6ee10: file test_factorial.adb, line 23. Breakpoint 1, test_factorial () at test_factorial.adb:34 34 Answer := Factorial(4);
and we continue the run
(gdb) continue Continuing. Breakpoint 2, test_factorial.factorial (n=4) at test_factorial.adb:23 23 if N = 1 then
Now we will set a watchpoint on the variable Result, so that the program will stop every time Result acuires a new value.
(gdb) watch result Watchpoint 3: test_factorial.factorial::result (gdb) continue Continuing. Watchpoint 3: test_factorial.factorial::result Old value = 57185676 New value = 57179476 0x1efec48 in test_factorial.factorial (n=32402616) at test_factorial.adb:13 13 function Factorial (N : IN Positive) return Positive is
The huge values (which vary from execution to execution) suggest that Result is uninitialized at this point. This is true.
(gdb) continue Continuing. Breakpoint 2, test_factorial.factorial (n=3) at test_factorial.adb:23 23 if N = 1 then (gdb) continue Continuing. Breakpoint 2, test_factorial.factorial (n=2) at test_factorial.adb:23 23 if N = 1 then (gdb) continue Continuing. Watchpoint 3: test_factorial.factorial::result Old value = 57179476 New value = 0 0x1efec48 in test_factorial.factorial (n=32402440) at test_factorial.adb:13 13 function Factorial (N : IN Positive) return Positive is (gdb) continue Continuing. Breakpoint 2, test_factorial.factorial (n=1) at test_factorial.adb:23 23 if N = 1 then (gdb) continue Continuing. Watchpoint 3: test_factorial.factorial::result Old value = 0 New value = 1 0x1efec64 in test_factorial.factorial (n=1) at test_factorial.adb:24 24 Result := 1; -- stopping case
Now we've recursed all the way down, and start back up
(gdb) continue Continuing. Watchpoint 3: test_factorial.factorial::result Old value = 1 New value = 57179476 0x1efed18 in test_factorial.factorial (n=2) at test_factorial.adb:29 29 return Result; (gdb) continue Continuing. Watchpoint 3: test_factorial.factorial::result Old value = 57179476 New value = 2 test_factorial.factorial (n=2) at test_factorial.adb:29 29 return Result; (gdb) continue Continuing. Watchpoint 3: test_factorial.factorial::result Old value = 2 New value = 57179476 0x1efed18 in test_factorial.factorial (n=3) at test_factorial.adb:29 29 return Result; (gdb) continue Continuing. Watchpoint 3: test_factorial.factorial::result Old value = 57179476 New value = 6 test_factorial.factorial (n=3) at test_factorial.adb:29 29 return Result; (gdb) continue Continuing. Watchpoint 3: test_factorial.factorial::result Old value = 6 New value = 57185676 0x1efed18 in test_factorial.factorial (n=4) at test_factorial.adb:29 29 return Result; (gdb) continue Continuing. Watchpoint 3: test_factorial.factorial::result Old value = 57185676 New value = 24 test_factorial.factorial (n=4) at test_factorial.adb:29 29 return Result; (gdb) continue Continuing. Watchpoint 3 deleted because the program has left the block in which its expression is valid. 0x1efecf8 in test_factorial.factorial (n=4) at test_factorial.adb:29 29 return Result; (gdb) continue Continuing. The value of 4! is 24 Program exited normally
Refer to the GNAT documents for a full set of documentation on gdb. gdb also provides fairly useful on-line help:
(gdb) help
List of classes of commands: running -- Running the program stack -- Examining the stack data -- Examining data breakpoints -- Making program stop at certain points files -- Specifying and examining files status -- Status inquiries support -- Support facilities user-defined -- User-defined commands aliases -- Aliases of other commands obscure -- Obscure features internals -- Maintenance commands Type "help" followed by a class name for a list of commands in that class. Type "help" followed by command name for full documentation. Command name abbreviations are allowed if unambiguous.
Suppose we wish to know, for a given program, all its declarations and all the declarations it uses from the packages it WITHs, and where (which lines) these are referenced. Looking again at our rationals demonstration, we type
gnatf -x6 prog25.adb
gnatf stores the cross reference information in the file X.ref, so let's look at its contents:
Here we see the variables declared in Test_Rationals_1, and where in that program each is used (line and character position within line).
cat X.ref %% prog25.adb 960922141401 %% test_rationals_1 procedure 4:11 a variable 13:3 prog25.adb {22:3 25:28 38:8 49:28} b variable 14:3 prog25.adb {23:3 28:28 38:12} c variable 15:3 prog25.adb {33:28 43:8} d variable 16:3 prog25.adb {35:28 43:12} e variable 17:3 prog25.adb {38:3 40:28 49:32} f variable 18:3 prog25.adb {43:3 45:28 49:36}
The main program calls some procedures from Ada.Text_IO
-- /usr/local/adainclude/a-textio.ads 960625050333 -- text_io package 30:13 prog25.adb {1:10 24:7 26:7 27:7 29:7 32:7 34:7 36:7 39:7 41:7 44:7 46:7 48:7 50:7} text_io.new_line procedure 141:14 prog25.adb {26:15 29:15 36:15 41:15 46:15 50:15} text_io.put procedure 217:14 prog25.adb {24:15 27:15 32:15 34:15 39:15 44:15 48:15} -- /usr/local/adainclude/ada.ads 960625050300 -- ada package 18:9 prog25.adb {24:3 26:3 27:3 29:3 32:3 34:3 36:3 39:3 41:3 44:3 46:3 48:3 50:3} 3}
and from Rationals
-- prog21.ads 960922141400 -- rationals package 1:9 prog25.adb {2:6 2:26 13:6 14:6 15:6 16:6 17:6 18:6 25:3 28:3 33:3 35:3 40:3 45 :3 49:3} rational private_type 15:8 37:8 prog25.adb {2:36 13:16 14:16 15:16 16:16 17:16 18:16} "/" function 19:12 prog25.adb {22:9 23:9} "+" function 27:12 prog25.adb {38:10 43:10 49:34 49:30}
and from Rationals.IO
-- prog23.ads 960922141400 -- io package 2:19 prog25.adb {3:16 25:13 28:13 33:13 35:13 40:13 45:13 49:13} io.get procedure 10:13 prog25.adb {33:16 35:16} io.put procedure 18:13 prog25.adb {25:16 28:16 40:16 45:16 49:16}
We saw above how to override the GNAT file-naming conventions using a configuration file. But suppose we prefer to follow GNAT's preferences. We must name our files according to the units they contain. This can cause a problem if a unit's name is longer than our computer's maximum name length. For example, the Apple Macintosh has a file-name limit of 31 characters. Because our GNAT file names all end with a dot and a 3-letter extension, effectively we have a 27-character limit on the file name.
For systems with limits on file names, GNAT has an algorithm (krunch) for "crunching" its preferred file names down to the limit. On the Mac, if we add the flag -gnatk27 to a gnatmake invocation, GNAT will assume that all source file names follow the krunch algorithm for 27 characters. The algorithm is a bit involved; it is documented a bit in the GNAT Users Guide. Suffice it to say that if the file name has 27 characters or less, it is used without change.
Suppose the file name is long. How do we determine its krunched name? The tool gnatk8 gives us this capability. (This is an odd name; it comes from the fact that file names in DOS or OS/2 FAT file systems are 8 characters or less; the tool was developed originally for those systems.)
Given a unit
Very_Long_Unit_Name.Long_Child_Package_Name
stored in a file some_file.adb. We can rename this file correctly on the Mac in two steps. First, ask gnatk8 what the name should be:
gnatk8 Very_Long_Unit_Name.Long_Child_Package_Name 27
verlonuninamlonchilpackname
then rename the file accordingly
mv some_file.adb verlonuninamlonchilpackname.adb