home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / gnat-2.06-src.tgz / tar.out / fsf / gnat / ada / gnatmake.adb < prev    next >
Text File  |  1996-09-28  |  31KB  |  1,016 lines

  1. ------------------------------------------------------------------------------
  2. --                                                                          --
  3. --                         GNAT COMPILER COMPONENTS                         --
  4. --                                                                          --
  5. --                             G N A T M A K E                              --
  6. --                                                                          --
  7. --                                 B o d y                                  --
  8. --                                                                          --
  9. --                            $Revision: 1.14 $                             --
  10. --                                                                          --
  11. --        Copyright (c) 1992,1993,1994,1995 NYU, All Rights Reserved        --
  12. --                                                                          --
  13. -- GNAT is free software;  you can  redistribute it  and/or modify it under --
  14. -- terms of the  GNU General Public License as published  by the Free Soft- --
  15. -- ware  Foundation;  either version 2,  or (at your option) any later ver- --
  16. -- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
  17. -- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
  18. -- or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License --
  19. -- for  more details.  You should have  received  a copy of the GNU General --
  20. -- Public License  distributed with GNAT;  see file COPYING.  If not, write --
  21. -- to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. --
  22. --                                                                          --
  23. ------------------------------------------------------------------------------
  24.  
  25. --  Contents
  26. --  --------
  27. --     Gnatmake usage: summary
  28. --     Smart gnatmake
  29. --     Gnatmake algorithm
  30. --     Gnat flags used in gnatmake
  31. --
  32. --
  33. --  Gnatmake usage: summary (consult gnat documentation for more info)
  34. --  ------------------------------------------------------------------
  35. --
  36. --    gnatmake [-c] [-f] [-g] [-n] [-q] [-s] [-v] [-search dir]
  37. --             unit_or_file_name
  38. --             {[-cargs options] [-bargs options] [-largs options]}
  39. --
  40. --  Automatically (re)compiles the ada sources needed by some ada compilation
  41. --  unit, Unit. Bind and link steps are performed by default.
  42. --  There are two ways to specify the actual compilation unit:
  43. --
  44. --    * By giving the name of the compilation unit ("gnatmake unit")
  45. --
  46. --    * By giving the name of the source containing it
  47. --      ("gnatmake file.adb" or "gnatmake file.ads")
  48. --
  49. --  All gnatmake output is to stderr.
  50. --
  51. --  [-a]
  52. --     Consider all files. Considers all files in the make process, even
  53. --     the GNAT internal system files.
  54. --
  55. --  [-c]
  56. --     Compile only. Do not perform the bind and link steps.
  57. --
  58. --  [-f]
  59. --     Force recompilations. Recompile sources even though some object
  60. --     files may be up to date but don't recompile predifined units if up
  61. --     to date.
  62. --
  63. --  [-g]
  64. --     Compile with debugging information. Same effect as -cargs -g -largs -g.
  65. --     See below for meaning of -cargs & -largs.
  66. --
  67. --  [-n]
  68. --     Don't compile, bind or link. Issue a (maybe innacurate) list of
  69. --     commands without actually executing them by guessing from the old
  70. --     ali (ada library information). If, during the process, any ali file
  71. --     is missing, gnatmake is halted and an error message is emitted.
  72. --
  73. --  [-q]
  74. --     Quiet. Without this flag set the commands carried out by gnatmake
  75. --     are displayed. If -q is set, they are not.
  76. --
  77. --  [-s]
  78. --     Smart. Performs smart recompilations.
  79. --     See section on smart gnatmake below.
  80. --
  81. --  [-v]
  82. --     Verbose. Motivates all (re)compilations (ie gives the reason why it
  83. --     is (re)compiling a source file).
  84. --
  85. --  [-cargs options]
  86. --     Compiler arguments. Without -cargs, gnatmake simply uses "gcc -c"
  87. --     to perform compilations. Otherwise gnatmake uses "gcc -c options".
  88. --     Note that by default "gnatmake -a" (see flag -a above) compiles all
  89. --     GNAT internal files with "gcc -c -gnatg" rather than just "gcc -c".
  90. --
  91. --  [-bargs options]
  92. --     Binder arguments. Without -bargs, gnatmake simply uses
  93. --     "gnatbind unit.ali" to bind. Otherwise gnatmake uses
  94. --     "gnatbind options unit.ali".
  95. --
  96. --  [-largs options]
  97. --     Linker arguments. Without -largs, gnatmake simply uses
  98. --     "gnatbl -linkony unit.ali" to link. Otherwise gnatmake uses
  99. --     "gnatbl -linkonly options unit.ali".
  100. --
  101. --  Smart gnatmake
  102. --  --------------
  103. --
  104. --  Not implemented yet.
  105. --
  106. --
  107. --  gnatmake ALGORITHM
  108. --  ------------------
  109. --
  110. --  gnatmake file.adb
  111. --
  112. --  1. Insert file.adb in the Queue (Q) and mark it.
  113. --
  114. --  2. Let unit be the file at the head of the Q. Look at the files under the
  115. --     D (dependency) section of unit.ali. If unit.ali does not exist or some
  116. --     of the  time stamps do not match, (re)compile unit.
  117. --
  118. --  3. Look into the W section of unit.ali (the with section) and insert
  119. --     into the Q all mentioned source files that are not marked.
  120. --     Specifically, assuming that the W section looks like
  121. --
  122. --     W types%s               types.adb               types.ali
  123. --     W unchecked_deallocation%s
  124. --     W xref_tab%s            xref_tab.adb            xref_tab.ali
  125. --
  126. --     Then xref_tab.adb and types.adb are inserted in the Q if they are not
  127. --     already marked.
  128. --     Note that there is no file listed under W unchecked_deallocation%s
  129. --     so no generic body should ever be explicitely compiled (unless the
  130. --     file.adb at the start was a generic body).
  131. --
  132. --  4. Repeat steps 2 and 3 above until the Q is empty
  133. --
  134. --  Note that the above algorithm works because the units withed in subnits
  135. --  are transitively included in the W section (with section) of the main unit.
  136. --  Likewise the withed units in a generic body needed during a compilation
  137. --  are also transitively included in the W section of the originally compiled
  138. --  file.
  139. --
  140. --  Flag Usage in Gnatmake
  141. --  ----------------------
  142. --
  143. --  The flags defined in package Opt, set in package Switch or Initialize
  144. --  and used by Gnatmake are the following:
  145. --
  146. --  * Check_Internal_Files: True when -a present
  147. --  * Compile_Only:         True when -c present
  148. --  * Force_Compilations:   True when -f present
  149. --  * Dont_Execute:         True when -n present
  150. --  * Quiet_Output:         True when -q present
  151. --  * Smart_Compilations:   True when -s present
  152. --  * Generate_Debug:       True when -g present
  153. --  * Verbose_Mode:         True when -v present
  154. --
  155. --  The following flags defined in Opt are set explicitely in gnatmake to
  156. --  affect the behavior of routines in ALI, specifically Set_Source_Tables.
  157. --
  158. --  * All_Sources: set to True to require all source files to be present.
  159. --  * Check_Source_Files: set to True to get the actual time stamp of sources.
  160.  
  161. with ALI;           use ALI;
  162. with Binderr;       use Binderr;
  163. with Fname;         use Fname;
  164. with Gnatvsn;       use Gnatvsn;
  165. with Namet;         use Namet;
  166. with Opt;           use Opt;
  167. with Osint;         use Osint;
  168. with GNAT.OS_Lib;   use GNAT.OS_Lib;
  169. with Output;        use Output;
  170. with Table;
  171. with Types;         use Types;
  172.  
  173. procedure Gnatmake is
  174.  
  175.    -------------------------------------
  176.    -- Queue (Q) Manipulation Routines --
  177.    -------------------------------------
  178.  
  179.    procedure Init_Q;
  180.    --  Must be called to initialize the Q.
  181.  
  182.    procedure Insert_Q (Source_File : File_Name_Type);
  183.    --  Inserts Source_File at the end of Q.
  184.  
  185.    function Empty_Q return Boolean;
  186.    --  Returns True if Q is empty.
  187.  
  188.    function Extract_From_Q return File_Name_Type;
  189.    --  Extracts the first element from the Q.
  190.  
  191.    ----------------------
  192.    -- Marking Routines --
  193.    ----------------------
  194.  
  195.    procedure Mark (Ali_File : File_Name_Type);
  196.    --  Used to mark an Ali_File. Marking is used to signal that a given source
  197.    --  has already been inserted in the Q. Because of the way things are set
  198.    --  up in package ALI, we cannot directly mark source files, but have to
  199.    --  mark their corresponding Ali_File.
  200.  
  201.    function Is_Marked (Ali_File : File_Name_Type) return Boolean;
  202.    --  Returns True if Ali_File was previously marked.
  203.  
  204.    -----------------------------------------
  205.    -- Compiler, Binder & Linker Interface --
  206.    -----------------------------------------
  207.  
  208.    function Compile (Source_File : File_Name_Type) return Exit_Code_Type;
  209.    --  Compiles Source_File and returns the compilation exit code.
  210.  
  211.    function Bind (Ali_File : File_Name_Type) return Exit_Code_Type;
  212.    --  Invokes the binder on Ali_File and returns the binder exit code.
  213.  
  214.    function Link (Ali_File : File_Name_Type) return Exit_Code_Type;
  215.    --  Invokes the linker on Ali_File and returns the linker exit code.
  216.  
  217.    ----------------------------
  218.    -- Miscellaneous Routines --
  219.    ----------------------------
  220.  
  221.    function First_New_Spec (A : ALI_Id) return File_Name_Type;
  222.    --  Looks in the with table entries of A and returns the spec file name of
  223.    --  the first withed unit (subprogram) for which no spec existed when A was
  224.    --  generated but for which there exists one now, implying that A is now
  225.    --  obsolete. If no such unit is found No_File is returned. Otherwise the
  226.    --  spec file name of the unit is returned.
  227.    --
  228.    --  **WARNING** in the event of Uname format modifications, one *MUST* make
  229.    --  sure this function is also updated.
  230.    --
  231.    --  This function should really be in ali.adb and use Uname services, but
  232.    --  this causes the whole compiler to be dragged along from gnatbind and
  233.    --  gnatmake.
  234.  
  235.    function Full_Name (N : File_Name_Type) return Name_Id;
  236.    --  Returns the full name of the file whose simple name is N. If the file
  237.    --  cannot be located N is returned. The full name includes the appropriate
  238.    --  directory information.
  239.  
  240.    procedure Makeusg;
  241.    --  Outputs gnatmake usage information.
  242.  
  243.    --------------------------------------
  244.    -- Queue (Q) Variables and Routines --
  245.    --------------------------------------
  246.  
  247.    --  Our Q implementation uses the GNAT generic table package Table.
  248.    --  We basically implement the Q as an array and explicitely keep a
  249.    --  pointer (Q_Front below), to indicate the front of the Q. The rear of
  250.    --  the Q is implicitly ket by the Table package and accessible through
  251.    --  subprogram Last.
  252.    --
  253.    --  Note that this implementation of the Q can actually use as much as
  254.    --  twice the amount of space as the number of elements inserted in the Q.
  255.    --  Given the amounts involved it is not worth loosing too much sleep over
  256.    --  this.
  257.  
  258.    Q_First : Natural := 0;
  259.    --  Points to the first valid element of the Q.
  260.  
  261.    package Queue is new Table (
  262.      Table_Component_Type => File_Name_Type,
  263.      Table_Index_Type     => Natural,
  264.      Table_Low_Bound      => Q_First,
  265.      Table_Initial        => 100,
  266.      Table_Increment      => 100,
  267.      Table_Name           => "gnatmake.Queue");
  268.    --  This is the actual Q.
  269.  
  270.    ------------
  271.    -- Init_Q --
  272.    ------------
  273.  
  274.    procedure Init_Q is
  275.    begin
  276.       Queue.Init;
  277.       Queue.Set_Last (Q_First);
  278.    end Init_Q;
  279.  
  280.    --------------
  281.    -- Insert_Q --
  282.    --------------
  283.  
  284.    procedure Insert_Q (Source_File : File_Name_Type) is
  285.    begin
  286.       Queue.Increment_Last;
  287.       Queue.Table (Queue.Last) := Source_File;
  288.    end Insert_Q;
  289.  
  290.    -------------
  291.    -- Empty_Q --
  292.    -------------
  293.  
  294.    function Empty_Q return Boolean is
  295.    begin
  296.       return Q_First >= Queue.Last;
  297.    end Empty_Q;
  298.  
  299.    --------------------
  300.    -- Extract_From_Q --
  301.    --------------------
  302.  
  303.    function Extract_From_Q return File_Name_Type is
  304.    begin
  305.       pragma Assert (not Empty_Q);
  306.  
  307.       Q_First := Q_First + 1;
  308.       return Queue.Table (Q_First);
  309.    end Extract_From_Q;
  310.  
  311.    ---------------
  312.    -- Is_Marked --
  313.    ---------------
  314.  
  315.    function Is_Marked (Ali_File : File_Name_Type) return Boolean is
  316.    begin
  317.       return Get_Name_Table_Info (Ali_File) /= 0;
  318.    end Is_Marked;
  319.  
  320.    ----------
  321.    -- Mark --
  322.    ----------
  323.  
  324.    procedure Mark (Ali_File : File_Name_Type) is
  325.    begin
  326.       Set_Name_Table_Info (Ali_File, Int (No_Unit_Id));
  327.    end Mark;
  328.  
  329.    ----------------------------------------------------
  330.    -- Compiler, Binder & Linker Variables & Routines --
  331.    ----------------------------------------------------
  332.  
  333.    Path : constant String_Access := Getenv ("PATH");
  334.  
  335.    Gcc      : constant String_Access :=
  336.      GNAT.OS_Lib.Locate_Regular_File ("gcc", Path.all);
  337.  
  338.    Gnatbind : constant String_Access :=
  339.      GNAT.OS_Lib.Locate_Regular_File ("gnatbind", Path.all);
  340.  
  341.    Gnatbl   : constant String_Access :=
  342.      GNAT.OS_Lib.Locate_Regular_File ("gnatbl", Path.all);
  343.  
  344.    function Execute (P : String_Access; Args : Argument_List) return Boolean;
  345.    --  Executes a program. P is the full pathname of the executable.
  346.    --  Args contains the arguments to be passed to the program P.
  347.    --  If the program is executed successfully True is returned.
  348.  
  349.    -------------
  350.    -- Execute --
  351.    -------------
  352.  
  353.    function Execute (P : String_Access; Args : Argument_List) return Boolean is
  354.       Success : Boolean := True;
  355.  
  356.    begin
  357.       if not Quiet_Output then
  358.          Write_Str (P.all);
  359.  
  360.          for J in Args'Range loop
  361.             Write_Str (" ");
  362.             Write_Str (Args (J).all);
  363.          end loop;
  364.  
  365.          Write_Eol;
  366.       end if;
  367.  
  368.       if not Dont_Execute then
  369.          GNAT.OS_Lib.Spawn (P.all, Args, Success);
  370.       end if;
  371.  
  372.       return Success;
  373.    end Execute;
  374.  
  375.    ----------
  376.    -- Bind --
  377.    ----------
  378.  
  379.    function Bind (Ali_File : File_Name_Type) return Exit_Code_Type is
  380.       Success_Of_Bind : Boolean := False;
  381.       Simple_Args     : Argument_List (1 .. 1);
  382.       Afile           : String_Access;
  383.  
  384.    begin
  385.       Get_Name_String (Ali_File);
  386.       Afile := new String'(Name_Buffer (1 .. Name_Len));
  387.  
  388.       if Binder_Switches.Last < Binder_Switches.First then
  389.          Simple_Args (1) := Afile;
  390.          Success_Of_Bind := Execute (Gnatbind, Simple_Args);
  391.  
  392.       else
  393.          declare
  394.             Complex_Args : Argument_List
  395.               (Binder_Switches.First .. Binder_Switches.Last + 1);
  396.          begin
  397.             for I in Binder_Switches.First .. Binder_Switches.Last loop
  398.                Complex_Args (I) := Binder_Switches.Table (I);
  399.             end loop;
  400.             Complex_Args (Binder_Switches.Last + 1) := Afile;
  401.             Success_Of_Bind := Execute (Gnatbind, Complex_Args);
  402.          end;
  403.       end if;
  404.  
  405.       if not Success_Of_Bind then
  406.          Osint.Write_Program_Name;
  407.          Write_Str (": *** bind failed.");
  408.          Write_Eol;
  409.          return E_Errors;
  410.       else
  411.          return E_Success;
  412.       end if;
  413.    end Bind;
  414.  
  415.    -------------
  416.    -- Compile --
  417.    -------------
  418.  
  419.    function Compile (Source_File : File_Name_Type) return Exit_Code_Type is
  420.       Success_Of_Compilation : Boolean := False;
  421.       Sfile                  : String_Access;
  422.       Arg_Count              : Positive := 2;
  423.  
  424.    begin
  425.       Get_Name_String (Full_Name (Source_File));
  426.       Sfile := new String'(Name_Buffer (1 .. Name_Len));
  427.  
  428.       if Gcc_Switches.Last < Gcc_Switches.First then
  429.          Arg_Count := 2;
  430.       else
  431.          Arg_Count :=
  432.            2 + Positive (1 + Gcc_Switches.Last - Gcc_Switches.First);
  433.       end if;
  434.  
  435.       if Generate_Debug then
  436.          Arg_Count := Arg_Count + 1;
  437.       end if;
  438.  
  439.       if Is_Language_Defined_Unit (Source_File) then
  440.          Arg_Count := Arg_Count + 1;
  441.       end if;
  442.  
  443.       declare
  444.          Args : Argument_List (1 .. Arg_Count);
  445.          Next_Arg : Positive := 2;
  446.  
  447.       begin
  448.          Args (1) := new String'("-c");
  449.  
  450.          if Generate_Debug then
  451.             Args (Next_Arg) := new String'("-g");
  452.             Next_Arg := Next_Arg + 1;
  453.          end if;
  454.  
  455.          if Is_Language_Defined_Unit (Source_File) then
  456.             Args (Next_Arg) := new String'("-gnatg");
  457.             Next_Arg := Next_Arg + 1;
  458.          end if;
  459.  
  460.          for J in Gcc_Switches.First .. Gcc_Switches.Last loop
  461.             Args (Next_Arg) := Gcc_Switches.Table (J);
  462.             Next_Arg := Next_Arg + 1;
  463.          end loop;
  464.  
  465.          Args (Next_Arg) := Sfile;
  466.          Success_Of_Compilation := Execute (Gcc, Args);
  467.       end;
  468.  
  469.       if not Success_Of_Compilation then
  470.          Osint.Write_Program_Name;
  471.          Write_Str (": *** compilation failed.");
  472.          Write_Eol;
  473.          return E_Errors;
  474.       else
  475.          return E_Success;
  476.       end if;
  477.    end Compile;
  478.  
  479.    ----------
  480.    -- Link --
  481.    ----------
  482.  
  483.    function Link (Ali_File : File_Name_Type) return Exit_Code_Type is
  484.       Success_Of_Link : Boolean := False;
  485.       Afile           : String_Access;
  486.       Arg_Count       : Positive := 2;
  487.  
  488.    begin
  489.       Get_Name_String (Ali_File);
  490.       Afile := new String'(Name_Buffer (1 .. Name_Len));
  491.  
  492.       if Linker_Switches.Last < Linker_Switches.First then
  493.          Arg_Count := 2;
  494.       else
  495.          Arg_Count :=
  496.            2 + Natural (1 + Linker_Switches.Last - Linker_Switches.First);
  497.       end if;
  498.  
  499.       if Generate_Debug then
  500.          Arg_Count := Arg_Count + 1;
  501.       end if;
  502.  
  503.       declare
  504.          Args : Argument_List (1 .. Arg_Count);
  505.          Next_Arg : Positive := 2;
  506.  
  507.       begin
  508.          Args (1) := new String'("-linkonly");
  509.  
  510.          if Generate_Debug then
  511.             Args (Next_Arg) := new String'("-g");
  512.             Next_Arg := Next_Arg + 1;
  513.          end if;
  514.  
  515.          for J in Linker_Switches.First .. Linker_Switches.Last loop
  516.             Args (Next_Arg) := Linker_Switches.Table (J);
  517.             Next_Arg := Next_Arg + 1;
  518.          end loop;
  519.  
  520.          Args (Next_Arg) := Afile;
  521.          Success_Of_Link := Execute (Gnatbl, Args);
  522.       end;
  523.  
  524.       if not Success_Of_Link then
  525.          Osint.Write_Program_Name;
  526.          Write_Str (": *** link failed.");
  527.          Write_Eol;
  528.          return E_Errors;
  529.       else
  530.          return E_Success;
  531.       end if;
  532.    end Link;
  533.  
  534.    --------------------
  535.    -- First_New_Spec --
  536.    --------------------
  537.  
  538.    function First_New_Spec (A : ALI_Id) return File_Name_Type is
  539.  
  540.       Spec_File_Name : File_Name_Type := No_File;
  541.  
  542.       function New_Spec (Uname : Unit_Name_Type) return Boolean;
  543.       --  Uname is the name of the spec or body of some ada unit.
  544.       --  This function returns True if the Uname is the name of a body
  545.       --  which has a spec not mentioned in ali file A. If True is returned
  546.       --  Spec_File_Name above is set to the name of this spec file.
  547.  
  548.       function New_Spec (Uname : Unit_Name_Type) return Boolean is
  549.          Spec_Name : Unit_Name_Type;
  550.          File_Name : File_Name_Type;
  551.  
  552.       begin
  553.          --  Test whether Uname is the name of a body unit (ie ends with %b)
  554.  
  555.          Get_Name_String (Uname);
  556.          pragma
  557.            Assert (Name_Len > 2 and then Name_Buffer (Name_Len - 1) = '%');
  558.  
  559.          if Name_Buffer (Name_Len) /= 'b' then
  560.             return False;
  561.          end if;
  562.  
  563.          --  Convert unit name into spec name
  564.  
  565.          Name_Buffer (Name_Len) := 's';
  566.          Spec_Name := Name_Find;
  567.          File_Name := Get_File_Name (Spec_Name);
  568.  
  569.          --  Look if File_Name is mentioned in A's sdep list.
  570.          --  If not look if the file exists. If it does return True.
  571.  
  572.          for D in
  573.            ALIs.Table (A).First_Sdep .. ALIs.Table (A).Last_Sdep
  574.          loop
  575.             if Sdep.Table (D).Sfile = File_Name then
  576.                return False;
  577.             end if;
  578.          end loop;
  579.  
  580.          if Full_Source_Name (File_Name) /= No_File then
  581.             Spec_File_Name := File_Name;
  582.             return True;
  583.          end if;
  584.  
  585.          return False;
  586.       end New_Spec;
  587.  
  588.    --  Start of processing for First_New_Spec
  589.  
  590.    begin
  591.       U_Chk : for U in
  592.         ALIs.Table (A).First_Unit .. ALIs.Table (A).Last_Unit
  593.       loop
  594.          exit U_Chk when New_Spec (Unit.Table (U).Uname);
  595.  
  596.          for W in Unit.Table (U).First_With .. Unit.Table (U).Last_With loop
  597.             exit U_Chk when
  598.               Withs.Table (W).Afile /= No_File
  599.                 and then New_Spec (Withs.Table (W).Uname);
  600.          end loop;
  601.       end loop U_Chk;
  602.  
  603.       return Spec_File_Name;
  604.    end First_New_Spec;
  605.  
  606.    ---------------
  607.    -- Full_Name --
  608.    ---------------
  609.  
  610.    function Full_Name (N : File_Name_Type) return Name_Id is
  611.       Name : constant Name_Id := Full_Source_Name (N);
  612.  
  613.    begin
  614.       if Name = No_Name then
  615.          return N;
  616.       else
  617.          return Name;
  618.       end if;
  619.    end Full_Name;
  620.  
  621.    -------------
  622.    -- Makeusg --
  623.    -------------
  624.  
  625.    procedure Makeusg is
  626.       procedure Write_Switch_Char;
  627.       --  Write two spaces followed by appropriate switch character
  628.  
  629.       procedure Write_Switch_Char is
  630.       begin
  631.          Write_Str ("  ");
  632.          Write_Char (Switch_Character);
  633.       end Write_Switch_Char;
  634.  
  635.    begin
  636.       --  Usage line
  637.  
  638.       Write_Str ("Usage: ");
  639.       Osint.Write_Program_Name;
  640.       Write_Char (' ');
  641.       Write_Str ("switches unit[.adb] ");
  642.       Write_Str ("{[-cargs opts] [-bargs opts] [-largs opts]}");
  643.       Write_Eol;
  644.       Write_Eol;
  645.  
  646.       --  Line for -a
  647.  
  648.       Write_Switch_Char;
  649.       Write_Str ("a          Consider all files, even GNAT internal files");
  650.       Write_Eol;
  651.  
  652.       --  Line for -c
  653.  
  654.       Write_Switch_Char;
  655.       Write_Str ("c          Compile only, do not bind and link");
  656.       Write_Eol;
  657.  
  658.       --  Line for -f
  659.  
  660.       Write_Switch_Char;
  661.       Write_Str ("f          Force recompilations of non predefined units");
  662.       Write_Eol;
  663.  
  664.       --  Line for -g
  665.  
  666.       Write_Switch_Char;
  667.       Write_Str ("g          Compile with debugging information");
  668.       Write_Eol;
  669.  
  670.       --  Line for -n
  671.  
  672.       Write_Switch_Char;
  673.       Write_Str ("n          Just output the commands, don't execute them");
  674.       Write_Eol;
  675.  
  676.       --  Line for -q
  677.  
  678.       Write_Switch_Char;
  679.       Write_Str ("q          Be quiet, do not display the executed commands");
  680.       Write_Eol;
  681.  
  682.       --  Line for -s
  683.  
  684.       Write_Switch_Char;
  685.       Write_Str ("s          Perform smart recompilations");
  686.       Write_Eol;
  687.  
  688.       --  Line for -v
  689.  
  690.       Write_Switch_Char;
  691.       Write_Str ("v          Motivate all (re)compilations");
  692.       Write_Eol;
  693.       Write_Eol;
  694.  
  695.       --  Line for unit[.adb]
  696.  
  697.       Write_Str ("  unit[.adb]  Compilation unit name or source file");
  698.       Write_Eol;
  699.       Write_Eol;
  700.  
  701.       --  Line for -cargs
  702.  
  703.       Write_Switch_Char;
  704.       Write_Str ("cargs opts Arguments to be passed to the compiler");
  705.       Write_Eol;
  706.  
  707.       --  Line for -bargs
  708.  
  709.       Write_Switch_Char;
  710.       Write_Str ("bargs opts Arguments to be passed to the binder");
  711.       Write_Eol;
  712.  
  713.       --  Line for -largs
  714.  
  715.       Write_Switch_Char;
  716.       Write_Str ("largs opts Arguments to be passed to the linker");
  717.       Write_Eol;
  718.  
  719.       Write_Eol;
  720.    end Makeusg;
  721.  
  722.    ------------------------
  723.    -- Gnatmake Variables --
  724.    ------------------------
  725.  
  726.    Main_Unit_Or_File_Name : Name_Id;
  727.    --  The name of the main compilation unit or of the source containing it
  728.  
  729.    Main_Ali_File : File_Name_Type;
  730.    --  The ali file corresponding to the unit input to gnatmake
  731.  
  732.    Source_File : File_Name_Type;
  733.    --  Current source file
  734.  
  735.    Lib_File : File_Name_Type;
  736.    --  Current library file
  737.  
  738.    Afile : File_Name_Type;
  739.    --  Contains, in turn, the ali file of the units withed by Source_File
  740.  
  741.    Sfile : File_Name_Type;
  742.    --  Contains, in turn, the source file of the units withed by Source_File
  743.  
  744.    Modified_Source : File_Name_Type;
  745.    --  The first source in Lib_File whose current time stamp differs
  746.    --  from that stored in Lib_File.
  747.  
  748.    New_Spec : File_Name_Type;
  749.    --  If Lib_File contains in its W (with) section a body (for a subprogram)
  750.    --  for which there exists a spec and the spec did not appear in the Sdep
  751.    --  section of Lib_File, New_Spec contains the file name of this new spec.
  752.  
  753.    Objects_Up_To_Date : Boolean := True;
  754.    Need_To_Compile    : Boolean := False;
  755.  
  756.    Exit_Code : Exit_Code_Type := E_Success;
  757.  
  758.    Text : Text_Buffer_Ptr;
  759.    Ali  : ALI_Id;
  760.  
  761.    --------------------------------------
  762.    -- Start of Processing for Gnatmake --
  763.    --------------------------------------
  764.  
  765. begin
  766.    --  Package and Queue initializations. The order of calls is important here.
  767.  
  768.    Output.Set_Standard_Error;
  769.    Osint.Initialize (Make);
  770.    Namet.Initialize;
  771.    Binderr.Initialize_Binderr;
  772.    Initialize_ALI;
  773.    Init_Q;
  774.  
  775.    --  The following two flags affects the behavior of Set_Source_Table. We set
  776.    --  Check_Source_Files to True to ensure that source file time stamps are
  777.    --  checked, and we set All_Sources to False to avoid checking the presence
  778.    --  of the source files listed in the source dependency section of an ali
  779.    --  file (which would be a mistake since the ali file may be obsolete).
  780.  
  781.    Check_Source_Files := True;
  782.    All_Sources := False;
  783.  
  784.    if Verbose_Mode then
  785.       Write_Eol;
  786.       Write_Str ("NYU GNAT Make Version ");
  787.       Write_Str (Gnat_Version_String);
  788.       Write_Str (" (C) NYU, 1995 All Rights Reserved");
  789.       Write_Eol;
  790.    end if;
  791.  
  792.    --  Output usage information if more than one file or compile unit
  793.  
  794.    if Number_Of_Files = 0 then
  795.       Makeusg;
  796.       Exit_Program (E_Fatal);
  797.  
  798.    elsif Number_Of_Files > 1 then
  799.       Osint.Write_Program_Name;
  800.       Write_Str (": error, only one source or compilation unit allowed.");
  801.       Write_Eol;
  802.       Exit_Program (E_Fatal);
  803.    end if;
  804.  
  805.    --  ??? get rid of the following when smart compilation is implemented
  806.  
  807.    if Smart_Compilations then
  808.       Osint.Write_Program_Name;
  809.       Write_Str (": WARNING smart recompilation not yet implemented.");
  810.       Write_Eol;
  811.    end if;
  812.  
  813.    --  If check only warn the user the list of files to recompile is tentative
  814.  
  815.    if Dont_Execute then
  816.       Osint.Write_Program_Name;
  817.       Write_Str (": providing a *tentative* list of commands");
  818.       Write_Eol;
  819.    end if;
  820.  
  821.    --  Now check if the user input a file or compilation unit name. If it is a
  822.    --  compilation unit name first check the existence of the source file for
  823.    --  the compilation unit body. If the file for the body of the compilation
  824.    --  unit does not exist try the spec.
  825.  
  826.    Main_Unit_Or_File_Name := Next_Main_Source;
  827.  
  828.    if Is_File_Name (Main_Unit_Or_File_Name) then
  829.       Source_File := Main_Unit_Or_File_Name;
  830.  
  831.    else
  832.       Source_File := File_Name_Of_Body (Main_Unit_Or_File_Name);
  833.  
  834.       if Full_Source_Name (Source_File) = No_Name then
  835.          Source_File := File_Name_Of_Spec (Main_Unit_Or_File_Name);
  836.  
  837.          if Full_Source_Name (Source_File) = No_Name then
  838.             Osint.Write_Program_Name;
  839.             Write_Str (": no file found for body or spec of """);
  840.             Write_Name (Main_Unit_Or_File_Name);
  841.             Write_Char ('"');
  842.             Write_Eol;
  843.             Exit_Program (E_Fatal);
  844.          end if;
  845.       end if;
  846.    end if;
  847.  
  848.    --  Consider GNAT predefined files only if -a switch is set.
  849.  
  850.    if Is_Language_Defined_Unit (Source_File)
  851.      and then not Check_Internal_Files
  852.    then
  853.       Osint.Write_Program_Name;
  854.       Write_Str (": use the -a switch to compile GNAT predefined files");
  855.       Write_Eol;
  856.       Exit_Program (E_Fatal);
  857.    end if;
  858.  
  859.    --  The gnatmake algorithm starts here.
  860.  
  861.    Main_Ali_File := Osint.Lib_File_Name (Source_File);
  862.    Insert_Q (Source_File);
  863.    Mark (Main_Ali_File);
  864.  
  865.    Make_Loop : while not Empty_Q loop
  866.       Need_To_Compile := False;
  867.  
  868.       Source_File := Extract_From_Q;
  869.       Lib_File    := Lib_File_Name (Source_File);
  870.  
  871.       if Verbose_Mode then
  872.          Write_Str ("Checking --> ");
  873.          Write_Name (Full_Name (Source_File));
  874.          Write_Eol;
  875.       end if;
  876.  
  877.       Text := Read_Library_Info (Lib_File, Fatal_Err => False);
  878.  
  879.       if Dont_Execute and then Text = null then
  880.          Osint.Write_Program_Name;
  881.          Write_Str (" -n: cannot find """);
  882.          Write_Name (Lib_File);
  883.          Write_Str (""" *tentative* check aborted.");
  884.          Write_Eol;
  885.          Exit_Program (E_Fatal);
  886.       end if;
  887.  
  888.       if Text = null then
  889.          Need_To_Compile := True;
  890.  
  891.          if Verbose_Mode then
  892.             Write_Str ("   """);
  893.             Write_Name (Lib_File);
  894.             Write_Str (""" not found.  **Recompile**");
  895.             Write_Eol;
  896.          end if;
  897.  
  898.       else
  899.          Ali := Scan_ALI (Lib_File, Text);
  900.  
  901.          Set_Source_Table (Ali);
  902.          --  get the source files and their time stamps. Note that some sources
  903.          --  may be missing is Ali is out-of-date.
  904.  
  905.          Modified_Source := Time_Stamp_Mismatch (Ali);
  906.  
  907.          if Modified_Source /= No_File then
  908.             Need_To_Compile := True;
  909.  
  910.             if Verbose_Mode then
  911.                Write_Str ("   """);
  912.                Write_Name (Full_Name (Modified_Source));
  913.                Write_Str (""" time stamp mismatch.  **Recompile**");
  914.                Write_Eol;
  915.             end if;
  916.  
  917.          else
  918.             New_Spec := First_New_Spec (Ali);
  919.  
  920.             if New_Spec /= No_File then
  921.                Need_To_Compile := True;
  922.  
  923.                if Verbose_Mode then
  924.                   Write_Str ("   """);
  925.                   Write_Name (Full_Name (New_Spec));
  926.                   Write_Str (""" new spec.  **Recompile**");
  927.                   Write_Eol;
  928.                end if;
  929.             end if;
  930.          end if;
  931.       end if;
  932.  
  933.       if Need_To_Compile or Force_Compilations then
  934.          Objects_Up_To_Date := False;
  935.  
  936.          Exit_Code := Compile (Source_File);
  937.  
  938.          if Exit_Code /= E_Success then
  939.             exit Make_Loop;
  940.          end if;
  941.  
  942.          --  Re-read the updated library file
  943.  
  944.          Text := Read_Library_Info (Lib_File, Fatal_Err => False);
  945.  
  946.          if Text /= null then
  947.             Ali := Scan_ALI (Lib_File, Text);
  948.          end if;
  949.       end if;
  950.  
  951.       --  Now insert in the Queue the unmarked source files (i.e. those which
  952.       --  have neever been inserted in the Queue and hance never considered).
  953.  
  954.       if Text /= null then
  955.          for J in
  956.            ALIs.Table (Ali).First_Unit .. ALIs.Table (Ali).Last_Unit
  957.          loop
  958.             for K in Unit.Table (J).First_With .. Unit.Table (J).Last_With loop
  959.                Afile := Withs.Table (K).Afile;
  960.                Sfile := Withs.Table (K).Sfile;
  961.  
  962.                --  Never consider generics (Afile /= No_File).
  963.                --  Consider GNAT internal files only if -a switch is set.
  964.  
  965.                if Afile /= No_File
  966.                  and then not Is_Marked (Afile)
  967.                  and then (not Is_Language_Defined_Unit (Sfile)
  968.                            or else Check_Internal_Files)
  969.                then
  970.                   Insert_Q (Sfile);
  971.                   Mark (Afile);
  972.                end if;
  973.             end loop;
  974.          end loop;
  975.       end if;
  976.    end loop Make_Loop;
  977.  
  978.    if Objects_Up_To_Date
  979.      and then Exit_Code = E_Success
  980.    then
  981.       Osint.Write_Program_Name;
  982.       Write_Str (": sources up to date. No recompilations needed.");
  983.       Write_Eol;
  984.    end if;
  985.  
  986.    if Exit_Code = E_Success and then not Compile_Only then
  987.       Exit_Code := Bind (Main_Ali_File);
  988.  
  989.       if Exit_Code = E_Success then
  990.          Exit_Code := Link (Main_Ali_File);
  991.       end if;
  992.    end if;
  993.  
  994.    Finalize_Binderr;
  995.    Namet.Finalize;
  996.  
  997.    if Exit_Code /= E_Success then
  998.       Osint.Write_Program_Name;
  999.       Write_Str (": *** make failed.");
  1000.       Write_Eol;
  1001.    end if;
  1002.  
  1003.    Exit_Program (Exit_Code);
  1004.  
  1005. exception
  1006.    when others =>
  1007.       Osint.Write_Program_Name;
  1008.       Write_Str (": internal error. Please report to gnat-report@cs.nyu.edu");
  1009.       Write_Eol;
  1010.       Osint.Write_Program_Name;
  1011.       Write_Str (": *** make failed.");
  1012.       Write_Eol;
  1013.       Exit_Program (E_Fatal);
  1014.  
  1015. end Gnatmake;
  1016.