1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
9 -- Copyright (C) 2004-2008, 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 3, 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 COPYING3. If not, go to --
19 -- http://www.gnu.org/licenses for a complete copy of the license. --
21 -- GNAT was originally developed by the GNAT team at New York University. --
22 -- Extensive contributions were provided by Ada Core Technologies Inc. --
24 ------------------------------------------------------------------------------
28 with Hostparm; use Hostparm;
29 with Makeutl; use Makeutl;
30 with MLib.Tgt; use MLib.Tgt;
31 with Namet; use Namet;
32 with Output; use Output;
34 with Osint; use Osint;
36 with Prj.Ext; use Prj.Ext;
38 with Prj.Util; use Prj.Util;
39 with Snames; use Snames;
41 with Types; use Types;
43 with Ada.Command_Line; use Ada.Command_Line;
44 with Ada.Strings.Fixed; use Ada.Strings.Fixed;
45 with Ada.Text_IO; use Ada.Text_IO;
46 with Ada.Unchecked_Deallocation;
48 with GNAT.Directory_Operations; use GNAT.Directory_Operations;
49 with GNAT.Dynamic_Tables;
50 with GNAT.Expect; use GNAT.Expect;
52 with GNAT.OS_Lib; use GNAT.OS_Lib;
53 with GNAT.Regpat; use GNAT.Regpat;
56 with System.Case_Util; use System.Case_Util;
58 package body Makegpr is
60 On_Windows : constant Boolean := Directory_Separator = '\';
61 -- True when on Windows. Used in Check_Compilation_Needed when processing
62 -- C/C++ dependency files for backslash handling.
64 Max_In_Archives : constant := 50;
65 -- The maximum number of arguments for a single invocation of the
66 -- Archive Indexer (ar).
68 No_Argument : aliased Argument_List := (1 .. 0 => null);
69 -- Null argument list representing case of no arguments
71 FD : Process_Descriptor;
72 -- The process descriptor used when invoking a non GNU compiler with -M
73 -- and getting the output with GNAT.Expect.
75 Line_Matcher : constant Pattern_Matcher := Compile ("^.*?\n", Single_Line);
76 -- Pattern for GNAT.Expect for the invocation of a non GNU compiler with -M
79 Name_Compiler_Command : Name_Id;
80 -- Names of package IDE and its attribute Compiler_Command.
81 -- Set up by Initialize.
83 Unique_Compile : Boolean := False;
84 -- True when switch -u is used on the command line
86 type Source_Index_Rec is record
89 Found : Boolean := False;
91 -- Used as Source_Indexes component to check if archive needs to be rebuilt
93 type Source_Index_Array is array (Positive range <>) of Source_Index_Rec;
94 type Source_Indexes_Ref is access Source_Index_Array;
96 procedure Free is new Ada.Unchecked_Deallocation
97 (Source_Index_Array, Source_Indexes_Ref);
99 Initial_Source_Index_Count : constant Positive := 20;
100 Source_Indexes : Source_Indexes_Ref :=
101 new Source_Index_Array (1 .. Initial_Source_Index_Count);
102 -- A list of the Other_Source_Ids of a project file, with an indication
103 -- that they have been found in the archive dependency file.
105 Last_Source : Natural := 0;
106 -- The index of the last valid component of Source_Indexes
108 Compiler_Names : array (First_Language_Indexes) of String_Access;
109 -- The names of the compilers to be used. Set up by Get_Compiler.
110 -- Used to display the commands spawned.
112 Gnatmake_String : constant String_Access := new String'("gnatmake");
113 GCC_String : constant String_Access := new String'("gcc");
114 G_Plus_Plus_String : constant String_Access := new String'("g++");
116 Default_Compiler_Names : constant array
117 (First_Language_Indexes range
118 Ada_Language_Index .. C_Plus_Plus_Language_Index)
120 (Ada_Language_Index => Gnatmake_String,
121 C_Language_Index => GCC_String,
122 C_Plus_Plus_Language_Index => G_Plus_Plus_String);
124 Compiler_Paths : array (First_Language_Indexes) of String_Access;
125 -- The path names of the compiler to be used. Set up by Get_Compiler.
126 -- Used to spawn compiling/linking processes.
128 Compiler_Is_Gcc : array (First_Language_Indexes) of Boolean;
129 -- An indication that a compiler is a GCC compiler, to be able to use
130 -- specific GCC switches.
132 Archive_Builder_Path : String_Access := null;
133 -- The path name of the archive builder (ar). To be used when spawning
136 Archive_Indexer_Path : String_Access := null;
137 -- The path name of the archive indexer (ranlib), if it exists
139 Copyright_Output : Boolean := False;
140 Usage_Output : Boolean := False;
141 -- Flags to avoid multiple displays of Copyright notice and of Usage
143 Output_File_Name : String_Access := null;
144 -- The name given after a switch -o
146 Output_File_Name_Expected : Boolean := False;
147 -- True when last switch was -o
149 Project_File_Name : String_Access := null;
150 -- The name of the project file specified with switch -P
152 Project_File_Name_Expected : Boolean := False;
153 -- True when last switch was -P
155 Naming_String : aliased String := "naming";
156 Builder_String : aliased String := "builder";
157 Compiler_String : aliased String := "compiler";
158 Binder_String : aliased String := "binder";
159 Linker_String : aliased String := "linker";
160 -- Name of packages to be checked when parsing/processing project files
162 List_Of_Packages : aliased String_List :=
163 (Naming_String 'Access,
164 Builder_String 'Access,
165 Compiler_String 'Access,
166 Binder_String 'Access,
167 Linker_String 'Access);
168 Packages_To_Check : constant String_List_Access := List_Of_Packages'Access;
169 -- List of the packages to be checked when parsing/processing project files
171 Project_Tree : constant Project_Tree_Ref := new Project_Tree_Data;
173 Main_Project : Project_Id;
174 -- The project id of the main project
176 type Processor is (None, Linker, Compiler);
177 Current_Processor : Processor := None;
178 -- This variable changes when switches -*args are used
180 Current_Language : Language_Index := Ada_Language_Index;
181 -- The compiler language to consider when Processor is Compiler
183 package Comp_Opts is new GNAT.Dynamic_Tables
184 (Table_Component_Type => String_Access,
185 Table_Index_Type => Integer,
186 Table_Low_Bound => 1,
188 Table_Increment => 100);
189 Options : array (First_Language_Indexes) of Comp_Opts.Instance;
190 -- Tables to store compiling options for the different compilers
192 package Linker_Options is new Table.Table
193 (Table_Component_Type => String_Access,
194 Table_Index_Type => Integer,
195 Table_Low_Bound => 1,
197 Table_Increment => 100,
198 Table_Name => "Makegpr.Linker_Options");
199 -- Table to store the linking options
201 package Library_Opts is new Table.Table
202 (Table_Component_Type => String_Access,
203 Table_Index_Type => Integer,
204 Table_Low_Bound => 1,
206 Table_Increment => 100,
207 Table_Name => "Makegpr.Library_Opts");
208 -- Table to store the linking options
210 package Ada_Mains is new Table.Table
211 (Table_Component_Type => String_Access,
212 Table_Index_Type => Integer,
213 Table_Low_Bound => 1,
215 Table_Increment => 100,
216 Table_Name => "Makegpr.Ada_Mains");
217 -- Table to store the Ada mains, either specified on the command line
218 -- or found in attribute Main of the main project file.
220 package Other_Mains is new Table.Table
221 (Table_Component_Type => Other_Source,
222 Table_Index_Type => Integer,
223 Table_Low_Bound => 1,
225 Table_Increment => 100,
226 Table_Name => "Makegpr.Other_Mains");
227 -- Table to store the mains of languages other than Ada, either specified
228 -- on the command line or found in attribute Main of the main project file.
230 package Sources_Compiled is new GNAT.HTable.Simple_HTable
231 (Header_Num => Header_Num,
234 Key => File_Name_Type,
238 package Saved_Switches is new Table.Table
239 (Table_Component_Type => String_Access,
240 Table_Index_Type => Integer,
241 Table_Low_Bound => 1,
243 Table_Increment => 100,
244 Table_Name => "Makegpr.Saved_Switches");
245 -- Table to store the switches to be passed to gnatmake
247 Initial_Argument_Count : constant Positive := 20;
248 type Boolean_Array is array (Positive range <>) of Boolean;
249 type Booleans is access Boolean_Array;
251 procedure Free is new Ada.Unchecked_Deallocation (Boolean_Array, Booleans);
253 Arguments : Argument_List_Access :=
254 new Argument_List (1 .. Initial_Argument_Count);
255 -- Used to store lists of arguments to be used when spawning a process
257 Arguments_Displayed : Booleans :=
258 new Boolean_Array (1 .. Initial_Argument_Count);
259 -- For each argument in Arguments, indicate if the argument should be
260 -- displayed when procedure Display_Command is called.
262 Last_Argument : Natural := 0;
263 -- Index of the last valid argument in Arguments
265 package Cache_Args is new Table.Table
266 (Table_Component_Type => String_Access,
267 Table_Index_Type => Integer,
268 Table_Low_Bound => 1,
269 Table_Initial => 200,
270 Table_Increment => 100,
271 Table_Name => "Makegpr.Cache_Args");
272 -- A table to cache arguments, to avoid multiple allocation of the same
273 -- strings. It is not possible to use a hash table, because String is
274 -- an unconstrained type.
276 -- Various switches used when spawning processes:
278 Dash_B_String : aliased String := "-B";
279 Dash_B : constant String_Access := Dash_B_String'Access;
280 Dash_c_String : aliased String := "-c";
281 Dash_c : constant String_Access := Dash_c_String'Access;
282 Dash_cargs_String : aliased String := "-cargs";
283 Dash_cargs : constant String_Access := Dash_cargs_String'Access;
284 Dash_d_String : aliased String := "-d";
285 Dash_d : constant String_Access := Dash_d_String'Access;
286 Dash_eL_String : aliased String := "-eL";
287 Dash_eL : constant String_Access := Dash_eL_String'Access;
288 Dash_f_String : aliased String := "-f";
289 Dash_f : constant String_Access := Dash_f_String'Access;
290 Dash_k_String : aliased String := "-k";
291 Dash_k : constant String_Access := Dash_k_String'Access;
292 Dash_largs_String : aliased String := "-largs";
293 Dash_largs : constant String_Access := Dash_largs_String'Access;
294 Dash_M_String : aliased String := "-M";
295 Dash_M : constant String_Access := Dash_M_String'Access;
296 Dash_margs_String : aliased String := "-margs";
297 Dash_margs : constant String_Access := Dash_margs_String'Access;
298 Dash_o_String : aliased String := "-o";
299 Dash_o : constant String_Access := Dash_o_String'Access;
300 Dash_P_String : aliased String := "-P";
301 Dash_P : constant String_Access := Dash_P_String'Access;
302 Dash_q_String : aliased String := "-q";
303 Dash_q : constant String_Access := Dash_q_String'Access;
304 Dash_u_String : aliased String := "-u";
305 Dash_u : constant String_Access := Dash_u_String'Access;
306 Dash_v_String : aliased String := "-v";
307 Dash_v : constant String_Access := Dash_v_String'Access;
308 Dash_vP1_String : aliased String := "-vP1";
309 Dash_vP1 : constant String_Access := Dash_vP1_String'Access;
310 Dash_vP2_String : aliased String := "-vP2";
311 Dash_vP2 : constant String_Access := Dash_vP2_String'Access;
312 Dash_x_String : aliased String := "-x";
313 Dash_x : constant String_Access := Dash_x_String'Access;
314 r_String : aliased String := "r";
315 r : constant String_Access := r_String'Access;
317 CPATH : constant String := "CPATH";
318 -- The environment variable to set when compiler is a GCC compiler
319 -- to indicate the include directory path.
321 Current_Include_Paths : array (First_Language_Indexes) of String_Access;
322 -- A cache for the paths of included directories, to avoid setting
323 -- env var CPATH unnecessarily.
325 C_Plus_Plus_Is_Used : Boolean := False;
326 -- True when there are sources in C++
328 Link_Options_Switches : Argument_List_Access := null;
329 -- The link options coming from the attributes Linker'Linker_Options in
330 -- project files imported, directly or indirectly, by the main project.
332 Total_Number_Of_Errors : Natural := 0;
333 -- Used when Keep_Going is True (switch -k) to keep the total number
334 -- of compilation/linking errors, to report at the end of execution.
336 Need_To_Rebuild_Global_Archive : Boolean := False;
338 Error_Header : constant String := "*** ERROR: ";
339 -- The beginning of error message, when Keep_Going is True
341 Need_To_Relink : Boolean := False;
342 -- True when an executable of a language other than Ada need to be linked
344 Global_Archive_Exists : Boolean := False;
345 -- True if there is a non empty global archive, to prevent creation
348 Path_Option : String_Access;
349 -- The path option switch, when supported
351 Project_Of_Current_Object_Directory : Project_Id := No_Project;
352 -- The object directory of the project for the last compilation. Avoid
353 -- calling Change_Dir if the current working directory is already this
356 package Lib_Path is new Table.Table
357 (Table_Component_Type => Character,
358 Table_Index_Type => Integer,
359 Table_Low_Bound => 1,
360 Table_Initial => 200,
361 Table_Increment => 100,
362 Table_Name => "Makegpr.Lib_Path");
363 -- A table to compute the path to put in the path option switch, when it
366 procedure Add_Archives (For_Gnatmake : Boolean);
367 -- Add to Arguments the list of archives for linking an executable
369 procedure Add_Argument (Arg : String_Access; Display : Boolean);
370 procedure Add_Argument (Arg : String; Display : Boolean);
371 -- Add an argument to Arguments. Reallocate if necessary
373 procedure Add_Arguments (Args : Argument_List; Display : Boolean);
374 -- Add a list of arguments to Arguments. Reallocate if necessary
376 procedure Add_Option (Arg : String);
377 -- Add a switch for the Ada, C or C++ compiler, or for the linker.
378 -- The table where this option is stored depends on the values of
379 -- Current_Processor and Current_Language.
381 procedure Add_Search_Directories
382 (Data : Project_Data;
383 Language : First_Language_Indexes);
384 -- Either add to the Arguments the necessary -I switches needed to
385 -- compile, or, when compiler is gcc/g++, set up the C*INCLUDE_PATH
386 -- environment variable, if necessary.
388 procedure Add_Source_Id (Project : Project_Id; Id : Other_Source_Id);
389 -- Add a source id to Source_Indexes, with Found set to False
391 procedure Add_Switches
392 (Data : Project_Data;
394 Language : Language_Index;
395 File_Name : File_Name_Type);
396 -- Add to Arguments the switches, if any, for a source (attribute Switches)
397 -- or language (attribute Default_Switches), coming from package Compiler
398 -- or Linker (depending on Proc) of a specified project file.
400 procedure Build_Global_Archive;
401 -- Build the archive for the main project
403 procedure Build_Library (Project : Project_Id; Unconditionally : Boolean);
404 -- Build the library for a library project. If Unconditionally is
405 -- False, first check if the library is up to date, and build it only
408 procedure Check (Option : String);
409 -- Check that a switch coming from a project file is not the concatenation
410 -- of several valid switch, for example "-g -v". If it is, issue a warning.
412 procedure Check_Archive_Builder;
413 -- Check if the archive builder (ar) is there
415 procedure Check_Compilation_Needed
416 (Source : Other_Source;
417 Need_To_Compile : out Boolean);
418 -- Check if a source of a language other than Ada needs to be compiled or
421 procedure Check_For_C_Plus_Plus;
422 -- Check if C++ is used in at least one project
425 (Source_Id : Other_Source_Id;
427 Local_Errors : in out Boolean);
428 -- Compile one non-Ada source
430 procedure Compile_Individual_Sources;
431 -- Compile the sources specified on the command line, when in
432 -- Unique_Compile mode.
434 procedure Compile_Link_With_Gnatmake (Mains_Specified : Boolean);
435 -- Compile/Link with gnatmake when there are Ada sources in the main
436 -- project. Arguments may already contain options to be used by
437 -- gnatmake. Used for both Ada mains and mains of other languages.
438 -- When Compile_Only is True, do not use the linking options
440 procedure Compile_Sources;
441 -- Compile the sources of languages other than Ada, if necessary
444 -- Output the Copyright notice
446 procedure Create_Archive_Dependency_File
448 First_Source : Other_Source_Id);
449 -- Create the archive dependency file for a library project
451 procedure Create_Global_Archive_Dependency_File (Name : String);
452 -- Create the archive dependency file for the main project
454 procedure Display_Command
456 Path : String_Access;
457 CPATH : String_Access := null;
458 Ellipse : Boolean := False);
459 -- Display the command for a spawned process, if in Verbose_Mode or not in
460 -- Quiet_Output. In non verbose mode, when Ellipse is True, display "..."
461 -- in place of the first argument that has Display set to False.
463 procedure Get_Compiler (For_Language : First_Language_Indexes);
464 -- Find the compiler name and path name for a specified programming
465 -- language, if not already done. Results are in the corresponding elements
466 -- of arrays Compiler_Names and Compiler_Paths. Name of compiler is found
467 -- in package IDE of the main project, or defaulted. Fail if compiler
468 -- cannot be found on the path. For the Ada language, gnatmake, rather than
469 -- the Ada compiler is returned.
471 procedure Get_Imported_Directories
472 (Project : Project_Id;
473 Data : in out Project_Data);
474 -- Find the necessary switches -I to be used when compiling sources of
475 -- languages other than Ada, in a specified project file. Cache the result
476 -- in component Imported_Directories_Switches of the project data. For
477 -- gcc/g++ compilers, get the value of the C*_INCLUDE_PATH, instead.
479 procedure Initialize;
480 -- Do the necessary package initialization and process the command line
483 function Is_Included_In_Global_Archive
484 (Object_Name : File_Name_Type;
485 Project : Project_Id) return Boolean;
486 -- Return True if the object Object_Name is not overridden by a source
487 -- in a project extending project Project.
489 procedure Link_Executables;
492 procedure Report_Error (S1 : String; S2 : String := ""; S3 : String := "");
493 -- Report an error. If Keep_Going is False, just call Osint.Fail. If
494 -- Keep_Going is True, display the error and increase the total number of
497 procedure Report_Total_Errors (Kind : String);
498 -- If Total_Number_Of_Errors is not zero, report it, and fail
500 procedure Scan_Arg (Arg : String);
501 -- Process one command line argument
503 function Strip_CR_LF (Text : String) return String;
504 -- Remove characters ASCII.CR and ASCII.LF from a String
513 procedure Add_Archives (For_Gnatmake : Boolean) is
514 Last_Arg : constant Natural := Last_Argument;
515 -- The position of the last argument before adding the archives. Used to
516 -- reverse the order of the arguments added when processing the
519 procedure Recursive_Add_Archives (Project : Project_Id);
520 -- Recursive procedure to add the archive of a project file, if any,
521 -- then call itself for the project imported.
523 ----------------------------
524 -- Recursive_Add_Archives --
525 ----------------------------
527 procedure Recursive_Add_Archives (Project : Project_Id) is
529 Imported : Project_List;
532 procedure Add_Archive_Path;
533 -- For a library project or the main project, add the archive
534 -- path to the arguments.
536 ----------------------
537 -- Add_Archive_Path --
538 ----------------------
540 procedure Add_Archive_Path is
541 Increment : Positive;
542 Prev_Last : Positive;
547 -- If it is a library project file, nothing to do if gnatmake
548 -- will be invoked, because gnatmake will take care of it, even
549 -- if the library is not an Ada library.
551 if not For_Gnatmake then
552 if Data.Library_Kind = Static then
554 (Get_Name_String (Data.Display_Library_Dir) &
555 Directory_Separator &
556 "lib" & Get_Name_String (Data.Library_Name) &
561 -- As we first insert in the reverse order,
562 -- -L<dir> is put after -l<lib>
565 ("-l" & Get_Name_String (Data.Library_Name),
568 Get_Name_String (Data.Display_Library_Dir);
571 ("-L" & Name_Buffer (1 .. Name_Len),
574 -- If there is a run path option, prepend this directory
575 -- to the library path. It is probable that the order of
576 -- the directories in the path option is not important,
577 -- but just in case put the directories in the same order
580 if Path_Option /= null then
582 -- If it is not the first directory, make room at the
583 -- beginning of the table, including for a path
586 if Lib_Path.Last > 0 then
587 Increment := Name_Len + 1;
588 Prev_Last := Lib_Path.Last;
589 Lib_Path.Set_Last (Prev_Last + Increment);
591 for Index in reverse 1 .. Prev_Last loop
592 Lib_Path.Table (Index + Increment) :=
593 Lib_Path.Table (Index);
596 Lib_Path.Table (Increment) := Path_Separator;
599 -- If it is the first directory, just set
600 -- Last to the length of the directory.
602 Lib_Path.Set_Last (Name_Len);
605 -- Put the directory at the beginning of the
608 for Index in 1 .. Name_Len loop
609 Lib_Path.Table (Index) := Name_Buffer (Index);
615 -- For a non-library project, the only archive needed is the one
616 -- for the main project, if there is one.
618 elsif Project = Main_Project and then Global_Archive_Exists then
620 (Get_Name_String (Data.Display_Object_Dir) &
621 Directory_Separator &
622 "lib" & Get_Name_String (Data.Display_Name)
626 end Add_Archive_Path;
629 -- Nothing to do when there is no project specified
631 if Project /= No_Project then
632 Data := Project_Tree.Projects.Table (Project);
634 -- Nothing to do if the project has already been processed
636 if not Data.Seen then
638 -- Mark the project as processed, to avoid processing it again
640 Project_Tree.Projects.Table (Project).Seen := True;
642 Recursive_Add_Archives (Data.Extends);
644 Imported := Data.Imported_Projects;
646 -- Call itself recursively for all imported projects
648 while Imported /= Empty_Project_List loop
649 Prj := Project_Tree.Project_Lists.Table
652 if Prj /= No_Project then
653 while Project_Tree.Projects.Table
654 (Prj).Extended_By /= No_Project
656 Prj := Project_Tree.Projects.Table
660 Recursive_Add_Archives (Prj);
663 Imported := Project_Tree.Project_Lists.Table
667 -- If there is sources of language other than Ada in this
668 -- project, add the path of the archive to Arguments.
670 if Project = Main_Project
671 or else Data.Other_Sources_Present
677 end Recursive_Add_Archives;
679 -- Start of processing for Add_Archives
682 -- First, mark all projects as not processed
684 for Project in Project_Table.First ..
685 Project_Table.Last (Project_Tree.Projects)
687 Project_Tree.Projects.Table (Project).Seen := False;
690 -- Take care of the run path option
692 if Path_Option = null then
693 Path_Option := MLib.Linker_Library_Path_Option;
696 Lib_Path.Set_Last (0);
698 -- Add archives in the reverse order
700 Recursive_Add_Archives (Main_Project);
702 -- And reverse the order
707 Temp : String_Access;
710 First := Last_Arg + 1;
711 Last := Last_Argument;
712 while First < Last loop
713 Temp := Arguments (First);
714 Arguments (First) := Arguments (Last);
715 Arguments (Last) := Temp;
726 procedure Add_Argument (Arg : String_Access; Display : Boolean) is
728 -- Nothing to do if no argument is specified or if argument is empty
730 if Arg /= null or else Arg'Length = 0 then
732 -- Reallocate arrays if necessary
734 if Last_Argument = Arguments'Last then
736 New_Arguments : constant Argument_List_Access :=
738 (1 .. Last_Argument +
739 Initial_Argument_Count);
741 New_Arguments_Displayed : constant Booleans :=
743 (1 .. Last_Argument +
744 Initial_Argument_Count);
747 New_Arguments (Arguments'Range) := Arguments.all;
749 -- To avoid deallocating the strings, nullify all components
750 -- of Arguments before calling Free.
752 Arguments.all := (others => null);
755 Arguments := New_Arguments;
757 New_Arguments_Displayed (Arguments_Displayed'Range) :=
758 Arguments_Displayed.all;
759 Free (Arguments_Displayed);
760 Arguments_Displayed := New_Arguments_Displayed;
764 -- Add the argument and its display indication
766 Last_Argument := Last_Argument + 1;
767 Arguments (Last_Argument) := Arg;
768 Arguments_Displayed (Last_Argument) := Display;
772 procedure Add_Argument (Arg : String; Display : Boolean) is
773 Argument : String_Access := null;
776 -- Nothing to do if argument is empty
778 if Arg'Length > 0 then
780 -- Check if the argument is already in the Cache_Args table.
781 -- If it is already there, reuse the allocated value.
783 for Index in 1 .. Cache_Args.Last loop
784 if Cache_Args.Table (Index).all = Arg then
785 Argument := Cache_Args.Table (Index);
790 -- If the argument is not in the cache, create a new entry in the
793 if Argument = null then
794 Argument := new String'(Arg);
795 Cache_Args.Increment_Last;
796 Cache_Args.Table (Cache_Args.Last) := Argument;
799 -- And add the argument
801 Add_Argument (Argument, Display);
809 procedure Add_Arguments (Args : Argument_List; Display : Boolean) is
811 -- Reallocate the arrays, if necessary
813 if Last_Argument + Args'Length > Arguments'Last then
815 New_Arguments : constant Argument_List_Access :=
817 (1 .. Last_Argument + Args'Length +
818 Initial_Argument_Count);
820 New_Arguments_Displayed : constant Booleans :=
822 (1 .. Last_Argument +
824 Initial_Argument_Count);
827 New_Arguments (1 .. Last_Argument) :=
828 Arguments (1 .. Last_Argument);
830 -- To avoid deallocating the strings, nullify all components
831 -- of Arguments before calling Free.
833 Arguments.all := (others => null);
836 Arguments := New_Arguments;
837 New_Arguments_Displayed (1 .. Last_Argument) :=
838 Arguments_Displayed (1 .. Last_Argument);
839 Free (Arguments_Displayed);
840 Arguments_Displayed := New_Arguments_Displayed;
844 -- Add the new arguments and the display indications
846 Arguments (Last_Argument + 1 .. Last_Argument + Args'Length) := Args;
847 Arguments_Displayed (Last_Argument + 1 .. Last_Argument + Args'Length) :=
849 Last_Argument := Last_Argument + Args'Length;
856 procedure Add_Option (Arg : String) is
857 Option : constant String_Access := new String'(Arg);
860 case Current_Processor is
866 -- Add option to the linker table
868 Linker_Options.Increment_Last;
869 Linker_Options.Table (Linker_Options.Last) := Option;
873 -- Add option to the compiler option table, depending on the
874 -- value of Current_Language.
876 Comp_Opts.Increment_Last (Options (Current_Language));
877 Options (Current_Language).Table
878 (Comp_Opts.Last (Options (Current_Language))) := Option;
887 procedure Add_Source_Id (Project : Project_Id; Id : Other_Source_Id) is
889 -- Reallocate the array, if necessary
891 if Last_Source = Source_Indexes'Last then
893 New_Indexes : constant Source_Indexes_Ref :=
894 new Source_Index_Array
895 (1 .. Source_Indexes'Last +
896 Initial_Source_Index_Count);
898 New_Indexes (Source_Indexes'Range) := Source_Indexes.all;
899 Free (Source_Indexes);
900 Source_Indexes := New_Indexes;
904 Last_Source := Last_Source + 1;
905 Source_Indexes (Last_Source) := (Project, Id, False);
908 ----------------------------
909 -- Add_Search_Directories --
910 ----------------------------
912 procedure Add_Search_Directories
913 (Data : Project_Data;
914 Language : First_Language_Indexes)
917 -- If a GNU compiler is used, set the CPATH environment variable,
918 -- if it does not already has the correct value.
920 if Compiler_Is_Gcc (Language) then
921 if Current_Include_Paths (Language) /= Data.Include_Path then
922 Current_Include_Paths (Language) := Data.Include_Path;
923 Setenv (CPATH, Data.Include_Path.all);
927 Add_Arguments (Data.Imported_Directories_Switches.all, Verbose_Mode);
929 end Add_Search_Directories;
935 procedure Add_Switches
936 (Data : Project_Data;
938 Language : Language_Index;
939 File_Name : File_Name_Type)
941 Switches : Variable_Value;
942 -- The switches, if any, for the file/language
945 -- The id of the package where to look for the switches
947 Defaults : Array_Element_Id;
948 -- The Default_Switches associative array
950 Switches_Array : Array_Element_Id;
951 -- The Switches associative array
953 Element_Id : String_List_Id;
954 Element : String_Element;
957 -- First, choose the proper package
964 Pkg := Value_Of (Name_Linker, Data.Decl.Packages, Project_Tree);
967 Pkg := Value_Of (Name_Compiler, Data.Decl.Packages, Project_Tree);
970 if Pkg /= No_Package then
972 -- Get the Switches ("file name"), if they exist
974 Switches_Array := Prj.Util.Value_Of
975 (Name => Name_Switches,
976 In_Arrays => Project_Tree.Packages.Table
978 In_Tree => Project_Tree);
982 (Index => Name_Id (File_Name),
984 In_Array => Switches_Array,
985 In_Tree => Project_Tree);
987 -- Otherwise, get the Default_Switches ("language"), if they exist
989 if Switches = Nil_Variable_Value then
990 Defaults := Prj.Util.Value_Of
991 (Name => Name_Default_Switches,
992 In_Arrays => Project_Tree.Packages.Table
994 In_Tree => Project_Tree);
995 Switches := Prj.Util.Value_Of
996 (Index => Language_Names.Table (Language),
998 In_Array => Defaults,
999 In_Tree => Project_Tree);
1002 -- If there are switches, add them to Arguments
1004 if Switches /= Nil_Variable_Value then
1005 Element_Id := Switches.Values;
1006 while Element_Id /= Nil_String loop
1007 Element := Project_Tree.String_Elements.Table
1010 if Element.Value /= No_Name then
1011 Get_Name_String (Element.Value);
1013 if not Quiet_Output then
1015 -- When not in quiet output (no -q), check that the
1016 -- switch is not the concatenation of several valid
1017 -- switches, such as "-g -v". If it is, issue a warning.
1019 Check (Option => Name_Buffer (1 .. Name_Len));
1022 Add_Argument (Name_Buffer (1 .. Name_Len), True);
1025 Element_Id := Element.Next;
1031 --------------------------
1032 -- Build_Global_Archive --
1033 --------------------------
1035 procedure Build_Global_Archive is
1036 Data : Project_Data := Project_Tree.Projects.Table (Main_Project);
1037 Source_Id : Other_Source_Id;
1038 S_Id : Other_Source_Id;
1039 Source : Other_Source;
1042 Archive_Name : constant String :=
1044 & Get_Name_String (Data.Display_Name)
1047 -- The name of the archive file for this project
1049 Archive_Dep_Name : constant String :=
1051 & Get_Name_String (Data.Display_Name)
1053 -- The name of the archive dependency file for this project
1055 Need_To_Rebuild : Boolean := Need_To_Rebuild_Global_Archive;
1056 -- When True, archive will be rebuilt
1058 File : Prj.Util.Text_File;
1059 Object_Path : Path_Name_Type;
1060 Time_Stamp : Time_Stamp_Type;
1061 Saved_Last_Argument : Natural;
1062 First_Object : Natural;
1065 pragma Warnings (Off, Discard);
1068 Check_Archive_Builder;
1070 if Project_Of_Current_Object_Directory /= Main_Project then
1071 Project_Of_Current_Object_Directory := Main_Project;
1072 Change_Dir (Get_Name_String (Data.Object_Directory));
1074 if Verbose_Mode then
1075 Write_Str ("Changing to object directory of """);
1076 Write_Name (Data.Display_Name);
1077 Write_Str (""": """);
1078 Write_Name (Data.Display_Object_Dir);
1083 if not Need_To_Rebuild then
1084 if Verbose_Mode then
1085 Write_Str (" Checking ");
1086 Write_Line (Archive_Name);
1089 -- If the archive does not exist, of course it needs to be built
1091 if not Is_Regular_File (Archive_Name) then
1092 Need_To_Rebuild := True;
1094 if Verbose_Mode then
1095 Write_Line (" -> archive does not exist");
1098 -- Archive does exist
1101 -- Check the archive dependency file
1103 Open (File, Archive_Dep_Name);
1105 -- If the archive dependency file does not exist, we need to
1106 -- rebuild the archive and to create its dependency file.
1108 if not Is_Valid (File) then
1109 Need_To_Rebuild := True;
1111 if Verbose_Mode then
1112 Write_Str (" -> archive dependency file ");
1113 Write_Str (Archive_Dep_Name);
1114 Write_Line (" does not exist");
1118 -- Put all sources of language other than Ada in Source_Indexes
1121 Local_Data : Project_Data;
1126 for Proj in Project_Table.First ..
1127 Project_Table.Last (Project_Tree.Projects)
1129 Local_Data := Project_Tree.Projects.Table (Proj);
1131 if not Local_Data.Library then
1132 Source_Id := Local_Data.First_Other_Source;
1133 while Source_Id /= No_Other_Source loop
1134 Add_Source_Id (Proj, Source_Id);
1135 Source_Id := Project_Tree.Other_Sources.Table
1142 -- Read the dependency file, line by line
1144 while not End_Of_File (File) loop
1145 Get_Line (File, Name_Buffer, Name_Len);
1147 -- First line is the path of the object file
1149 Object_Path := Name_Find;
1150 Source_Id := No_Other_Source;
1152 -- Check if this object file is for a source of this project
1154 for S in 1 .. Last_Source loop
1155 S_Id := Source_Indexes (S).Id;
1156 Source := Project_Tree.Other_Sources.Table (S_Id);
1158 if (not Source_Indexes (S).Found)
1159 and then Source.Object_Path = Object_Path
1161 -- We have found the object file: get the source data,
1162 -- and mark it as found.
1165 Source_Indexes (S).Found := True;
1170 -- If it is not for a source of this project, then the
1171 -- archive needs to be rebuilt.
1173 if Source_Id = No_Other_Source then
1174 Need_To_Rebuild := True;
1175 if Verbose_Mode then
1177 Write_Str (Get_Name_String (Object_Path));
1178 Write_Line (" is not an object of any project");
1184 -- The second line is the time stamp of the object file. If
1185 -- there is no next line, then the dependency file is
1186 -- truncated, and the archive need to be rebuilt.
1188 if End_Of_File (File) then
1189 Need_To_Rebuild := True;
1191 if Verbose_Mode then
1192 Write_Str (" -> archive dependency file ");
1193 Write_Line (" is truncated");
1199 Get_Line (File, Name_Buffer, Name_Len);
1201 -- If the line has the wrong number of characters, then
1202 -- the dependency file is incorrectly formatted, and the
1203 -- archive needs to be rebuilt.
1205 if Name_Len /= Time_Stamp_Length then
1206 Need_To_Rebuild := True;
1208 if Verbose_Mode then
1209 Write_Str (" -> archive dependency file ");
1210 Write_Line (" is incorrectly formatted (time stamp)");
1216 Time_Stamp := Time_Stamp_Type (Name_Buffer (1 .. Name_Len));
1218 -- If the time stamp in the dependency file is different
1219 -- from the time stamp of the object file, then the archive
1220 -- needs to be rebuilt.
1222 if Time_Stamp /= Source.Object_TS then
1223 Need_To_Rebuild := True;
1225 if Verbose_Mode then
1226 Write_Str (" -> time stamp of ");
1227 Write_Str (Get_Name_String (Object_Path));
1228 Write_Str (" is incorrect in the archive");
1229 Write_Line (" dependency file");
1241 if not Need_To_Rebuild then
1242 if Verbose_Mode then
1243 Write_Line (" -> up to date");
1246 -- No need to create a global archive, if there is no object
1247 -- file to put into.
1249 Global_Archive_Exists := Last_Source /= 0;
1251 -- Archive needs to be rebuilt
1254 -- If archive already exists, first delete it
1256 -- Comment needed on why we discard result???
1258 if Is_Regular_File (Archive_Name) then
1259 Delete_File (Archive_Name, Discard);
1264 -- Start with the options found in MLib.Tgt (usually just "rc")
1266 Add_Arguments (Archive_Builder_Options.all, True);
1268 -- Followed by the archive name
1270 Add_Argument (Archive_Name, True);
1272 First_Object := Last_Argument;
1274 -- Followed by all the object files of the non library projects
1276 for Proj in Project_Table.First ..
1277 Project_Table.Last (Project_Tree.Projects)
1279 Data := Project_Tree.Projects.Table (Proj);
1281 if not Data.Library then
1282 Source_Id := Data.First_Other_Source;
1283 while Source_Id /= No_Other_Source loop
1285 Project_Tree.Other_Sources.Table (Source_Id);
1287 -- Only include object file name that have not been
1288 -- overridden in extending projects.
1290 if Is_Included_In_Global_Archive
1291 (Source.Object_Name, Proj)
1294 (Get_Name_String (Source.Object_Path),
1295 Verbose_Mode or (First_Object = Last_Argument));
1298 Source_Id := Source.Next;
1303 -- No need to create a global archive, if there is no object
1304 -- file to put into.
1306 Global_Archive_Exists := Last_Argument > First_Object;
1308 if Global_Archive_Exists then
1310 -- If the archive is built, then linking will need to occur
1313 Need_To_Relink := True;
1315 -- Spawn the archive builder (ar)
1317 Saved_Last_Argument := Last_Argument;
1318 Last_Argument := First_Object + Max_In_Archives;
1320 if Last_Argument > Saved_Last_Argument then
1321 Last_Argument := Saved_Last_Argument;
1326 Archive_Builder_Path,
1330 (Archive_Builder_Path.all,
1331 Arguments (1 .. Last_Argument),
1334 exit when not Success
1335 or else Last_Argument = Saved_Last_Argument;
1338 Arguments (3 .. Saved_Last_Argument - Last_Argument + 2) :=
1339 Arguments (Last_Argument + 1 .. Saved_Last_Argument);
1340 Saved_Last_Argument := Saved_Last_Argument - Last_Argument + 2;
1343 -- If the archive was built, run the archive indexer (ranlib)
1348 if Archive_Indexer_Path /= null then
1350 Add_Argument (Archive_Name, True);
1352 Display_Command (Archive_Indexer, Archive_Indexer_Path);
1355 (Archive_Indexer_Path.all, Arguments (1 .. 1), Success);
1359 -- Running ranlib failed, delete the dependency file,
1362 if Is_Regular_File (Archive_Dep_Name) then
1363 Delete_File (Archive_Dep_Name, Success);
1366 -- And report the error
1369 ("running" & Archive_Indexer & " for project """,
1370 Get_Name_String (Data.Display_Name),
1376 -- The archive was correctly built, create its dependency file
1378 Create_Global_Archive_Dependency_File (Archive_Dep_Name);
1380 -- Building the archive failed, delete dependency file if one
1384 if Is_Regular_File (Archive_Dep_Name) then
1385 Delete_File (Archive_Dep_Name, Success);
1388 -- And report the error
1391 ("building archive for project """,
1392 Get_Name_String (Data.Display_Name),
1397 end Build_Global_Archive;
1403 procedure Build_Library (Project : Project_Id; Unconditionally : Boolean) is
1404 Data : constant Project_Data :=
1405 Project_Tree.Projects.Table (Project);
1406 Source_Id : Other_Source_Id;
1407 Source : Other_Source;
1409 Archive_Name : constant String :=
1410 "lib" & Get_Name_String (Data.Library_Name)
1411 & '.' & Archive_Ext;
1412 -- The name of the archive file for this project
1414 Archive_Dep_Name : constant String :=
1415 "lib" & Get_Name_String (Data.Library_Name)
1417 -- The name of the archive dependency file for this project
1419 Need_To_Rebuild : Boolean := Unconditionally;
1420 -- When True, archive will be rebuilt
1422 File : Prj.Util.Text_File;
1424 Object_Name : File_Name_Type;
1425 Time_Stamp : Time_Stamp_Type;
1426 Driver_Name : Name_Id := No_Name;
1428 Lib_Opts : Argument_List_Access := No_Argument'Access;
1431 -- Nothing to do if the project is externally built
1433 if Data.Externally_Built then
1437 Check_Archive_Builder;
1439 -- If Unconditionally is False, check if the archive need to be built
1441 if not Need_To_Rebuild then
1442 if Verbose_Mode then
1443 Write_Str (" Checking ");
1444 Write_Line (Archive_Name);
1447 -- If the archive does not exist, of course it needs to be built
1449 if not Is_Regular_File (Archive_Name) then
1450 Need_To_Rebuild := True;
1452 if Verbose_Mode then
1453 Write_Line (" -> archive does not exist");
1456 -- Archive does exist
1459 -- Check the archive dependency file
1461 Open (File, Archive_Dep_Name);
1463 -- If the archive dependency file does not exist, we need to
1464 -- rebuild the archive and to create its dependency file.
1466 if not Is_Valid (File) then
1467 Need_To_Rebuild := True;
1469 if Verbose_Mode then
1470 Write_Str (" -> archive dependency file ");
1471 Write_Str (Archive_Dep_Name);
1472 Write_Line (" does not exist");
1476 -- Put all sources of language other than Ada in Source_Indexes
1480 Source_Id := Data.First_Other_Source;
1481 while Source_Id /= No_Other_Source loop
1482 Add_Source_Id (Project, Source_Id);
1484 Project_Tree.Other_Sources.Table (Source_Id).Next;
1487 -- Read the dependency file, line by line
1489 while not End_Of_File (File) loop
1490 Get_Line (File, Name_Buffer, Name_Len);
1492 -- First line is the name of an object file
1494 Object_Name := Name_Find;
1495 Source_Id := No_Other_Source;
1497 -- Check if this object file is for a source of this project
1499 for S in 1 .. Last_Source loop
1500 if (not Source_Indexes (S).Found)
1502 Project_Tree.Other_Sources.Table
1503 (Source_Indexes (S).Id).Object_Name = Object_Name
1505 -- We have found the object file: get the source
1506 -- data, and mark it as found.
1508 Source_Id := Source_Indexes (S).Id;
1509 Source := Project_Tree.Other_Sources.Table
1511 Source_Indexes (S).Found := True;
1516 -- If it is not for a source of this project, then the
1517 -- archive needs to be rebuilt.
1519 if Source_Id = No_Other_Source then
1520 Need_To_Rebuild := True;
1522 if Verbose_Mode then
1524 Write_Str (Get_Name_String (Object_Name));
1525 Write_Line (" is not an object of the project");
1531 -- The second line is the time stamp of the object file.
1532 -- If there is no next line, then the dependency file is
1533 -- truncated, and the archive need to be rebuilt.
1535 if End_Of_File (File) then
1536 Need_To_Rebuild := True;
1538 if Verbose_Mode then
1539 Write_Str (" -> archive dependency file ");
1540 Write_Line (" is truncated");
1546 Get_Line (File, Name_Buffer, Name_Len);
1548 -- If the line has the wrong number of character, then
1549 -- the dependency file is incorrectly formatted, and the
1550 -- archive needs to be rebuilt.
1552 if Name_Len /= Time_Stamp_Length then
1553 Need_To_Rebuild := True;
1555 if Verbose_Mode then
1556 Write_Str (" -> archive dependency file ");
1557 Write_Line (" is incorrectly formatted (time stamp)");
1563 Time_Stamp := Time_Stamp_Type (Name_Buffer (1 .. Name_Len));
1565 -- If the time stamp in the dependency file is different
1566 -- from the time stamp of the object file, then the archive
1567 -- needs to be rebuilt.
1569 if Time_Stamp /= Source.Object_TS then
1570 Need_To_Rebuild := True;
1572 if Verbose_Mode then
1573 Write_Str (" -> time stamp of ");
1574 Write_Str (Get_Name_String (Object_Name));
1575 Write_Str (" is incorrect in the archive");
1576 Write_Line (" dependency file");
1585 if not Need_To_Rebuild then
1587 -- Now, check if all object files of the project have been
1588 -- accounted for. If any of them is not in the dependency
1589 -- file, the archive needs to be rebuilt.
1591 for Index in 1 .. Last_Source loop
1592 if not Source_Indexes (Index).Found then
1593 Need_To_Rebuild := True;
1595 if Verbose_Mode then
1596 Source_Id := Source_Indexes (Index).Id;
1597 Source := Project_Tree.Other_Sources.Table
1600 Write_Str (Get_Name_String (Source.Object_Name));
1601 Write_Str (" is not in the archive ");
1602 Write_Line ("dependency file");
1610 if (not Need_To_Rebuild) and Verbose_Mode then
1611 Write_Line (" -> up to date");
1617 -- Build the library if necessary
1619 if Need_To_Rebuild then
1621 -- If a library is built, then linking will need to occur
1624 Need_To_Relink := True;
1628 -- If there are sources in Ada, then gnatmake will build the library,
1629 -- so nothing to do.
1631 if not Data.Langs (Ada_Language_Index) then
1633 -- Get all the object files of the project
1635 Source_Id := Data.First_Other_Source;
1636 while Source_Id /= No_Other_Source loop
1637 Source := Project_Tree.Other_Sources.Table (Source_Id);
1639 (Get_Name_String (Source.Object_Name), Verbose_Mode);
1640 Source_Id := Source.Next;
1643 -- If it is a library, it need to be built it the same way Ada
1644 -- libraries are built.
1646 if Data.Library_Kind = Static then
1648 (Ofiles => Arguments (1 .. Last_Argument),
1649 Output_File => Get_Name_String (Data.Library_Name),
1650 Output_Dir => Get_Name_String (Data.Display_Library_Dir));
1653 -- Link with g++ if C++ is one of the languages, otherwise
1654 -- building the library may fail with unresolved symbols.
1656 if C_Plus_Plus_Is_Used then
1657 if Compiler_Names (C_Plus_Plus_Language_Index) = null then
1658 Get_Compiler (C_Plus_Plus_Language_Index);
1661 if Compiler_Is_Gcc (C_Plus_Plus_Language_Index) then
1663 Add_Str_To_Name_Buffer
1664 (Compiler_Names (C_Plus_Plus_Language_Index).all);
1665 Driver_Name := Name_Find;
1669 -- If Library_Options is specified, add these options
1672 Library_Options : constant Variable_Value :=
1674 (Name_Library_Options,
1675 Data.Decl.Attributes,
1679 if not Library_Options.Default then
1681 Current : String_List_Id;
1682 Element : String_Element;
1685 Current := Library_Options.Values;
1686 while Current /= Nil_String loop
1688 Project_Tree.String_Elements.Table (Current);
1689 Get_Name_String (Element.Value);
1691 if Name_Len /= 0 then
1692 Library_Opts.Increment_Last;
1693 Library_Opts.Table (Library_Opts.Last) :=
1694 new String'(Name_Buffer (1 .. Name_Len));
1697 Current := Element.Next;
1703 new Argument_List'(Argument_List
1704 (Library_Opts.Table (1 .. Library_Opts.Last)));
1707 MLib.Tgt.Build_Dynamic_Library
1708 (Ofiles => Arguments (1 .. Last_Argument),
1709 Options => Lib_Opts.all,
1710 Interfaces => No_Argument,
1711 Lib_Filename => Get_Name_String (Data.Library_Name),
1712 Lib_Dir => Get_Name_String (Data.Library_Dir),
1713 Symbol_Data => No_Symbols,
1714 Driver_Name => Driver_Name,
1716 Auto_Init => False);
1720 -- Create fake empty archive, so we can check its time stamp later
1723 Archive : Ada.Text_IO.File_Type;
1725 Create (Archive, Out_File, Archive_Name);
1729 Create_Archive_Dependency_File
1730 (Archive_Dep_Name, Data.First_Other_Source);
1738 procedure Check (Option : String) is
1739 First : Positive := Option'First;
1743 for Index in Option'First + 1 .. Option'Last - 1 loop
1744 if Option (Index) = ' ' and then Option (Index + 1) = '-' then
1745 Write_Str ("warning: switch """);
1747 Write_Str (""" is suspicious; consider using ");
1750 while Last <= Option'Last loop
1751 if Option (Last) = ' ' then
1752 if First /= Option'First then
1757 Write_Str (Option (First .. Last - 1));
1760 while Last <= Option'Last and then Option (Last) = ' ' loop
1767 if Last = Option'Last then
1768 if First /= Option'First then
1773 Write_Str (Option (First .. Last));
1781 Write_Line (" instead");
1787 ---------------------------
1788 -- Check_Archive_Builder --
1789 ---------------------------
1791 procedure Check_Archive_Builder is
1793 -- First, make sure that the archive builder (ar) is on the path
1795 if Archive_Builder_Path = null then
1796 Archive_Builder_Path := Locate_Exec_On_Path (Archive_Builder);
1798 if Archive_Builder_Path = null then
1800 ("unable to locate archive builder """,
1805 -- If there is an archive indexer (ranlib), try to locate it on the
1806 -- path. Don't fail if it is not found.
1808 if Archive_Indexer /= "" then
1809 Archive_Indexer_Path := Locate_Exec_On_Path (Archive_Indexer);
1812 end Check_Archive_Builder;
1814 ------------------------------
1815 -- Check_Compilation_Needed --
1816 ------------------------------
1818 procedure Check_Compilation_Needed
1819 (Source : Other_Source;
1820 Need_To_Compile : out Boolean)
1822 Source_Name : constant String := Get_Name_String (Source.File_Name);
1823 Source_Path : constant String := Get_Name_String (Source.Path_Name);
1824 Object_Name : constant String := Get_Name_String (Source.Object_Name);
1825 C_Object_Name : String := Object_Name;
1826 Dep_Name : constant String := Get_Name_String (Source.Dep_Name);
1827 C_Source_Path : constant String :=
1829 (Name => Source_Path,
1830 Resolve_Links => False,
1831 Case_Sensitive => False);
1833 Source_In_Dependencies : Boolean := False;
1834 -- Set True if source was found in dependency file of its object file
1836 Dep_File : Prj.Util.Text_File;
1840 Looping : Boolean := False;
1841 -- Set to True at the end of the first Big_Loop
1844 Canonical_Case_File_Name (C_Object_Name);
1846 -- Assume the worst, so that statement "return;" may be used if there
1849 Need_To_Compile := True;
1851 if Verbose_Mode then
1852 Write_Str (" Checking ");
1853 Write_Str (Source_Name);
1854 Write_Line (" ... ");
1857 -- If object file does not exist, of course source need to be compiled
1859 if Source.Object_TS = Empty_Time_Stamp then
1860 if Verbose_Mode then
1861 Write_Str (" -> object file ");
1862 Write_Str (Object_Name);
1863 Write_Line (" does not exist");
1869 -- If the object file has been created before the last modification
1870 -- of the source, the source need to be recompiled.
1872 if Source.Object_TS < Source.Source_TS then
1873 if Verbose_Mode then
1874 Write_Str (" -> object file ");
1875 Write_Str (Object_Name);
1876 Write_Line (" has time stamp earlier than source");
1882 -- If there is no dependency file, then the source needs to be
1883 -- recompiled and the dependency file need to be created.
1885 if Source.Dep_TS = Empty_Time_Stamp then
1886 if Verbose_Mode then
1887 Write_Str (" -> dependency file ");
1888 Write_Str (Dep_Name);
1889 Write_Line (" does not exist");
1895 -- The source needs to be recompiled if the source has been modified
1896 -- after the dependency file has been created.
1898 if Source.Dep_TS < Source.Source_TS then
1899 if Verbose_Mode then
1900 Write_Str (" -> dependency file ");
1901 Write_Str (Dep_Name);
1902 Write_Line (" has time stamp earlier than source");
1908 -- Look for all dependencies
1910 Open (Dep_File, Dep_Name);
1912 -- If dependency file cannot be open, we need to recompile the source
1914 if not Is_Valid (Dep_File) then
1915 if Verbose_Mode then
1916 Write_Str (" -> could not open dependency file ");
1917 Write_Line (Dep_Name);
1923 -- Loop Big_Loop is executed several times only when the dependency file
1924 -- contains several times
1925 -- <object file>: <source1> ...
1926 -- When there is only one of such occurrence, Big_Loop is exited
1927 -- successfully at the beginning of the second loop.
1932 End_Of_File_Reached : Boolean := False;
1936 if End_Of_File (Dep_File) then
1937 End_Of_File_Reached := True;
1941 Get_Line (Dep_File, Name_Buffer, Name_Len);
1943 exit when Name_Len > 0 and then Name_Buffer (1) /= '#';
1946 -- If dependency file contains only empty lines or comments, then
1947 -- dependencies are unknown, and the source needs to be
1950 if End_Of_File_Reached then
1951 -- If we have reached the end of file after the first loop,
1952 -- there is nothing else to do.
1954 exit Big_Loop when Looping;
1956 if Verbose_Mode then
1957 Write_Str (" -> dependency file ");
1958 Write_Str (Dep_Name);
1959 Write_Line (" is empty");
1968 Finish := Index (Name_Buffer (1 .. Name_Len), ": ");
1971 Canonical_Case_File_Name (Name_Buffer (1 .. Finish - 1));
1974 -- First line must start with name of object file, followed by colon
1976 if Finish = 0 or else
1977 Name_Buffer (1 .. Finish - 1) /= C_Object_Name
1979 if Verbose_Mode then
1980 Write_Str (" -> dependency file ");
1981 Write_Str (Dep_Name);
1982 Write_Line (" has wrong format");
1989 Start := Finish + 2;
1991 -- Process each line
1995 Line : String := Name_Buffer (1 .. Name_Len);
1996 Last : Natural := Name_Len;
2001 -- Find the beginning of the next source path name
2003 while Start < Last and then Line (Start) = ' ' loop
2007 -- Go to next line when there is a continuation character
2008 -- \ at the end of the line.
2010 exit Name_Loop when Start = Last
2011 and then Line (Start) = '\';
2013 -- We should not be at the end of the line, without
2014 -- a continuation character \.
2016 if Start = Last then
2017 if Verbose_Mode then
2018 Write_Str (" -> dependency file ");
2019 Write_Str (Dep_Name);
2020 Write_Line (" has wrong format");
2027 -- Look for the end of the source path name
2030 while Finish < Last loop
2031 if Line (Finish) = '\' then
2033 -- On Windows, a '\' is part of the path name,
2034 -- except when it is followed by another '\' or by
2035 -- a space. On other platforms, when we are getting
2036 -- a '\' that is not the last character of the
2037 -- line, the next character is part of the path
2038 -- name, even if it is a space.
2041 and then Line (Finish + 1) /= '\'
2042 and then Line (Finish + 1) /= ' '
2044 Finish := Finish + 1;
2047 Line (Finish .. Last - 1) :=
2048 Line (Finish + 1 .. Last);
2053 -- A space that is not preceded by '\' indicates
2054 -- the end of the path name.
2056 exit when Line (Finish + 1) = ' ';
2058 Finish := Finish + 1;
2062 -- Check this source
2065 Src_Name : constant String :=
2068 Line (Start .. Finish),
2069 Resolve_Links => False,
2070 Case_Sensitive => False);
2071 Src_TS : Time_Stamp_Type;
2074 -- If it is original source, set
2075 -- Source_In_Dependencies.
2077 if Src_Name = C_Source_Path then
2078 Source_In_Dependencies := True;
2082 Add_Str_To_Name_Buffer (Src_Name);
2083 Src_TS := File_Stamp (File_Name_Type'(Name_Find));
2085 -- If the source does not exist, we need to recompile
2087 if Src_TS = Empty_Time_Stamp then
2088 if Verbose_Mode then
2089 Write_Str (" -> source ");
2090 Write_Str (Src_Name);
2091 Write_Line (" does not exist");
2097 -- If the source has been modified after the object
2098 -- file, we need to recompile.
2100 elsif Src_TS > Source.Object_TS then
2101 if Verbose_Mode then
2102 Write_Str (" -> source ");
2103 Write_Str (Src_Name);
2105 (" has time stamp later than object file");
2113 -- If the source path name ends the line, we are done
2115 exit Line_Loop when Finish = Last;
2117 -- Go get the next source on the line
2119 Start := Finish + 1;
2123 -- If we are here, we had a continuation character \ at the end
2124 -- of the line, so we continue with the next line.
2126 Get_Line (Dep_File, Name_Buffer, Name_Len);
2131 -- Set Looping at the end of the first loop
2137 -- If the original sources were not in the dependency file, then we
2138 -- need to recompile. It may mean that we are using a different source
2139 -- (different variant) for this object file.
2141 if not Source_In_Dependencies then
2142 if Verbose_Mode then
2143 Write_Str (" -> source ");
2144 Write_Str (Source_Path);
2145 Write_Line (" is not in the dependencies");
2151 -- If we are here, then everything is OK, no need to recompile
2153 if Verbose_Mode then
2154 Write_Line (" -> up to date");
2157 Need_To_Compile := False;
2158 end Check_Compilation_Needed;
2160 ---------------------------
2161 -- Check_For_C_Plus_Plus --
2162 ---------------------------
2164 procedure Check_For_C_Plus_Plus is
2166 C_Plus_Plus_Is_Used := False;
2168 for Project in Project_Table.First ..
2169 Project_Table.Last (Project_Tree.Projects)
2172 Project_Tree.Projects.Table (Project).Langs
2173 (C_Plus_Plus_Language_Index)
2175 C_Plus_Plus_Is_Used := True;
2179 end Check_For_C_Plus_Plus;
2186 (Source_Id : Other_Source_Id;
2187 Data : Project_Data;
2188 Local_Errors : in out Boolean)
2190 Source : Other_Source :=
2191 Project_Tree.Other_Sources.Table (Source_Id);
2193 CPATH : String_Access := null;
2196 -- If the compiler is not known yet, get its path name
2198 if Compiler_Names (Source.Language) = null then
2199 Get_Compiler (Source.Language);
2202 -- For non GCC compilers, get the dependency file, first calling the
2203 -- compiler with the switch -M.
2205 if not Compiler_Is_Gcc (Source.Language) then
2208 -- Add the source name, preceded by -M
2210 Add_Argument (Dash_M, True);
2211 Add_Argument (Get_Name_String (Source.Path_Name), True);
2213 -- Add the compiling switches for this source found in
2214 -- package Compiler of the project file, if they exist.
2217 (Data, Compiler, Source.Language, Source.File_Name);
2219 -- Add the compiling switches for the language specified
2220 -- on the command line, if any.
2223 J in 1 .. Comp_Opts.Last (Options (Source.Language))
2225 Add_Argument (Options (Source.Language).Table (J), True);
2228 -- Finally, add imported directory switches for this project file
2230 Add_Search_Directories (Data, Source.Language);
2232 -- And invoke the compiler using GNAT.Expect
2235 (Compiler_Names (Source.Language).all,
2236 Compiler_Paths (Source.Language));
2241 Compiler_Paths (Source.Language).all,
2242 Arguments (1 .. Last_Argument),
2244 Err_To_Out => True);
2247 Dep_File : Ada.Text_IO.File_Type;
2248 Result : Expect_Match;
2251 pragma Warnings (Off, Status);
2254 -- Create the dependency file
2256 Create (Dep_File, Out_File, Get_Name_String (Source.Dep_Name));
2259 Expect (FD, Result, Line_Matcher);
2261 exit when Result = Expect_Timeout;
2264 S : constant String := Strip_CR_LF (Expect_Out (FD));
2267 -- Each line of the output is put in the dependency
2268 -- file, including errors. If there are errors, the
2269 -- syntax of the dependency file will be incorrect and
2270 -- recompilation will occur automatically the next time
2271 -- the dependencies are checked.
2273 Put_Line (Dep_File, S);
2277 -- If we are here, it means we had a timeout, so the
2278 -- dependency file may be incomplete. It is safer to
2279 -- delete it, otherwise the dependencies may be wrong.
2283 Delete_File (Get_Name_String (Source.Dep_Name), Success);
2286 when Process_Died =>
2288 -- This is the normal outcome. Just close the file
2295 -- Something wrong happened. It is safer to delete the
2296 -- dependency file, otherwise the dependencies may be wrong.
2300 if Is_Open (Dep_File) then
2304 Delete_File (Get_Name_String (Source.Dep_Name), Success);
2308 -- If we cannot spawn the compiler, then the dependencies are
2309 -- not updated. It is safer then to delete the dependency file,
2310 -- otherwise the dependencies may be wrong.
2312 when Invalid_Process =>
2313 Delete_File (Get_Name_String (Source.Dep_Name), Success);
2319 -- For GCC compilers, make sure the language is always specified to
2320 -- to the GCC driver, in case the extension is not recognized by the
2321 -- GCC driver as a source of the language.
2323 if Compiler_Is_Gcc (Source.Language) then
2324 Add_Argument (Dash_x, Verbose_Mode);
2326 (Get_Name_String (Language_Names.Table (Source.Language)),
2330 Add_Argument (Dash_c, True);
2332 -- Add the compiling switches for this source found in package Compiler
2333 -- of the project file, if they exist.
2336 (Data, Compiler, Source.Language, Source.File_Name);
2338 -- Specify the source to be compiled
2340 Add_Argument (Get_Name_String (Source.Path_Name), True);
2342 -- If non static library project, compile with the PIC option if there
2343 -- is one (when there is no PIC option, MLib.Tgt.PIC_Option returns an
2344 -- empty string, and Add_Argument with an empty string has no effect).
2346 if Data.Library and then Data.Library_Kind /= Static then
2347 Add_Argument (PIC_Option, True);
2350 -- Indicate the name of the object
2352 Add_Argument (Dash_o, True);
2353 Add_Argument (Get_Name_String (Source.Object_Name), True);
2355 -- When compiler is GCC, use the magic switch that creates the
2356 -- dependency file in the correct format.
2358 if Compiler_Is_Gcc (Source.Language) then
2360 ("-Wp,-MD," & Get_Name_String (Source.Dep_Name),
2364 -- Add the compiling switches for the language specified on the command
2367 for J in 1 .. Comp_Opts.Last (Options (Source.Language)) loop
2368 Add_Argument (Options (Source.Language).Table (J), True);
2371 -- Finally, add the imported directory switches for this project file
2372 -- (or, for gcc compilers, set up the CPATH env var if needed).
2374 Add_Search_Directories (Data, Source.Language);
2376 -- Set CPATH, if compiler is GCC
2378 if Compiler_Is_Gcc (Source.Language) then
2379 CPATH := Current_Include_Paths (Source.Language);
2382 -- And invoke the compiler
2385 (Name => Compiler_Names (Source.Language).all,
2386 Path => Compiler_Paths (Source.Language),
2390 (Compiler_Paths (Source.Language).all,
2391 Arguments (1 .. Last_Argument),
2394 -- Case of successful compilation
2398 -- Update the time stamp of the object file
2400 Source.Object_TS := File_Stamp (Source.Object_Name);
2402 -- Do some sanity checks
2404 if Source.Object_TS = Empty_Time_Stamp then
2405 Local_Errors := True;
2408 Get_Name_String (Source.Object_Name),
2409 " has not been created");
2411 elsif Source.Object_TS < Source.Source_TS then
2412 Local_Errors := True;
2415 Get_Name_String (Source.Object_Name),
2416 " has not been modified");
2419 -- Everything looks fine, update the Other_Sources table
2421 Project_Tree.Other_Sources.Table (Source_Id) := Source;
2424 -- Compilation failed
2427 Local_Errors := True;
2430 Get_Name_String (Source.Path_Name),
2435 --------------------------------
2436 -- Compile_Individual_Sources --
2437 --------------------------------
2439 procedure Compile_Individual_Sources is
2440 Data : Project_Data :=
2441 Project_Tree.Projects.Table (Main_Project);
2442 Source_Id : Other_Source_Id;
2443 Source : Other_Source;
2444 Source_Name : File_Name_Type;
2445 Project_Name : String := Get_Name_String (Data.Name);
2446 Dummy : Boolean := False;
2448 Ada_Is_A_Language : constant Boolean :=
2449 Data.Langs (Ada_Language_Index);
2453 To_Mixed (Project_Name);
2454 Compile_Only := True;
2456 Get_Imported_Directories (Main_Project, Data);
2457 Project_Tree.Projects.Table (Main_Project) := Data;
2459 -- Compilation will occur in the object directory
2461 if Project_Of_Current_Object_Directory /= Main_Project then
2462 Project_Of_Current_Object_Directory := Main_Project;
2463 Change_Dir (Get_Name_String (Data.Object_Directory));
2465 if Verbose_Mode then
2466 Write_Str ("Changing to object directory of """);
2467 Write_Name (Data.Name);
2468 Write_Str (""": """);
2469 Write_Name (Data.Display_Object_Dir);
2474 if not Data.Other_Sources_Present then
2475 if Ada_Is_A_Language then
2480 Main : constant String := Mains.Next_Main;
2482 exit when Main'Length = 0;
2483 Ada_Mains.Increment_Last;
2484 Ada_Mains.Table (Ada_Mains.Last) := new String'(Main);
2489 Osint.Fail ("project ", Project_Name, " contains no source");
2497 Main : constant String := Mains.Next_Main;
2499 Name_Len := Main'Length;
2500 exit when Name_Len = 0;
2501 Name_Buffer (1 .. Name_Len) := Main;
2502 Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len));
2503 Source_Name := Name_Find;
2505 if not Sources_Compiled.Get (Source_Name) then
2506 Sources_Compiled.Set (Source_Name, True);
2508 Source_Id := Data.First_Other_Source;
2509 while Source_Id /= No_Other_Source loop
2510 Source := Project_Tree.Other_Sources.Table (Source_Id);
2511 exit when Source.File_Name = Source_Name;
2512 Source_Id := Source.Next;
2515 if Source_Id = No_Other_Source then
2516 if Ada_Is_A_Language then
2517 Ada_Mains.Increment_Last;
2518 Ada_Mains.Table (Ada_Mains.Last) := new String'(Main);
2523 " is not a valid source of project ",
2528 Compile (Source_Id, Data, Dummy);
2535 if Ada_Mains.Last > 0 then
2537 -- Invoke gnatmake for all Ada sources
2540 Add_Argument (Dash_u, True);
2542 for Index in 1 .. Ada_Mains.Last loop
2543 Add_Argument (Ada_Mains.Table (Index), True);
2546 Compile_Link_With_Gnatmake (Mains_Specified => False);
2548 end Compile_Individual_Sources;
2550 --------------------------------
2551 -- Compile_Link_With_Gnatmake --
2552 --------------------------------
2554 procedure Compile_Link_With_Gnatmake (Mains_Specified : Boolean) is
2555 Data : constant Project_Data :=
2556 Project_Tree.Projects.Table (Main_Project);
2560 -- Array Arguments may already contain some arguments, so we don't
2561 -- set Last_Argument to 0.
2563 -- Get the gnatmake to invoke
2565 Get_Compiler (Ada_Language_Index);
2567 -- Specify the project file
2569 Add_Argument (Dash_P, True);
2570 Add_Argument (Get_Name_String (Data.Display_Path_Name), True);
2572 -- Add the saved switches, if any
2574 for Index in 1 .. Saved_Switches.Last loop
2575 Add_Argument (Saved_Switches.Table (Index), True);
2578 -- If Mains_Specified is True, find the mains in package Mains
2580 if Mains_Specified then
2585 Main : constant String := Mains.Next_Main;
2587 exit when Main'Length = 0;
2588 Add_Argument (Main, True);
2593 -- Specify output file name, if any was specified on the command line
2595 if Output_File_Name /= null then
2596 Add_Argument (Dash_o, True);
2597 Add_Argument (Output_File_Name, True);
2600 -- Transmit some switches to gnatmake
2604 if Compile_Only then
2605 Add_Argument (Dash_c, True);
2610 if Display_Compilation_Progress then
2611 Add_Argument (Dash_d, True);
2616 if Follow_Links_For_Files then
2617 Add_Argument (Dash_eL, True);
2623 Add_Argument (Dash_k, True);
2628 if Force_Compilations then
2629 Add_Argument (Dash_f, True);
2634 if Verbose_Mode then
2635 Add_Argument (Dash_v, True);
2640 if Quiet_Output then
2641 Add_Argument (Dash_q, True);
2646 case Current_Verbosity is
2651 Add_Argument (Dash_vP1, True);
2654 Add_Argument (Dash_vP2, True);
2657 -- If there are compiling options for Ada, transmit them to gnatmake
2659 if Comp_Opts.Last (Options (Ada_Language_Index)) /= 0 then
2660 Add_Argument (Dash_cargs, True);
2662 for Arg in 1 .. Comp_Opts.Last (Options (Ada_Language_Index)) loop
2663 Add_Argument (Options (Ada_Language_Index).Table (Arg), True);
2667 if not Compile_Only then
2671 if Linker_Options.Last /= 0 then
2672 Add_Argument (Dash_largs, True);
2674 Add_Argument (Dash_largs, Verbose_Mode);
2679 Add_Archives (For_Gnatmake => True);
2681 -- If there are linking options from the command line,
2682 -- transmit them to gnatmake.
2684 for Arg in 1 .. Linker_Options.Last loop
2685 Add_Argument (Linker_Options.Table (Arg), True);
2689 -- And invoke gnatmake
2692 (Compiler_Names (Ada_Language_Index).all,
2693 Compiler_Paths (Ada_Language_Index));
2696 (Compiler_Paths (Ada_Language_Index).all,
2697 Arguments (1 .. Last_Argument),
2700 -- Report an error if call to gnatmake failed
2705 Compiler_Names (Ada_Language_Index).all,
2708 end Compile_Link_With_Gnatmake;
2710 ---------------------
2711 -- Compile_Sources --
2712 ---------------------
2714 procedure Compile_Sources is
2715 Data : Project_Data;
2716 Source_Id : Other_Source_Id;
2717 Source : Other_Source;
2719 Local_Errors : Boolean := False;
2720 -- Set to True when there is a compilation error. Used only when
2721 -- Keep_Going is True, to inhibit the building of the archive.
2723 Need_To_Compile : Boolean;
2724 -- Set to True when a source needs to be compiled/recompiled
2726 Need_To_Rebuild_Archive : Boolean := Force_Compilations;
2727 -- True when the archive needs to be built/rebuilt unconditionally
2729 Total_Number_Of_Sources : Int := 0;
2731 Current_Source_Number : Int := 0;
2734 -- First, get the number of sources
2736 for Project in Project_Table.First ..
2737 Project_Table.Last (Project_Tree.Projects)
2739 Data := Project_Tree.Projects.Table (Project);
2741 if not Data.Virtual and then Data.Other_Sources_Present then
2742 Source_Id := Data.First_Other_Source;
2743 while Source_Id /= No_Other_Source loop
2744 Source := Project_Tree.Other_Sources.Table (Source_Id);
2745 Total_Number_Of_Sources := Total_Number_Of_Sources + 1;
2746 Source_Id := Source.Next;
2751 -- Loop through project files
2753 for Project in Project_Table.First ..
2754 Project_Table.Last (Project_Tree.Projects)
2756 Local_Errors := False;
2757 Data := Project_Tree.Projects.Table (Project);
2759 -- Nothing to do when no sources of language other than Ada
2761 if (not Data.Virtual) and then Data.Other_Sources_Present then
2763 -- If the imported directory switches are unknown, compute them
2765 if not Data.Include_Data_Set then
2766 Get_Imported_Directories (Project, Data);
2767 Data.Include_Data_Set := True;
2768 Project_Tree.Projects.Table (Project) := Data;
2771 Need_To_Rebuild_Archive := Force_Compilations;
2773 -- Compilation will occur in the object directory
2775 if Project_Of_Current_Object_Directory /= Project then
2776 Project_Of_Current_Object_Directory := Project;
2777 Change_Dir (Get_Name_String (Data.Object_Directory));
2779 if Verbose_Mode then
2780 Write_Str ("Changing to object directory of """);
2781 Write_Name (Data.Display_Name);
2782 Write_Str (""": """);
2783 Write_Name (Data.Display_Object_Dir);
2788 -- Process each source one by one
2790 Source_Id := Data.First_Other_Source;
2791 while Source_Id /= No_Other_Source loop
2792 Source := Project_Tree.Other_Sources.Table (Source_Id);
2793 Current_Source_Number := Current_Source_Number + 1;
2794 Need_To_Compile := Force_Compilations;
2796 -- Check if compilation is needed
2798 if not Need_To_Compile then
2799 Check_Compilation_Needed (Source, Need_To_Compile);
2802 -- Proceed, if compilation is needed
2804 if Need_To_Compile then
2806 -- If a source is compiled/recompiled, of course the
2807 -- archive will need to be built/rebuilt.
2809 Need_To_Rebuild_Archive := True;
2810 Compile (Source_Id, Data, Local_Errors);
2813 if Display_Compilation_Progress then
2814 Write_Str ("completed ");
2815 Write_Int (Current_Source_Number);
2816 Write_Str (" out of ");
2817 Write_Int (Total_Number_Of_Sources);
2820 ((Current_Source_Number * 100) / Total_Number_Of_Sources);
2821 Write_Str ("%)...");
2825 -- Next source, if any
2827 Source_Id := Source.Next;
2830 if Need_To_Rebuild_Archive and then (not Data.Library) then
2831 Need_To_Rebuild_Global_Archive := True;
2834 -- If there was no compilation error and -c was not used,
2835 -- build / rebuild the archive if necessary.
2838 and then Data.Library
2839 and then not Data.Langs (Ada_Language_Index)
2840 and then not Compile_Only
2842 Build_Library (Project, Need_To_Rebuild_Archive);
2846 end Compile_Sources;
2852 procedure Copyright is
2854 -- Only output the Copyright notice once
2856 if not Copyright_Output then
2857 Copyright_Output := True;
2859 Write_Str ("GPRMAKE ");
2860 Write_Str (Gnatvsn.Gnat_Version_String);
2861 Write_Str (" Copyright 2004-");
2862 Write_Str (Gnatvsn.Current_Year);
2863 Write_Str (" Free Software Foundation, Inc.");
2868 ------------------------------------
2869 -- Create_Archive_Dependency_File --
2870 ------------------------------------
2872 procedure Create_Archive_Dependency_File
2874 First_Source : Other_Source_Id)
2876 Source_Id : Other_Source_Id;
2877 Source : Other_Source;
2878 Dep_File : Ada.Text_IO.File_Type;
2881 -- Create the file in Append mode, to avoid automatic insertion of
2882 -- an end of line if file is empty.
2884 Create (Dep_File, Append_File, Name);
2886 Source_Id := First_Source;
2887 while Source_Id /= No_Other_Source loop
2888 Source := Project_Tree.Other_Sources.Table (Source_Id);
2889 Put_Line (Dep_File, Get_Name_String (Source.Object_Name));
2890 Put_Line (Dep_File, String (Source.Object_TS));
2891 Source_Id := Source.Next;
2898 if Is_Open (Dep_File) then
2901 end Create_Archive_Dependency_File;
2903 -------------------------------------------
2904 -- Create_Global_Archive_Dependency_File --
2905 -------------------------------------------
2907 procedure Create_Global_Archive_Dependency_File (Name : String) is
2908 Source_Id : Other_Source_Id;
2909 Source : Other_Source;
2910 Dep_File : Ada.Text_IO.File_Type;
2913 -- Create the file in Append mode, to avoid automatic insertion of
2914 -- an end of line if file is empty.
2916 Create (Dep_File, Append_File, Name);
2918 -- Get all the object files of non-Ada sources in non-library projects
2920 for Project in Project_Table.First ..
2921 Project_Table.Last (Project_Tree.Projects)
2923 if not Project_Tree.Projects.Table (Project).Library then
2925 Project_Tree.Projects.Table (Project).First_Other_Source;
2926 while Source_Id /= No_Other_Source loop
2927 Source := Project_Tree.Other_Sources.Table (Source_Id);
2929 -- Put only those object files that are in the global archive
2931 if Is_Included_In_Global_Archive
2932 (Source.Object_Name, Project)
2934 Put_Line (Dep_File, Get_Name_String (Source.Object_Path));
2935 Put_Line (Dep_File, String (Source.Object_TS));
2938 Source_Id := Source.Next;
2947 if Is_Open (Dep_File) then
2950 end Create_Global_Archive_Dependency_File;
2952 ---------------------
2953 -- Display_Command --
2954 ---------------------
2956 procedure Display_Command
2958 Path : String_Access;
2959 CPATH : String_Access := null;
2960 Ellipse : Boolean := False)
2962 Display_Ellipse : Boolean := Ellipse;
2965 -- Only display the command in Verbose Mode (-v) or when
2966 -- not in Quiet Output (no -q).
2968 if Verbose_Mode or (not Quiet_Output) then
2970 -- In Verbose Mode output the full path of the spawned process
2972 if Verbose_Mode then
2973 if CPATH /= null then
2974 Write_Str ("CPATH = ");
2975 Write_Line (CPATH.all);
2978 Write_Str (Path.all);
2984 -- Display only the arguments for which the display flag is set
2985 -- (in Verbose Mode, the display flag is set for all arguments)
2987 for Arg in 1 .. Last_Argument loop
2988 if Arguments_Displayed (Arg) then
2990 Write_Str (Arguments (Arg).all);
2992 elsif Display_Ellipse then
2994 Display_Ellipse := False;
3000 end Display_Command;
3006 procedure Get_Compiler (For_Language : First_Language_Indexes) is
3007 Data : constant Project_Data :=
3008 Project_Tree.Projects.Table (Main_Project);
3010 Ide : constant Package_Id :=
3013 In_Packages => Data.Decl.Packages,
3014 In_Tree => Project_Tree);
3015 -- The id of the package IDE in the project file
3017 Compiler : constant Variable_Value :=
3019 (Name => Language_Names.Table (For_Language),
3021 Attribute_Or_Array_Name => Name_Compiler_Command,
3023 In_Tree => Project_Tree);
3024 -- The value of Compiler_Command ("language") in package IDE, if defined
3027 -- No need to do it again if the compiler is known for this language
3029 if Compiler_Names (For_Language) = null then
3031 -- If compiler command is not defined for this language in package
3032 -- IDE, use the default compiler for this language.
3034 if Compiler = Nil_Variable_Value then
3035 if For_Language in Default_Compiler_Names'Range then
3036 Compiler_Names (For_Language) :=
3037 Default_Compiler_Names (For_Language);
3041 ("unknown compiler name for language """,
3042 Get_Name_String (Language_Names.Table (For_Language)),
3047 Compiler_Names (For_Language) :=
3048 new String'(Get_Name_String (Compiler.Value));
3051 -- Check we have a GCC compiler (name ends with "gcc" or "g++")
3054 Comp_Name : constant String := Compiler_Names (For_Language).all;
3055 Last3 : String (1 .. 3);
3057 if Comp_Name'Length >= 3 then
3058 Last3 := Comp_Name (Comp_Name'Last - 2 .. Comp_Name'Last);
3059 Compiler_Is_Gcc (For_Language) :=
3060 (Last3 = "gcc") or (Last3 = "g++");
3062 Compiler_Is_Gcc (For_Language) := False;
3066 -- Locate the compiler on the path
3068 Compiler_Paths (For_Language) :=
3069 Locate_Exec_On_Path (Compiler_Names (For_Language).all);
3071 -- Fail if compiler cannot be found
3073 if Compiler_Paths (For_Language) = null then
3074 if For_Language = Ada_Language_Index then
3076 ("unable to locate """,
3077 Compiler_Names (For_Language).all,
3082 ("unable to locate " &
3083 Get_Name_String (Language_Names.Table (For_Language)),
3084 " compiler """, Compiler_Names (For_Language).all & '"');
3090 ------------------------------
3091 -- Get_Imported_Directories --
3092 ------------------------------
3094 procedure Get_Imported_Directories
3095 (Project : Project_Id;
3096 Data : in out Project_Data)
3098 Imported_Projects : Project_List := Data.Imported_Projects;
3100 Path_Length : Natural := 0;
3101 Position : Natural := 0;
3103 procedure Add (Source_Dirs : String_List_Id);
3104 -- Add a list of source directories
3106 procedure Recursive_Get_Dirs (Prj : Project_Id);
3107 -- Recursive procedure to get the source directories of this project
3108 -- file and of the project files it imports, in the correct order.
3114 procedure Add (Source_Dirs : String_List_Id) is
3115 Element_Id : String_List_Id;
3116 Element : String_Element;
3117 Add_Arg : Boolean := True;
3120 -- Add each source directory path name, preceded by "-I" to Arguments
3122 Element_Id := Source_Dirs;
3123 while Element_Id /= Nil_String loop
3124 Element := Project_Tree.String_Elements.Table (Element_Id);
3126 if Element.Value /= No_Name then
3127 Get_Name_String (Element.Display_Value);
3129 if Name_Len > 0 then
3131 -- Remove a trailing directory separator: this may cause
3132 -- problems on Windows.
3135 and then Name_Buffer (Name_Len) = Directory_Separator
3137 Name_Len := Name_Len - 1;
3141 Arg : constant String :=
3142 "-I" & Name_Buffer (1 .. Name_Len);
3144 -- Check if directory is already in the list. If it is,
3145 -- no need to put it there again.
3149 for Index in 1 .. Last_Argument loop
3150 if Arguments (Index).all = Arg then
3157 if Path_Length /= 0 then
3158 Path_Length := Path_Length + 1;
3161 Path_Length := Path_Length + Name_Len;
3163 Add_Argument (Arg, True);
3169 Element_Id := Element.Next;
3173 ------------------------
3174 -- Recursive_Get_Dirs --
3175 ------------------------
3177 procedure Recursive_Get_Dirs (Prj : Project_Id) is
3178 Data : Project_Data;
3179 Imported : Project_List;
3182 -- Nothing to do if project is undefined
3184 if Prj /= No_Project then
3185 Data := Project_Tree.Projects.Table (Prj);
3187 -- Nothing to do if project has already been processed
3189 if not Data.Seen then
3191 -- Mark the project as processed, to avoid multiple processing
3192 -- of the same project.
3194 Project_Tree.Projects.Table (Prj).Seen := True;
3196 -- Add the source directories of this project
3198 if not Data.Virtual then
3199 Add (Data.Source_Dirs);
3202 Recursive_Get_Dirs (Data.Extends);
3204 -- Call itself for all imported projects, if any
3206 Imported := Data.Imported_Projects;
3207 while Imported /= Empty_Project_List loop
3209 (Project_Tree.Project_Lists.Table (Imported).Project);
3211 Project_Tree.Project_Lists.Table (Imported).Next;
3215 end Recursive_Get_Dirs;
3217 -- Start of processing for Get_Imported_Directories
3220 -- First, mark all project as not processed
3222 for J in Project_Table.First ..
3223 Project_Table.Last (Project_Tree.Projects)
3225 Project_Tree.Projects.Table (J).Seen := False;
3232 -- Process this project individually, project data are already known
3234 Project_Tree.Projects.Table (Project).Seen := True;
3236 Add (Data.Source_Dirs);
3238 Recursive_Get_Dirs (Data.Extends);
3240 while Imported_Projects /= Empty_Project_List loop
3242 (Project_Tree.Project_Lists.Table
3243 (Imported_Projects).Project);
3244 Imported_Projects := Project_Tree.Project_Lists.Table
3245 (Imported_Projects).Next;
3248 Data.Imported_Directories_Switches :=
3249 new Argument_List'(Arguments (1 .. Last_Argument));
3251 -- Create the Include_Path, from the Arguments
3253 Data.Include_Path := new String (1 .. Path_Length);
3254 Data.Include_Path (1 .. Arguments (1)'Length - 2) :=
3255 Arguments (1)(Arguments (1)'First + 2 .. Arguments (1)'Last);
3256 Position := Arguments (1)'Length - 2;
3258 for Arg in 2 .. Last_Argument loop
3259 Position := Position + 1;
3260 Data.Include_Path (Position) := Path_Separator;
3262 (Position + 1 .. Position + Arguments (Arg)'Length - 2) :=
3263 Arguments (Arg)(Arguments (Arg)'First + 2 .. Arguments (Arg)'Last);
3264 Position := Position + Arguments (Arg)'Length - 2;
3268 end Get_Imported_Directories;
3274 procedure Gprmake is
3278 if Verbose_Mode then
3280 Write_Str ("Parsing project file """);
3281 Write_Str (Project_File_Name.all);
3286 -- Parse and process project files for other languages (not for Ada)
3289 (Project => Main_Project,
3290 In_Tree => Project_Tree,
3291 Project_File_Name => Project_File_Name.all,
3292 Packages_To_Check => Packages_To_Check);
3294 -- Fail if parsing/processing was unsuccessful
3296 if Main_Project = No_Project then
3297 Osint.Fail ("""", Project_File_Name.all, """ processing failed");
3300 if Verbose_Mode then
3302 Write_Str ("Parsing of project file """);
3303 Write_Str (Project_File_Name.all);
3304 Write_Str (""" is finished.");
3308 -- If -f was specified, we will certainly need to link (except when
3309 -- -u or -c were specified, of course).
3311 Need_To_Relink := Force_Compilations;
3313 if Unique_Compile then
3314 if Mains.Number_Of_Mains = 0 then
3316 ("No source specified to compile in 'unique compile' mode");
3318 Compile_Individual_Sources;
3319 Report_Total_Errors ("compilation");
3324 Data : constant Prj.Project_Data :=
3325 Project_Tree.Projects.Table (Main_Project);
3327 if Data.Library and then Mains.Number_Of_Mains /= 0 then
3329 ("Cannot specify mains on the command line " &
3330 "for a Library Project");
3333 -- First check for C++, to link libraries with g++,
3336 Check_For_C_Plus_Plus;
3338 -- Compile sources and build archives for library project,
3343 -- When Keep_Going is True, if we had some errors, fail now,
3344 -- reporting the number of compilation errors.
3345 -- Do not attempt to link.
3347 Report_Total_Errors ("compilation");
3349 -- If -c was not specified, link the executables,
3350 -- if there are any.
3353 and then not Data.Library
3354 and then Data.Object_Directory /= No_Path
3356 Build_Global_Archive;
3360 -- When Keep_Going is True, if we had some errors, fail, reporting
3361 -- the number of linking errors.
3363 Report_Total_Errors ("linking");
3372 procedure Initialize is
3374 Set_Mode (Ada_Only);
3376 -- Do some necessary package initializations
3381 Prj.Initialize (Project_Tree);
3384 -- Add the directory where gprmake is invoked in front of the path,
3385 -- if gprmake is invoked from a bin directory or with directory
3386 -- information. Only do this if the platform is not VMS, where the
3387 -- notion of path does not really exist.
3389 -- Below code shares nasty code duplication with make.adb code???
3393 Prefix : constant String := Executable_Prefix_Path;
3394 Command : constant String := Command_Name;
3397 if Prefix'Length > 0 then
3399 PATH : constant String :=
3400 Prefix & Directory_Separator & "bin" &
3402 Getenv ("PATH").all;
3404 Setenv ("PATH", PATH);
3408 for Index in reverse Command'Range loop
3409 if Command (Index) = Directory_Separator then
3411 Absolute_Dir : constant String :=
3413 (Command (Command'First .. Index));
3414 PATH : constant String :=
3417 Getenv ("PATH").all;
3419 Setenv ("PATH", PATH);
3429 -- Set Name_Ide and Name_Compiler_Command
3432 Add_Str_To_Name_Buffer ("ide");
3433 Name_Ide := Name_Find;
3436 Add_Str_To_Name_Buffer ("compiler_command");
3437 Name_Compiler_Command := Name_Find;
3439 -- Make sure the Saved_Switches table is empty
3441 Saved_Switches.Set_Last (0);
3443 -- Get the command line arguments
3445 Scan_Args : for Next_Arg in 1 .. Argument_Count loop
3446 Scan_Arg (Argument (Next_Arg));
3449 -- Fail if command line ended with "-P"
3451 if Project_File_Name_Expected then
3452 Osint.Fail ("project file name missing after -P");
3454 -- Or if it ended with "-o"
3456 elsif Output_File_Name_Expected then
3457 Osint.Fail ("output file name missing after -o");
3460 -- If no project file was specified, display the usage and fail
3462 if Project_File_Name = null then
3464 Exit_Program (E_Success);
3467 -- To be able of finding libgnat.a in MLib.Tgt, we need to have the
3468 -- default search dirs established in Osint.
3470 Osint.Add_Default_Search_Dirs;
3473 -----------------------------------
3474 -- Is_Included_In_Global_Archive --
3475 -----------------------------------
3477 function Is_Included_In_Global_Archive
3478 (Object_Name : File_Name_Type;
3479 Project : Project_Id) return Boolean
3481 Data : Project_Data := Project_Tree.Projects.Table (Project);
3482 Source : Other_Source_Id;
3485 while Data.Extended_By /= No_Project loop
3486 Data := Project_Tree.Projects.Table (Data.Extended_By);
3488 Source := Data.First_Other_Source;
3489 while Source /= No_Other_Source loop
3490 if Project_Tree.Other_Sources.Table (Source).Object_Name =
3496 Project_Tree.Other_Sources.Table (Source).Next;
3502 end Is_Included_In_Global_Archive;
3504 ----------------------
3505 -- Link_Executables --
3506 ----------------------
3508 procedure Link_Executables is
3509 Data : constant Project_Data :=
3510 Project_Tree.Projects.Table (Main_Project);
3512 Mains_Specified : constant Boolean := Mains.Number_Of_Mains /= 0;
3513 -- True if main sources were specified on the command line
3515 Object_Dir : constant String :=
3516 Get_Name_String (Data.Display_Object_Dir);
3517 -- Path of the object directory of the main project
3519 Source_Id : Other_Source_Id;
3520 Source : Other_Source;
3523 Linker_Name : String_Access;
3524 Linker_Path : String_Access;
3525 -- The linker name and path, when linking is not done by gnatlink
3527 Link_Done : Boolean := False;
3528 -- Set to True when the linker is invoked directly (not through
3529 -- gnatmake) to be able to report if mains were up to date at the end
3532 procedure Add_C_Plus_Plus_Link_For_Gnatmake;
3533 -- Add the --LINK= switch for gnatlink, depending on the C++ compiler
3535 procedure Check_Time_Stamps (Exec_Time_Stamp : Time_Stamp_Type);
3536 -- Check if there is an archive that is more recent than the executable
3537 -- to decide if we need to relink.
3539 procedure Choose_C_Plus_Plus_Link_Process;
3540 -- If the C++ compiler is not g++, create the correct script to link
3542 procedure Link_Foreign
3544 Main_Id : File_Name_Type;
3545 Source : Other_Source);
3546 -- Link a non-Ada main, when there is no Ada code
3548 ---------------------------------------
3549 -- Add_C_Plus_Plus_Link_For_Gnatmake --
3550 ---------------------------------------
3552 procedure Add_C_Plus_Plus_Link_For_Gnatmake is
3555 ("--LINK=" & Compiler_Names (C_Plus_Plus_Language_Index).all,
3557 end Add_C_Plus_Plus_Link_For_Gnatmake;
3559 -----------------------
3560 -- Check_Time_Stamps --
3561 -----------------------
3563 procedure Check_Time_Stamps (Exec_Time_Stamp : Time_Stamp_Type) is
3564 Prj_Data : Project_Data;
3567 for Prj in Project_Table.First ..
3568 Project_Table.Last (Project_Tree.Projects)
3570 Prj_Data := Project_Tree.Projects.Table (Prj);
3572 -- There is an archive only in project
3573 -- files with sources other than Ada
3576 if Data.Other_Sources_Present then
3578 Archive_Path : constant String := Get_Name_String
3579 (Prj_Data.Display_Object_Dir) & Directory_Separator
3580 & "lib" & Get_Name_String (Prj_Data.Display_Name)
3581 & '.' & Archive_Ext;
3582 Archive_TS : Time_Stamp_Type;
3585 Add_Str_To_Name_Buffer (Archive_Path);
3586 Archive_TS := File_Stamp (File_Name_Type'(Name_Find));
3588 -- If the archive is later than the
3589 -- executable, we need to relink.
3591 if Archive_TS /= Empty_Time_Stamp
3593 Exec_Time_Stamp < Archive_TS
3595 Need_To_Relink := True;
3597 if Verbose_Mode then
3599 Write_Str (Archive_Path);
3600 Write_Str (" has time stamp ");
3601 Write_Str ("later than ");
3602 Write_Line ("executable");
3610 end Check_Time_Stamps;
3612 -------------------------------------
3613 -- Choose_C_Plus_Plus_Link_Process --
3614 -------------------------------------
3616 procedure Choose_C_Plus_Plus_Link_Process is
3618 if Compiler_Names (C_Plus_Plus_Language_Index) = null then
3619 Get_Compiler (C_Plus_Plus_Language_Index);
3621 end Choose_C_Plus_Plus_Link_Process;
3627 procedure Link_Foreign
3629 Main_Id : File_Name_Type;
3630 Source : Other_Source)
3632 Executable_Name : constant String :=
3635 (Project => Main_Project,
3636 In_Tree => Project_Tree,
3639 Ada_Main => False));
3640 -- File name of the executable
3642 Executable_Path : constant String :=
3644 (Data.Display_Exec_Dir) &
3645 Directory_Separator & Executable_Name;
3646 -- Path name of the executable
3648 Exec_Time_Stamp : Time_Stamp_Type;
3651 -- Now, check if the executable is up to date. It is considered
3652 -- up to date if its time stamp is not earlier that the time stamp
3653 -- of any archive. Only do that if we don't know if we need to link.
3655 if not Need_To_Relink then
3657 -- Get the time stamp of the executable
3660 Add_Str_To_Name_Buffer (Executable_Path);
3661 Exec_Time_Stamp := File_Stamp (File_Name_Type'(Name_Find));
3663 if Verbose_Mode then
3664 Write_Str (" Checking executable ");
3665 Write_Line (Executable_Name);
3668 -- If executable does not exist, we need to link
3670 if Exec_Time_Stamp = Empty_Time_Stamp then
3671 Need_To_Relink := True;
3673 if Verbose_Mode then
3674 Write_Line (" -> not found");
3677 -- Otherwise, get the time stamps of each archive. If one of
3678 -- them is found later than the executable, we need to relink.
3681 Check_Time_Stamps (Exec_Time_Stamp);
3684 -- If Need_To_Relink is False, we are done
3686 if Verbose_Mode and (not Need_To_Relink) then
3687 Write_Line (" -> up to date");
3693 if Need_To_Relink then
3698 -- Specify the executable path name
3700 Add_Argument (Dash_o, True);
3702 (Get_Name_String (Data.Display_Exec_Dir) &
3703 Directory_Separator &
3706 (Project => Main_Project,
3707 In_Tree => Project_Tree,
3710 Ada_Main => False)),
3713 -- Specify the object file of the main source
3716 (Object_Dir & Directory_Separator &
3717 Get_Name_String (Source.Object_Name),
3720 -- Add all the archives, in a correct order
3722 Add_Archives (For_Gnatmake => False);
3724 -- Add the switches specified in package Linker of
3725 -- the main project.
3730 Language => Source.Language,
3731 File_Name => Main_Id);
3733 -- Add the switches specified in attribute
3734 -- Linker_Options of packages Linker.
3736 if Link_Options_Switches = null then
3737 Link_Options_Switches :=
3739 (Linker_Options_Switches (Main_Project, Project_Tree));
3742 Add_Arguments (Link_Options_Switches.all, True);
3744 -- Add the linking options specified on the
3747 for Arg in 1 .. Linker_Options.Last loop
3748 Add_Argument (Linker_Options.Table (Arg), True);
3751 -- If there are shared libraries and the run path
3752 -- option is supported, add the run path switch.
3754 if Lib_Path.Last > 0 then
3757 String (Lib_Path.Table (1 .. Lib_Path.Last)),
3761 -- And invoke the linker
3763 Display_Command (Linker_Name.all, Linker_Path);
3766 Arguments (1 .. Last_Argument),
3770 Report_Error ("could not link ", Main);
3775 -- Start of processing of Link_Executables
3778 -- If no mains specified, get mains from attribute Main, if it exists
3780 if not Mains_Specified then
3782 Element_Id : String_List_Id;
3783 Element : String_Element;
3786 Element_Id := Data.Mains;
3787 while Element_Id /= Nil_String loop
3788 Element := Project_Tree.String_Elements.Table (Element_Id);
3790 if Element.Value /= No_Name then
3791 Mains.Add_Main (Get_Name_String (Element.Value));
3794 Element_Id := Element.Next;
3799 if Mains.Number_Of_Mains = 0 then
3801 -- If the attribute Main is an empty list or not specified,
3802 -- there is nothing to do.
3804 if Verbose_Mode then
3805 Write_Line ("No main to link");
3810 -- Check if -o was used for several mains
3812 if Output_File_Name /= null and then Mains.Number_Of_Mains > 1 then
3813 Osint.Fail ("cannot specify an executable name for several mains");
3816 -- Check how we are going to do the link
3818 if not Data.Other_Sources_Present then
3820 -- Only Ada sources in the main project, and even maybe not
3822 if Data.Extends = No_Project and then
3823 not Data.Langs (Ada_Language_Index)
3825 -- Fail if the main project has no source of any language
3829 Get_Name_String (Data.Name),
3830 """ has no sources, so no main can be linked");
3833 -- Only Ada sources in the main project, call gnatmake directly
3837 -- Choose correct linker if there is C++ code in other projects
3839 if C_Plus_Plus_Is_Used then
3840 Choose_C_Plus_Plus_Link_Process;
3841 Add_Argument (Dash_largs, Verbose_Mode);
3842 Add_C_Plus_Plus_Link_For_Gnatmake;
3843 Add_Argument (Dash_margs, Verbose_Mode);
3846 Compile_Link_With_Gnatmake (Mains_Specified);
3850 -- There are other language sources. First check if there are also
3853 if Data.Langs (Ada_Language_Index) then
3855 -- There is a mix of Ada and other language sources in the main
3856 -- project. Any main that is not a source of the other languages
3857 -- will be deemed to be an Ada main.
3859 -- Find the mains of the other languages and the Ada mains
3862 Ada_Mains.Set_Last (0);
3863 Other_Mains.Set_Last (0);
3869 Main : constant String := Mains.Next_Main;
3870 Main_Id : File_Name_Type;
3873 exit when Main'Length = 0;
3875 -- Get the main file name
3878 Add_Str_To_Name_Buffer (Main);
3879 Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len));
3880 Main_Id := Name_Find;
3882 -- Check if it is a source of a language other than Ada
3884 Source_Id := Data.First_Other_Source;
3885 while Source_Id /= No_Other_Source loop
3887 Project_Tree.Other_Sources.Table (Source_Id);
3888 exit when Source.File_Name = Main_Id;
3889 Source_Id := Source.Next;
3892 -- If it is not, put it in the list of Ada mains
3894 if Source_Id = No_Other_Source then
3895 Ada_Mains.Increment_Last;
3896 Ada_Mains.Table (Ada_Mains.Last) := new String'(Main);
3898 -- Otherwise, put it in the list of other mains
3901 Other_Mains.Increment_Last;
3902 Other_Mains.Table (Other_Mains.Last) := Source;
3907 -- If C++ is one of the other language, create the shell script
3910 if C_Plus_Plus_Is_Used then
3911 Choose_C_Plus_Plus_Link_Process;
3914 -- Call gnatmake with the necessary switches for each non-Ada
3915 -- main, if there are some.
3917 for Main in 1 .. Other_Mains.Last loop
3919 Source : constant Other_Source := Other_Mains.Table (Main);
3924 -- Add -o if -o was specified
3926 if Output_File_Name = null then
3927 Add_Argument (Dash_o, True);
3931 (Project => Main_Project,
3932 In_Tree => Project_Tree,
3933 Main => Other_Mains.Table (Main).File_Name,
3935 Ada_Main => False)),
3939 -- Call gnatmake with the -B switch
3941 Add_Argument (Dash_B, True);
3943 -- Add to the linking options the object file of the source
3945 Add_Argument (Dash_largs, Verbose_Mode);
3947 (Get_Name_String (Source.Object_Name), Verbose_Mode);
3949 -- If C++ is one of the language, add the --LINK switch
3950 -- to the linking switches.
3952 if C_Plus_Plus_Is_Used then
3953 Add_C_Plus_Plus_Link_For_Gnatmake;
3956 -- Add -margs so that the following switches are for
3959 Add_Argument (Dash_margs, Verbose_Mode);
3961 -- And link with gnatmake
3963 Compile_Link_With_Gnatmake (Mains_Specified => False);
3967 -- If there are also Ada mains, call gnatmake for all these mains
3969 if Ada_Mains.Last /= 0 then
3972 -- Put all the Ada mains as the first arguments
3974 for Main in 1 .. Ada_Mains.Last loop
3975 Add_Argument (Ada_Mains.Table (Main).all, True);
3978 -- If C++ is one of the languages, add the --LINK switch to
3979 -- the linking switches.
3981 if Data.Langs (C_Plus_Plus_Language_Index) then
3982 Add_Argument (Dash_largs, Verbose_Mode);
3983 Add_C_Plus_Plus_Link_For_Gnatmake;
3984 Add_Argument (Dash_margs, Verbose_Mode);
3987 -- And link with gnatmake
3989 Compile_Link_With_Gnatmake (Mains_Specified => False);
3993 -- No Ada source in main project
3995 -- First, get the linker to invoke
3997 if Data.Langs (C_Plus_Plus_Language_Index) then
3998 Get_Compiler (C_Plus_Plus_Language_Index);
3999 Linker_Name := Compiler_Names (C_Plus_Plus_Language_Index);
4000 Linker_Path := Compiler_Paths (C_Plus_Plus_Language_Index);
4003 Get_Compiler (C_Language_Index);
4004 Linker_Name := Compiler_Names (C_Language_Index);
4005 Linker_Path := Compiler_Paths (C_Language_Index);
4012 -- Get each main, check if it is a source of the main project,
4013 -- and if it is, invoke the linker.
4017 Main : constant String := Mains.Next_Main;
4018 Main_Id : File_Name_Type;
4021 exit when Main'Length = 0;
4023 -- Get the file name of the main
4026 Add_Str_To_Name_Buffer (Main);
4027 Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len));
4028 Main_Id := Name_Find;
4030 -- Check if it is a source of the main project file
4032 Source_Id := Data.First_Other_Source;
4033 while Source_Id /= No_Other_Source loop
4035 Project_Tree.Other_Sources.Table (Source_Id);
4036 exit when Source.File_Name = Main_Id;
4037 Source_Id := Source.Next;
4040 -- Report an error if it is not
4042 if Source_Id = No_Other_Source then
4044 (Main, "is not a source of project ",
4045 Get_Name_String (Data.Name));
4048 Link_Foreign (Main, Main_Id, Source);
4053 -- If no linking was done, report it, except in Quiet Output
4055 if (Verbose_Mode or (not Quiet_Output)) and (not Link_Done) then
4056 Osint.Write_Program_Name;
4058 if Mains.Number_Of_Mains = 1 then
4060 -- If there is only one executable, report its name too
4066 Main : constant String := Mains.Next_Main;
4067 Main_Id : File_Name_Type;
4070 Add_Str_To_Name_Buffer (Main);
4071 Main_Id := Name_Find;
4075 (Project => Main_Project,
4076 In_Tree => Project_Tree,
4079 Ada_Main => False)));
4080 Write_Line (""" up to date");
4084 Write_Line (": all executables up to date");
4089 end Link_Executables;
4095 procedure Report_Error
4101 -- If Keep_Going is True, output error message preceded by error header
4104 Total_Number_Of_Errors := Total_Number_Of_Errors + 1;
4105 Write_Str (Error_Header);
4111 -- Otherwise just fail
4114 Osint.Fail (S1, S2, S3);
4118 -------------------------
4119 -- Report_Total_Errors --
4120 -------------------------
4122 procedure Report_Total_Errors (Kind : String) is
4124 if Total_Number_Of_Errors /= 0 then
4125 if Total_Number_Of_Errors = 1 then
4127 ("One ", Kind, " error");
4131 ("Total of" & Total_Number_Of_Errors'Img,
4132 ' ' & Kind & " errors");
4135 end Report_Total_Errors;
4141 procedure Scan_Arg (Arg : String) is
4143 pragma Assert (Arg'First = 1);
4145 if Arg'Length = 0 then
4149 -- If preceding switch was -P, a project file name need to be
4150 -- specified, not a switch.
4152 if Project_File_Name_Expected then
4153 if Arg (1) = '-' then
4154 Osint.Fail ("project file name missing after -P");
4156 Project_File_Name_Expected := False;
4157 Project_File_Name := new String'(Arg);
4160 -- If preceding switch was -o, an executable name need to be
4161 -- specified, not a switch.
4163 elsif Output_File_Name_Expected then
4164 if Arg (1) = '-' then
4165 Osint.Fail ("output file name missing after -o");
4167 Output_File_Name_Expected := False;
4168 Output_File_Name := new String'(Arg);
4171 -- Set the processor/language for the following switches
4173 -- -cargs: Ada compiler arguments
4175 elsif Arg = "-cargs" then
4176 Current_Language := Ada_Language_Index;
4177 Current_Processor := Compiler;
4179 elsif Arg'Length > 7 and then Arg (1 .. 7) = "-cargs:" then
4181 Add_Str_To_Name_Buffer (Arg (8 .. Arg'Last));
4182 To_Lower (Name_Buffer (1 .. Name_Len));
4185 Lang : constant Name_Id := Name_Find;
4187 Current_Language := Language_Indexes.Get (Lang);
4189 if Current_Language = No_Language_Index then
4190 Add_Language_Name (Lang);
4191 Current_Language := Last_Language_Index;
4194 Current_Processor := Compiler;
4197 elsif Arg = "-largs" then
4198 Current_Processor := Linker;
4202 elsif Arg = "-gargs" then
4203 Current_Processor := None;
4205 -- A special test is needed for the -o switch within a -largs since
4206 -- that is another way to specify the name of the final executable.
4208 elsif Current_Processor = Linker and then Arg = "-o" then
4210 ("switch -o not allowed within a -largs. Use -o directly.");
4212 -- If current processor is not gprmake directly, store the option in
4213 -- the appropriate table.
4215 elsif Current_Processor /= None then
4218 -- Switches start with '-'
4220 elsif Arg (1) = '-' then
4221 if Arg'Length > 3 and then Arg (1 .. 3) = "-aP" then
4222 Add_Search_Project_Directory (Arg (4 .. Arg'Last));
4224 -- Record the switch, so that it is passed to gnatmake, if
4225 -- gnatmake is called.
4227 Saved_Switches.Append (new String'(Arg));
4229 elsif Arg = "-c" then
4230 Compile_Only := True;
4232 -- Make sure that when a main is specified and switch -c is used,
4233 -- only the main(s) is/are compiled.
4235 if Mains.Number_Of_Mains > 0 then
4236 Unique_Compile := True;
4239 elsif Arg = "-d" then
4240 Display_Compilation_Progress := True;
4242 elsif Arg = "-eL" then
4243 Follow_Links_For_Files := True;
4245 elsif Arg = "-f" then
4246 Force_Compilations := True;
4248 elsif Arg = "-h" then
4251 elsif Arg = "-k" then
4254 elsif Arg = "-o" then
4255 if Output_File_Name /= null then
4256 Osint.Fail ("cannot specify several -o switches");
4259 Output_File_Name_Expected := True;
4262 elsif Arg'Length >= 2 and then Arg (2) = 'P' then
4263 if Project_File_Name /= null then
4264 Osint.Fail ("cannot have several project files specified");
4266 elsif Arg'Length = 2 then
4267 Project_File_Name_Expected := True;
4270 Project_File_Name := new String'(Arg (3 .. Arg'Last));
4273 elsif Arg = "-p" or else Arg = "--create-missing-dirs" then
4274 Setup_Projects := True;
4276 elsif Arg = "-q" then
4277 Quiet_Output := True;
4279 elsif Arg = "-u" then
4280 Unique_Compile := True;
4281 Compile_Only := True;
4283 elsif Arg = "-v" then
4284 Verbose_Mode := True;
4287 elsif Arg'Length = 4 and then Arg (1 .. 3) = "-vP"
4288 and then Arg (4) in '0' .. '2'
4292 Current_Verbosity := Prj.Default;
4294 Current_Verbosity := Prj.Medium;
4296 Current_Verbosity := Prj.High;
4301 elsif Arg'Length >= 3 and then Arg (2) = 'X'
4302 and then Is_External_Assignment (Arg)
4304 -- Is_External_Assignment has side effects when it returns True
4306 -- Record the -X switch, so that it will be passed to gnatmake,
4307 -- if gnatmake is called.
4309 Saved_Switches.Append (new String'(Arg));
4312 Osint.Fail ("illegal option """, Arg, """");
4316 -- Not a switch: must be a main
4318 Mains.Add_Main (Arg);
4320 -- Make sure that when a main is specified and switch -c is used,
4321 -- only the main(s) is/are compiled.
4323 if Compile_Only then
4324 Unique_Compile := True;
4333 function Strip_CR_LF (Text : String) return String is
4334 To : String (1 .. Text'Length);
4335 Index_To : Natural := 0;
4338 for Index in Text'Range loop
4339 if (Text (Index) /= ASCII.CR) and then (Text (Index) /= ASCII.LF) then
4340 Index_To := Index_To + 1;
4341 To (Index_To) := Text (Index);
4345 return To (1 .. Index_To);
4354 if not Usage_Output then
4355 Usage_Output := True;
4358 Write_Str ("Usage: ");
4359 Osint.Write_Program_Name;
4360 Write_Str (" -P<project file> [opts] [name] {");
4361 Write_Str ("[-cargs:lang opts] ");
4362 Write_Str ("[-largs opts] [-gargs opts]}");
4365 Write_Str (" name is zero or more file names");
4371 Write_Str ("gprmake switches:");
4376 Write_Str (" -aPdir Add directory dir to project search path");
4381 Write_Str (" -c Compile only");
4386 Write_Str (" -eL Follow symbolic links when processing " &
4392 Write_Str (" -f Force recompilations");
4397 Write_Str (" -k Keep going after compilation errors");
4402 Write_Str (" -o name Choose an alternate executable name");
4407 Write_Str (" -p Create missing obj, lib and exec dirs");
4412 Write_Str (" -Pproj Use GNAT Project File proj");
4417 Write_Str (" -q Be quiet/terse");
4423 (" -u Unique compilation. Only compile the given files");
4428 Write_Str (" -v Verbose output");
4433 Write_Str (" -vPx Specify verbosity when parsing Project Files");
4438 Write_Str (" -Xnm=val Specify an external reference for " &
4445 Write_Line (" -cargs opts opts are passed to the Ada compiler");
4447 -- Line for -cargs:lang
4449 Write_Line (" -cargs:<lang> opts");
4450 Write_Line (" opts are passed to the compiler " &
4451 "for language < lang > ");
4455 Write_Str (" -largs opts opts are passed to the linker");
4460 Write_Str (" -gargs opts opts directly interpreted by gprmake");
4468 Makeutl.Do_Fail := Report_Error'Access;