1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
9 -- Copyright (C) 2003-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 ------------------------------------------------------------------------------
29 with Gnatvsn; use Gnatvsn;
31 with MLib.Tgt; use MLib.Tgt;
32 with Namet; use Namet;
34 with Osint; use Osint;
35 with Osint.M; use Osint.M;
40 with Prj.Util; use Prj.Util;
43 with Targparm; use Targparm;
44 with Types; use Types;
46 with Ada.Command_Line; use Ada.Command_Line;
48 with GNAT.Directory_Operations; use GNAT.Directory_Operations;
49 with GNAT.IO; use GNAT.IO;
50 with GNAT.OS_Lib; use GNAT.OS_Lib;
54 Initialized : Boolean := False;
55 -- Set to True by the first call to Initialize.
56 -- To avoid reinitialization of some packages.
58 -- Suffixes of various files
60 Assembly_Suffix : constant String := ".s";
61 ALI_Suffix : constant String := ".ali";
62 Tree_Suffix : constant String := ".adt";
63 Object_Suffix : constant String := Get_Target_Object_Suffix.all;
64 Debug_Suffix : String := ".dg";
65 -- Changed to "_dg" for VMS in the body of the package
67 Repinfo_Suffix : String := ".rep";
68 -- Changed to "_rep" for VMS in the body of the package
70 B_Start : String_Ptr := new String'("b~");
71 -- Prefix of binder generated file, and number of actual characters used.
72 -- Changed to "b__" for VMS in the body of the package.
74 Object_Directory_Path : String_Access := null;
75 -- The path name of the object directory, set with switch -D
77 Force_Deletions : Boolean := False;
78 -- Set to True by switch -f. When True, attempts to delete non writable
79 -- files will be done.
81 Do_Nothing : Boolean := False;
82 -- Set to True when switch -n is specified. When True, no file is deleted.
83 -- gnatclean only lists the files that would have been deleted if the
84 -- switch -n had not been specified.
86 File_Deleted : Boolean := False;
87 -- Set to True if at least one file has been deleted
89 Copyright_Displayed : Boolean := False;
90 Usage_Displayed : Boolean := False;
92 Project_File_Name : String_Access := null;
94 Project_Tree : constant Prj.Project_Tree_Ref := new Prj.Project_Tree_Data;
96 Main_Project : Prj.Project_Id := Prj.No_Project;
98 All_Projects : Boolean := False;
100 -- Packages of project files where unknown attributes are errors
102 Naming_String : aliased String := "naming";
103 Builder_String : aliased String := "builder";
104 Compiler_String : aliased String := "compiler";
105 Binder_String : aliased String := "binder";
106 Linker_String : aliased String := "linker";
108 Gnatmake_Packages : aliased String_List :=
109 (Naming_String 'Access,
110 Builder_String 'Access,
111 Compiler_String 'Access,
112 Binder_String 'Access,
113 Linker_String 'Access);
115 Packages_To_Check_By_Gnatmake : constant String_List_Access :=
116 Gnatmake_Packages'Access;
118 package Processed_Projects is new Table.Table
119 (Table_Component_Type => Project_Id,
120 Table_Index_Type => Natural,
121 Table_Low_Bound => 0,
123 Table_Increment => 100,
124 Table_Name => "Clean.Processed_Projects");
125 -- Table to keep track of what project files have been processed, when
126 -- switch -r is specified.
128 package Sources is new Table.Table
129 (Table_Component_Type => File_Name_Type,
130 Table_Index_Type => Natural,
131 Table_Low_Bound => 0,
133 Table_Increment => 100,
134 Table_Name => "Clean.Processed_Projects");
135 -- Table to store all the source files of a library unit: spec, body and
136 -- subunits, to detect .dg files and delete them.
138 ----------------------------
139 -- Queue (Q) manipulation --
140 ----------------------------
143 -- Must be called to initialize the Q
145 procedure Insert_Q (Lib_File : File_Name_Type);
146 -- If Lib_File is not marked, inserts it at the end of Q and mark it
148 function Empty_Q return Boolean;
149 -- Returns True if Q is empty
151 procedure Extract_From_Q (Lib_File : out File_Name_Type);
152 -- Extracts the first element from the Q
155 -- Points to the first valid element in the Q
157 package Q is new Table.Table (
158 Table_Component_Type => File_Name_Type,
159 Table_Index_Type => Natural,
160 Table_Low_Bound => 0,
161 Table_Initial => 4000,
162 Table_Increment => 100,
163 Table_Name => "Clean.Q");
164 -- This is the actual queue
166 -----------------------------
167 -- Other local subprograms --
168 -----------------------------
170 procedure Add_Source_Dir (N : String);
171 -- Call Add_Src_Search_Dir.
172 -- Output one line when in verbose mode.
174 procedure Add_Source_Directories is
175 new Prj.Env.For_All_Source_Dirs (Action => Add_Source_Dir);
177 procedure Add_Object_Dir (N : String);
178 -- Call Add_Lib_Search_Dir.
179 -- Output one line when in verbose mode.
181 procedure Add_Object_Directories is
182 new Prj.Env.For_All_Object_Dirs (Action => Add_Object_Dir);
184 function ALI_File_Name (Source : File_Name_Type) return String;
185 -- Returns the name of the ALI file corresponding to Source
187 function Assembly_File_Name (Source : File_Name_Type) return String;
188 -- Returns the assembly file name corresponding to Source
190 procedure Clean_Archive (Project : Project_Id);
191 -- Delete a global archive or a fake library project archive and the
192 -- dependency file, if they exist.
194 procedure Clean_Executables;
195 -- Do the cleaning work when no project file is specified
197 procedure Clean_Interface_Copy_Directory (Project : Project_Id);
198 -- Delete files in an interface copy directory: any file that is a copy of
199 -- a source of the project.
201 procedure Clean_Library_Directory (Project : Project_Id);
202 -- Delete the library file in a library directory and any ALI file
203 -- of a source of the project in a library ALI directory.
205 procedure Clean_Project (Project : Project_Id);
206 -- Do the cleaning work when a project file is specified.
207 -- This procedure calls itself recursively when there are several
208 -- project files in the tree rooted at the main project file and switch -r
209 -- has been specified.
211 function Debug_File_Name (Source : File_Name_Type) return String;
212 -- Name of the expanded source file corresponding to Source
214 procedure Delete (In_Directory : String; File : String);
215 -- Delete one file, or list the file name if switch -n is specified
217 procedure Delete_Binder_Generated_Files
219 Source : File_Name_Type);
220 -- Delete the binder generated file in directory Dir for Source, if they
221 -- exist: for Unix these are b~<source>.ads, b~<source>.adb,
222 -- b~<source>.ali and b~<source>.o.
224 procedure Display_Copyright;
225 -- Display the Copyright notice. If called several times, display the
226 -- Copyright notice only the first time.
228 procedure Initialize;
229 -- Call the necessary package initializations
231 function Object_File_Name (Source : File_Name_Type) return String;
232 -- Returns the object file name corresponding to Source
234 procedure Parse_Cmd_Line;
235 -- Parse the command line
237 function Repinfo_File_Name (Source : File_Name_Type) return String;
238 -- Returns the repinfo file name corresponding to Source
240 function Tree_File_Name (Source : File_Name_Type) return String;
241 -- Returns the tree file name corresponding to Source
243 function In_Extension_Chain
244 (Of_Project : Project_Id;
245 Prj : Project_Id) return Boolean;
246 -- Returns True iff Prj is an extension of Of_Project or if Of_Project is
247 -- an extension of Prj.
249 function Ultimate_Extension_Of (Project : Project_Id) return Project_Id;
250 -- Returns either Project, if it is not extended by another project, or
251 -- the project that extends Project, directly or indirectly, and that is
252 -- not itself extended. Returns No_Project if Project is No_Project.
255 -- Display the usage.
256 -- If called several times, the usage is displayed only the first time.
262 procedure Add_Object_Dir (N : String) is
264 Add_Lib_Search_Dir (N);
266 if Opt.Verbose_Mode then
267 Put ("Adding object directory """);
278 procedure Add_Source_Dir (N : String) is
280 Add_Src_Search_Dir (N);
282 if Opt.Verbose_Mode then
283 Put ("Adding source directory """);
294 function ALI_File_Name (Source : File_Name_Type) return String is
295 Src : constant String := Get_Name_String (Source);
298 -- If the source name has an extension, then replace it with
301 for Index in reverse Src'First + 1 .. Src'Last loop
302 if Src (Index) = '.' then
303 return Src (Src'First .. Index - 1) & ALI_Suffix;
307 -- If there is no dot, or if it is the first character, just add the
310 return Src & ALI_Suffix;
313 ------------------------
314 -- Assembly_File_Name --
315 ------------------------
317 function Assembly_File_Name (Source : File_Name_Type) return String is
318 Src : constant String := Get_Name_String (Source);
321 -- If the source name has an extension, then replace it with
322 -- the assembly suffix.
324 for Index in reverse Src'First + 1 .. Src'Last loop
325 if Src (Index) = '.' then
326 return Src (Src'First .. Index - 1) & Assembly_Suffix;
330 -- If there is no dot, or if it is the first character, just add the
333 return Src & Assembly_Suffix;
334 end Assembly_File_Name;
340 procedure Clean_Archive (Project : Project_Id) is
341 Current_Dir : constant Dir_Name_Str := Get_Current_Dir;
342 Data : constant Project_Data :=
343 Project_Tree.Projects.Table (Project);
344 Lib_Prefix : constant String :=
345 "lib" & Get_Name_String (Data.Display_Name);
347 Archive_Name : constant String :=
348 Lib_Prefix & '.' & Archive_Ext;
349 -- The name of the archive file for this project
351 Archive_Dep_Name : constant String :=
352 Lib_Prefix & ".deps";
353 -- The name of the archive dependency file for this project
355 Obj_Dir : constant String :=
356 Get_Name_String (Data.Display_Object_Dir);
359 Change_Dir (Obj_Dir);
361 if Is_Regular_File (Archive_Name) then
362 Delete (Obj_Dir, Archive_Name);
365 if Is_Regular_File (Archive_Dep_Name) then
366 Delete (Obj_Dir, Archive_Dep_Name);
369 Change_Dir (Current_Dir);
372 -----------------------
373 -- Clean_Executables --
374 -----------------------
376 procedure Clean_Executables is
377 Main_Source_File : File_Name_Type;
378 -- Current main source
380 Main_Lib_File : File_Name_Type;
381 -- ALI file of the current main
383 Lib_File : File_Name_Type;
386 Full_Lib_File : File_Name_Type;
387 -- Full name of the current ALI file
389 Text : Text_Buffer_Ptr;
395 -- It does not really matter if there is or not an object file
396 -- corresponding to an ALI file: if there is one, it will be deleted.
398 Opt.Check_Object_Consistency := False;
400 -- Proceed each executable one by one. Each source is marked as it is
401 -- processed, so common sources between executables will not be
402 -- processed several times.
404 for N_File in 1 .. Osint.Number_Of_Files loop
405 Main_Source_File := Next_Main_Source;
406 Main_Lib_File := Osint.Lib_File_Name
407 (Main_Source_File, Current_File_Index);
408 Insert_Q (Main_Lib_File);
410 while not Empty_Q loop
411 Sources.Set_Last (0);
412 Extract_From_Q (Lib_File);
413 Full_Lib_File := Osint.Full_Lib_File_Name (Lib_File);
415 -- If we have existing ALI file that is not read-only, process it
417 if Full_Lib_File /= No_File
418 and then not Is_Readonly_Library (Full_Lib_File)
420 Text := Read_Library_Info (Lib_File);
424 Scan_ALI (Lib_File, Text, Ignore_ED => False, Err => True);
427 -- If no error was produced while loading this ALI file,
428 -- insert into the queue all the unmarked withed sources.
430 if The_ALI /= No_ALI_Id then
431 for J in ALIs.Table (The_ALI).First_Unit ..
432 ALIs.Table (The_ALI).Last_Unit
434 Sources.Increment_Last;
435 Sources.Table (Sources.Last) :=
436 ALI.Units.Table (J).Sfile;
438 for K in ALI.Units.Table (J).First_With ..
439 ALI.Units.Table (J).Last_With
441 Insert_Q (Withs.Table (K).Afile);
445 -- Look for subunits and put them in the Sources table
447 for J in ALIs.Table (The_ALI).First_Sdep ..
448 ALIs.Table (The_ALI).Last_Sdep
450 if Sdep.Table (J).Subunit_Name /= No_Name then
451 Sources.Increment_Last;
452 Sources.Table (Sources.Last) :=
453 Sdep.Table (J).Sfile;
459 -- Now delete all existing files corresponding to this ALI file
462 Obj_Dir : constant String :=
463 Dir_Name (Get_Name_String (Full_Lib_File));
464 Obj : constant String := Object_File_Name (Lib_File);
465 Adt : constant String := Tree_File_Name (Lib_File);
466 Asm : constant String := Assembly_File_Name (Lib_File);
469 Delete (Obj_Dir, Get_Name_String (Lib_File));
471 if Is_Regular_File (Obj_Dir & Dir_Separator & Obj) then
472 Delete (Obj_Dir, Obj);
475 if Is_Regular_File (Obj_Dir & Dir_Separator & Adt) then
476 Delete (Obj_Dir, Adt);
479 if Is_Regular_File (Obj_Dir & Dir_Separator & Asm) then
480 Delete (Obj_Dir, Asm);
483 -- Delete expanded source files (.dg) and/or repinfo files
486 for J in 1 .. Sources.Last loop
488 Deb : constant String :=
489 Debug_File_Name (Sources.Table (J));
490 Rep : constant String :=
491 Repinfo_File_Name (Sources.Table (J));
494 if Is_Regular_File (Obj_Dir & Dir_Separator & Deb) then
495 Delete (Obj_Dir, Deb);
498 if Is_Regular_File (Obj_Dir & Dir_Separator & Rep) then
499 Delete (Obj_Dir, Rep);
507 -- Delete the executable, if it exists, and the binder generated
510 if not Compile_Only then
512 Source : constant File_Name_Type :=
513 Strip_Suffix (Main_Lib_File);
514 Executable : constant String :=
515 Get_Name_String (Executable_Name (Source));
517 if Is_Regular_File (Executable) then
518 Delete ("", Executable);
521 Delete_Binder_Generated_Files (Get_Current_Dir, Source);
525 end Clean_Executables;
527 ------------------------------------
528 -- Clean_Interface_Copy_Directory --
529 ------------------------------------
531 procedure Clean_Interface_Copy_Directory (Project : Project_Id) is
532 Current : constant String := Get_Current_Dir;
533 Data : constant Project_Data := Project_Tree.Projects.Table (Project);
537 Name : String (1 .. 200);
540 Delete_File : Boolean;
544 if Data.Library and then Data.Library_Src_Dir /= No_Path then
546 Directory : constant String :=
547 Get_Name_String (Data.Display_Library_Src_Dir);
550 Change_Dir (Directory);
553 -- For each regular file in the directory, if switch -n has not
554 -- been specified, make it writable and delete the file if it is
555 -- a copy of a source of the project.
558 Read (Direc, Name, Last);
562 Filename : constant String := Name (1 .. Last);
565 if Is_Regular_File (Filename) then
566 Canonical_Case_File_Name (Name (1 .. Last));
567 Delete_File := False;
569 -- Compare with source file names of the project
572 1 .. Unit_Table.Last (Project_Tree.Units)
574 Unit := Project_Tree.Units.Table (Index);
576 if Ultimate_Extension_Of
577 (Unit.File_Names (Body_Part).Project) = Project
580 (Unit.File_Names (Body_Part).Name) =
587 if Ultimate_Extension_Of
588 (Unit.File_Names (Specification).Project) = Project
591 (Unit.File_Names (Specification).Name) =
600 if not Do_Nothing then
601 Set_Writable (Filename);
604 Delete (Directory, Filename);
612 -- Restore the initial working directory
614 Change_Dir (Current);
617 end Clean_Interface_Copy_Directory;
619 -----------------------------
620 -- Clean_Library_Directory --
621 -----------------------------
623 procedure Clean_Library_Directory (Project : Project_Id) is
624 Current : constant String := Get_Current_Dir;
625 Data : constant Project_Data := Project_Tree.Projects.Table (Project);
627 Lib_Filename : constant String := Get_Name_String (Data.Library_Name);
629 DLL_Prefix & Lib_Filename & "." & DLL_Ext;
630 Archive_Name : String :=
631 "lib" & Lib_Filename & "." & Archive_Ext;
634 Name : String (1 .. 200);
637 Delete_File : Boolean;
642 Lib_Directory : constant String :=
643 Get_Name_String (Data.Display_Library_Dir);
644 Lib_ALI_Directory : constant String :=
646 (Data.Display_Library_ALI_Dir);
649 Canonical_Case_File_Name (Archive_Name);
650 Canonical_Case_File_Name (DLL_Name);
652 Change_Dir (Lib_Directory);
655 -- For each regular file in the directory, if switch -n has not
656 -- been specified, make it writable and delete the file if it is
660 Read (Direc, Name, Last);
664 Filename : constant String := Name (1 .. Last);
666 if Is_Regular_File (Filename) then
667 Canonical_Case_File_Name (Name (1 .. Last));
668 Delete_File := False;
670 if (Data.Library_Kind = Static
671 and then Name (1 .. Last) = Archive_Name)
673 ((Data.Library_Kind = Dynamic or else
674 Data.Library_Kind = Relocatable)
675 and then Name (1 .. Last) = DLL_Name)
677 if not Do_Nothing then
678 Set_Writable (Filename);
681 Delete (Lib_Directory, Filename);
690 Change_Dir (Lib_ALI_Directory);
693 -- For each regular file in the directory, if switch -n has not
694 -- been specified, make it writable and delete the file if it is
695 -- any ALI file of a source of the project.
698 Read (Direc, Name, Last);
702 Filename : constant String := Name (1 .. Last);
704 if Is_Regular_File (Filename) then
705 Canonical_Case_File_Name (Name (1 .. Last));
706 Delete_File := False;
708 if Last > 4 and then Name (Last - 3 .. Last) = ".ali" then
712 -- Compare with ALI file names of the project
715 Index in 1 .. Unit_Table.Last (Project_Tree.Units)
717 Unit := Project_Tree.Units.Table (Index);
719 if Unit.File_Names (Body_Part).Project /=
722 if Ultimate_Extension_Of
723 (Unit.File_Names (Body_Part).Project) =
727 (Unit.File_Names (Body_Part).Name);
728 Name_Len := Name_Len -
730 (Name (1 .. Name_Len))'Length;
731 if Name_Buffer (1 .. Name_Len) =
739 elsif Ultimate_Extension_Of
740 (Unit.File_Names (Specification).Project) =
744 (Unit.File_Names (Specification).Name);
745 Name_Len := Name_Len -
747 (Name (1 .. Name_Len))'Length;
749 if Name_Buffer (1 .. Name_Len) =
761 if not Do_Nothing then
762 Set_Writable (Filename);
765 Delete (Lib_ALI_Directory, Filename);
773 -- Restore the initial working directory
775 Change_Dir (Current);
778 end Clean_Library_Directory;
784 procedure Clean_Project (Project : Project_Id) is
785 Main_Source_File : File_Name_Type;
786 -- Name of executable on the command line without directory info
788 Executable : File_Name_Type;
789 -- Name of the executable file
791 Current_Dir : constant Dir_Name_Str := Get_Current_Dir;
792 Data : constant Project_Data :=
793 Project_Tree.Projects.Table (Project);
795 File_Name1 : File_Name_Type;
797 File_Name2 : File_Name_Type;
799 Lib_File : File_Name_Type;
801 Source_Id : Other_Source_Id;
802 Source : Other_Source;
804 Global_Archive : Boolean := False;
807 -- Check that we don't specify executable on the command line for
808 -- a main library project.
810 if Project = Main_Project
811 and then Osint.Number_Of_Files /= 0
812 and then Data.Library
815 ("Cannot specify executable(s) for a Library Project File");
818 -- Nothing to clean in an externally built project
820 if Data.Externally_Built then
822 Put ("Nothing to do to clean externally built project """);
823 Put (Get_Name_String (Data.Name));
829 Put ("Cleaning project """);
830 Put (Get_Name_String (Data.Name));
834 -- Add project to the list of processed projects
836 Processed_Projects.Increment_Last;
837 Processed_Projects.Table (Processed_Projects.Last) := Project;
839 if Data.Object_Directory /= No_Path then
841 Obj_Dir : constant String :=
842 Get_Name_String (Data.Display_Object_Dir);
845 Change_Dir (Obj_Dir);
847 -- First, deal with Ada
849 -- Look through the units to find those that are either
850 -- immediate sources or inherited sources of the project.
851 -- Extending projects may have no language specified, if
852 -- Source_Dirs or Source_Files is specified as an empty list,
853 -- so always look for Ada units in extending projects.
855 if Data.Languages (Ada_Language_Index)
856 or else Data.Extends /= No_Project
858 for Unit in Unit_Table.First ..
859 Unit_Table.Last (Project_Tree.Units)
861 U_Data := Project_Tree.Units.Table (Unit);
862 File_Name1 := No_File;
863 File_Name2 := No_File;
865 -- If either the spec or the body is a source of the
866 -- project, check for the corresponding ALI file in the
869 if In_Extension_Chain
870 (U_Data.File_Names (Body_Part).Project, Project)
873 (U_Data.File_Names (Specification).Project, Project)
875 File_Name1 := U_Data.File_Names (Body_Part).Name;
876 Index1 := U_Data.File_Names (Body_Part).Index;
877 File_Name2 := U_Data.File_Names (Specification).Name;
878 Index2 := U_Data.File_Names (Specification).Index;
880 -- If there is no body file name, then there may be
883 if File_Name1 = No_File then
884 File_Name1 := File_Name2;
886 File_Name2 := No_File;
891 -- If there is either a spec or a body, look for files
892 -- in the object directory.
894 if File_Name1 /= No_File then
895 Lib_File := Osint.Lib_File_Name (File_Name1, Index1);
898 Asm : constant String :=
899 Assembly_File_Name (Lib_File);
900 ALI : constant String :=
901 ALI_File_Name (Lib_File);
902 Obj : constant String :=
903 Object_File_Name (Lib_File);
904 Adt : constant String :=
905 Tree_File_Name (Lib_File);
906 Deb : constant String :=
907 Debug_File_Name (File_Name1);
908 Rep : constant String :=
909 Repinfo_File_Name (File_Name1);
910 Del : Boolean := True;
913 -- If the ALI file exists and is read-only, no file
916 if Is_Regular_File (ALI) then
917 if Is_Writable_File (ALI) then
918 Delete (Obj_Dir, ALI);
927 if Obj_Dir (Obj_Dir'Last) /=
934 Put_Line (""" is read-only");
943 if Is_Regular_File (Obj) then
944 Delete (Obj_Dir, Obj);
949 if Is_Regular_File (Asm) then
950 Delete (Obj_Dir, Asm);
955 if Is_Regular_File (Adt) then
956 Delete (Obj_Dir, Adt);
959 -- First expanded source file
961 if Is_Regular_File (Deb) then
962 Delete (Obj_Dir, Deb);
967 if Is_Regular_File (Rep) then
968 Delete (Obj_Dir, Rep);
971 -- Second expanded source file
973 if File_Name2 /= No_File then
975 Deb : constant String :=
976 Debug_File_Name (File_Name2);
977 Rep : constant String :=
978 Repinfo_File_Name (File_Name2);
981 if Is_Regular_File (Deb) then
982 Delete (Obj_Dir, Deb);
985 if Is_Regular_File (Rep) then
986 Delete (Obj_Dir, Rep);
996 -- Check if a global archive and it dependency file could have
997 -- been created and, if they exist, delete them.
999 if Project = Main_Project and then not Data.Library then
1000 Global_Archive := False;
1002 for Proj in Project_Table.First ..
1003 Project_Table.Last (Project_Tree.Projects)
1005 if Project_Tree.Projects.Table
1006 (Proj).Other_Sources_Present
1008 Global_Archive := True;
1013 if Global_Archive then
1014 Clean_Archive (Project);
1018 if Data.Other_Sources_Present then
1020 -- There is non-Ada code: delete the object files and
1021 -- the dependency files if they exist.
1023 Source_Id := Data.First_Other_Source;
1024 while Source_Id /= No_Other_Source loop
1026 Project_Tree.Other_Sources.Table (Source_Id);
1029 (Get_Name_String (Source.Object_Name))
1031 Delete (Obj_Dir, Get_Name_String (Source.Object_Name));
1035 Is_Regular_File (Get_Name_String (Source.Dep_Name))
1037 Delete (Obj_Dir, Get_Name_String (Source.Dep_Name));
1040 Source_Id := Source.Next;
1043 -- If it is a library with only non Ada sources, delete
1044 -- the fake archive and the dependency file, if they exist.
1047 and then not Data.Languages (Ada_Language_Index)
1049 Clean_Archive (Project);
1055 -- If this is a library project, clean the library directory, the
1056 -- interface copy dir and, for a Stand-Alone Library, the binder
1057 -- generated files of the library.
1059 -- The directories are cleaned only if switch -c is not specified
1061 if Data.Library then
1062 if not Compile_Only then
1063 Clean_Library_Directory (Project);
1065 if Data.Library_Src_Dir /= No_Path then
1066 Clean_Interface_Copy_Directory (Project);
1070 if Data.Standalone_Library and then
1071 Data.Object_Directory /= No_Path
1073 Delete_Binder_Generated_Files
1074 (Get_Name_String (Data.Display_Object_Dir),
1079 if Verbose_Mode then
1084 -- If switch -r is specified, call Clean_Project recursively for the
1085 -- imported projects and the project being extended.
1087 if All_Projects then
1089 Imported : Project_List := Data.Imported_Projects;
1090 Element : Project_Element;
1094 -- For each imported project, call Clean_Project if the project
1095 -- has not been processed already.
1097 while Imported /= Empty_Project_List loop
1098 Element := Project_Tree.Project_Lists.Table (Imported);
1099 Imported := Element.Next;
1103 J in Processed_Projects.First .. Processed_Projects.Last
1105 if Element.Project = Processed_Projects.Table (J) then
1112 Clean_Project (Element.Project);
1116 -- If this project extends another project, call Clean_Project for
1117 -- the project being extended. It is guaranteed that it has not
1118 -- called before, because no other project may import or extend
1121 if Data.Extends /= No_Project then
1122 Clean_Project (Data.Extends);
1127 -- For the main project, delete the executables and the binder
1130 -- The executables are deleted only if switch -c is not specified
1132 if Project = Main_Project and then Data.Exec_Directory /= No_Path then
1134 Exec_Dir : constant String :=
1135 Get_Name_String (Data.Display_Exec_Dir);
1138 Change_Dir (Exec_Dir);
1140 for N_File in 1 .. Osint.Number_Of_Files loop
1141 Main_Source_File := Next_Main_Source;
1143 if not Compile_Only then
1149 Current_File_Index);
1152 Exec_File_Name : constant String :=
1153 Get_Name_String (Executable);
1156 if Is_Absolute_Path (Name => Exec_File_Name) then
1157 if Is_Regular_File (Exec_File_Name) then
1158 Delete ("", Exec_File_Name);
1162 if Is_Regular_File (Exec_File_Name) then
1163 Delete (Exec_Dir, Exec_File_Name);
1169 if Data.Object_Directory /= No_Path then
1170 Delete_Binder_Generated_Files
1171 (Get_Name_String (Data.Display_Object_Dir),
1172 Strip_Suffix (Main_Source_File));
1178 -- Change back to previous directory
1180 Change_Dir (Current_Dir);
1183 ---------------------
1184 -- Debug_File_Name --
1185 ---------------------
1187 function Debug_File_Name (Source : File_Name_Type) return String is
1189 return Get_Name_String (Source) & Debug_Suffix;
1190 end Debug_File_Name;
1196 procedure Delete (In_Directory : String; File : String) is
1197 Full_Name : String (1 .. In_Directory'Length + File'Length + 1);
1198 Last : Natural := 0;
1202 -- Indicate that at least one file is deleted or is to be deleted
1204 File_Deleted := True;
1206 -- Build the path name of the file to delete
1208 Last := In_Directory'Length;
1209 Full_Name (1 .. Last) := In_Directory;
1211 if Last > 0 and then Full_Name (Last) /= Directory_Separator then
1213 Full_Name (Last) := Directory_Separator;
1216 Full_Name (Last + 1 .. Last + File'Length) := File;
1217 Last := Last + File'Length;
1219 -- If switch -n was used, simply output the path name
1222 Put_Line (Full_Name (1 .. Last));
1224 -- Otherwise, delete the file if it is writable
1228 or else Is_Writable_File (Full_Name (1 .. Last))
1230 Delete_File (Full_Name (1 .. Last), Success);
1235 if Verbose_Mode or else not Quiet_Output then
1237 Put ("Warning: """);
1238 Put (Full_Name (1 .. Last));
1239 Put_Line (""" could not be deleted");
1243 Put (Full_Name (1 .. Last));
1244 Put_Line (""" has been deleted");
1250 -----------------------------------
1251 -- Delete_Binder_Generated_Files --
1252 -----------------------------------
1254 procedure Delete_Binder_Generated_Files
1256 Source : File_Name_Type)
1258 Source_Name : constant String := Get_Name_String (Source);
1259 Current : constant String := Get_Current_Dir;
1260 Last : constant Positive := B_Start'Length + Source_Name'Length;
1261 File_Name : String (1 .. Last + 4);
1266 -- Build the file name (before the extension)
1268 File_Name (1 .. B_Start'Length) := B_Start.all;
1269 File_Name (B_Start'Length + 1 .. Last) := Source_Name;
1273 File_Name (Last + 1 .. Last + 4) := ".ads";
1275 if Is_Regular_File (File_Name (1 .. Last + 4)) then
1276 Delete (Dir, File_Name (1 .. Last + 4));
1281 File_Name (Last + 1 .. Last + 4) := ".adb";
1283 if Is_Regular_File (File_Name (1 .. Last + 4)) then
1284 Delete (Dir, File_Name (1 .. Last + 4));
1289 File_Name (Last + 1 .. Last + 4) := ".ali";
1291 if Is_Regular_File (File_Name (1 .. Last + 4)) then
1292 Delete (Dir, File_Name (1 .. Last + 4));
1297 File_Name (Last + 1 .. Last + Object_Suffix'Length) := Object_Suffix;
1299 if Is_Regular_File (File_Name (1 .. Last + Object_Suffix'Length)) then
1300 Delete (Dir, File_Name (1 .. Last + Object_Suffix'Length));
1303 -- Change back to previous directory
1305 Change_Dir (Current);
1306 end Delete_Binder_Generated_Files;
1308 -----------------------
1309 -- Display_Copyright --
1310 -----------------------
1312 procedure Display_Copyright is
1314 if not Copyright_Displayed then
1315 Copyright_Displayed := True;
1317 ("GNATCLEAN " & Gnatvsn.Gnat_Version_String
1318 & " Copyright 2003-"
1320 & " Free Software Foundation, Inc.");
1322 end Display_Copyright;
1328 function Empty_Q return Boolean is
1330 return Q_Front >= Q.Last;
1333 --------------------
1334 -- Extract_From_Q --
1335 --------------------
1337 procedure Extract_From_Q (Lib_File : out File_Name_Type) is
1338 Lib : constant File_Name_Type := Q.Table (Q_Front);
1340 Q_Front := Q_Front + 1;
1348 procedure Gnatclean is
1350 -- Do the necessary initializations
1354 -- Parse the command line, getting the switches and the executable names
1358 if Verbose_Mode then
1362 if Project_File_Name /= null then
1364 -- A project file was specified by a -P switch
1366 if Opt.Verbose_Mode then
1368 Put ("Parsing Project File """);
1369 Put (Project_File_Name.all);
1374 -- Set the project parsing verbosity to whatever was specified
1375 -- by a possible -vP switch.
1377 Prj.Pars.Set_Verbosity (To => Current_Verbosity);
1379 -- Parse the project file. If there is an error, Main_Project
1380 -- will still be No_Project.
1383 (Project => Main_Project,
1384 In_Tree => Project_Tree,
1385 Project_File_Name => Project_File_Name.all,
1386 Packages_To_Check => Packages_To_Check_By_Gnatmake);
1388 if Main_Project = No_Project then
1389 Fail ("""" & Project_File_Name.all & """ processing failed");
1392 if Opt.Verbose_Mode then
1394 Put ("Parsing of Project File """);
1395 Put (Project_File_Name.all);
1396 Put (""" is finished.");
1400 -- Add source directories and object directories to the search paths
1402 Add_Source_Directories (Main_Project, Project_Tree);
1403 Add_Object_Directories (Main_Project, Project_Tree);
1406 Osint.Add_Default_Search_Dirs;
1408 -- If a project file was specified, but no executable name, put all
1409 -- the mains of the project file (if any) as if there were on the
1412 if Main_Project /= No_Project and then Osint.Number_Of_Files = 0 then
1414 Value : String_List_Id :=
1415 Project_Tree.Projects.Table (Main_Project).Mains;
1416 Main : String_Element;
1418 while Value /= Prj.Nil_String loop
1419 Main := Project_Tree.String_Elements.Table (Value);
1421 (File_Name => Get_Name_String (Main.Value),
1422 Index => Main.Index);
1428 -- If neither a project file nor an executable were specified,
1429 -- output the usage and exit.
1431 if Main_Project = No_Project and then Osint.Number_Of_Files = 0 then
1436 if Verbose_Mode then
1440 if Main_Project /= No_Project then
1442 -- If a project file has been specified, call Clean_Project with the
1443 -- project id of this project file, after resetting the list of
1444 -- processed projects.
1446 Processed_Projects.Init;
1447 Clean_Project (Main_Project);
1450 -- If no project file has been specified, the work is done in
1451 -- Clean_Executables.
1456 -- In verbose mode, if Delete has not been called, indicate that
1457 -- no file needs to be deleted.
1459 if Verbose_Mode and (not File_Deleted) then
1463 Put_Line ("No file needs to be deleted");
1465 Put_Line ("No file has been deleted");
1470 ------------------------
1471 -- In_Extension_Chain --
1472 ------------------------
1474 function In_Extension_Chain
1475 (Of_Project : Project_Id;
1476 Prj : Project_Id) return Boolean
1478 Data : Project_Data;
1481 if Prj = No_Project or else Of_Project = No_Project then
1485 if Of_Project = Prj then
1489 Data := Project_Tree.Projects.Table (Of_Project);
1491 while Data.Extends /= No_Project loop
1492 if Data.Extends = Prj then
1496 Data := Project_Tree.Projects.Table (Data.Extends);
1499 Data := Project_Tree.Projects.Table (Prj);
1501 while Data.Extends /= No_Project loop
1502 if Data.Extends = Of_Project then
1506 Data := Project_Tree.Projects.Table (Data.Extends);
1510 end In_Extension_Chain;
1519 Q.Set_Last (Q.First);
1526 procedure Initialize is
1528 if not Initialized then
1529 Initialized := True;
1531 -- Get default search directories to locate system.ads when calling
1532 -- Targparm.Get_Target_Parameters.
1534 Osint.Add_Default_Search_Dirs;
1536 -- Initialize some packages
1541 Prj.Initialize (Project_Tree);
1543 -- Check if the platform is VMS and, if it is, change some variables
1545 Targparm.Get_Target_Parameters;
1547 if OpenVMS_On_Target then
1548 Debug_Suffix (Debug_Suffix'First) := '_';
1549 Repinfo_Suffix (Repinfo_Suffix'First) := '_';
1550 B_Start := new String'("b__");
1554 -- Reset global variables
1556 Free (Object_Directory_Path);
1557 Do_Nothing := False;
1558 File_Deleted := False;
1559 Copyright_Displayed := False;
1560 Usage_Displayed := False;
1561 Free (Project_File_Name);
1562 Main_Project := Prj.No_Project;
1563 All_Projects := False;
1570 procedure Insert_Q (Lib_File : File_Name_Type) is
1572 -- Do not insert an empty name or an already marked source
1574 if Lib_File /= No_File and then not Makeutl.Is_Marked (Lib_File) then
1575 Q.Table (Q.Last) := Lib_File;
1578 -- Mark the source that has been just added to the Q
1580 Makeutl.Mark (Lib_File);
1584 ----------------------
1585 -- Object_File_Name --
1586 ----------------------
1588 function Object_File_Name (Source : File_Name_Type) return String is
1589 Src : constant String := Get_Name_String (Source);
1592 -- If the source name has an extension, then replace it with
1593 -- the Object suffix.
1595 for Index in reverse Src'First + 1 .. Src'Last loop
1596 if Src (Index) = '.' then
1597 return Src (Src'First .. Index - 1) & Object_Suffix;
1601 -- If there is no dot, or if it is the first character, just add the
1604 return Src & Object_Suffix;
1605 end Object_File_Name;
1607 --------------------
1608 -- Parse_Cmd_Line --
1609 --------------------
1611 procedure Parse_Cmd_Line is
1612 Last : constant Natural := Argument_Count;
1613 Source_Index : Int := 0;
1614 Index : Positive := 1;
1617 while Index <= Last loop
1619 Arg : constant String := Argument (Index);
1621 procedure Bad_Argument;
1622 -- Signal bad argument
1628 procedure Bad_Argument is
1630 Fail ("invalid argument """, Arg, """");
1634 if Arg'Length /= 0 then
1635 if Arg (1) = '-' then
1636 if Arg'Length = 1 then
1642 if Arg'Length < 4 then
1646 if Arg (3) = 'O' then
1647 Add_Lib_Search_Dir (Arg (4 .. Arg'Last));
1649 elsif Arg (3) = 'P' then
1650 Prj.Ext.Add_Search_Project_Directory
1651 (Arg (4 .. Arg'Last));
1658 Compile_Only := True;
1661 if Object_Directory_Path /= null then
1662 Fail ("duplicate -D switch");
1664 elsif Project_File_Name /= null then
1665 Fail ("-P and -D cannot be used simultaneously");
1668 if Arg'Length > 2 then
1670 Dir : constant String := Arg (3 .. Arg'Last);
1672 if not Is_Directory (Dir) then
1673 Fail (Dir, " is not a directory");
1675 Add_Lib_Search_Dir (Dir);
1680 if Index = Last then
1681 Fail ("no directory specified after -D");
1687 Dir : constant String := Argument (Index);
1689 if not Is_Directory (Dir) then
1690 Fail (Dir, " is not a directory");
1692 Add_Lib_Search_Dir (Dir);
1698 Force_Deletions := True;
1701 Full_Path_Name_For_Brief_Errors := True;
1707 if Arg'Length = 2 then
1713 for J in 3 .. Arg'Last loop
1714 if Arg (J) not in '0' .. '9' then
1719 (20 * Source_Index) +
1720 (Character'Pos (Arg (J)) - Character'Pos ('0'));
1725 Opt.Look_In_Primary_Dir := False;
1728 if Arg'Length = 2 then
1732 Add_Lib_Search_Dir (Arg (3 .. Arg'Last));
1739 if Project_File_Name /= null then
1740 Fail ("multiple -P switches");
1742 elsif Object_Directory_Path /= null then
1743 Fail ("-D and -P cannot be used simultaneously");
1747 if Arg'Length > 2 then
1749 Prj : constant String := Arg (3 .. Arg'Last);
1751 if Prj'Length > 1 and then
1752 Prj (Prj'First) = '='
1754 Project_File_Name :=
1756 (Prj (Prj'First + 1 .. Prj'Last));
1758 Project_File_Name := new String'(Prj);
1763 if Index = Last then
1764 Fail ("no project specified after -P");
1768 Project_File_Name := new String'(Argument (Index));
1772 Quiet_Output := True;
1775 All_Projects := True;
1779 Verbose_Mode := True;
1781 elsif Arg = "-vP0" then
1782 Current_Verbosity := Prj.Default;
1784 elsif Arg = "-vP1" then
1785 Current_Verbosity := Prj.Medium;
1787 elsif Arg = "-vP2" then
1788 Current_Verbosity := Prj.High;
1795 if Arg'Length = 2 then
1800 Ext_Asgn : constant String := Arg (3 .. Arg'Last);
1801 Start : Positive := Ext_Asgn'First;
1802 Stop : Natural := Ext_Asgn'Last;
1803 Equal_Pos : Natural;
1804 OK : Boolean := True;
1807 if Ext_Asgn (Start) = '"' then
1808 if Ext_Asgn (Stop) = '"' then
1819 while Equal_Pos <= Stop
1820 and then Ext_Asgn (Equal_Pos) /= '='
1822 Equal_Pos := Equal_Pos + 1;
1825 if Equal_Pos = Start or else Equal_Pos > Stop then
1832 Ext_Asgn (Start .. Equal_Pos - 1),
1834 Ext_Asgn (Equal_Pos + 1 .. Stop));
1838 ("illegal external assignment '",
1848 Add_File (Arg, Source_Index);
1857 -----------------------
1858 -- Repinfo_File_Name --
1859 -----------------------
1861 function Repinfo_File_Name (Source : File_Name_Type) return String is
1863 return Get_Name_String (Source) & Repinfo_Suffix;
1864 end Repinfo_File_Name;
1866 --------------------
1867 -- Tree_File_Name --
1868 --------------------
1870 function Tree_File_Name (Source : File_Name_Type) return String is
1871 Src : constant String := Get_Name_String (Source);
1874 -- If the source name has an extension, then replace it with
1877 for Index in reverse Src'First + 1 .. Src'Last loop
1878 if Src (Index) = '.' then
1879 return Src (Src'First .. Index - 1) & Tree_Suffix;
1883 -- If there is no dot, or if it is the first character, just add the
1886 return Src & Tree_Suffix;
1889 ---------------------------
1890 -- Ultimate_Extension_Of --
1891 ---------------------------
1893 function Ultimate_Extension_Of (Project : Project_Id) return Project_Id is
1894 Result : Project_Id := Project;
1895 Data : Project_Data;
1898 if Project /= No_Project then
1900 Data := Project_Tree.Projects.Table (Result);
1901 exit when Data.Extended_By = No_Project;
1902 Result := Data.Extended_By;
1907 end Ultimate_Extension_Of;
1915 if not Usage_Displayed then
1916 Usage_Displayed := True;
1918 Put_Line ("Usage: gnatclean [switches] {[-innn] name}");
1921 Put_Line (" names is one or more file names from which " &
1922 "the .adb or .ads suffix may be omitted");
1923 Put_Line (" names may be omitted if -P<project> is specified");
1926 Put_Line (" -c Only delete compiler generated files");
1927 Put_Line (" -D dir Specify dir as the object library");
1928 Put_Line (" -f Force deletions of unwritable files");
1929 Put_Line (" -F Full project path name " &
1930 "in brief error messages");
1931 Put_Line (" -h Display this message");
1932 Put_Line (" -innn Index of unit in source for following names");
1933 Put_Line (" -n Nothing to do: only list files to delete");
1934 Put_Line (" -Pproj Use GNAT Project File proj");
1935 Put_Line (" -q Be quiet/terse");
1936 Put_Line (" -r Clean all projects recursively");
1937 Put_Line (" -v Verbose mode");
1938 Put_Line (" -vPx Specify verbosity when parsing " &
1939 "GNAT Project Files");
1940 Put_Line (" -Xnm=val Specify an external reference " &
1941 "for GNAT Project Files");
1944 Put_Line (" -aOdir Specify ALI/object files search path");
1945 Put_Line (" -Idir Like -aOdir");
1946 Put_Line (" -I- Don't look for source/library files " &
1947 "in the default directory");