1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
9 -- Copyright (C) 1996-2007, Free Software Foundation, Inc. --
11 -- GNAT is free software; you can redistribute it and/or modify it under --
12 -- terms of the GNU General Public License as published by the Free Soft- --
13 -- ware Foundation; either version 2, or (at your option) any later ver- --
14 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
17 -- for more details. You should have received a copy of the GNU General --
18 -- Public License distributed with GNAT; see file COPYING. If not, write --
19 -- to the Free Software Foundation, 51 Franklin Street, Fifth Floor, --
20 -- Boston, MA 02110-1301, USA. --
22 -- GNAT was originally developed by the GNAT team at New York University. --
23 -- Extensive contributions were provided by Ada Core Technologies Inc. --
25 ------------------------------------------------------------------------------
27 with GNAT.Directory_Operations; use GNAT.Directory_Operations;
30 with MLib.Tgt; use MLib.Tgt;
33 with Namet; use Namet;
35 with Osint; use Osint;
39 with Prj.Ext; use Prj.Ext;
41 with Prj.Util; use Prj.Util;
43 with Snames; use Snames;
46 with Types; use Types;
47 with Hostparm; use Hostparm;
48 -- Used to determine if we are in VMS or not for error message purposes
50 with Ada.Characters.Handling; use Ada.Characters.Handling;
51 with Ada.Command_Line; use Ada.Command_Line;
52 with Ada.Text_IO; use Ada.Text_IO;
54 with GNAT.OS_Lib; use GNAT.OS_Lib;
56 with VMS_Conv; use VMS_Conv;
59 Project_Tree : constant Project_Tree_Ref := new Project_Tree_Data;
60 Project_File : String_Access;
61 Project : Prj.Project_Id;
62 Current_Verbosity : Prj.Verbosity := Prj.Default;
63 Tool_Package_Name : Name_Id := No_Name;
65 B_Start : String_Ptr := new String'("b~");
66 -- Prefix of binder generated file, changed to b__ for VMS
68 Old_Project_File_Used : Boolean := False;
69 -- This flag indicates a switch -p (for gnatxref and gnatfind) for
70 -- an old fashioned project file. -p cannot be used in conjonction
73 Max_Files_On_The_Command_Line : constant := 30; -- Arbitrary
75 Temp_File_Name : String_Access := null;
76 -- The name of the temporary text file to put a list of source/object
77 -- files to pass to a tool, when there are more than
78 -- Max_Files_On_The_Command_Line files.
80 ASIS_Main : String_Access := null;
81 -- Main for commands Check, Metric and Pretty, when -U is used
83 package First_Switches is new Table.Table
84 (Table_Component_Type => String_Access,
85 Table_Index_Type => Integer,
88 Table_Increment => 100,
89 Table_Name => "Gnatcmd.First_Switches");
90 -- A table to keep the switches from the project file
92 package Carg_Switches is new Table.Table
93 (Table_Component_Type => String_Access,
94 Table_Index_Type => Integer,
97 Table_Increment => 100,
98 Table_Name => "Gnatcmd.Carg_Switches");
99 -- A table to keep the switches following -cargs for ASIS tools
101 package Rules_Switches is new Table.Table
102 (Table_Component_Type => String_Access,
103 Table_Index_Type => Integer,
104 Table_Low_Bound => 1,
106 Table_Increment => 100,
107 Table_Name => "Gnatcmd.Rules_Switches");
108 -- A table to keep the switches following -rules for gnatcheck
110 package Library_Paths is new Table.Table (
111 Table_Component_Type => String_Access,
112 Table_Index_Type => Integer,
113 Table_Low_Bound => 1,
115 Table_Increment => 100,
116 Table_Name => "Make.Library_Path");
118 -- Packages of project files to pass to Prj.Pars.Parse, depending on the
119 -- tool. We allocate objects because we cannot declare aliased objects
120 -- as we are in a procedure, not a library level package.
122 Naming_String : constant String_Access := new String'("naming");
123 Binder_String : constant String_Access := new String'("binder");
124 Compiler_String : constant String_Access := new String'("compiler");
125 Check_String : constant String_Access := new String'("check");
126 Eliminate_String : constant String_Access := new String'("eliminate");
127 Finder_String : constant String_Access := new String'("finder");
128 Linker_String : constant String_Access := new String'("linker");
129 Gnatls_String : constant String_Access := new String'("gnatls");
130 Pretty_String : constant String_Access := new String'("pretty_printer");
131 Stack_String : constant String_Access := new String'("stack");
132 Gnatstub_String : constant String_Access := new String'("gnatstub");
133 Metric_String : constant String_Access := new String'("metrics");
134 Xref_String : constant String_Access := new String'("cross_reference");
136 Packages_To_Check_By_Binder : constant String_List_Access :=
137 new String_List'((Naming_String, Binder_String));
139 Packages_To_Check_By_Check : constant String_List_Access :=
140 new String_List'((Naming_String, Check_String, Compiler_String));
142 Packages_To_Check_By_Eliminate : constant String_List_Access :=
143 new String_List'((Naming_String, Eliminate_String, Compiler_String));
145 Packages_To_Check_By_Finder : constant String_List_Access :=
146 new String_List'((Naming_String, Finder_String));
148 Packages_To_Check_By_Linker : constant String_List_Access :=
149 new String_List'((Naming_String, Linker_String));
151 Packages_To_Check_By_Gnatls : constant String_List_Access :=
152 new String_List'((Naming_String, Gnatls_String));
154 Packages_To_Check_By_Pretty : constant String_List_Access :=
155 new String_List'((Naming_String, Pretty_String, Compiler_String));
157 Packages_To_Check_By_Stack : constant String_List_Access :=
158 new String_List'((Naming_String, Stack_String));
160 Packages_To_Check_By_Gnatstub : constant String_List_Access :=
161 new String_List'((Naming_String, Gnatstub_String, Compiler_String));
163 Packages_To_Check_By_Metric : constant String_List_Access :=
164 new String_List'((Naming_String, Metric_String, Compiler_String));
166 Packages_To_Check_By_Xref : constant String_List_Access :=
167 new String_List'((Naming_String, Xref_String));
169 Packages_To_Check : String_List_Access := Prj.All_Packages;
171 ----------------------------------
172 -- Declarations for GNATCMD use --
173 ----------------------------------
175 The_Command : Command_Type;
176 -- The command specified in the invocation of the GNAT driver
178 Command_Arg : Positive := 1;
179 -- The index of the command in the arguments of the GNAT driver
181 My_Exit_Status : Exit_Status := Success;
182 -- The exit status of the spawned tool. Used to set the correct VMS
185 Current_Work_Dir : constant String := Get_Current_Dir;
186 -- The path of the working directory
188 All_Projects : Boolean := False;
189 -- Flag used for GNAT CHECK, GNAT PRETTY, GNAT METRIC, and GNAT STACK to
190 -- indicate that the underlying tool (gnatcheck, gnatpp or gnatmetric)
191 -- should be invoked for all sources of all projects.
193 -----------------------
194 -- Local Subprograms --
195 -----------------------
197 procedure Add_To_Carg_Switches (Switch : String_Access);
198 -- Add a switch to the Carg_Switches table. If it is the first one, put the
199 -- switch "-cargs" at the beginning of the table.
201 procedure Add_To_Rules_Switches (Switch : String_Access);
202 -- Add a switch to the Rules_Switches table. If it is the first one, put
203 -- the switch "-crules" at the beginning of the table.
205 procedure Check_Files;
206 -- For GNAT LIST, GNAT PRETTY, GNAT METRIC, and GNAT STACK, check if a
207 -- project file is specified, without any file arguments. If it is the
208 -- case, invoke the GNAT tool with the proper list of files, derived from
209 -- the sources of the project.
211 function Check_Project
212 (Project : Project_Id;
213 Root_Project : Project_Id) return Boolean;
214 -- Returns True if Project = Root_Project or if we want to consider all
215 -- sources of all projects. For GNAT METRIC, also returns True if Project
216 -- is extended by Root_Project.
218 procedure Check_Relative_Executable (Name : in out String_Access);
219 -- Check if an executable is specified as a relative path. If it is, and
220 -- the path contains directory information, fail. Otherwise, prepend the
221 -- exec directory. This procedure is only used for GNAT LINK when a project
222 -- file is specified.
224 function Configuration_Pragmas_File return Path_Name_Type;
225 -- Return an argument, if there is a configuration pragmas file to be
226 -- specified for Project, otherwise return No_Name. Used for gnatstub (GNAT
227 -- STUB), gnatpp (GNAT PRETTY), gnatelim (GNAT ELIM), and gnatmetric (GNAT
230 procedure Delete_Temp_Config_Files;
231 -- Delete all temporary config files
233 procedure Get_Closure;
234 -- Get the sources in the closure of the ASIS_Main and add them to the
235 -- list of arguments.
237 function Index (Char : Character; Str : String) return Natural;
238 -- Returns first occurrence of Char in Str, returns 0 if Char not in Str
240 procedure Non_VMS_Usage;
241 -- Display usage for platforms other than VMS
243 procedure Process_Link;
244 -- Process GNAT LINK, when there is a project file specified
246 procedure Set_Library_For
247 (Project : Project_Id;
248 There_Are_Libraries : in out Boolean);
249 -- If Project is a library project, add the correct -L and -l switches to
250 -- the linker invocation.
252 procedure Set_Libraries is
253 new For_Every_Project_Imported (Boolean, Set_Library_For);
254 -- Add the -L and -l switches to the linker for all of the library
257 procedure Test_If_Relative_Path
258 (Switch : in out String_Access;
260 -- Test if Switch is a relative search path switch. If it is and it
261 -- includes directory information, prepend the path with Parent. This
262 -- subprogram is only called when using project files.
264 --------------------------
265 -- Add_To_Carg_Switches --
266 --------------------------
268 procedure Add_To_Carg_Switches (Switch : String_Access) is
270 -- If the Carg_Switches table is empty, put "-cargs" at the beginning
272 if Carg_Switches.Last = 0 then
273 Carg_Switches.Increment_Last;
274 Carg_Switches.Table (Carg_Switches.Last) := new String'("-cargs");
277 Carg_Switches.Increment_Last;
278 Carg_Switches.Table (Carg_Switches.Last) := Switch;
279 end Add_To_Carg_Switches;
281 ---------------------------
282 -- Add_To_Rules_Switches --
283 ---------------------------
285 procedure Add_To_Rules_Switches (Switch : String_Access) is
287 -- If the Rules_Switches table is empty, put "-rules" at the beginning
289 if Rules_Switches.Last = 0 then
290 Rules_Switches.Increment_Last;
291 Rules_Switches.Table (Rules_Switches.Last) := new String'("-rules");
294 Rules_Switches.Increment_Last;
295 Rules_Switches.Table (Rules_Switches.Last) := Switch;
296 end Add_To_Rules_Switches;
302 procedure Check_Files is
303 Add_Sources : Boolean := True;
304 Unit_Data : Prj.Unit_Data;
305 Subunit : Boolean := False;
308 -- Check if there is at least one argument that is not a switch
310 for Index in 1 .. Last_Switches.Last loop
311 if Last_Switches.Table (Index) (1) /= '-' then
312 Add_Sources := False;
317 -- If all arguments were switches, add the path names of all the sources
318 -- of the main project.
322 Current_Last : constant Integer := Last_Switches.Last;
324 -- Gnatstack needs to add the the .ci file for the binder
325 -- generated files corresponding to all of the library projects
326 -- and main units belonging to the application.
328 if The_Command = Stack then
329 for Proj in Project_Table.First ..
330 Project_Table.Last (Project_Tree.Projects)
332 if Check_Project (Proj, Project) then
334 Data : Project_Data renames
335 Project_Tree.Projects.Table (Proj);
336 Main : String_List_Id := Data.Mains;
337 File : String_Access;
340 -- Include binder generated files for main programs
342 while Main /= Nil_String loop
345 (Get_Name_String (Data.Object_Directory) &
346 Directory_Separator &
350 (Project_Tree.String_Elements.Table
354 if Is_Regular_File (File.all) then
355 Last_Switches.Increment_Last;
356 Last_Switches.Table (Last_Switches.Last) := File;
360 Project_Tree.String_Elements.Table (Main).Next;
365 -- Include the .ci file for the binder generated
366 -- files that contains the initialization and
367 -- finalization of the library.
371 (Get_Name_String (Data.Object_Directory) &
372 Directory_Separator &
374 Get_Name_String (Data.Library_Name) &
377 if Is_Regular_File (File.all) then
378 Last_Switches.Increment_Last;
379 Last_Switches.Table (Last_Switches.Last) := File;
387 for Unit in Unit_Table.First ..
388 Unit_Table.Last (Project_Tree.Units)
390 Unit_Data := Project_Tree.Units.Table (Unit);
392 -- For gnatls, we only need to put the library units, body or
393 -- spec, but not the subunits.
395 if The_Command = List then
397 Unit_Data.File_Names (Body_Part).Name /= No_File
399 -- There is a body, check if it is for this project
401 if All_Projects or else
402 Unit_Data.File_Names (Body_Part).Project = Project
407 Unit_Data.File_Names (Specification).Name = No_File
409 -- We have a body with no spec: we need to check if
410 -- this is a subunit, because gnatls will complain
414 Src_Ind : Source_File_Index;
417 Src_Ind := Sinput.P.Load_Project_File
419 (Unit_Data.File_Names
423 Sinput.P.Source_File_Is_Subunit
429 Last_Switches.Increment_Last;
430 Last_Switches.Table (Last_Switches.Last) :=
433 (Unit_Data.File_Names
434 (Body_Part).Display_Name));
439 Unit_Data.File_Names (Specification).Name /= No_File
441 -- We have a spec with no body; check if it is for this
444 if All_Projects or else
445 Unit_Data.File_Names (Specification).Project = Project
447 Last_Switches.Increment_Last;
448 Last_Switches.Table (Last_Switches.Last) :=
451 (Unit_Data.File_Names
452 (Specification).Display_Name));
456 -- For gnatstack, we put the .ci files corresponding to the
457 -- different units, including the binder generated files. We
458 -- only need to do that for the library units, body or spec,
459 -- but not the subunits.
461 elsif The_Command = Stack then
463 Unit_Data.File_Names (Body_Part).Name /= No_File
465 -- There is a body. Check if .ci files for this project
470 (Unit_Data.File_Names (Body_Part).Project, Project)
475 Unit_Data.File_Names (Specification).Name = No_File
477 -- We have a body with no spec: we need to check
478 -- if this is a subunit, because .ci files are not
479 -- generated for subunits.
482 Src_Ind : Source_File_Index;
485 Src_Ind := Sinput.P.Load_Project_File
487 (Unit_Data.File_Names (Body_Part).Path));
490 Sinput.P.Source_File_Is_Subunit (Src_Ind);
495 Last_Switches.Increment_Last;
496 Last_Switches.Table (Last_Switches.Last) :=
499 (Project_Tree.Projects.Table
500 (Unit_Data.File_Names
501 (Body_Part).Project).
503 Directory_Separator &
506 (Unit_Data.File_Names
507 (Body_Part).Display_Name),
513 Unit_Data.File_Names (Specification).Name /= No_File
515 -- We have a spec with no body. Check if it is for this
520 (Unit_Data.File_Names (Specification).Project,
523 Last_Switches.Increment_Last;
524 Last_Switches.Table (Last_Switches.Last) :=
527 (Project_Tree.Projects.Table
528 (Unit_Data.File_Names
529 (Specification).Project).
534 (Unit_Data.File_Names
535 (Specification).Name),
541 -- For gnatcheck, gnatpp and gnatmetric, put all sources
542 -- of the project, or of all projects if -U was specified.
544 for Kind in Spec_Or_Body loop
546 -- Put only sources that belong to the main project
549 (Unit_Data.File_Names (Kind).Project, Project)
551 Last_Switches.Increment_Last;
552 Last_Switches.Table (Last_Switches.Last) :=
555 (Unit_Data.File_Names
556 (Kind).Display_Path));
562 -- If the list of files is too long, create a temporary text file
563 -- that lists these files, and pass this temp file to gnatcheck,
564 -- gnatpp or gnatmetric using switch -files=.
566 if Last_Switches.Last - Current_Last >
567 Max_Files_On_The_Command_Line
570 Temp_File_FD : File_Descriptor;
571 Buffer : String (1 .. 1_000);
573 OK : Boolean := True;
576 Create_Temp_File (Temp_File_FD, Temp_File_Name);
578 if Temp_File_Name /= null then
579 for Index in Current_Last + 1 ..
582 Len := Last_Switches.Table (Index)'Length;
583 Buffer (1 .. Len) := Last_Switches.Table (Index).all;
585 Buffer (Len) := ASCII.LF;
586 Buffer (Len + 1) := ASCII.NUL;
595 Close (Temp_File_FD, OK);
597 Close (Temp_File_FD, OK);
601 -- If there were any problem creating the temp file, then
602 -- pass the list of files.
606 -- Replace list of files with -files=<temp file name>
608 Last_Switches.Set_Last (Current_Last + 1);
609 Last_Switches.Table (Last_Switches.Last) :=
610 new String'("-files=" & Temp_File_Name.all);
623 function Check_Project
624 (Project : Project_Id;
625 Root_Project : Project_Id) return Boolean
628 if Project = No_Project then
631 elsif All_Projects or Project = Root_Project then
634 elsif The_Command = Metric then
639 Data := Project_Tree.Projects.Table (Root_Project);
640 while Data.Extends /= No_Project loop
641 if Project = Data.Extends then
645 Data := Project_Tree.Projects.Table (Data.Extends);
653 -------------------------------
654 -- Check_Relative_Executable --
655 -------------------------------
657 procedure Check_Relative_Executable (Name : in out String_Access) is
658 Exec_File_Name : constant String := Name.all;
661 if not Is_Absolute_Path (Exec_File_Name) then
662 for Index in Exec_File_Name'Range loop
663 if Exec_File_Name (Index) = Directory_Separator then
664 Fail ("relative executable (""" &
666 """) with directory part not allowed " &
667 "when using project files");
671 Get_Name_String (Project_Tree.Projects.Table
672 (Project).Exec_Directory);
674 if Name_Buffer (Name_Len) /= Directory_Separator then
675 Name_Len := Name_Len + 1;
676 Name_Buffer (Name_Len) := Directory_Separator;
679 Name_Buffer (Name_Len + 1 ..
680 Name_Len + Exec_File_Name'Length) :=
682 Name_Len := Name_Len + Exec_File_Name'Length;
683 Name := new String'(Name_Buffer (1 .. Name_Len));
685 end Check_Relative_Executable;
687 --------------------------------
688 -- Configuration_Pragmas_File --
689 --------------------------------
691 function Configuration_Pragmas_File return Path_Name_Type is
693 Prj.Env.Create_Config_Pragmas_File
694 (Project, Project, Project_Tree, Include_Config_Files => False);
695 return Project_Tree.Projects.Table (Project).Config_File_Name;
696 end Configuration_Pragmas_File;
698 ------------------------------
699 -- Delete_Temp_Config_Files --
700 ------------------------------
702 procedure Delete_Temp_Config_Files is
706 if not Keep_Temporary_Files then
707 if Project /= No_Project then
708 for Prj in Project_Table.First ..
709 Project_Table.Last (Project_Tree.Projects)
712 Project_Tree.Projects.Table (Prj).Config_File_Temp
715 Output.Write_Str ("Deleting temp configuration file """);
718 (Project_Tree.Projects.Table
719 (Prj).Config_File_Name));
720 Output.Write_Line ("""");
724 (Name => Get_Name_String
725 (Project_Tree.Projects.Table
726 (Prj).Config_File_Name),
732 -- If a temporary text file that contains a list of files for a tool
733 -- has been created, delete this temporary file.
735 if Temp_File_Name /= null then
736 Delete_File (Temp_File_Name.all, Success);
739 end Delete_Temp_Config_Files;
745 procedure Get_Closure is
746 Args : constant Argument_List :=
747 (1 => new String'("-q"),
748 2 => new String'("-b"),
749 3 => new String'("-P"),
752 6 => new String'("-bargs"),
753 7 => new String'("-R"),
754 8 => new String'("-Z"));
755 -- Arguments of the invocation of gnatmake to get the list of
757 FD : File_Descriptor;
758 -- File descriptor for the temp file that will get the output of the
759 -- invocation of gnatmake.
761 Name : Path_Name_Type;
762 -- Path of the file FD
764 GN_Name : constant String := Program_Name ("gnatmake").all;
767 GN_Path : constant String_Access := Locate_Exec_On_Path (GN_Name);
770 Return_Code : Integer;
773 pragma Warnings (Off, Unused);
775 File : Ada.Text_IO.File_Type;
776 Line : String (1 .. 250);
780 Path : Path_Name_Type;
783 if GN_Path = null then
784 Put_Line (Standard_Error, "could not locate " & GN_Name);
788 -- Create the temp file
790 Tempdir.Create_Temp_File (FD, Name);
792 -- And close it, because on VMS Spawn with a file descriptor created
793 -- with Create_Temp_File does not redirect output.
797 -- Spawn "gnatmake -q -b -P <project> <main> -bargs -R -Z"
800 (Program_Name => GN_Path.all,
802 Output_File => Get_Name_String (Name),
804 Return_Code => Return_Code,
809 -- Read the output of the invocation of gnatmake
811 Open (File, In_File, Get_Name_String (Name));
813 -- If it was unsuccessful, display the first line in the file and exit
816 if Return_Code /= 0 then
817 Get_Line (File, Line, Last);
819 if not Keep_Temporary_Files then
825 Put_Line (Standard_Error, Line (1 .. Last));
827 (Standard_Error, "could not get closure of " & ASIS_Main.all);
831 -- Get each file name in the file, find its path and add it the the
832 -- list of arguments.
834 while not End_Of_File (File) loop
835 Get_Line (File, Line, Last);
838 for Unit in Unit_Table.First ..
839 Unit_Table.Last (Project_Tree.Units)
841 Udata := Project_Tree.Units.Table (Unit);
843 if Udata.File_Names (Specification).Name /= No_File
845 Get_Name_String (Udata.File_Names (Specification).Name) =
848 Path := Udata.File_Names (Specification).Path;
851 elsif Udata.File_Names (Body_Part).Name /= No_File
853 Get_Name_String (Udata.File_Names (Body_Part).Name) =
856 Path := Udata.File_Names (Body_Part).Path;
861 Last_Switches.Increment_Last;
863 if Path /= No_Path then
864 Last_Switches.Table (Last_Switches.Last) :=
865 new String'(Get_Name_String (Path));
868 Last_Switches.Table (Last_Switches.Last) :=
869 new String'(Line (1 .. Last));
873 if not Keep_Temporary_Files then
886 function Index (Char : Character; Str : String) return Natural is
888 for Index in Str'Range loop
889 if Str (Index) = Char then
901 procedure Process_Link is
902 Look_For_Executable : Boolean := True;
903 There_Are_Libraries : Boolean := False;
904 Path_Option : constant String_Access :=
905 MLib.Linker_Library_Path_Option;
906 Prj : Project_Id := Project;
909 Skip_Executable : Boolean := False;
912 -- Add the default search directories, to be able to find
913 -- libgnat in call to MLib.Utl.Lib_Directory.
915 Add_Default_Search_Dirs;
917 Library_Paths.Set_Last (0);
919 -- Check if there are library project files
921 if MLib.Tgt.Support_For_Libraries /= None then
922 Set_Libraries (Project, Project_Tree, There_Are_Libraries);
925 -- If there are, add the necessary additional switches
927 if There_Are_Libraries then
929 -- Add -L<lib_dir> -lgnarl -lgnat -Wl,-rpath,<lib_dir>
931 Last_Switches.Increment_Last;
932 Last_Switches.Table (Last_Switches.Last) :=
933 new String'("-L" & MLib.Utl.Lib_Directory);
934 Last_Switches.Increment_Last;
935 Last_Switches.Table (Last_Switches.Last) :=
936 new String'("-lgnarl");
937 Last_Switches.Increment_Last;
938 Last_Switches.Table (Last_Switches.Last) :=
939 new String'("-lgnat");
941 -- If Path_Option is not null, create the switch ("-Wl,-rpath," or
942 -- equivalent) with all the library dirs plus the standard GNAT
945 if Path_Option /= null then
947 Option : String_Access;
948 Length : Natural := Path_Option'Length;
952 -- First, compute the exact length for the switch
955 Library_Paths.First .. Library_Paths.Last
957 -- Add the length of the library dir plus one for the
958 -- directory separator.
962 Library_Paths.Table (Index)'Length + 1;
965 -- Finally, add the length of the standard GNAT library dir
967 Length := Length + MLib.Utl.Lib_Directory'Length;
968 Option := new String (1 .. Length);
969 Option (1 .. Path_Option'Length) := Path_Option.all;
970 Current := Path_Option'Length;
972 -- Put each library dir followed by a dir separator
975 Library_Paths.First .. Library_Paths.Last
980 Library_Paths.Table (Index)'Length) :=
981 Library_Paths.Table (Index).all;
984 Library_Paths.Table (Index)'Length + 1;
985 Option (Current) := Path_Separator;
988 -- Finally put the standard GNAT library dir
992 Current + MLib.Utl.Lib_Directory'Length) :=
993 MLib.Utl.Lib_Directory;
995 -- And add the switch to the last switches
997 Last_Switches.Increment_Last;
998 Last_Switches.Table (Last_Switches.Last) :=
1004 -- Check if the first ALI file specified can be found, either in the
1005 -- object directory of the main project or in an object directory of a
1006 -- project file extended by the main project. If the ALI file can be
1007 -- found, replace its name with its absolute path.
1009 Skip_Executable := False;
1011 Switch_Loop : for J in 1 .. Last_Switches.Last loop
1013 -- If we have an executable just reset the flag
1015 if Skip_Executable then
1016 Skip_Executable := False;
1018 -- If -o, set flag so that next switch is not processed
1020 elsif Last_Switches.Table (J).all = "-o" then
1021 Skip_Executable := True;
1027 Switch : constant String :=
1028 Last_Switches.Table (J).all;
1030 ALI_File : constant String (1 .. Switch'Length + 4) :=
1033 Test_Existence : Boolean := False;
1036 Last := Switch'Length;
1038 -- Skip real switches
1040 if Switch'Length /= 0
1041 and then Switch (Switch'First) /= '-'
1043 -- Append ".ali" if file name does not end with it
1045 if Switch'Length <= 4
1046 or else Switch (Switch'Last - 3 .. Switch'Last)
1049 Last := ALI_File'Last;
1052 -- If file name includes directory information, stop if ALI
1055 if Is_Absolute_Path (ALI_File (1 .. Last)) then
1056 Test_Existence := True;
1059 for K in Switch'Range loop
1060 if Switch (K) = '/' or else
1061 Switch (K) = Directory_Separator
1063 Test_Existence := True;
1069 if Test_Existence then
1070 if Is_Regular_File (ALI_File (1 .. Last)) then
1074 -- Look in object directories if ALI file exists
1079 Dir : constant String :=
1081 (Project_Tree.Projects.Table
1082 (Prj).Object_Directory);
1086 Directory_Separator &
1087 ALI_File (1 .. Last))
1089 -- We have found the correct project, so we
1090 -- replace the file with the absolute path.
1092 Last_Switches.Table (J) :=
1094 (Dir & Directory_Separator &
1095 ALI_File (1 .. Last));
1103 -- Go to the project being extended, if any
1106 Project_Tree.Projects.Table (Prj).Extends;
1107 exit Project_Loop when Prj = No_Project;
1108 end loop Project_Loop;
1113 end loop Switch_Loop;
1115 -- If a relative path output file has been specified, we add the exec
1118 for J in reverse 1 .. Last_Switches.Last - 1 loop
1119 if Last_Switches.Table (J).all = "-o" then
1120 Check_Relative_Executable
1121 (Name => Last_Switches.Table (J + 1));
1122 Look_For_Executable := False;
1127 if Look_For_Executable then
1128 for J in reverse 1 .. First_Switches.Last - 1 loop
1129 if First_Switches.Table (J).all = "-o" then
1130 Look_For_Executable := False;
1131 Check_Relative_Executable
1132 (Name => First_Switches.Table (J + 1));
1138 -- If no executable is specified, then find the name of the first ALI
1139 -- file on the command line and issue a -o switch with the absolute path
1140 -- of the executable in the exec directory.
1142 if Look_For_Executable then
1143 for J in 1 .. Last_Switches.Last loop
1144 Arg := Last_Switches.Table (J);
1147 if Arg'Length /= 0 and then Arg (Arg'First) /= '-' then
1149 and then Arg (Arg'Last - 3 .. Arg'Last) = ".ali"
1151 Last := Arg'Last - 4;
1153 elsif Is_Regular_File (Arg.all & ".ali") then
1158 Last_Switches.Increment_Last;
1159 Last_Switches.Table (Last_Switches.Last) :=
1162 (Project_Tree.Projects.Table
1163 (Project).Exec_Directory);
1164 Last_Switches.Increment_Last;
1165 Last_Switches.Table (Last_Switches.Last) :=
1166 new String'(Name_Buffer (1 .. Name_Len) &
1167 Directory_Separator &
1169 (Base_Name (Arg (Arg'First .. Last))));
1177 ---------------------
1178 -- Set_Library_For --
1179 ---------------------
1181 procedure Set_Library_For
1182 (Project : Project_Id;
1183 There_Are_Libraries : in out Boolean)
1185 Path_Option : constant String_Access :=
1186 MLib.Linker_Library_Path_Option;
1189 -- Case of library project
1191 if Project_Tree.Projects.Table (Project).Library then
1192 There_Are_Libraries := True;
1194 -- Add the -L switch
1196 Last_Switches.Increment_Last;
1197 Last_Switches.Table (Last_Switches.Last) :=
1200 (Project_Tree.Projects.Table
1201 (Project).Library_Dir));
1203 -- Add the -l switch
1205 Last_Switches.Increment_Last;
1206 Last_Switches.Table (Last_Switches.Last) :=
1209 (Project_Tree.Projects.Table
1210 (Project).Library_Name));
1212 -- Add the directory to table Library_Paths, to be processed later
1213 -- if library is not static and if Path_Option is not null.
1215 if Project_Tree.Projects.Table (Project).Library_Kind /=
1217 and then Path_Option /= null
1219 Library_Paths.Increment_Last;
1220 Library_Paths.Table (Library_Paths.Last) :=
1221 new String'(Get_Name_String
1222 (Project_Tree.Projects.Table
1223 (Project).Library_Dir));
1226 end Set_Library_For;
1228 ---------------------------
1229 -- Test_If_Relative_Path --
1230 ---------------------------
1232 procedure Test_If_Relative_Path
1233 (Switch : in out String_Access;
1237 if Switch /= null then
1240 Sw : String (1 .. Switch'Length);
1241 Start : Positive := 1;
1246 if Sw (1) = '-' then
1248 and then (Sw (2) = 'A' or else
1249 Sw (2) = 'I' or else
1258 elsif Sw'Length >= 4
1259 and then (Sw (2 .. 3) = "aL" or else
1260 Sw (2 .. 3) = "aO" or else
1265 elsif Sw'Length >= 7
1266 and then Sw (2 .. 6) = "-RTS="
1274 -- If the path is relative, test if it includes directory
1275 -- information. If it does, prepend Parent to the path.
1277 if not Is_Absolute_Path (Sw (Start .. Sw'Last)) then
1278 for J in Start .. Sw'Last loop
1279 if Sw (J) = Directory_Separator then
1282 (Sw (1 .. Start - 1) &
1284 Directory_Separator &
1285 Sw (Start .. Sw'Last));
1292 end Test_If_Relative_Path;
1298 procedure Non_VMS_Usage is
1302 Put_Line ("List of available commands");
1305 for C in Command_List'Range loop
1306 if not Command_List (C).VMS_Only then
1307 Put ("gnat " & To_Lower (Command_List (C).Cname.all));
1309 Put (Command_List (C).Unixcmd.all);
1312 Sws : Argument_List_Access renames Command_List (C).Unixsws;
1315 for J in Sws'Range loop
1327 Put_Line ("Commands find, list, metric, pretty, stack, stub and xref " &
1328 "accept project file switches -vPx, -Pprj and -Xnam=val");
1332 -------------------------------------
1333 -- Start of processing for GNATCmd --
1334 -------------------------------------
1344 Prj.Initialize (Project_Tree);
1347 Last_Switches.Set_Last (0);
1349 First_Switches.Init;
1350 First_Switches.Set_Last (0);
1352 Carg_Switches.Set_Last (0);
1353 Rules_Switches.Init;
1354 Rules_Switches.Set_Last (0);
1356 VMS_Conv.Initialize;
1358 Set_Mode (Ada_Only);
1360 -- Add the directory where the GNAT driver is invoked in front of the path,
1361 -- if the GNAT driver is invoked with directory information. Do not do this
1362 -- for VMS, where the notion of path does not really exist.
1366 Command : constant String := Command_Name;
1369 for Index in reverse Command'Range loop
1370 if Command (Index) = Directory_Separator then
1372 Absolute_Dir : constant String :=
1374 (Command (Command'First .. Index));
1376 PATH : constant String :=
1379 Getenv ("PATH").all;
1382 Setenv ("PATH", PATH);
1391 -- If on VMS, or if VMS emulation is on, convert VMS style /qualifiers,
1392 -- filenames and pathnames to Unix style.
1395 or else To_Lower (Getenv ("EMULATE_VMS").all) = "true"
1397 VMS_Conversion (The_Command);
1399 B_Start := new String'("b__");
1401 -- If not on VMS, scan the command line directly
1404 if Argument_Count = 0 then
1410 if Argument_Count > Command_Arg
1411 and then Argument (Command_Arg) = "-v"
1413 Verbose_Mode := True;
1414 Command_Arg := Command_Arg + 1;
1416 elsif Argument_Count > Command_Arg
1417 and then Argument (Command_Arg) = "-dn"
1419 Keep_Temporary_Files := True;
1420 Command_Arg := Command_Arg + 1;
1427 The_Command := Real_Command_Type'Value (Argument (Command_Arg));
1429 if Command_List (The_Command).VMS_Only then
1433 Command_List (The_Command).Cname.all,
1434 """ can only be used on VMS");
1438 when Constraint_Error =>
1440 -- Check if it is an alternate command
1443 Alternate : Alternate_Command;
1446 Alternate := Alternate_Command'Value
1447 (Argument (Command_Arg));
1448 The_Command := Corresponding_To (Alternate);
1451 when Constraint_Error =>
1453 Fail ("Unknown command: ", Argument (Command_Arg));
1457 -- Get the arguments from the command line and from the eventual
1458 -- argument file(s) specified on the command line.
1460 for Arg in Command_Arg + 1 .. Argument_Count loop
1462 The_Arg : constant String := Argument (Arg);
1465 -- Check if an argument file is specified
1467 if The_Arg (The_Arg'First) = '@' then
1469 Arg_File : Ada.Text_IO.File_Type;
1470 Line : String (1 .. 256);
1474 -- Open the file and fail if the file cannot be found
1479 The_Arg (The_Arg'First + 1 .. The_Arg'Last));
1484 (Standard_Error, "Cannot open argument file """);
1487 The_Arg (The_Arg'First + 1 .. The_Arg'Last));
1489 Put_Line (Standard_Error, """");
1493 -- Read line by line and put the content of each non-
1494 -- empty line in the Last_Switches table.
1496 while not End_Of_File (Arg_File) loop
1497 Get_Line (Arg_File, Line, Last);
1500 Last_Switches.Increment_Last;
1501 Last_Switches.Table (Last_Switches.Last) :=
1502 new String'(Line (1 .. Last));
1510 -- It is not an argument file; just put the argument in
1511 -- the Last_Switches table.
1513 Last_Switches.Increment_Last;
1514 Last_Switches.Table (Last_Switches.Last) :=
1515 new String'(The_Arg);
1523 Program : constant String :=
1524 Program_Name (Command_List (The_Command).Unixcmd.all).all;
1526 Exec_Path : String_Access;
1529 -- Locate the executable for the command
1531 Exec_Path := Locate_Exec_On_Path (Program);
1533 if Exec_Path = null then
1534 Put_Line (Standard_Error, "could not locate " & Program);
1538 -- If there are switches for the executable, put them as first switches
1540 if Command_List (The_Command).Unixsws /= null then
1541 for J in Command_List (The_Command).Unixsws'Range loop
1542 First_Switches.Increment_Last;
1543 First_Switches.Table (First_Switches.Last) :=
1544 Command_List (The_Command).Unixsws (J);
1548 -- For BIND, CHECK, ELIM, FIND, LINK, LIST, PRETTY, STACK, STUB,
1549 -- METRIC ad XREF, look for project file related switches.
1551 if The_Command = Bind
1552 or else The_Command = Check
1553 or else The_Command = Elim
1554 or else The_Command = Find
1555 or else The_Command = Link
1556 or else The_Command = List
1557 or else The_Command = Xref
1558 or else The_Command = Pretty
1559 or else The_Command = Stack
1560 or else The_Command = Stub
1561 or else The_Command = Metric
1565 Tool_Package_Name := Name_Binder;
1566 Packages_To_Check := Packages_To_Check_By_Binder;
1568 Tool_Package_Name := Name_Check;
1569 Packages_To_Check := Packages_To_Check_By_Check;
1571 Tool_Package_Name := Name_Eliminate;
1572 Packages_To_Check := Packages_To_Check_By_Eliminate;
1574 Tool_Package_Name := Name_Finder;
1575 Packages_To_Check := Packages_To_Check_By_Finder;
1577 Tool_Package_Name := Name_Linker;
1578 Packages_To_Check := Packages_To_Check_By_Linker;
1580 Tool_Package_Name := Name_Gnatls;
1581 Packages_To_Check := Packages_To_Check_By_Gnatls;
1583 Tool_Package_Name := Name_Metrics;
1584 Packages_To_Check := Packages_To_Check_By_Metric;
1586 Tool_Package_Name := Name_Pretty_Printer;
1587 Packages_To_Check := Packages_To_Check_By_Pretty;
1589 Tool_Package_Name := Name_Stack;
1590 Packages_To_Check := Packages_To_Check_By_Stack;
1592 Tool_Package_Name := Name_Gnatstub;
1593 Packages_To_Check := Packages_To_Check_By_Gnatstub;
1595 Tool_Package_Name := Name_Cross_Reference;
1596 Packages_To_Check := Packages_To_Check_By_Xref;
1601 -- Check that the switches are consistent. Detect project file
1602 -- related switches.
1606 Arg_Num : Positive := 1;
1607 Argv : String_Access;
1609 procedure Remove_Switch (Num : Positive);
1610 -- Remove a project related switch from table Last_Switches
1616 procedure Remove_Switch (Num : Positive) is
1618 Last_Switches.Table (Num .. Last_Switches.Last - 1) :=
1619 Last_Switches.Table (Num + 1 .. Last_Switches.Last);
1620 Last_Switches.Decrement_Last;
1623 -- Start of processing for Inspect_Switches
1626 while Arg_Num <= Last_Switches.Last loop
1627 Argv := Last_Switches.Table (Arg_Num);
1629 if Argv (Argv'First) = '-' then
1630 if Argv'Length = 1 then
1632 ("switch character cannot be followed by a blank");
1635 -- The two style project files (-p and -P) cannot be used
1638 if (The_Command = Find or else The_Command = Xref)
1639 and then Argv (2) = 'p'
1641 Old_Project_File_Used := True;
1642 if Project_File /= null then
1643 Fail ("-P and -p cannot be used together");
1647 -- -aPdir Add dir to the project search path
1650 and then Argv (Argv'First + 1 .. Argv'First + 2) = "aP"
1652 Add_Search_Project_Directory
1653 (Argv (Argv'First + 3 .. Argv'Last));
1655 Remove_Switch (Arg_Num);
1657 -- -vPx Specify verbosity while parsing project files
1659 elsif Argv'Length = 4
1660 and then Argv (Argv'First + 1 .. Argv'First + 2) = "vP"
1662 case Argv (Argv'Last) is
1664 Current_Verbosity := Prj.Default;
1666 Current_Verbosity := Prj.Medium;
1668 Current_Verbosity := Prj.High;
1670 Fail ("Invalid switch: ", Argv.all);
1673 Remove_Switch (Arg_Num);
1675 -- -Pproject_file Specify project file to be used
1677 elsif Argv (Argv'First + 1) = 'P' then
1679 -- Only one -P switch can be used
1681 if Project_File /= null then
1684 ": second project file forbidden (first is """,
1685 Project_File.all & """)");
1687 -- The two style project files (-p and -P) cannot be
1690 elsif Old_Project_File_Used then
1691 Fail ("-p and -P cannot be used together");
1693 elsif Argv'Length = 2 then
1695 -- There is space between -P and the project file
1696 -- name. -P cannot be the last option.
1698 if Arg_Num = Last_Switches.Last then
1699 Fail ("project file name missing after -P");
1702 Remove_Switch (Arg_Num);
1703 Argv := Last_Switches.Table (Arg_Num);
1705 -- After -P, there must be a project file name,
1706 -- not another switch.
1708 if Argv (Argv'First) = '-' then
1709 Fail ("project file name missing after -P");
1712 Project_File := new String'(Argv.all);
1717 -- No space between -P and project file name
1720 new String'(Argv (Argv'First + 2 .. Argv'Last));
1723 Remove_Switch (Arg_Num);
1725 -- -Xexternal=value Specify an external reference to be
1726 -- used in project files
1728 elsif Argv'Length >= 5
1729 and then Argv (Argv'First + 1) = 'X'
1732 Equal_Pos : constant Natural :=
1735 Argv (Argv'First + 2 .. Argv'Last));
1737 if Equal_Pos >= Argv'First + 3 and then
1738 Equal_Pos /= Argv'Last then
1739 Add (External_Name =>
1740 Argv (Argv'First + 2 .. Equal_Pos - 1),
1741 Value => Argv (Equal_Pos + 1 .. Argv'Last));
1745 " is not a valid external assignment.");
1749 Remove_Switch (Arg_Num);
1752 (The_Command = Check or else
1753 The_Command = Pretty or else
1754 The_Command = Metric or else
1755 The_Command = Stack or else
1757 and then Argv'Length = 2
1758 and then Argv (2) = 'U'
1760 All_Projects := True;
1761 Remove_Switch (Arg_Num);
1764 Arg_Num := Arg_Num + 1;
1767 elsif ((The_Command = Check and then Argv (Argv'First) /= '+')
1768 or else The_Command = Metric
1769 or else The_Command = Pretty)
1770 and then Project_File /= null
1771 and then All_Projects
1773 if ASIS_Main /= null then
1774 Fail ("cannot specify more than one main after -U");
1777 Remove_Switch (Arg_Num);
1781 Arg_Num := Arg_Num + 1;
1784 end Inspect_Switches;
1787 -- If there is a project file specified, parse it, get the switches
1788 -- for the tool and setup PATH environment variables.
1790 if Project_File /= null then
1791 Prj.Pars.Set_Verbosity (To => Current_Verbosity);
1794 (Project => Project,
1795 In_Tree => Project_Tree,
1796 Project_File_Name => Project_File.all,
1797 Packages_To_Check => Packages_To_Check);
1799 if Project = Prj.No_Project then
1800 Fail ("""", Project_File.all, """ processing failed");
1803 -- Check if a package with the name of the tool is in the project
1804 -- file and if there is one, get the switches, if any, and scan them.
1807 Data : constant Prj.Project_Data :=
1808 Project_Tree.Projects.Table (Project);
1810 Pkg : constant Prj.Package_Id :=
1812 (Name => Tool_Package_Name,
1813 In_Packages => Data.Decl.Packages,
1814 In_Tree => Project_Tree);
1816 Element : Package_Element;
1818 Default_Switches_Array : Array_Element_Id;
1820 The_Switches : Prj.Variable_Value;
1821 Current : Prj.String_List_Id;
1822 The_String : String_Element;
1825 if Pkg /= No_Package then
1826 Element := Project_Tree.Packages.Table (Pkg);
1828 -- Packages Gnatls and Gnatstack have a single attribute
1829 -- Switches, that is not an associative array.
1831 if The_Command = List or else The_Command = Stack then
1834 (Variable_Name => Snames.Name_Switches,
1835 In_Variables => Element.Decl.Attributes,
1836 In_Tree => Project_Tree);
1838 -- Packages Binder (for gnatbind), Cross_Reference (for
1839 -- gnatxref), Linker (for gnatlink), Finder (for gnatfind),
1840 -- Pretty_Printer (for gnatpp), Eliminate (for gnatelim), Check
1841 -- (for gnatcheck), and Metric (for gnatmetric) have an
1842 -- attributed Switches, an associative array, indexed by the
1843 -- name of the file.
1845 -- They also have an attribute Default_Switches, indexed by the
1846 -- name of the programming language.
1849 if The_Switches.Kind = Prj.Undefined then
1850 Default_Switches_Array :=
1852 (Name => Name_Default_Switches,
1853 In_Arrays => Element.Decl.Arrays,
1854 In_Tree => Project_Tree);
1855 The_Switches := Prj.Util.Value_Of
1858 In_Array => Default_Switches_Array,
1859 In_Tree => Project_Tree);
1863 -- If there are switches specified in the package of the
1864 -- project file corresponding to the tool, scan them.
1866 case The_Switches.Kind is
1867 when Prj.Undefined =>
1872 Switch : constant String :=
1873 Get_Name_String (The_Switches.Value);
1876 if Switch'Length > 0 then
1877 First_Switches.Increment_Last;
1878 First_Switches.Table (First_Switches.Last) :=
1879 new String'(Switch);
1884 Current := The_Switches.Values;
1885 while Current /= Prj.Nil_String loop
1886 The_String := Project_Tree.String_Elements.
1890 Switch : constant String :=
1891 Get_Name_String (The_String.Value);
1894 if Switch'Length > 0 then
1895 First_Switches.Increment_Last;
1896 First_Switches.Table (First_Switches.Last) :=
1897 new String'(Switch);
1901 Current := The_String.Next;
1907 if The_Command = Bind
1908 or else The_Command = Link
1909 or else The_Command = Elim
1913 (Project_Tree.Projects.Table
1914 (Project).Object_Directory));
1917 -- Set up the env vars for project path files
1919 Prj.Env.Set_Ada_Paths
1920 (Project, Project_Tree, Including_Libraries => False);
1922 -- For gnatcheck, gnatstub, gnatmetric, gnatpp and gnatelim, create
1923 -- a configuration pragmas file, if necessary.
1925 if The_Command = Pretty
1926 or else The_Command = Metric
1927 or else The_Command = Stub
1928 or else The_Command = Elim
1929 or else The_Command = Check
1931 -- If there are switches in package Compiler, put them in the
1932 -- Carg_Switches table.
1935 Data : constant Prj.Project_Data :=
1936 Project_Tree.Projects.Table (Project);
1938 Pkg : constant Prj.Package_Id :=
1940 (Name => Name_Compiler,
1941 In_Packages => Data.Decl.Packages,
1942 In_Tree => Project_Tree);
1944 Element : Package_Element;
1946 Default_Switches_Array : Array_Element_Id;
1948 The_Switches : Prj.Variable_Value;
1949 Current : Prj.String_List_Id;
1950 The_String : String_Element;
1953 if Pkg /= No_Package then
1954 Element := Project_Tree.Packages.Table (Pkg);
1956 Default_Switches_Array :=
1958 (Name => Name_Default_Switches,
1959 In_Arrays => Element.Decl.Arrays,
1960 In_Tree => Project_Tree);
1961 The_Switches := Prj.Util.Value_Of
1964 In_Array => Default_Switches_Array,
1965 In_Tree => Project_Tree);
1967 -- If there are switches specified in the package of the
1968 -- project file corresponding to the tool, scan them.
1970 case The_Switches.Kind is
1971 when Prj.Undefined =>
1976 Switch : constant String :=
1977 Get_Name_String (The_Switches.Value);
1979 if Switch'Length > 0 then
1980 Add_To_Carg_Switches (new String'(Switch));
1985 Current := The_Switches.Values;
1986 while Current /= Prj.Nil_String loop
1988 Project_Tree.String_Elements.Table (Current);
1991 Switch : constant String :=
1992 Get_Name_String (The_String.Value);
1994 if Switch'Length > 0 then
1995 Add_To_Carg_Switches (new String'(Switch));
1999 Current := The_String.Next;
2005 -- If -cargs is one of the switches, move the following switches
2006 -- to the Carg_Switches table.
2008 for J in 1 .. First_Switches.Last loop
2009 if First_Switches.Table (J).all = "-cargs" then
2010 for K in J + 1 .. First_Switches.Last loop
2011 Add_To_Carg_Switches (First_Switches.Table (K));
2013 First_Switches.Set_Last (J - 1);
2018 for J in 1 .. Last_Switches.Last loop
2019 if Last_Switches.Table (J).all = "-cargs" then
2020 for K in J + 1 .. Last_Switches.Last loop
2021 Add_To_Carg_Switches (Last_Switches.Table (K));
2023 Last_Switches.Set_Last (J - 1);
2029 CP_File : constant Path_Name_Type := Configuration_Pragmas_File;
2032 if CP_File /= No_Path then
2033 if The_Command = Elim then
2034 First_Switches.Increment_Last;
2035 First_Switches.Table (First_Switches.Last) :=
2036 new String'("-C" & Get_Name_String (CP_File));
2039 Add_To_Carg_Switches
2040 (new String'("-gnatec=" & Get_Name_String (CP_File)));
2046 if The_Command = Link then
2050 if The_Command = Link or The_Command = Bind then
2052 -- For files that are specified as relative paths with directory
2053 -- information, we convert them to absolute paths, with parent
2054 -- being the current working directory if specified on the command
2055 -- line and the project directory if specified in the project
2056 -- file. This is what gnatmake is doing for linker and binder
2059 for J in 1 .. Last_Switches.Last loop
2060 Test_If_Relative_Path
2061 (Last_Switches.Table (J), Current_Work_Dir);
2065 (Project_Tree.Projects.Table (Project).Directory);
2068 Project_Dir : constant String := Name_Buffer (1 .. Name_Len);
2070 for J in 1 .. First_Switches.Last loop
2071 Test_If_Relative_Path
2072 (First_Switches.Table (J), Project_Dir);
2076 elsif The_Command = Stub then
2078 Data : constant Prj.Project_Data :=
2079 Project_Tree.Projects.Table (Project);
2080 File_Index : Integer := 0;
2081 Dir_Index : Integer := 0;
2082 Last : constant Integer := Last_Switches.Last;
2085 for Index in 1 .. Last loop
2086 if Last_Switches.Table (Index)
2087 (Last_Switches.Table (Index)'First) /= '-'
2089 File_Index := Index;
2094 -- If the naming scheme of the project file is not standard,
2095 -- and if the file name ends with the spec suffix, then
2096 -- indicate to gnatstub the name of the body file with
2099 if Body_Suffix_Id_Of (Project_Tree, "ada", Data.Naming) /=
2100 Prj.Default_Ada_Spec_Suffix
2102 if File_Index /= 0 then
2104 Spec : constant String :=
2105 Base_Name (Last_Switches.Table (File_Index).all);
2106 Last : Natural := Spec'Last;
2111 (Project_Tree, "ada", Data.Naming));
2113 if Spec'Length > Name_Len
2114 and then Spec (Last - Name_Len + 1 .. Last) =
2115 Name_Buffer (1 .. Name_Len)
2117 Last := Last - Name_Len;
2120 (Project_Tree, "ada", Data.Naming));
2121 Last_Switches.Increment_Last;
2122 Last_Switches.Table (Last_Switches.Last) :=
2124 Last_Switches.Increment_Last;
2125 Last_Switches.Table (Last_Switches.Last) :=
2126 new String'(Spec (Spec'First .. Last) &
2127 Name_Buffer (1 .. Name_Len));
2133 -- Add the directory of the spec as the destination directory
2134 -- of the body, if there is no destination directory already
2137 if File_Index /= 0 then
2138 for Index in File_Index + 1 .. Last loop
2139 if Last_Switches.Table (Index)
2140 (Last_Switches.Table (Index)'First) /= '-'
2147 if Dir_Index = 0 then
2148 Last_Switches.Increment_Last;
2149 Last_Switches.Table (Last_Switches.Last) :=
2151 (Dir_Name (Last_Switches.Table (File_Index).all));
2157 -- For gnatmetric, the generated files should be put in the object
2158 -- directory. This must be the first switch, because it may be
2159 -- overriden by a switch in package Metrics in the project file or by
2160 -- a command line option.
2162 if The_Command = Metric then
2163 First_Switches.Increment_Last;
2164 First_Switches.Table (2 .. First_Switches.Last) :=
2165 First_Switches.Table (1 .. First_Switches.Last - 1);
2166 First_Switches.Table (1) :=
2169 (Project_Tree.Projects.Table
2170 (Project).Object_Directory));
2173 -- For gnat check, -rules and the following switches need to be the
2174 -- last options. So, we move all these switches to table
2177 if The_Command = Check then
2180 -- Set to rank of options preceding "-rules"
2182 In_Rules_Switches : Boolean;
2183 -- Set to True when options "-rules" is found
2186 New_Last := First_Switches.Last;
2187 In_Rules_Switches := False;
2189 for J in 1 .. First_Switches.Last loop
2190 if In_Rules_Switches then
2191 Add_To_Rules_Switches (First_Switches.Table (J));
2193 elsif First_Switches.Table (J).all = "-rules" then
2195 In_Rules_Switches := True;
2199 if In_Rules_Switches then
2200 First_Switches.Set_Last (New_Last);
2203 New_Last := Last_Switches.Last;
2204 In_Rules_Switches := False;
2206 for J in 1 .. Last_Switches.Last loop
2207 if In_Rules_Switches then
2208 Add_To_Rules_Switches (Last_Switches.Table (J));
2210 elsif Last_Switches.Table (J).all = "-rules" then
2212 In_Rules_Switches := True;
2216 if In_Rules_Switches then
2217 Last_Switches.Set_Last (New_Last);
2222 -- For gnat check, metric or pretty with -U + a main, get the list
2223 -- of sources from the closure and add them to the arguments.
2225 if ASIS_Main /= null then
2228 -- On VMS, set up again the env var for source dirs file. This is
2229 -- because the call to gnatmake has set this env var to another
2230 -- file that has now been deleted.
2232 if Hostparm.OpenVMS then
2234 (Project_Include_Path_File,
2235 Prj.Env.Ada_Include_Path
2236 (Project, Project_Tree, Recursive => True));
2239 -- For gnat check, gnat pretty, gnat metric, gnat list, and gnat
2240 -- stack, if no file has been put on the command line, call tool
2241 -- with all the sources of the main project.
2243 elsif The_Command = Check or else
2244 The_Command = Pretty or else
2245 The_Command = Metric or else
2246 The_Command = List or else
2253 -- Gather all the arguments and invoke the executable
2256 The_Args : Argument_List
2257 (1 .. First_Switches.Last +
2258 Last_Switches.Last +
2259 Carg_Switches.Last +
2260 Rules_Switches.Last);
2261 Arg_Num : Natural := 0;
2264 for J in 1 .. First_Switches.Last loop
2265 Arg_Num := Arg_Num + 1;
2266 The_Args (Arg_Num) := First_Switches.Table (J);
2269 for J in 1 .. Last_Switches.Last loop
2270 Arg_Num := Arg_Num + 1;
2271 The_Args (Arg_Num) := Last_Switches.Table (J);
2274 for J in 1 .. Carg_Switches.Last loop
2275 Arg_Num := Arg_Num + 1;
2276 The_Args (Arg_Num) := Carg_Switches.Table (J);
2279 for J in 1 .. Rules_Switches.Last loop
2280 Arg_Num := Arg_Num + 1;
2281 The_Args (Arg_Num) := Rules_Switches.Table (J);
2284 -- If Display_Command is on, only display the generated command
2286 if Display_Command then
2287 Put (Standard_Error, "generated command -->");
2288 Put (Standard_Error, Exec_Path.all);
2290 for Arg in The_Args'Range loop
2291 Put (Standard_Error, " ");
2292 Put (Standard_Error, The_Args (Arg).all);
2295 Put (Standard_Error, "<--");
2296 New_Line (Standard_Error);
2300 if Verbose_Mode then
2301 Output.Write_Str (Exec_Path.all);
2303 for Arg in The_Args'Range loop
2304 Output.Write_Char (' ');
2305 Output.Write_Str (The_Args (Arg).all);
2312 Exit_Status (Spawn (Exec_Path.all, The_Args));
2319 if not Keep_Temporary_Files then
2320 Prj.Env.Delete_All_Path_Files (Project_Tree);
2321 Delete_Temp_Config_Files;
2324 Set_Exit_Status (Failure);
2327 if not Keep_Temporary_Files then
2328 Prj.Env.Delete_All_Path_Files (Project_Tree);
2329 Delete_Temp_Config_Files;
2332 -- Since GNATCmd is normally called from DCL (the VMS shell), it must
2333 -- return an understandable VMS exit status. However the exit status
2334 -- returned *to* GNATCmd is a Posix style code, so we test it and return
2335 -- just a simple success or failure on VMS.
2337 if Hostparm.OpenVMS and then My_Exit_Status /= Success then
2338 Set_Exit_Status (Failure);
2340 Set_Exit_Status (My_Exit_Status);