1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
9 -- Copyright (C) 1996-2004 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, 59 Temple Place - Suite 330, Boston, --
20 -- MA 02111-1307, 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;
32 with Namet; use Namet;
34 with Osint; use Osint;
39 with Prj.Ext; use Prj.Ext;
41 with Prj.Util; use Prj.Util;
42 with Snames; use Snames;
44 with Types; use Types;
45 with Hostparm; use Hostparm;
46 -- Used to determine if we are in VMS or not for error message purposes
48 with Ada.Characters.Handling; use Ada.Characters.Handling;
49 with Ada.Command_Line; use Ada.Command_Line;
50 with Ada.Text_IO; use Ada.Text_IO;
52 with GNAT.OS_Lib; use GNAT.OS_Lib;
56 with VMS_Conv; use VMS_Conv;
59 Project_File : String_Access;
60 Project : Prj.Project_Id;
61 Current_Verbosity : Prj.Verbosity := Prj.Default;
62 Tool_Package_Name : Name_Id := No_Name;
64 -- This flag indicates a switch -p (for gnatxref and gnatfind) for
65 -- an old fashioned project file. -p cannot be used in conjonction
68 Old_Project_File_Used : Boolean := False;
70 -- A table to keep the switches from the project file
72 package First_Switches is new Table.Table
73 (Table_Component_Type => String_Access,
74 Table_Index_Type => Integer,
77 Table_Increment => 100,
78 Table_Name => "Gnatcmd.First_Switches");
80 package Library_Paths is new Table.Table (
81 Table_Component_Type => String_Access,
82 Table_Index_Type => Integer,
85 Table_Increment => 100,
86 Table_Name => "Make.Library_Path");
88 -- Packages of project files to pass to Prj.Pars.Parse, depending on the
89 -- tool. We allocate objects because we cannot declare aliased objects
90 -- as we are in a procedure, not a library level package.
92 Naming_String : constant String_Access := new String'("naming");
93 Binder_String : constant String_Access := new String'("binder");
94 Eliminate_String : constant String_Access := new String'("eliminate");
95 Finder_String : constant String_Access := new String'("finder");
96 Linker_String : constant String_Access := new String'("linker");
97 Gnatls_String : constant String_Access := new String'("gnatls");
98 Pretty_String : constant String_Access := new String'("pretty_printer");
99 Gnatstub_String : constant String_Access := new String'("gnatstub");
100 Xref_String : constant String_Access := new String'("cross_reference");
102 Packages_To_Check_By_Binder : constant String_List_Access :=
103 new String_List'((Naming_String, Binder_String));
105 Packages_To_Check_By_Eliminate : constant String_List_Access :=
106 new String_List'((Naming_String, Eliminate_String));
108 Packages_To_Check_By_Finder : constant String_List_Access :=
109 new String_List'((Naming_String, Finder_String));
111 Packages_To_Check_By_Linker : constant String_List_Access :=
112 new String_List'((Naming_String, Linker_String));
114 Packages_To_Check_By_Gnatls : constant String_List_Access :=
115 new String_List'((Naming_String, Gnatls_String));
117 Packages_To_Check_By_Pretty : constant String_List_Access :=
118 new String_List'((Naming_String, Pretty_String));
120 Packages_To_Check_By_Gnatstub : constant String_List_Access :=
121 new String_List'((Naming_String, Gnatstub_String));
123 Packages_To_Check_By_Xref : constant String_List_Access :=
124 new String_List'((Naming_String, Xref_String));
126 Packages_To_Check : String_List_Access := Prj.All_Packages;
128 ----------------------------------
129 -- Declarations for GNATCMD use --
130 ----------------------------------
132 The_Command : Command_Type;
134 Command_Arg : Positive := 1;
136 My_Exit_Status : Exit_Status := Success;
138 Current_Work_Dir : constant String := Get_Current_Dir;
140 -----------------------
141 -- Local Subprograms --
142 -----------------------
144 procedure Check_Relative_Executable (Name : in out String_Access);
145 -- Check if an executable is specified as a relative path.
146 -- If it is, and the path contains directory information, fail.
147 -- Otherwise, prepend the exec directory.
148 -- This procedure is only used for GNAT LINK when a project file
151 function Configuration_Pragmas_File return Name_Id;
152 -- Return an argument, if there is a configuration pragmas file to be
153 -- specified for Project, otherwise return No_Name.
154 -- Used for gnatstub (GNAT STUB), gnatpp (GNAT PRETTY) and gnatelim
157 procedure Delete_Temp_Config_Files;
158 -- Delete all temporary config files
160 function Index (Char : Character; Str : String) return Natural;
161 -- Returns the first occurrence of Char in Str.
162 -- Returns 0 if Char is not in Str.
164 procedure Non_VMS_Usage;
165 -- Display usage for platforms other than VMS
167 procedure Set_Library_For
168 (Project : Project_Id;
169 There_Are_Libraries : in out Boolean);
170 -- If Project is a library project, add the correct
171 -- -L and -l switches to the linker invocation.
173 procedure Set_Libraries is
174 new For_Every_Project_Imported (Boolean, Set_Library_For);
175 -- Add the -L and -l switches to the linker for all
176 -- of the library projects.
178 procedure Test_If_Relative_Path
179 (Switch : in out String_Access;
181 -- Test if Switch is a relative search path switch.
182 -- If it is and it includes directory information, prepend the path with
183 -- Parent.This subprogram is only called when using project files.
185 -------------------------------
186 -- Check_Relative_Executable --
187 -------------------------------
189 procedure Check_Relative_Executable (Name : in out String_Access) is
190 Exec_File_Name : constant String := Name.all;
193 if not Is_Absolute_Path (Exec_File_Name) then
194 for Index in Exec_File_Name'Range loop
195 if Exec_File_Name (Index) = Directory_Separator then
196 Fail ("relative executable (""" &
198 """) with directory part not allowed " &
199 "when using project files");
203 Get_Name_String (Projects.Table
204 (Project).Exec_Directory);
206 if Name_Buffer (Name_Len) /= Directory_Separator then
207 Name_Len := Name_Len + 1;
208 Name_Buffer (Name_Len) := Directory_Separator;
211 Name_Buffer (Name_Len + 1 ..
212 Name_Len + Exec_File_Name'Length) :=
214 Name_Len := Name_Len + Exec_File_Name'Length;
215 Name := new String'(Name_Buffer (1 .. Name_Len));
217 end Check_Relative_Executable;
219 --------------------------------
220 -- Configuration_Pragmas_File --
221 --------------------------------
223 function Configuration_Pragmas_File return Name_Id is
225 Prj.Env.Create_Config_Pragmas_File
226 (Project, Project, Include_Config_Files => False);
227 return Projects.Table (Project).Config_File_Name;
228 end Configuration_Pragmas_File;
230 ------------------------------
231 -- Delete_Temp_Config_Files --
232 ------------------------------
234 procedure Delete_Temp_Config_Files is
238 if Project /= No_Project then
239 for Prj in 1 .. Projects.Last loop
240 if Projects.Table (Prj).Config_File_Temp then
241 if Opt.Verbose_Mode then
242 Output.Write_Str ("Deleting temp configuration file """);
243 Output.Write_Str (Get_Name_String
244 (Projects.Table (Prj).Config_File_Name));
245 Output.Write_Line ("""");
249 (Name => Get_Name_String
250 (Projects.Table (Prj).Config_File_Name),
255 end Delete_Temp_Config_Files;
261 function Index (Char : Character; Str : String) return Natural is
263 for Index in Str'Range loop
264 if Str (Index) = Char then
272 ---------------------
273 -- Set_Library_For --
274 ---------------------
276 procedure Set_Library_For
277 (Project : Project_Id;
278 There_Are_Libraries : in out Boolean)
280 Path_Option : constant String_Access :=
281 MLib.Linker_Library_Path_Option;
284 -- Case of library project
286 if Projects.Table (Project).Library then
287 There_Are_Libraries := True;
291 Last_Switches.Increment_Last;
292 Last_Switches.Table (Last_Switches.Last) :=
295 (Projects.Table (Project).Library_Dir));
299 Last_Switches.Increment_Last;
300 Last_Switches.Table (Last_Switches.Last) :=
303 (Projects.Table (Project).Library_Name));
305 -- Add the directory to table Library_Paths, to be processed later
306 -- if library is not static and if Path_Option is not null.
308 if Projects.Table (Project).Library_Kind /= Static
309 and then Path_Option /= null
311 Library_Paths.Increment_Last;
312 Library_Paths.Table (Library_Paths.Last) :=
313 new String'(Get_Name_String
314 (Projects.Table (Project).Library_Dir));
320 ---------------------------
321 -- Test_If_Relative_Path --
322 ---------------------------
324 procedure Test_If_Relative_Path
325 (Switch : in out String_Access;
329 if Switch /= null then
332 Sw : String (1 .. Switch'Length);
333 Start : Positive := 1;
340 and then (Sw (2) = 'A'
342 or else Sw (2) = 'L')
351 and then (Sw (2 .. 3) = "aL"
352 or else Sw (2 .. 3) = "aO"
353 or else Sw (2 .. 3) = "aI")
358 and then Sw (2 .. 6) = "-RTS="
366 -- If the path is relative, test if it includes directory
367 -- information. If it does, prepend Parent to the path.
369 if not Is_Absolute_Path (Sw (Start .. Sw'Last)) then
370 for J in Start .. Sw'Last loop
371 if Sw (J) = Directory_Separator then
374 (Sw (1 .. Start - 1) &
376 Directory_Separator &
377 Sw (Start .. Sw'Last));
384 end Test_If_Relative_Path;
390 procedure Non_VMS_Usage is
394 Put_Line ("List of available commands");
397 for C in Command_List'Range loop
398 if not Command_List (C).VMS_Only then
399 Put ("GNAT " & Command_List (C).Cname.all);
401 Put (Command_List (C).Unixcmd.all);
404 Sws : Argument_List_Access renames Command_List (C).Unixsws;
407 for J in Sws'Range loop
419 Put_Line ("Commands FIND, LIST, PRETTY, STUB and XREF accept " &
420 "project file switches -vPx, -Pprj and -Xnam=val");
424 -------------------------------------
425 -- Start of processing for GNATCmd --
426 -------------------------------------
439 Last_Switches.Set_Last (0);
442 First_Switches.Set_Last (0);
446 -- If on VMS, or if VMS emulation is on, convert VMS style /qualifiers,
447 -- filenames and pathnames to Unix style.
450 or else To_Lower (Getenv ("EMULATE_VMS").all) = "true"
452 VMS_Conversion (The_Command);
454 -- If not on VMS, scan the command line directly
457 if Argument_Count = 0 then
462 if Argument_Count > 1 and then Argument (1) = "-v" then
463 Opt.Verbose_Mode := True;
467 The_Command := Real_Command_Type'Value (Argument (Command_Arg));
469 if Command_List (The_Command).VMS_Only then
473 Command_List (The_Command).Cname.all,
474 """ can only be used on VMS");
478 when Constraint_Error =>
480 -- Check if it is an alternate command
483 Alternate : Alternate_Command;
486 Alternate := Alternate_Command'Value
487 (Argument (Command_Arg));
488 The_Command := Corresponding_To (Alternate);
491 when Constraint_Error =>
493 Fail ("Unknown command: ", Argument (Command_Arg));
497 -- Get the arguments from the command line and from the eventual
498 -- argument file(s) specified on the command line.
500 for Arg in Command_Arg + 1 .. Argument_Count loop
502 The_Arg : constant String := Argument (Arg);
505 -- Check if an argument file is specified
507 if The_Arg (The_Arg'First) = '@' then
509 Arg_File : Ada.Text_IO.File_Type;
510 Line : String (1 .. 256);
514 -- Open the file and fail if the file cannot be found
519 The_Arg (The_Arg'First + 1 .. The_Arg'Last));
524 (Standard_Error, "Cannot open argument file """);
527 The_Arg (The_Arg'First + 1 .. The_Arg'Last));
529 Put_Line (Standard_Error, """");
533 -- Read line by line and put the content of each
534 -- non empty line in the Last_Switches table.
536 while not End_Of_File (Arg_File) loop
537 Get_Line (Arg_File, Line, Last);
540 Last_Switches.Increment_Last;
541 Last_Switches.Table (Last_Switches.Last) :=
542 new String'(Line (1 .. Last));
550 -- It is not an argument file; just put the argument in
551 -- the Last_Switches table.
553 Last_Switches.Increment_Last;
554 Last_Switches.Table (Last_Switches.Last) :=
555 new String'(The_Arg);
563 Program : constant String :=
564 Program_Name (Command_List (The_Command).Unixcmd.all).all;
566 Exec_Path : String_Access;
569 -- Locate the executable for the command
571 Exec_Path := Locate_Exec_On_Path (Program);
573 if Exec_Path = null then
574 Put_Line (Standard_Error, "Couldn't locate " & Program);
578 -- If there are switches for the executable, put them as first switches
580 if Command_List (The_Command).Unixsws /= null then
581 for J in Command_List (The_Command).Unixsws'Range loop
582 First_Switches.Increment_Last;
583 First_Switches.Table (First_Switches.Last) :=
584 Command_List (The_Command).Unixsws (J);
588 -- For BIND, FIND, LINK, LIST, PRETTY ad XREF, look for project file
591 if The_Command = Bind
592 or else The_Command = Elim
593 or else The_Command = Find
594 or else The_Command = Link
595 or else The_Command = List
596 or else The_Command = Xref
597 or else The_Command = Pretty
598 or else The_Command = Stub
602 Tool_Package_Name := Name_Binder;
603 Packages_To_Check := Packages_To_Check_By_Binder;
605 Tool_Package_Name := Name_Eliminate;
606 Packages_To_Check := Packages_To_Check_By_Eliminate;
608 Tool_Package_Name := Name_Finder;
609 Packages_To_Check := Packages_To_Check_By_Finder;
611 Tool_Package_Name := Name_Linker;
612 Packages_To_Check := Packages_To_Check_By_Linker;
614 Tool_Package_Name := Name_Gnatls;
615 Packages_To_Check := Packages_To_Check_By_Gnatls;
617 Tool_Package_Name := Name_Pretty_Printer;
618 Packages_To_Check := Packages_To_Check_By_Pretty;
620 Tool_Package_Name := Name_Gnatstub;
621 Packages_To_Check := Packages_To_Check_By_Gnatstub;
623 Tool_Package_Name := Name_Cross_Reference;
624 Packages_To_Check := Packages_To_Check_By_Xref;
629 -- Check that the switches are consistent.
630 -- Detect project file related switches.
634 Arg_Num : Positive := 1;
635 Argv : String_Access;
637 procedure Remove_Switch (Num : Positive);
638 -- Remove a project related switch from table Last_Switches
644 procedure Remove_Switch (Num : Positive) is
646 Last_Switches.Table (Num .. Last_Switches.Last - 1) :=
647 Last_Switches.Table (Num + 1 .. Last_Switches.Last);
648 Last_Switches.Decrement_Last;
651 -- Start of processing for Inspect_Switches
654 while Arg_Num <= Last_Switches.Last loop
655 Argv := Last_Switches.Table (Arg_Num);
657 if Argv (Argv'First) = '-' then
658 if Argv'Length = 1 then
660 ("switch character cannot be followed by a blank");
663 -- The two style project files (-p and -P) cannot be used
666 if (The_Command = Find or else The_Command = Xref)
667 and then Argv (2) = 'p'
669 Old_Project_File_Used := True;
670 if Project_File /= null then
671 Fail ("-P and -p cannot be used together");
675 -- -vPx Specify verbosity while parsing project files
678 and then Argv (Argv'First + 1 .. Argv'First + 2) = "vP"
680 case Argv (Argv'Last) is
682 Current_Verbosity := Prj.Default;
684 Current_Verbosity := Prj.Medium;
686 Current_Verbosity := Prj.High;
688 Fail ("Invalid switch: ", Argv.all);
691 Remove_Switch (Arg_Num);
693 -- -Pproject_file Specify project file to be used
695 elsif Argv (Argv'First + 1) = 'P' then
697 -- Only one -P switch can be used
699 if Project_File /= null then
702 ": second project file forbidden (first is """,
703 Project_File.all & """)");
705 -- The two style project files (-p and -P) cannot be
708 elsif Old_Project_File_Used then
709 Fail ("-p and -P cannot be used together");
711 elsif Argv'Length = 2 then
713 -- There is space between -P and the project file
714 -- name. -P cannot be the last option.
716 if Arg_Num = Last_Switches.Last then
717 Fail ("project file name missing after -P");
720 Remove_Switch (Arg_Num);
721 Argv := Last_Switches.Table (Arg_Num);
723 -- After -P, there must be a project file name,
724 -- not another switch.
726 if Argv (Argv'First) = '-' then
727 Fail ("project file name missing after -P");
730 Project_File := new String'(Argv.all);
735 -- No space between -P and project file name
738 new String'(Argv (Argv'First + 2 .. Argv'Last));
741 Remove_Switch (Arg_Num);
743 -- -Xexternal=value Specify an external reference to be
744 -- used in project files
746 elsif Argv'Length >= 5
747 and then Argv (Argv'First + 1) = 'X'
750 Equal_Pos : constant Natural :=
751 Index ('=', Argv (Argv'First + 2 .. Argv'Last));
753 if Equal_Pos >= Argv'First + 3 and then
754 Equal_Pos /= Argv'Last then
755 Add (External_Name =>
756 Argv (Argv'First + 2 .. Equal_Pos - 1),
757 Value => Argv (Equal_Pos + 1 .. Argv'Last));
761 " is not a valid external assignment.");
765 Remove_Switch (Arg_Num);
768 Arg_Num := Arg_Num + 1;
772 Arg_Num := Arg_Num + 1;
775 end Inspect_Switches;
778 -- If there is a project file specified, parse it, get the switches
779 -- for the tool and setup PATH environment variables.
781 if Project_File /= null then
782 Prj.Pars.Set_Verbosity (To => Current_Verbosity);
786 Project_File_Name => Project_File.all,
787 Packages_To_Check => Packages_To_Check);
789 if Project = Prj.No_Project then
790 Fail ("""", Project_File.all, """ processing failed");
793 -- Check if a package with the name of the tool is in the project
794 -- file and if there is one, get the switches, if any, and scan them.
797 Data : constant Prj.Project_Data :=
798 Prj.Projects.Table (Project);
800 Pkg : constant Prj.Package_Id :=
802 (Name => Tool_Package_Name,
803 In_Packages => Data.Decl.Packages);
805 Element : Package_Element;
807 Default_Switches_Array : Array_Element_Id;
809 The_Switches : Prj.Variable_Value;
810 Current : Prj.String_List_Id;
811 The_String : String_Element;
814 if Pkg /= No_Package then
815 Element := Packages.Table (Pkg);
817 -- Packages Gnatls has a single attribute Switches, that is
818 -- not an associative array.
820 if The_Command = List then
823 (Variable_Name => Snames.Name_Switches,
824 In_Variables => Element.Decl.Attributes);
826 -- Packages Binder (for gnatbind), Cross_Reference (for
827 -- gnatxref), Linker (for gnatlink) Finder (for gnatfind),
828 -- Pretty_Printer (for gnatpp) and Eliminate (for gnatelim)
829 -- have an attributed Switches, an associative array, indexed
830 -- by the name of the file.
832 -- They also have an attribute Default_Switches, indexed
833 -- by the name of the programming language.
836 if The_Switches.Kind = Prj.Undefined then
837 Default_Switches_Array :=
839 (Name => Name_Default_Switches,
840 In_Arrays => Element.Decl.Arrays);
841 The_Switches := Prj.Util.Value_Of
844 In_Array => Default_Switches_Array);
848 -- If there are switches specified in the package of the
849 -- project file corresponding to the tool, scan them.
851 case The_Switches.Kind is
852 when Prj.Undefined =>
857 Switch : constant String :=
858 Get_Name_String (The_Switches.Value);
861 if Switch'Length > 0 then
862 First_Switches.Increment_Last;
863 First_Switches.Table (First_Switches.Last) :=
869 Current := The_Switches.Values;
870 while Current /= Prj.Nil_String loop
871 The_String := String_Elements.Table (Current);
874 Switch : constant String :=
875 Get_Name_String (The_String.Value);
878 if Switch'Length > 0 then
879 First_Switches.Increment_Last;
880 First_Switches.Table (First_Switches.Last) :=
885 Current := The_String.Next;
891 if The_Command = Bind
892 or else The_Command = Link
893 or else The_Command = Elim
897 (Projects.Table (Project).Object_Directory));
900 -- Set up the env vars for project path files
902 Prj.Env.Set_Ada_Paths (Project, Including_Libraries => False);
904 -- For gnatstub, gnatpp and gnatelim, create a configuration pragmas
905 -- file, if necessary.
907 if The_Command = Pretty
908 or else The_Command = Stub
909 or else The_Command = Elim
912 CP_File : constant Name_Id := Configuration_Pragmas_File;
915 if CP_File /= No_Name then
916 First_Switches.Increment_Last;
918 if The_Command = Elim then
919 First_Switches.Table (First_Switches.Last) :=
920 new String'("-C" & Get_Name_String (CP_File));
923 First_Switches.Table (First_Switches.Last) :=
924 new String'("-gnatec=" & Get_Name_String (CP_File));
930 if The_Command = Link then
932 -- Add the default search directories, to be able to find
933 -- libgnat in call to MLib.Utl.Lib_Directory.
935 Add_Default_Search_Dirs;
938 There_Are_Libraries : Boolean := False;
939 Path_Option : constant String_Access :=
940 MLib.Linker_Library_Path_Option;
943 Library_Paths.Set_Last (0);
945 -- Check if there are library project files
947 if MLib.Tgt.Support_For_Libraries /= MLib.Tgt.None then
948 Set_Libraries (Project, There_Are_Libraries);
951 -- If there are, add the necessary additional switches
953 if There_Are_Libraries then
955 -- Add -L<lib_dir> -lgnarl -lgnat -Wl,-rpath,<lib_dir>
957 Last_Switches.Increment_Last;
958 Last_Switches.Table (Last_Switches.Last) :=
959 new String'("-L" & MLib.Utl.Lib_Directory);
960 Last_Switches.Increment_Last;
961 Last_Switches.Table (Last_Switches.Last) :=
962 new String'("-lgnarl");
963 Last_Switches.Increment_Last;
964 Last_Switches.Table (Last_Switches.Last) :=
965 new String'("-lgnat");
967 -- If Path_Option is not null, create the switch
968 -- ("-Wl,-rpath," or equivalent) with all the library dirs
969 -- plus the standard GNAT library dir.
971 if Path_Option /= null then
973 Option : String_Access;
974 Length : Natural := Path_Option'Length;
978 -- First, compute the exact length for the switch
981 Library_Paths.First .. Library_Paths.Last
983 -- Add the length of the library dir plus one
984 -- for the directory separator.
988 Library_Paths.Table (Index)'Length + 1;
991 -- Finally, add the length of the standard GNAT
994 Length := Length + MLib.Utl.Lib_Directory'Length;
995 Option := new String (1 .. Length);
996 Option (1 .. Path_Option'Length) := Path_Option.all;
997 Current := Path_Option'Length;
999 -- Put each library dir followed by a dir separator
1002 Library_Paths.First .. Library_Paths.Last
1007 Library_Paths.Table (Index)'Length) :=
1008 Library_Paths.Table (Index).all;
1011 Library_Paths.Table (Index)'Length + 1;
1012 Option (Current) := Path_Separator;
1015 -- Finally put the standard GNAT library dir
1019 Current + MLib.Utl.Lib_Directory'Length) :=
1020 MLib.Utl.Lib_Directory;
1022 -- And add the switch to the last switches
1024 Last_Switches.Increment_Last;
1025 Last_Switches.Table (Last_Switches.Last) :=
1032 -- Check if the first ALI file specified can be found, either
1033 -- in the object directory of the main project or in an object
1034 -- directory of a project file extended by the main project.
1035 -- If the ALI file can be found, replace its name with its
1039 Skip_Executable : Boolean := False;
1042 Switch_Loop : for J in 1 .. Last_Switches.Last loop
1044 -- If we have an executable just reset the flag
1046 if Skip_Executable then
1047 Skip_Executable := False;
1049 -- If -o, set flag so that next switch is not processed
1051 elsif Last_Switches.Table (J).all = "-o" then
1052 Skip_Executable := True;
1058 Switch : constant String :=
1059 Last_Switches.Table (J).all;
1061 ALI_File : constant String (1 .. Switch'Length + 4) :=
1064 Last : Natural := Switch'Length;
1065 Test_Existence : Boolean := False;
1068 -- Skip real switches
1070 if Switch'Length /= 0 and then
1071 Switch (Switch'First) /= '-'
1073 -- Append ".ali" if file name does not end with it
1075 if Switch'Length <= 4 or else
1076 Switch (Switch'Last - 3 .. Switch'Last) /= ".ali"
1078 Last := ALI_File'Last;
1081 -- If file name includes directory information,
1082 -- stop if ALI file exists.
1084 if Is_Absolute_Path (ALI_File (1 .. Last)) then
1085 Test_Existence := True;
1088 for K in Switch'Range loop
1089 if Switch (K) = '/' or else
1090 Switch (K) = Directory_Separator
1092 Test_Existence := True;
1098 if Test_Existence then
1099 if Is_Regular_File (ALI_File (1 .. Last)) then
1104 -- Look in the object directories if the ALI
1108 Prj : Project_Id := Project;
1113 Dir : constant String :=
1115 (Projects.Table (Prj).
1119 (Dir & Directory_Separator &
1120 ALI_File (1 .. Last))
1122 -- We have found the correct
1123 -- project, so we replace the file
1124 -- with the absolute path.
1126 Last_Switches.Table (J) :=
1128 (Dir & Directory_Separator &
1129 ALI_File (1 .. Last));
1137 -- Go to the project being extended,
1140 Prj := Projects.Table (Prj).Extends;
1141 exit Project_Loop when Prj = No_Project;
1142 end loop Project_Loop;
1148 end loop Switch_Loop;
1151 -- If a relative path output file has been specified, we add
1152 -- the exec directory.
1155 Look_For_Executable : Boolean := True;
1159 for J in reverse 1 .. Last_Switches.Last - 1 loop
1160 if Last_Switches.Table (J).all = "-o" then
1161 Check_Relative_Executable
1162 (Name => Last_Switches.Table (J + 1));
1163 Look_For_Executable := False;
1168 if Look_For_Executable then
1169 for J in reverse 1 .. First_Switches.Last - 1 loop
1170 if First_Switches.Table (J).all = "-o" then
1171 Look_For_Executable := False;
1172 Check_Relative_Executable
1173 (Name => First_Switches.Table (J + 1));
1179 -- If no executable is specified, then find the name
1180 -- of the first ALI file on the command line and issue
1181 -- a -o switch with the absolute path of the executable
1182 -- in the exec directory.
1184 if Look_For_Executable then
1185 for J in 1 .. Last_Switches.Last loop
1187 Arg : constant String_Access :=
1188 Last_Switches.Table (J);
1189 Last : Natural := 0;
1192 if Arg'Length /= 0 and then Arg (Arg'First) /= '-' then
1194 and then Arg (Arg'Last - 3 .. Arg'Last) = ".ali"
1196 Last := Arg'Last - 4;
1198 elsif Is_Regular_File (Arg.all & ".ali") then
1204 Executable_Name : constant String :=
1205 Base_Name (Arg (Arg'First .. Last));
1207 Last_Switches.Increment_Last;
1208 Last_Switches.Table (Last_Switches.Last) :=
1211 (Projects.Table (Project).Exec_Directory);
1212 Last_Switches.Increment_Last;
1213 Last_Switches.Table (Last_Switches.Last) :=
1214 new String'(Name_Buffer (1 .. Name_Len) &
1215 Directory_Separator &
1217 Get_Executable_Suffix.all);
1228 if The_Command = Link or The_Command = Bind then
1230 -- For files that are specified as relative paths with directory
1231 -- information, we convert them to absolute paths, with parent
1232 -- being the current working directory if specified on the command
1233 -- line and the project directory if specified in the project
1234 -- file. This is what gnatmake is doing for linker and binder
1237 for J in 1 .. Last_Switches.Last loop
1238 Test_If_Relative_Path
1239 (Last_Switches.Table (J), Current_Work_Dir);
1242 Get_Name_String (Projects.Table (Project).Directory);
1245 Project_Dir : constant String := Name_Buffer (1 .. Name_Len);
1248 for J in 1 .. First_Switches.Last loop
1249 Test_If_Relative_Path
1250 (First_Switches.Table (J), Project_Dir);
1254 elsif The_Command = Stub then
1256 Data : constant Prj.Project_Data :=
1257 Prj.Projects.Table (Project);
1258 File_Index : Integer := 0;
1259 Dir_Index : Integer := 0;
1260 Last : constant Integer := Last_Switches.Last;
1263 for Index in 1 .. Last loop
1264 if Last_Switches.Table (Index)
1265 (Last_Switches.Table (Index)'First) /= '-'
1267 File_Index := Index;
1272 -- If the naming scheme of the project file is not standard,
1273 -- and if the file name ends with the spec suffix, then
1274 -- indicate to gnatstub the name of the body file with
1277 if Data.Naming.Current_Spec_Suffix /=
1278 Prj.Default_Ada_Spec_Suffix
1280 if File_Index /= 0 then
1282 Spec : constant String :=
1283 Base_Name (Last_Switches.Table (File_Index).all);
1284 Last : Natural := Spec'Last;
1287 Get_Name_String (Data.Naming.Current_Spec_Suffix);
1289 if Spec'Length > Name_Len
1290 and then Spec (Last - Name_Len + 1 .. Last) =
1291 Name_Buffer (1 .. Name_Len)
1293 Last := Last - Name_Len;
1294 Get_Name_String (Data.Naming.Current_Body_Suffix);
1295 Last_Switches.Increment_Last;
1296 Last_Switches.Table (Last_Switches.Last) :=
1298 Last_Switches.Increment_Last;
1299 Last_Switches.Table (Last_Switches.Last) :=
1300 new String'(Spec (Spec'First .. Last) &
1301 Name_Buffer (1 .. Name_Len));
1307 -- Add the directory of the spec as the destination directory
1308 -- of the body, if there is no destination directory already
1311 if File_Index /= 0 then
1312 for Index in File_Index + 1 .. Last loop
1313 if Last_Switches.Table (Index)
1314 (Last_Switches.Table (Index)'First) /= '-'
1321 if Dir_Index = 0 then
1322 Last_Switches.Increment_Last;
1323 Last_Switches.Table (Last_Switches.Last) :=
1325 (Dir_Name (Last_Switches.Table (File_Index).all));
1331 -- For gnat pretty, if no file has been put on the command line,
1332 -- call gnatpp with all the sources of the main project.
1334 if The_Command = Pretty then
1336 Add_Sources : Boolean := True;
1337 Unit_Data : Prj.Com.Unit_Data;
1339 -- Check if there is at least one argument that is not a switch
1341 for Index in 1 .. Last_Switches.Last loop
1342 if Last_Switches.Table (Index)(1) /= '-' then
1343 Add_Sources := False;
1348 -- If all arguments were switches, add the path names of
1349 -- all the sources of the main project.
1352 for Unit in 1 .. Prj.Com.Units.Last loop
1353 Unit_Data := Prj.Com.Units.Table (Unit);
1355 for Kind in Prj.Com.Spec_Or_Body loop
1357 -- Put only sources that belong to the main project
1359 if Unit_Data.File_Names (Kind).Project = Project then
1360 Last_Switches.Increment_Last;
1361 Last_Switches.Table (Last_Switches.Last) :=
1364 (Unit_Data.File_Names (Kind).Display_Path));
1373 -- Gather all the arguments and invoke the executable
1376 The_Args : Argument_List
1377 (1 .. First_Switches.Last + Last_Switches.Last);
1378 Arg_Num : Natural := 0;
1380 for J in 1 .. First_Switches.Last loop
1381 Arg_Num := Arg_Num + 1;
1382 The_Args (Arg_Num) := First_Switches.Table (J);
1385 for J in 1 .. Last_Switches.Last loop
1386 Arg_Num := Arg_Num + 1;
1387 The_Args (Arg_Num) := Last_Switches.Table (J);
1390 -- If Display_Command is on, only display the generated command
1392 if Display_Command then
1393 Put (Standard_Error, "generated command -->");
1394 Put (Standard_Error, Exec_Path.all);
1396 for Arg in The_Args'Range loop
1397 Put (Standard_Error, " ");
1398 Put (Standard_Error, The_Args (Arg).all);
1401 Put (Standard_Error, "<--");
1402 New_Line (Standard_Error);
1406 if Opt.Verbose_Mode then
1407 Output.Write_Str (Exec_Path.all);
1409 for Arg in The_Args'Range loop
1410 Output.Write_Char (' ');
1411 Output.Write_Str (The_Args (Arg).all);
1418 Exit_Status (Spawn (Exec_Path.all, The_Args));
1425 Prj.Env.Delete_All_Path_Files;
1426 Delete_Temp_Config_Files;
1427 Set_Exit_Status (Failure);
1430 Prj.Env.Delete_All_Path_Files;
1431 Delete_Temp_Config_Files;
1433 -- Since GNATCmd is normally called from DCL (the VMS shell),
1434 -- it must return an understandable VMS exit status. However
1435 -- the exit status returned *to* GNATCmd is a Posix style code,
1436 -- so we test it and return just a simple success or failure on VMS.
1438 if Hostparm.OpenVMS and then My_Exit_Status /= Success then
1439 Set_Exit_Status (Failure);
1441 Set_Exit_Status (My_Exit_Status);