OSDN Git Service

PR 33870
[pf3gnuchains/gcc-fork.git] / gcc / ada / makegpr.adb
1 ------------------------------------------------------------------------------
2 --                                                                          --
3 --                         GNAT COMPILER COMPONENTS                         --
4 --                                                                          --
5 --                              M A K E G P R                               --
6 --                                                                          --
7 --                                 B o d y                                  --
8 --                                                                          --
9 --          Copyright (C) 2004-2007, Free Software Foundation, Inc.         --
10 --                                                                          --
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.          --
20 --                                                                          --
21 -- GNAT was originally developed  by the GNAT team at  New York University. --
22 -- Extensive contributions were provided by Ada Core Technologies Inc.      --
23 --                                                                          --
24 ------------------------------------------------------------------------------
25
26 with Csets;
27 with Gnatvsn;
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;
33 with Opt;      use Opt;
34 with Osint;    use Osint;
35 with Prj;      use Prj;
36 with Prj.Ext;  use Prj.Ext;
37 with Prj.Pars;
38 with Prj.Util; use Prj.Util;
39 with Snames;   use Snames;
40 with Table;
41 with Types;    use Types;
42
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;
47
48 with GNAT.Directory_Operations;  use GNAT.Directory_Operations;
49 with GNAT.Dynamic_Tables;
50 with GNAT.Expect;                use GNAT.Expect;
51 with GNAT.HTable;
52 with GNAT.OS_Lib;                use GNAT.OS_Lib;
53 with GNAT.Regpat;                use GNAT.Regpat;
54
55 with System;
56 with System.Case_Util;           use System.Case_Util;
57
58 package body Makegpr is
59
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.
63
64    Max_In_Archives : constant := 50;
65    --  The maximum number of arguments for a single invocation of the
66    --  Archive Indexer (ar).
67
68    No_Argument : aliased Argument_List := (1 .. 0 => null);
69    --  Null argument list representing case of no arguments
70
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.
74
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
77
78    Name_Ide              : Name_Id;
79    Name_Compiler_Command : Name_Id;
80    --  Names of package IDE and its attribute Compiler_Command.
81    --  Set up by Initialize.
82
83    Unique_Compile : Boolean := False;
84    --  True when switch -u is used on the command line
85
86    type Source_Index_Rec is record
87       Project : Project_Id;
88       Id      : Other_Source_Id;
89       Found   : Boolean := False;
90    end record;
91    --  Used as Source_Indexes component to check if archive needs to be rebuilt
92
93    type Source_Index_Array is array (Positive range <>) of Source_Index_Rec;
94    type Source_Indexes_Ref is access Source_Index_Array;
95
96    procedure Free is new Ada.Unchecked_Deallocation
97      (Source_Index_Array, Source_Indexes_Ref);
98
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.
104
105    Last_Source : Natural := 0;
106    --  The index of the last valid component of Source_Indexes
107
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.
111
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++");
115
116    Default_Compiler_Names : constant array
117      (First_Language_Indexes range
118         Ada_Language_Index .. C_Plus_Plus_Language_Index)
119      of String_Access :=
120        (Ada_Language_Index         => Gnatmake_String,
121         C_Language_Index           => GCC_String,
122         C_Plus_Plus_Language_Index => G_Plus_Plus_String);
123
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.
127
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.
131
132    Archive_Builder_Path : String_Access := null;
133    --  The path name of the archive builder (ar). To be used when spawning
134    --  ar commands.
135
136    Archive_Indexer_Path : String_Access := null;
137    --  The path name of the archive indexer (ranlib), if it exists
138
139    Copyright_Output : Boolean := False;
140    Usage_Output     : Boolean := False;
141    --  Flags to avoid multiple displays of Copyright notice and of Usage
142
143    Output_File_Name           : String_Access := null;
144    --  The name given after a switch -o
145
146    Output_File_Name_Expected  : Boolean := False;
147    --  True when last switch was -o
148
149    Project_File_Name          : String_Access := null;
150    --  The name of the project file specified with switch -P
151
152    Project_File_Name_Expected : Boolean := False;
153    --  True when last switch was -P
154
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
161
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
170
171    Project_Tree : constant Project_Tree_Ref := new Project_Tree_Data;
172
173    Main_Project : Project_Id;
174    --  The project id of the main project
175
176    type Processor is (None, Linker, Compiler);
177    Current_Processor : Processor := None;
178    --  This variable changes when switches -*args are used
179
180    Current_Language  : Language_Index := Ada_Language_Index;
181    --  The compiler language to consider when Processor is Compiler
182
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,
187       Table_Initial        => 20,
188       Table_Increment      => 100);
189    Options : array (First_Language_Indexes) of Comp_Opts.Instance;
190    --  Tables to store compiling options for the different compilers
191
192    package Linker_Options is new Table.Table
193      (Table_Component_Type => String_Access,
194       Table_Index_Type     => Integer,
195       Table_Low_Bound      => 1,
196       Table_Initial        => 20,
197       Table_Increment      => 100,
198       Table_Name           => "Makegpr.Linker_Options");
199    --  Table to store the linking options
200
201    package Library_Opts is new Table.Table
202      (Table_Component_Type => String_Access,
203       Table_Index_Type     => Integer,
204       Table_Low_Bound      => 1,
205       Table_Initial        => 20,
206       Table_Increment      => 100,
207       Table_Name           => "Makegpr.Library_Opts");
208    --  Table to store the linking options
209
210    package Ada_Mains is new Table.Table
211      (Table_Component_Type => String_Access,
212       Table_Index_Type     => Integer,
213       Table_Low_Bound      => 1,
214       Table_Initial        => 20,
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.
219
220    package Other_Mains is new Table.Table
221      (Table_Component_Type => Other_Source,
222       Table_Index_Type     => Integer,
223       Table_Low_Bound      => 1,
224       Table_Initial        => 20,
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.
229
230    package Sources_Compiled is new GNAT.HTable.Simple_HTable
231      (Header_Num => Header_Num,
232       Element    => Boolean,
233       No_Element => False,
234       Key        => File_Name_Type,
235       Hash       => Hash,
236       Equal      => "=");
237
238    package Saved_Switches is new Table.Table
239      (Table_Component_Type => String_Access,
240       Table_Index_Type     => Integer,
241       Table_Low_Bound      => 1,
242       Table_Initial        => 10,
243       Table_Increment      => 100,
244       Table_Name           => "Makegpr.Saved_Switches");
245    --  Table to store the switches to be passed to gnatmake
246
247    Initial_Argument_Count : constant Positive := 20;
248    type Boolean_Array is array (Positive range <>) of Boolean;
249    type Booleans is access Boolean_Array;
250
251    procedure Free is new Ada.Unchecked_Deallocation (Boolean_Array, Booleans);
252
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
256
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.
261
262    Last_Argument : Natural := 0;
263    --  Index of the last valid argument in Arguments
264
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.
275
276    --  Various switches used when spawning processes:
277
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_f_String     : aliased  String := "-f";
287    Dash_f            : constant String_Access := Dash_f_String'Access;
288    Dash_k_String     : aliased  String := "-k";
289    Dash_k            : constant String_Access := Dash_k_String'Access;
290    Dash_largs_String : aliased  String := "-largs";
291    Dash_largs        : constant String_Access := Dash_largs_String'Access;
292    Dash_M_String     : aliased  String := "-M";
293    Dash_M            : constant String_Access := Dash_M_String'Access;
294    Dash_margs_String : aliased  String := "-margs";
295    Dash_margs        : constant String_Access := Dash_margs_String'Access;
296    Dash_o_String     : aliased  String := "-o";
297    Dash_o            : constant String_Access := Dash_o_String'Access;
298    Dash_P_String     : aliased  String := "-P";
299    Dash_P            : constant String_Access := Dash_P_String'Access;
300    Dash_q_String     : aliased  String := "-q";
301    Dash_q            : constant String_Access := Dash_q_String'Access;
302    Dash_u_String     : aliased  String := "-u";
303    Dash_u            : constant String_Access := Dash_u_String'Access;
304    Dash_v_String     : aliased  String := "-v";
305    Dash_v            : constant String_Access := Dash_v_String'Access;
306    Dash_vP1_String   : aliased  String := "-vP1";
307    Dash_vP1          : constant String_Access := Dash_vP1_String'Access;
308    Dash_vP2_String   : aliased  String := "-vP2";
309    Dash_vP2          : constant String_Access := Dash_vP2_String'Access;
310    Dash_x_String     : aliased  String := "-x";
311    Dash_x            : constant String_Access := Dash_x_String'Access;
312    r_String          : aliased  String := "r";
313    r                 : constant String_Access := r_String'Access;
314
315    CPATH : constant String := "CPATH";
316    --  The environment variable to set when compiler is a GCC compiler
317    --  to indicate the include directory path.
318
319    Current_Include_Paths : array (First_Language_Indexes) of String_Access;
320    --  A cache for the paths of included directories, to avoid setting
321    --  env var CPATH unnecessarily.
322
323    C_Plus_Plus_Is_Used : Boolean := False;
324    --  True when there are sources in C++
325
326    Link_Options_Switches : Argument_List_Access := null;
327    --  The link options coming from the attributes Linker'Linker_Options in
328    --  project files imported, directly or indirectly, by the main project.
329
330    Total_Number_Of_Errors : Natural := 0;
331    --  Used when Keep_Going is True (switch -k) to keep the total number
332    --  of compilation/linking errors, to report at the end of execution.
333
334    Need_To_Rebuild_Global_Archive : Boolean := False;
335
336    Error_Header : constant String := "*** ERROR: ";
337    --  The beginning of error message, when Keep_Going is True
338
339    Need_To_Relink : Boolean := False;
340    --  True when an executable of a language other than Ada need to be linked
341
342    Global_Archive_Exists : Boolean := False;
343    --  True if there is a non empty global archive, to prevent creation
344    --  of such archives.
345
346    Path_Option : String_Access;
347    --  The path option switch, when supported
348
349    Project_Of_Current_Object_Directory : Project_Id := No_Project;
350    --  The object directory of the project for the last compilation. Avoid
351    --  calling Change_Dir if the current working directory is already this
352    --  directory.
353
354    package Lib_Path is new Table.Table
355      (Table_Component_Type => Character,
356       Table_Index_Type     => Integer,
357       Table_Low_Bound      => 1,
358       Table_Initial        => 200,
359       Table_Increment      => 100,
360       Table_Name           => "Makegpr.Lib_Path");
361    --  A table to compute the path to put in the path option switch, when it
362    --  is supported.
363
364    procedure Add_Archives (For_Gnatmake : Boolean);
365    --  Add to Arguments the list of archives for linking an executable
366
367    procedure Add_Argument (Arg : String_Access; Display : Boolean);
368    procedure Add_Argument (Arg : String; Display : Boolean);
369    --  Add an argument to Arguments. Reallocate if necessary
370
371    procedure Add_Arguments (Args : Argument_List; Display : Boolean);
372    --  Add a list of arguments to Arguments. Reallocate if necessary
373
374    procedure Add_Option (Arg : String);
375    --  Add a switch for the Ada, C or C++ compiler, or for the linker.
376    --  The table where this option is stored depends on the values of
377    --  Current_Processor and Current_Language.
378
379    procedure Add_Search_Directories
380      (Data     : Project_Data;
381       Language : First_Language_Indexes);
382    --  Either add to the Arguments the necessary -I switches needed to
383    --  compile, or, when compiler is gcc/g++, set up the C*INCLUDE_PATH
384    --  environment variable, if necessary.
385
386    procedure Add_Source_Id (Project : Project_Id; Id : Other_Source_Id);
387    --  Add a source id to Source_Indexes, with Found set to False
388
389    procedure Add_Switches
390      (Data      : Project_Data;
391       Proc      : Processor;
392       Language  : Language_Index;
393       File_Name : File_Name_Type);
394    --  Add to Arguments the switches, if any, for a source (attribute Switches)
395    --  or language (attribute Default_Switches), coming from package Compiler
396    --  or Linker (depending on Proc) of a specified project file.
397
398    procedure Build_Global_Archive;
399    --  Build the archive for the main project
400
401    procedure Build_Library (Project : Project_Id; Unconditionally : Boolean);
402    --  Build the library for a library project. If Unconditionally is
403    --  False, first check if the library is up to date, and build it only
404    --  if it is not.
405
406    procedure Check (Option : String);
407    --  Check that a switch coming from a project file is not the concatenation
408    --  of several valid switch, for example "-g -v". If it is, issue a warning.
409
410    procedure Check_Archive_Builder;
411    --  Check if the archive builder (ar) is there
412
413    procedure Check_Compilation_Needed
414      (Source          : Other_Source;
415       Need_To_Compile : out Boolean);
416    --  Check if a source of a language other than Ada needs to be compiled or
417    --  recompiled.
418
419    procedure Check_For_C_Plus_Plus;
420    --  Check if C++ is used in at least one project
421
422    procedure Compile
423      (Source_Id    : Other_Source_Id;
424       Data         : Project_Data;
425       Local_Errors : in out Boolean);
426    --  Compile one non-Ada source
427
428    procedure Compile_Individual_Sources;
429    --  Compile the sources specified on the command line, when in
430    --  Unique_Compile mode.
431
432    procedure Compile_Link_With_Gnatmake (Mains_Specified : Boolean);
433    --  Compile/Link with gnatmake when there are Ada sources in the main
434    --  project. Arguments may already contain options to be used by
435    --  gnatmake. Used for both Ada mains and mains of other languages.
436    --  When Compile_Only is True, do not use the linking options
437
438    procedure Compile_Sources;
439    --  Compile the sources of languages other than Ada, if necessary
440
441    procedure Copyright;
442    --  Output the Copyright notice
443
444    procedure Create_Archive_Dependency_File
445      (Name         : String;
446       First_Source : Other_Source_Id);
447    --  Create the archive dependency file for a library project
448
449    procedure Create_Global_Archive_Dependency_File (Name : String);
450    --  Create the archive depenency file for the main project
451
452    procedure Display_Command
453      (Name    : String;
454       Path    : String_Access;
455       CPATH   : String_Access := null;
456       Ellipse : Boolean := False);
457    --  Display the command for a spawned process, if in Verbose_Mode or not in
458    --  Quiet_Output. In non verbose mode, when Ellipse is True, display "..."
459    --  in place of the first argument that has Display set to False.
460
461    procedure Get_Compiler (For_Language : First_Language_Indexes);
462    --  Find the compiler name and path name for a specified programming
463    --  language, if not already done. Results are in the corresponding elements
464    --  of arrays Compiler_Names and Compiler_Paths. Name of compiler is found
465    --  in package IDE of the main project, or defaulted. Fail if compiler
466    --  cannot be found on the path. For the Ada language, gnatmake, rather than
467    --  the Ada compiler is returned.
468
469    procedure Get_Imported_Directories
470      (Project : Project_Id;
471       Data    : in out Project_Data);
472    --  Find the necessary switches -I to be used when compiling sources of
473    --  languages other than Ada, in a specified project file. Cache the result
474    --  in component Imported_Directories_Switches of the project data. For
475    --  gcc/g++ compilers, get the value of the C*_INCLUDE_PATH, instead.
476
477    procedure Initialize;
478    --  Do the necessary package initialization and process the command line
479    --  arguments.
480
481    function Is_Included_In_Global_Archive
482      (Object_Name : File_Name_Type;
483       Project     : Project_Id) return Boolean;
484    --  Return True if the object Object_Name is not overridden by a source
485    --  in a project extending project Project.
486
487    procedure Link_Executables;
488    --  Link executables
489
490    procedure Report_Error (S1 : String; S2 : String := ""; S3 : String := "");
491    --  Report an error. If Keep_Going is False, just call Osint.Fail. If
492    --  Keep_Going is True, display the error and increase the total number of
493    --  errors.
494
495    procedure Report_Total_Errors (Kind : String);
496    --  If Total_Number_Of_Errors is not zero, report it, and fail
497
498    procedure Scan_Arg (Arg : String);
499    --  Process one command line argument
500
501    function Strip_CR_LF (Text : String) return String;
502    --  Remove characters ASCII.CR and ASCII.LF from a String
503
504    procedure Usage;
505    --  Display the usage
506
507    ------------------
508    -- Add_Archives --
509    ------------------
510
511    procedure Add_Archives (For_Gnatmake : Boolean) is
512       Last_Arg : constant Natural := Last_Argument;
513       --  The position of the last argument before adding the archives. Used to
514       --  reverse the order of the arguments added when processing the
515       --  archives.
516
517       procedure Recursive_Add_Archives (Project : Project_Id);
518       --  Recursive procedure to add the archive of a project file, if any,
519       --  then call itself for the project imported.
520
521       ----------------------------
522       -- Recursive_Add_Archives --
523       ----------------------------
524
525       procedure Recursive_Add_Archives (Project : Project_Id) is
526          Data     : Project_Data;
527          Imported : Project_List;
528          Prj      : Project_Id;
529
530          procedure Add_Archive_Path;
531          --  For a library project or the main project, add the archive
532          --  path to the arguments.
533
534          ----------------------
535          -- Add_Archive_Path --
536          ----------------------
537
538          procedure Add_Archive_Path is
539             Increment : Positive;
540             Prev_Last : Positive;
541
542          begin
543             if Data.Library then
544
545                --  If it is a library project file, nothing to do if gnatmake
546                --  will be invoked, because gnatmake will take care of it, even
547                --  if the library is not an Ada library.
548
549                if not For_Gnatmake then
550                   if Data.Library_Kind = Static then
551                      Add_Argument
552                        (Get_Name_String (Data.Display_Library_Dir) &
553                         Directory_Separator &
554                         "lib" & Get_Name_String (Data.Library_Name) &
555                         '.' & Archive_Ext,
556                         Verbose_Mode);
557
558                   else
559                      --  As we first insert in the reverse order,
560                      --  -L<dir> is put after -l<lib>
561
562                      Add_Argument
563                        ("-l" & Get_Name_String (Data.Library_Name),
564                         Verbose_Mode);
565
566                      Get_Name_String (Data.Display_Library_Dir);
567
568                      Add_Argument
569                        ("-L" & Name_Buffer (1 .. Name_Len),
570                         Verbose_Mode);
571
572                      --  If there is a run path option, prepend this directory
573                      --  to the library path. It is probable that the order of
574                      --  the directories in the path option is not important,
575                      --  but just in case put the directories in the same order
576                      --  as the libraries.
577
578                      if Path_Option /= null then
579
580                         --  If it is not the first directory, make room at the
581                         --  beginning of the table, including for a path
582                         --  separator.
583
584                         if Lib_Path.Last > 0 then
585                            Increment := Name_Len + 1;
586                            Prev_Last := Lib_Path.Last;
587                            Lib_Path.Set_Last (Prev_Last + Increment);
588
589                            for Index in reverse 1 .. Prev_Last loop
590                               Lib_Path.Table (Index + Increment) :=
591                                 Lib_Path.Table (Index);
592                            end loop;
593
594                            Lib_Path.Table (Increment) := Path_Separator;
595
596                         else
597                            --  If it is the first directory, just set
598                            --  Last to the length of the directory.
599
600                            Lib_Path.Set_Last (Name_Len);
601                         end if;
602
603                         --  Put the directory at the beginning of the
604                         --  table.
605
606                         for Index in 1 .. Name_Len loop
607                            Lib_Path.Table (Index) := Name_Buffer (Index);
608                         end loop;
609                      end if;
610                   end if;
611                end if;
612
613             --  For a non-library project, the only archive needed is the one
614             --  for the main project, if there is one.
615
616             elsif Project = Main_Project and then Global_Archive_Exists then
617                Add_Argument
618                  (Get_Name_String (Data.Display_Object_Dir) &
619                   Directory_Separator &
620                   "lib" & Get_Name_String (Data.Display_Name)
621                   & '.' & Archive_Ext,
622                   Verbose_Mode);
623             end if;
624          end Add_Archive_Path;
625
626       begin
627          --  Nothing to do when there is no project specified
628
629          if Project /= No_Project then
630             Data := Project_Tree.Projects.Table (Project);
631
632             --  Nothing to do if the project has already been processed
633
634             if not Data.Seen then
635
636                --  Mark the project as processed, to avoid processing it again
637
638                Project_Tree.Projects.Table (Project).Seen := True;
639
640                Recursive_Add_Archives (Data.Extends);
641
642                Imported := Data.Imported_Projects;
643
644                --  Call itself recursively for all imported projects
645
646                while Imported /= Empty_Project_List loop
647                   Prj := Project_Tree.Project_Lists.Table
648                            (Imported).Project;
649
650                   if Prj /= No_Project then
651                      while Project_Tree.Projects.Table
652                              (Prj).Extended_By /= No_Project
653                      loop
654                         Prj := Project_Tree.Projects.Table
655                                  (Prj).Extended_By;
656                      end loop;
657
658                      Recursive_Add_Archives (Prj);
659                   end if;
660
661                   Imported := Project_Tree.Project_Lists.Table
662                                 (Imported).Next;
663                end loop;
664
665                --  If there is sources of language other than Ada in this
666                --  project, add the path of the archive to Arguments.
667
668                if Project = Main_Project
669                  or else Data.Other_Sources_Present
670                then
671                   Add_Archive_Path;
672                end if;
673             end if;
674          end if;
675       end Recursive_Add_Archives;
676
677    --  Start of processing for Add_Archives
678
679    begin
680       --  First, mark all projects as not processed
681
682       for Project in Project_Table.First ..
683                      Project_Table.Last (Project_Tree.Projects)
684       loop
685          Project_Tree.Projects.Table (Project).Seen := False;
686       end loop;
687
688       --  Take care of the run path option
689
690       if Path_Option = null then
691          Path_Option := MLib.Linker_Library_Path_Option;
692       end if;
693
694       Lib_Path.Set_Last (0);
695
696       --  Add archives in the reverse order
697
698       Recursive_Add_Archives (Main_Project);
699
700       --  And reverse the order
701
702       declare
703          First : Positive;
704          Last  : Natural;
705          Temp  : String_Access;
706
707       begin
708          First := Last_Arg + 1;
709          Last  := Last_Argument;
710          while First < Last loop
711             Temp := Arguments (First);
712             Arguments (First) := Arguments (Last);
713             Arguments (Last)  := Temp;
714             First := First + 1;
715             Last := Last - 1;
716          end loop;
717       end;
718    end Add_Archives;
719
720    ------------------
721    -- Add_Argument --
722    ------------------
723
724    procedure Add_Argument (Arg : String_Access; Display : Boolean) is
725    begin
726       --  Nothing to do if no argument is specified or if argument is empty
727
728       if Arg /= null or else Arg'Length = 0 then
729
730          --  Reallocate arrays if necessary
731
732          if Last_Argument = Arguments'Last then
733             declare
734                New_Arguments : constant Argument_List_Access :=
735                                  new Argument_List
736                                    (1 .. Last_Argument +
737                                            Initial_Argument_Count);
738
739                New_Arguments_Displayed : constant Booleans :=
740                                            new Boolean_Array
741                                              (1 .. Last_Argument +
742                                                      Initial_Argument_Count);
743
744             begin
745                New_Arguments (Arguments'Range) := Arguments.all;
746
747                --  To avoid deallocating the strings, nullify all components
748                --  of Arguments before calling Free.
749
750                Arguments.all := (others => null);
751
752                Free (Arguments);
753                Arguments := New_Arguments;
754
755                New_Arguments_Displayed (Arguments_Displayed'Range) :=
756                  Arguments_Displayed.all;
757                Free (Arguments_Displayed);
758                Arguments_Displayed := New_Arguments_Displayed;
759             end;
760          end if;
761
762          --  Add the argument and its display indication
763
764          Last_Argument := Last_Argument + 1;
765          Arguments (Last_Argument) := Arg;
766          Arguments_Displayed (Last_Argument) := Display;
767       end if;
768    end Add_Argument;
769
770    procedure Add_Argument (Arg : String; Display : Boolean) is
771       Argument : String_Access := null;
772
773    begin
774       --  Nothing to do if argument is empty
775
776       if Arg'Length > 0 then
777
778          --  Check if the argument is already in the Cache_Args table.
779          --  If it is already there, reuse the allocated value.
780
781          for Index in 1 .. Cache_Args.Last loop
782             if Cache_Args.Table (Index).all = Arg then
783                Argument := Cache_Args.Table (Index);
784                exit;
785             end if;
786          end loop;
787
788          --  If the argument is not in the cache, create a new entry in the
789          --  cache.
790
791          if Argument = null then
792             Argument := new String'(Arg);
793             Cache_Args.Increment_Last;
794             Cache_Args.Table (Cache_Args.Last) := Argument;
795          end if;
796
797          --  And add the argument
798
799          Add_Argument (Argument, Display);
800       end if;
801    end Add_Argument;
802
803    -------------------
804    -- Add_Arguments --
805    -------------------
806
807    procedure Add_Arguments (Args : Argument_List; Display : Boolean) is
808    begin
809       --  Reallocate the arrays, if necessary
810
811       if Last_Argument + Args'Length > Arguments'Last then
812          declare
813             New_Arguments : constant Argument_List_Access :=
814                               new Argument_List
815                                     (1 .. Last_Argument + Args'Length +
816                                           Initial_Argument_Count);
817
818             New_Arguments_Displayed : constant Booleans :=
819                                         new Boolean_Array
820                                               (1 .. Last_Argument +
821                                                     Args'Length +
822                                                     Initial_Argument_Count);
823
824          begin
825             New_Arguments (1 .. Last_Argument) :=
826               Arguments (1 .. Last_Argument);
827
828             --  To avoid deallocating the strings, nullify all components
829             --  of Arguments before calling Free.
830
831             Arguments.all := (others => null);
832             Free (Arguments);
833
834             Arguments := New_Arguments;
835             New_Arguments_Displayed (1 .. Last_Argument) :=
836               Arguments_Displayed (1 .. Last_Argument);
837             Free (Arguments_Displayed);
838             Arguments_Displayed := New_Arguments_Displayed;
839          end;
840       end if;
841
842       --  Add the new arguments and the display indications
843
844       Arguments (Last_Argument + 1 .. Last_Argument + Args'Length) := Args;
845       Arguments_Displayed (Last_Argument + 1 .. Last_Argument + Args'Length) :=
846         (others => Display);
847       Last_Argument := Last_Argument + Args'Length;
848    end Add_Arguments;
849
850    ----------------
851    -- Add_Option --
852    ----------------
853
854    procedure Add_Option (Arg : String) is
855       Option : constant String_Access := new String'(Arg);
856
857    begin
858       case Current_Processor is
859          when None =>
860             null;
861
862          when Linker =>
863
864             --  Add option to the linker table
865
866             Linker_Options.Increment_Last;
867             Linker_Options.Table (Linker_Options.Last) := Option;
868
869          when Compiler =>
870
871             --  Add option to the compiler option table, depending on the
872             --  value of Current_Language.
873
874             Comp_Opts.Increment_Last (Options (Current_Language));
875             Options (Current_Language).Table
876               (Comp_Opts.Last (Options (Current_Language))) := Option;
877
878       end case;
879    end Add_Option;
880
881    -------------------
882    -- Add_Source_Id --
883    -------------------
884
885    procedure Add_Source_Id (Project : Project_Id; Id : Other_Source_Id) is
886    begin
887       --  Reallocate the array, if necessary
888
889       if Last_Source = Source_Indexes'Last then
890          declare
891             New_Indexes : constant Source_Indexes_Ref :=
892                             new Source_Index_Array
893                               (1 .. Source_Indexes'Last +
894                                       Initial_Source_Index_Count);
895          begin
896             New_Indexes (Source_Indexes'Range) := Source_Indexes.all;
897             Free (Source_Indexes);
898             Source_Indexes := New_Indexes;
899          end;
900       end if;
901
902       Last_Source := Last_Source + 1;
903       Source_Indexes (Last_Source) := (Project, Id, False);
904    end Add_Source_Id;
905
906    ----------------------------
907    -- Add_Search_Directories --
908    ----------------------------
909
910    procedure Add_Search_Directories
911      (Data     : Project_Data;
912       Language : First_Language_Indexes)
913    is
914    begin
915       --  If a GNU compiler is used, set the CPATH environment variable,
916       --  if it does not already has the correct value.
917
918       if Compiler_Is_Gcc (Language) then
919          if Current_Include_Paths (Language) /= Data.Include_Path then
920             Current_Include_Paths (Language) := Data.Include_Path;
921             Setenv (CPATH, Data.Include_Path.all);
922          end if;
923
924       else
925          Add_Arguments (Data.Imported_Directories_Switches.all, Verbose_Mode);
926       end if;
927    end Add_Search_Directories;
928
929    ------------------
930    -- Add_Switches --
931    ------------------
932
933    procedure Add_Switches
934      (Data      : Project_Data;
935       Proc      : Processor;
936       Language  : Language_Index;
937       File_Name : File_Name_Type)
938    is
939       Switches       : Variable_Value;
940       --  The switches, if any, for the file/language
941
942       Pkg            : Package_Id;
943       --  The id of the package where to look for the switches
944
945       Defaults       : Array_Element_Id;
946       --  The Default_Switches associative array
947
948       Switches_Array : Array_Element_Id;
949       --  The Switches associative array
950
951       Element_Id     : String_List_Id;
952       Element        : String_Element;
953
954    begin
955       --  First, choose the proper package
956
957       case Proc is
958          when None =>
959             raise Program_Error;
960
961          when Linker =>
962             Pkg := Value_Of (Name_Linker, Data.Decl.Packages, Project_Tree);
963
964          when Compiler =>
965             Pkg := Value_Of (Name_Compiler, Data.Decl.Packages, Project_Tree);
966       end case;
967
968       if Pkg /= No_Package then
969
970          --  Get the Switches ("file name"), if they exist
971
972          Switches_Array := Prj.Util.Value_Of
973            (Name      => Name_Switches,
974             In_Arrays => Project_Tree.Packages.Table
975                           (Pkg).Decl.Arrays,
976             In_Tree   => Project_Tree);
977
978          Switches :=
979            Prj.Util.Value_Of
980              (Index     => Name_Id (File_Name),
981               Src_Index => 0,
982               In_Array  => Switches_Array,
983               In_Tree   => Project_Tree);
984
985          --  Otherwise, get the Default_Switches ("language"), if they exist
986
987          if Switches = Nil_Variable_Value then
988             Defaults := Prj.Util.Value_Of
989               (Name      => Name_Default_Switches,
990                In_Arrays => Project_Tree.Packages.Table
991                               (Pkg).Decl.Arrays,
992                In_Tree   => Project_Tree);
993             Switches := Prj.Util.Value_Of
994               (Index     => Language_Names.Table (Language),
995                Src_Index => 0,
996                In_Array  => Defaults,
997                In_Tree   => Project_Tree);
998          end if;
999
1000          --  If there are switches, add them to Arguments
1001
1002          if Switches /= Nil_Variable_Value then
1003             Element_Id := Switches.Values;
1004             while Element_Id /= Nil_String loop
1005                Element := Project_Tree.String_Elements.Table
1006                             (Element_Id);
1007
1008                if Element.Value /= No_Name then
1009                   Get_Name_String (Element.Value);
1010
1011                   if not Quiet_Output then
1012
1013                      --  When not in quiet output (no -q), check that the
1014                      --  switch is not the concatenation of several valid
1015                      --  switches, such as "-g -v". If it is, issue a warning.
1016
1017                      Check (Option => Name_Buffer (1 .. Name_Len));
1018                   end if;
1019
1020                   Add_Argument (Name_Buffer (1 .. Name_Len), True);
1021                end if;
1022
1023                Element_Id := Element.Next;
1024             end loop;
1025          end if;
1026       end if;
1027    end Add_Switches;
1028
1029    --------------------------
1030    -- Build_Global_Archive --
1031    --------------------------
1032
1033    procedure Build_Global_Archive is
1034       Data      : Project_Data := Project_Tree.Projects.Table (Main_Project);
1035       Source_Id : Other_Source_Id;
1036       S_Id      : Other_Source_Id;
1037       Source    : Other_Source;
1038       Success   : Boolean;
1039
1040       Archive_Name : constant String :=
1041                        "lib"
1042                          & Get_Name_String (Data.Display_Name)
1043                          & '.'
1044                          & Archive_Ext;
1045       --  The name of the archive file for this project
1046
1047       Archive_Dep_Name : constant String :=
1048                            "lib"
1049                              & Get_Name_String (Data.Display_Name)
1050                              & ".deps";
1051       --  The name of the archive dependency file for this project
1052
1053       Need_To_Rebuild : Boolean := Need_To_Rebuild_Global_Archive;
1054       --  When True, archive will be rebuilt
1055
1056       File                : Prj.Util.Text_File;
1057       Object_Path         : Path_Name_Type;
1058       Time_Stamp          : Time_Stamp_Type;
1059       Saved_Last_Argument : Natural;
1060       First_Object        : Natural;
1061
1062       Discard : Boolean;
1063       pragma Warnings (Off, Discard);
1064
1065    begin
1066       Check_Archive_Builder;
1067
1068       if Project_Of_Current_Object_Directory /= Main_Project then
1069          Project_Of_Current_Object_Directory := Main_Project;
1070          Change_Dir (Get_Name_String (Data.Object_Directory));
1071
1072          if Verbose_Mode then
1073             Write_Str  ("Changing to object directory of """);
1074             Write_Name (Data.Display_Name);
1075             Write_Str  (""": """);
1076             Write_Name (Data.Display_Object_Dir);
1077             Write_Line ("""");
1078          end if;
1079       end if;
1080
1081       if not Need_To_Rebuild then
1082          if Verbose_Mode then
1083             Write_Str  ("   Checking ");
1084             Write_Line (Archive_Name);
1085          end if;
1086
1087          --  If the archive does not exist, of course it needs to be built
1088
1089          if not Is_Regular_File (Archive_Name) then
1090             Need_To_Rebuild := True;
1091
1092             if Verbose_Mode then
1093                Write_Line ("      -> archive does not exist");
1094             end if;
1095
1096          --  Archive does exist
1097
1098          else
1099             --  Check the archive dependency file
1100
1101             Open (File, Archive_Dep_Name);
1102
1103             --  If the archive dependency file does not exist, we need to
1104             --  rebuild the archive and to create its dependency file.
1105
1106             if not Is_Valid (File) then
1107                Need_To_Rebuild := True;
1108
1109                if Verbose_Mode then
1110                   Write_Str  ("      -> archive dependency file ");
1111                   Write_Str  (Archive_Dep_Name);
1112                   Write_Line (" does not exist");
1113                end if;
1114
1115             else
1116                --  Put all sources of language other than Ada in Source_Indexes
1117
1118                declare
1119                   Local_Data : Project_Data;
1120
1121                begin
1122                   Last_Source := 0;
1123
1124                   for Proj in Project_Table.First ..
1125                     Project_Table.Last (Project_Tree.Projects)
1126                   loop
1127                      Local_Data := Project_Tree.Projects.Table (Proj);
1128
1129                      if not Local_Data.Library then
1130                         Source_Id := Local_Data.First_Other_Source;
1131                         while Source_Id /= No_Other_Source loop
1132                            Add_Source_Id (Proj, Source_Id);
1133                            Source_Id := Project_Tree.Other_Sources.Table
1134                              (Source_Id).Next;
1135                         end loop;
1136                      end if;
1137                   end loop;
1138                end;
1139
1140                --  Read the dependency file, line by line
1141
1142                while not End_Of_File (File) loop
1143                   Get_Line (File, Name_Buffer, Name_Len);
1144
1145                   --  First line is the path of the object file
1146
1147                   Object_Path := Name_Find;
1148                   Source_Id := No_Other_Source;
1149
1150                   --  Check if this object file is for a source of this project
1151
1152                   for S in 1 .. Last_Source loop
1153                      S_Id := Source_Indexes (S).Id;
1154                      Source := Project_Tree.Other_Sources.Table (S_Id);
1155
1156                      if (not Source_Indexes (S).Found)
1157                        and then Source.Object_Path = Object_Path
1158                      then
1159                         --  We have found the object file: get the source data,
1160                         --  and mark it as found.
1161
1162                         Source_Id := S_Id;
1163                         Source_Indexes (S).Found := True;
1164                         exit;
1165                      end if;
1166                   end loop;
1167
1168                   --  If it is not for a source of this project, then the
1169                   --  archive needs to be rebuilt.
1170
1171                   if Source_Id = No_Other_Source then
1172                      Need_To_Rebuild := True;
1173                      if Verbose_Mode then
1174                         Write_Str  ("      -> ");
1175                         Write_Str  (Get_Name_String (Object_Path));
1176                         Write_Line (" is not an object of any project");
1177                      end if;
1178
1179                      exit;
1180                   end if;
1181
1182                   --  The second line is the time stamp of the object file. If
1183                   --  there is no next line, then the dependency file is
1184                   --  truncated, and the archive need to be rebuilt.
1185
1186                   if End_Of_File (File) then
1187                      Need_To_Rebuild := True;
1188
1189                      if Verbose_Mode then
1190                         Write_Str  ("      -> archive dependency file ");
1191                         Write_Line (" is truncated");
1192                      end if;
1193
1194                      exit;
1195                   end if;
1196
1197                   Get_Line (File, Name_Buffer, Name_Len);
1198
1199                   --  If the line has the wrong number of characters, then
1200                   --  the dependency file is incorrectly formatted, and the
1201                   --  archive needs to be rebuilt.
1202
1203                   if Name_Len /= Time_Stamp_Length then
1204                      Need_To_Rebuild := True;
1205
1206                      if Verbose_Mode then
1207                         Write_Str  ("      -> archive dependency file ");
1208                         Write_Line (" is incorrectly formatted (time stamp)");
1209                      end if;
1210
1211                      exit;
1212                   end if;
1213
1214                   Time_Stamp := Time_Stamp_Type (Name_Buffer (1 .. Name_Len));
1215
1216                   --  If the time stamp in the dependency file is different
1217                   --  from the time stamp of the object file, then the archive
1218                   --  needs to be rebuilt.
1219
1220                   if Time_Stamp /= Source.Object_TS then
1221                      Need_To_Rebuild := True;
1222
1223                      if Verbose_Mode then
1224                         Write_Str  ("      -> time stamp of ");
1225                         Write_Str  (Get_Name_String (Object_Path));
1226                         Write_Str  (" is incorrect in the archive");
1227                         Write_Line (" dependency file");
1228                      end if;
1229
1230                      exit;
1231                   end if;
1232                end loop;
1233
1234                Close (File);
1235             end if;
1236          end if;
1237       end if;
1238
1239       if not Need_To_Rebuild then
1240          if Verbose_Mode then
1241             Write_Line  ("      -> up to date");
1242          end if;
1243
1244          --  No need to create a global archive, if there is no object
1245          --  file to put into.
1246
1247          Global_Archive_Exists := Last_Source /= 0;
1248
1249       --  Archive needs to be rebuilt
1250
1251       else
1252          --  If archive already exists, first delete it
1253
1254          --  Comment needed on why we discard result???
1255
1256          if Is_Regular_File (Archive_Name) then
1257             Delete_File (Archive_Name, Discard);
1258          end if;
1259
1260          Last_Argument := 0;
1261
1262          --  Start with the options found in MLib.Tgt (usually just "rc")
1263
1264          Add_Arguments (Archive_Builder_Options.all, True);
1265
1266          --  Followed by the archive name
1267
1268          Add_Argument (Archive_Name, True);
1269
1270          First_Object := Last_Argument;
1271
1272          --  Followed by all the object files of the non library projects
1273
1274          for Proj in Project_Table.First ..
1275                      Project_Table.Last (Project_Tree.Projects)
1276          loop
1277             Data := Project_Tree.Projects.Table (Proj);
1278
1279             if not Data.Library then
1280                Source_Id := Data.First_Other_Source;
1281                while Source_Id /= No_Other_Source loop
1282                   Source :=
1283                     Project_Tree.Other_Sources.Table (Source_Id);
1284
1285                   --  Only include object file name that have not been
1286                   --  overriden in extending projects.
1287
1288                   if Is_Included_In_Global_Archive
1289                        (Source.Object_Name, Proj)
1290                   then
1291                      Add_Argument
1292                        (Get_Name_String (Source.Object_Path),
1293                         Verbose_Mode or (First_Object = Last_Argument));
1294                   end if;
1295
1296                   Source_Id := Source.Next;
1297                end loop;
1298             end if;
1299          end loop;
1300
1301          --  No need to create a global archive, if there is no object
1302          --  file to put into.
1303
1304          Global_Archive_Exists := Last_Argument > First_Object;
1305
1306          if Global_Archive_Exists then
1307
1308             --  If the archive is built, then linking will need to occur
1309             --  unconditionally.
1310
1311             Need_To_Relink := True;
1312
1313             --  Spawn the archive builder (ar)
1314
1315             Saved_Last_Argument := Last_Argument;
1316             Last_Argument := First_Object + Max_In_Archives;
1317             loop
1318                if Last_Argument > Saved_Last_Argument then
1319                   Last_Argument := Saved_Last_Argument;
1320                end if;
1321
1322                Display_Command
1323                  (Archive_Builder,
1324                   Archive_Builder_Path,
1325                   Ellipse => True);
1326
1327                Spawn
1328                  (Archive_Builder_Path.all,
1329                   Arguments (1 .. Last_Argument),
1330                   Success);
1331
1332                exit when not Success
1333                  or else Last_Argument = Saved_Last_Argument;
1334
1335                Arguments (1) := r;
1336                Arguments (3 .. Saved_Last_Argument - Last_Argument + 2) :=
1337                  Arguments (Last_Argument + 1 .. Saved_Last_Argument);
1338                Saved_Last_Argument := Saved_Last_Argument - Last_Argument + 2;
1339             end loop;
1340
1341             --  If the archive was built, run the archive indexer (ranlib)
1342             --  if there is one.
1343
1344             if Success then
1345
1346                if Archive_Indexer_Path /= null then
1347                   Last_Argument := 0;
1348                   Add_Argument (Archive_Name, True);
1349
1350                   Display_Command (Archive_Indexer, Archive_Indexer_Path);
1351
1352                   Spawn
1353                     (Archive_Indexer_Path.all, Arguments (1 .. 1), Success);
1354
1355                   if not Success then
1356
1357                      --  Running ranlib failed, delete the dependency file,
1358                      --  if it exists.
1359
1360                      if Is_Regular_File (Archive_Dep_Name) then
1361                         Delete_File (Archive_Dep_Name, Success);
1362                      end if;
1363
1364                      --  And report the error
1365
1366                      Report_Error
1367                        ("running" & Archive_Indexer & " for project """,
1368                         Get_Name_String (Data.Display_Name),
1369                         """ failed");
1370                      return;
1371                   end if;
1372                end if;
1373
1374                --  The archive was correctly built, create its dependency file
1375
1376                Create_Global_Archive_Dependency_File (Archive_Dep_Name);
1377
1378             --  Building the archive failed, delete dependency file if one
1379             --  exists.
1380
1381             else
1382                if Is_Regular_File (Archive_Dep_Name) then
1383                   Delete_File (Archive_Dep_Name, Success);
1384                end if;
1385
1386                --  And report the error
1387
1388                Report_Error
1389                  ("building archive for project """,
1390                   Get_Name_String (Data.Display_Name),
1391                   """ failed");
1392             end if;
1393          end if;
1394       end if;
1395    end Build_Global_Archive;
1396
1397    -------------------
1398    -- Build_Library --
1399    -------------------
1400
1401    procedure Build_Library (Project : Project_Id; Unconditionally : Boolean) is
1402       Data      : constant Project_Data :=
1403                     Project_Tree.Projects.Table (Project);
1404       Source_Id : Other_Source_Id;
1405       Source    : Other_Source;
1406
1407       Archive_Name : constant String :=
1408                        "lib" & Get_Name_String (Data.Library_Name)
1409                        & '.' & Archive_Ext;
1410       --  The name of the archive file for this project
1411
1412       Archive_Dep_Name : constant String :=
1413                            "lib" & Get_Name_String (Data.Library_Name)
1414                            & ".deps";
1415       --  The name of the archive dependency file for this project
1416
1417       Need_To_Rebuild : Boolean := Unconditionally;
1418       --  When True, archive will be rebuilt
1419
1420       File : Prj.Util.Text_File;
1421
1422       Object_Name : File_Name_Type;
1423       Time_Stamp  : Time_Stamp_Type;
1424       Driver_Name : Name_Id := No_Name;
1425
1426       Lib_Opts    : Argument_List_Access := No_Argument'Access;
1427
1428    begin
1429       --  Nothing to do if the project is externally built
1430
1431       if Data.Externally_Built then
1432          return;
1433       end if;
1434
1435       Check_Archive_Builder;
1436
1437       --  If Unconditionally is False, check if the archive need to be built
1438
1439       if not Need_To_Rebuild then
1440          if Verbose_Mode then
1441             Write_Str  ("   Checking ");
1442             Write_Line (Archive_Name);
1443          end if;
1444
1445          --  If the archive does not exist, of course it needs to be built
1446
1447          if not Is_Regular_File (Archive_Name) then
1448             Need_To_Rebuild := True;
1449
1450             if Verbose_Mode then
1451                Write_Line ("      -> archive does not exist");
1452             end if;
1453
1454          --  Archive does exist
1455
1456          else
1457             --  Check the archive dependency file
1458
1459             Open (File, Archive_Dep_Name);
1460
1461             --  If the archive dependency file does not exist, we need to
1462             --  rebuild the archive and to create its dependency file.
1463
1464             if not Is_Valid (File) then
1465                Need_To_Rebuild := True;
1466
1467                if Verbose_Mode then
1468                   Write_Str  ("      -> archive dependency file ");
1469                   Write_Str  (Archive_Dep_Name);
1470                   Write_Line (" does not exist");
1471                end if;
1472
1473             else
1474                --  Put all sources of language other than Ada in Source_Indexes
1475
1476                Last_Source := 0;
1477
1478                Source_Id := Data.First_Other_Source;
1479                while Source_Id /= No_Other_Source loop
1480                   Add_Source_Id (Project, Source_Id);
1481                   Source_Id :=
1482                     Project_Tree.Other_Sources.Table (Source_Id).Next;
1483                end loop;
1484
1485                --  Read the dependency file, line by line
1486
1487                while not End_Of_File (File) loop
1488                   Get_Line (File, Name_Buffer, Name_Len);
1489
1490                   --  First line is the name of an object file
1491
1492                   Object_Name := Name_Find;
1493                   Source_Id := No_Other_Source;
1494
1495                   --  Check if this object file is for a source of this project
1496
1497                   for S in 1 .. Last_Source loop
1498                      if (not Source_Indexes (S).Found)
1499                        and then
1500                          Project_Tree.Other_Sources.Table
1501                            (Source_Indexes (S).Id).Object_Name = Object_Name
1502                      then
1503                         --  We have found the object file: get the source
1504                         --  data, and mark it as found.
1505
1506                         Source_Id := Source_Indexes (S).Id;
1507                         Source := Project_Tree.Other_Sources.Table
1508                                     (Source_Id);
1509                         Source_Indexes (S).Found := True;
1510                         exit;
1511                      end if;
1512                   end loop;
1513
1514                   --  If it is not for a source of this project, then the
1515                   --  archive needs to be rebuilt.
1516
1517                   if Source_Id = No_Other_Source then
1518                      Need_To_Rebuild := True;
1519
1520                      if Verbose_Mode then
1521                         Write_Str  ("      -> ");
1522                         Write_Str  (Get_Name_String (Object_Name));
1523                         Write_Line (" is not an object of the project");
1524                      end if;
1525
1526                      exit;
1527                   end if;
1528
1529                   --  The second line is the time stamp of the object file.
1530                   --  If there is no next line, then the dependency file is
1531                   --  truncated, and the archive need to be rebuilt.
1532
1533                   if End_Of_File (File) then
1534                      Need_To_Rebuild := True;
1535
1536                      if Verbose_Mode then
1537                         Write_Str  ("      -> archive dependency file ");
1538                         Write_Line (" is truncated");
1539                      end if;
1540
1541                      exit;
1542                   end if;
1543
1544                   Get_Line (File, Name_Buffer, Name_Len);
1545
1546                   --  If the line has the wrong number of character, then
1547                   --  the dependency file is incorrectly formatted, and the
1548                   --  archive needs to be rebuilt.
1549
1550                   if Name_Len /= Time_Stamp_Length then
1551                      Need_To_Rebuild := True;
1552
1553                      if Verbose_Mode then
1554                         Write_Str  ("      -> archive dependency file ");
1555                         Write_Line (" is incorrectly formatted (time stamp)");
1556                      end if;
1557
1558                      exit;
1559                   end if;
1560
1561                   Time_Stamp := Time_Stamp_Type (Name_Buffer (1 .. Name_Len));
1562
1563                   --  If the time stamp in the dependency file is different
1564                   --  from the time stamp of the object file, then the archive
1565                   --  needs to be rebuilt.
1566
1567                   if Time_Stamp /= Source.Object_TS then
1568                      Need_To_Rebuild := True;
1569
1570                      if Verbose_Mode then
1571                         Write_Str  ("      -> time stamp of ");
1572                         Write_Str  (Get_Name_String (Object_Name));
1573                         Write_Str  (" is incorrect in the archive");
1574                         Write_Line (" dependency file");
1575                      end if;
1576
1577                      exit;
1578                   end if;
1579                end loop;
1580
1581                Close (File);
1582
1583                if not Need_To_Rebuild then
1584
1585                   --  Now, check if all object files of the project have been
1586                   --  accounted for. If any of them is not in the dependency
1587                   --  file, the archive needs to be rebuilt.
1588
1589                   for Index in 1 .. Last_Source loop
1590                      if not Source_Indexes (Index).Found then
1591                         Need_To_Rebuild := True;
1592
1593                         if Verbose_Mode then
1594                            Source_Id := Source_Indexes (Index).Id;
1595                            Source := Project_Tree.Other_Sources.Table
1596                                        (Source_Id);
1597                            Write_Str  ("      -> ");
1598                            Write_Str  (Get_Name_String (Source.Object_Name));
1599                            Write_Str  (" is not in the archive ");
1600                            Write_Line ("dependency file");
1601                         end if;
1602
1603                         exit;
1604                      end if;
1605                   end loop;
1606                end if;
1607
1608                if (not Need_To_Rebuild) and Verbose_Mode then
1609                   Write_Line ("      -> up to date");
1610                end if;
1611             end if;
1612          end if;
1613       end if;
1614
1615       --  Build the library if necessary
1616
1617       if Need_To_Rebuild then
1618
1619          --  If a library is built, then linking will need to occur
1620          --  unconditionally.
1621
1622          Need_To_Relink := True;
1623
1624          Last_Argument := 0;
1625
1626          --  If there are sources in Ada, then gnatmake will build the library,
1627          --  so nothing to do.
1628
1629          if not Data.Langs (Ada_Language_Index) then
1630
1631             --  Get all the object files of the project
1632
1633             Source_Id := Data.First_Other_Source;
1634             while Source_Id /= No_Other_Source loop
1635                Source := Project_Tree.Other_Sources.Table (Source_Id);
1636                Add_Argument
1637                  (Get_Name_String (Source.Object_Name), Verbose_Mode);
1638                Source_Id := Source.Next;
1639             end loop;
1640
1641             --  If it is a library, it need to be built it the same way Ada
1642             --  libraries are built.
1643
1644             if Data.Library_Kind = Static then
1645                MLib.Build_Library
1646                  (Ofiles      => Arguments (1 .. Last_Argument),
1647                   Output_File => Get_Name_String (Data.Library_Name),
1648                   Output_Dir  => Get_Name_String (Data.Display_Library_Dir));
1649
1650             else
1651                --  Link with g++ if C++ is one of the languages, otherwise
1652                --  building the library may fail with unresolved symbols.
1653
1654                if C_Plus_Plus_Is_Used then
1655                   if Compiler_Names (C_Plus_Plus_Language_Index) = null then
1656                      Get_Compiler (C_Plus_Plus_Language_Index);
1657                   end if;
1658
1659                   if Compiler_Is_Gcc (C_Plus_Plus_Language_Index) then
1660                      Name_Len := 0;
1661                      Add_Str_To_Name_Buffer
1662                        (Compiler_Names (C_Plus_Plus_Language_Index).all);
1663                      Driver_Name := Name_Find;
1664                   end if;
1665                end if;
1666
1667                --  If Library_Options is specified, add these options
1668
1669                declare
1670                   Library_Options : constant Variable_Value :=
1671                                       Value_Of
1672                                         (Name_Library_Options,
1673                                          Data.Decl.Attributes,
1674                                          Project_Tree);
1675
1676                begin
1677                   if not Library_Options.Default then
1678                      declare
1679                         Current : String_List_Id;
1680                         Element : String_Element;
1681
1682                      begin
1683                         Current := Library_Options.Values;
1684                         while Current /= Nil_String loop
1685                            Element :=
1686                              Project_Tree.String_Elements.Table (Current);
1687                            Get_Name_String (Element.Value);
1688
1689                            if Name_Len /= 0 then
1690                               Library_Opts.Increment_Last;
1691                               Library_Opts.Table (Library_Opts.Last) :=
1692                                 new String'(Name_Buffer (1 .. Name_Len));
1693                            end if;
1694
1695                            Current := Element.Next;
1696                         end loop;
1697                      end;
1698                   end if;
1699
1700                   Lib_Opts :=
1701                     new Argument_List'(Argument_List
1702                        (Library_Opts.Table (1 .. Library_Opts.Last)));
1703                end;
1704
1705                MLib.Tgt.Build_Dynamic_Library
1706                  (Ofiles       => Arguments (1 .. Last_Argument),
1707                   Options      => Lib_Opts.all,
1708                   Interfaces   => No_Argument,
1709                   Lib_Filename => Get_Name_String (Data.Library_Name),
1710                   Lib_Dir      => Get_Name_String (Data.Library_Dir),
1711                   Symbol_Data  => No_Symbols,
1712                   Driver_Name  => Driver_Name,
1713                   Lib_Version  => "",
1714                   Auto_Init    => False);
1715             end if;
1716          end if;
1717
1718          --  Create fake empty archive, so we can check its time stamp later
1719
1720          declare
1721             Archive : Ada.Text_IO.File_Type;
1722          begin
1723             Create (Archive, Out_File, Archive_Name);
1724             Close (Archive);
1725          end;
1726
1727          Create_Archive_Dependency_File
1728            (Archive_Dep_Name, Data.First_Other_Source);
1729       end if;
1730    end Build_Library;
1731
1732    -----------
1733    -- Check --
1734    -----------
1735
1736    procedure Check (Option : String) is
1737       First : Positive := Option'First;
1738       Last  : Natural;
1739
1740    begin
1741       for Index in Option'First + 1 .. Option'Last - 1 loop
1742          if Option (Index) = ' ' and then Option (Index + 1) = '-' then
1743             Write_Str ("warning: switch """);
1744             Write_Str (Option);
1745             Write_Str (""" is suspicious; consider using ");
1746
1747             Last := First;
1748             while Last <= Option'Last loop
1749                if Option (Last) = ' ' then
1750                   if First /= Option'First then
1751                      Write_Str (", ");
1752                   end if;
1753
1754                   Write_Char ('"');
1755                   Write_Str (Option (First .. Last - 1));
1756                   Write_Char ('"');
1757
1758                   while Last <= Option'Last and then Option (Last) = ' ' loop
1759                      Last := Last + 1;
1760                   end loop;
1761
1762                   First := Last;
1763
1764                else
1765                   if Last = Option'Last then
1766                      if First /= Option'First then
1767                         Write_Str (", ");
1768                      end if;
1769
1770                      Write_Char ('"');
1771                      Write_Str (Option (First .. Last));
1772                      Write_Char ('"');
1773                   end if;
1774
1775                   Last := Last + 1;
1776                end if;
1777             end loop;
1778
1779             Write_Line (" instead");
1780             exit;
1781          end if;
1782       end loop;
1783    end Check;
1784
1785    ---------------------------
1786    -- Check_Archive_Builder --
1787    ---------------------------
1788
1789    procedure Check_Archive_Builder is
1790    begin
1791       --  First, make sure that the archive builder (ar) is on the path
1792
1793       if Archive_Builder_Path = null then
1794          Archive_Builder_Path := Locate_Exec_On_Path (Archive_Builder);
1795
1796          if Archive_Builder_Path = null then
1797             Osint.Fail
1798               ("unable to locate archive builder """,
1799                Archive_Builder,
1800                """");
1801          end if;
1802
1803          --  If there is an archive indexer (ranlib), try to locate it on the
1804          --  path. Don't fail if it is not found.
1805
1806          if Archive_Indexer /= "" then
1807             Archive_Indexer_Path := Locate_Exec_On_Path (Archive_Indexer);
1808          end if;
1809       end if;
1810    end Check_Archive_Builder;
1811
1812    ------------------------------
1813    -- Check_Compilation_Needed --
1814    ------------------------------
1815
1816    procedure Check_Compilation_Needed
1817      (Source          : Other_Source;
1818       Need_To_Compile : out Boolean)
1819    is
1820       Source_Name   : constant String := Get_Name_String (Source.File_Name);
1821       Source_Path   : constant String := Get_Name_String (Source.Path_Name);
1822       Object_Name   : constant String := Get_Name_String (Source.Object_Name);
1823       C_Object_Name : String := Object_Name;
1824       Dep_Name      : constant String := Get_Name_String (Source.Dep_Name);
1825       C_Source_Path : String := Source_Path;
1826
1827       Source_In_Dependencies : Boolean := False;
1828       --  Set True if source was found in dependency file of its object file
1829
1830       Dep_File : Prj.Util.Text_File;
1831       Start    : Natural;
1832       Finish   : Natural;
1833
1834       Looping : Boolean := False;
1835       --  Set to True at the end of the first Big_Loop
1836
1837    begin
1838       Canonical_Case_File_Name (C_Source_Path);
1839       Canonical_Case_File_Name (C_Object_Name);
1840
1841       --  Assume the worst, so that statement "return;" may be used if there
1842       --  is any problem.
1843
1844       Need_To_Compile := True;
1845
1846       if Verbose_Mode then
1847          Write_Str  ("   Checking ");
1848          Write_Str  (Source_Name);
1849          Write_Line (" ... ");
1850       end if;
1851
1852       --  If object file does not exist, of course source need to be compiled
1853
1854       if Source.Object_TS = Empty_Time_Stamp then
1855          if Verbose_Mode then
1856             Write_Str  ("      -> object file ");
1857             Write_Str  (Object_Name);
1858             Write_Line (" does not exist");
1859          end if;
1860
1861          return;
1862       end if;
1863
1864       --  If the object file has been created before the last modification
1865       --  of the source, the source need to be recompiled.
1866
1867       if Source.Object_TS < Source.Source_TS then
1868          if Verbose_Mode then
1869             Write_Str  ("      -> object file ");
1870             Write_Str  (Object_Name);
1871             Write_Line (" has time stamp earlier than source");
1872          end if;
1873
1874          return;
1875       end if;
1876
1877       --  If there is no dependency file, then the source needs to be
1878       --  recompiled and the dependency file need to be created.
1879
1880       if Source.Dep_TS = Empty_Time_Stamp then
1881          if Verbose_Mode then
1882             Write_Str  ("      -> dependency file ");
1883             Write_Str  (Dep_Name);
1884             Write_Line (" does not exist");
1885          end if;
1886
1887          return;
1888       end if;
1889
1890       --  The source needs to be recompiled if the source has been modified
1891       --  after the dependency file has been created.
1892
1893       if Source.Dep_TS < Source.Source_TS then
1894          if Verbose_Mode then
1895             Write_Str  ("      -> dependency file ");
1896             Write_Str  (Dep_Name);
1897             Write_Line (" has time stamp earlier than source");
1898          end if;
1899
1900          return;
1901       end if;
1902
1903       --  Look for all dependencies
1904
1905       Open (Dep_File, Dep_Name);
1906
1907       --  If dependency file cannot be open, we need to recompile the source
1908
1909       if not Is_Valid (Dep_File) then
1910          if Verbose_Mode then
1911             Write_Str  ("      -> could not open dependency file ");
1912             Write_Line (Dep_Name);
1913          end if;
1914
1915          return;
1916       end if;
1917
1918       --  Loop Big_Loop is executed several times only when the dependency file
1919       --  contains several times
1920       --     <object file>: <source1> ...
1921       --  When there is only one of such occurence, Big_Loop is exited
1922       --  successfully at the beginning of the second loop.
1923
1924       Big_Loop :
1925       loop
1926          declare
1927             End_Of_File_Reached : Boolean := False;
1928
1929          begin
1930             loop
1931                if End_Of_File (Dep_File) then
1932                   End_Of_File_Reached := True;
1933                   exit;
1934                end if;
1935
1936                Get_Line (Dep_File, Name_Buffer, Name_Len);
1937
1938                exit when Name_Len > 0 and then Name_Buffer (1) /= '#';
1939             end loop;
1940
1941             --  If dependency file contains only empty lines or comments, then
1942             --  dependencies are unknown, and the source needs to be
1943             --  recompiled.
1944
1945             if End_Of_File_Reached then
1946                --  If we have reached the end of file after the first loop,
1947                --  there is nothing else to do.
1948
1949                exit Big_Loop when Looping;
1950
1951                if Verbose_Mode then
1952                   Write_Str  ("      -> dependency file ");
1953                   Write_Str  (Dep_Name);
1954                   Write_Line (" is empty");
1955                end if;
1956
1957                Close (Dep_File);
1958                return;
1959             end if;
1960          end;
1961
1962          Start  := 1;
1963          Finish := Index (Name_Buffer (1 .. Name_Len), ": ");
1964
1965          if Finish /= 0 then
1966             Canonical_Case_File_Name (Name_Buffer (1 .. Finish - 1));
1967          end if;
1968
1969          --  First line must start with name of object file, followed by colon
1970
1971          if Finish = 0 or else
1972             Name_Buffer (1 .. Finish - 1) /= C_Object_Name
1973          then
1974             if Verbose_Mode then
1975                Write_Str  ("      -> dependency file ");
1976                Write_Str  (Dep_Name);
1977                Write_Line (" has wrong format");
1978             end if;
1979
1980             Close (Dep_File);
1981             return;
1982
1983          else
1984             Start := Finish + 2;
1985
1986             --  Process each line
1987
1988             Line_Loop : loop
1989                declare
1990                   Line : String  := Name_Buffer (1 .. Name_Len);
1991                   Last : Natural := Name_Len;
1992
1993                begin
1994                   Name_Loop : loop
1995
1996                      --  Find the beginning of the next source path name
1997
1998                      while Start < Last and then Line (Start) = ' ' loop
1999                         Start := Start + 1;
2000                      end loop;
2001
2002                      --  Go to next line when there is a continuation character
2003                      --  \ at the end of the line.
2004
2005                      exit Name_Loop when Start = Last
2006                        and then Line (Start) = '\';
2007
2008                      --  We should not be at the end of the line, without
2009                      --  a continuation character \.
2010
2011                      if Start = Last then
2012                         if Verbose_Mode then
2013                            Write_Str  ("      -> dependency file ");
2014                            Write_Str  (Dep_Name);
2015                            Write_Line (" has wrong format");
2016                         end if;
2017
2018                         Close (Dep_File);
2019                         return;
2020                      end if;
2021
2022                      --  Look for the end of the source path name
2023
2024                      Finish := Start;
2025                      while Finish < Last loop
2026                         if Line (Finish) = '\' then
2027
2028                            --  On Windows, a '\' is part of the path name,
2029                            --  except when it is followed by another '\' or by
2030                            --  a space. On other platforms, when we are getting
2031                            --  a '\' that is not the last character of the
2032                            --  line, the next character is part of the path
2033                            --  name, even if it is a space.
2034
2035                            if On_Windows
2036                              and then Line (Finish + 1) /= '\'
2037                              and then Line (Finish + 1) /= ' '
2038                            then
2039                               Finish := Finish + 1;
2040
2041                            else
2042                               Line (Finish .. Last - 1) :=
2043                                 Line (Finish + 1 .. Last);
2044                               Last := Last - 1;
2045                            end if;
2046
2047                         else
2048                            --  A space that is not preceded by '\' indicates
2049                            --  the end of the path name.
2050
2051                            exit when Line (Finish + 1) = ' ';
2052
2053                            Finish := Finish + 1;
2054                         end if;
2055                      end loop;
2056
2057                      --  Check this source
2058
2059                      declare
2060                         Src_Name : constant String :=
2061                                      Normalize_Pathname
2062                                        (Name           =>
2063                                                        Line (Start .. Finish),
2064                                         Resolve_Links  => False,
2065                                         Case_Sensitive => False);
2066                         Src_TS   : Time_Stamp_Type;
2067
2068                      begin
2069                         --  If it is original source, set
2070                         --  Source_In_Dependencies.
2071
2072                         if Src_Name = C_Source_Path then
2073                            Source_In_Dependencies := True;
2074                         end if;
2075
2076                         Name_Len := 0;
2077                         Add_Str_To_Name_Buffer (Src_Name);
2078                         Src_TS := File_Stamp (File_Name_Type'(Name_Find));
2079
2080                         --  If the source does not exist, we need to recompile
2081
2082                         if Src_TS = Empty_Time_Stamp then
2083                            if Verbose_Mode then
2084                               Write_Str  ("      -> source ");
2085                               Write_Str  (Src_Name);
2086                               Write_Line (" does not exist");
2087                            end if;
2088
2089                            Close (Dep_File);
2090                            return;
2091
2092                            --  If the source has been modified after the object
2093                            --  file, we need to recompile.
2094
2095                         elsif Src_TS > Source.Object_TS then
2096                            if Verbose_Mode then
2097                               Write_Str  ("      -> source ");
2098                               Write_Str  (Src_Name);
2099                               Write_Line
2100                                 (" has time stamp later than object file");
2101                            end if;
2102
2103                            Close (Dep_File);
2104                            return;
2105                         end if;
2106                      end;
2107
2108                      --  If the source path name ends the line, we are done
2109
2110                      exit Line_Loop when Finish = Last;
2111
2112                      --  Go get the next source on the line
2113
2114                      Start := Finish + 1;
2115                   end loop Name_Loop;
2116                end;
2117
2118                --  If we are here, we had a continuation character \ at the end
2119                --  of the line, so we continue with the next line.
2120
2121                Get_Line (Dep_File, Name_Buffer, Name_Len);
2122                Start := 1;
2123             end loop Line_Loop;
2124          end if;
2125
2126          --  Set Looping at the end of the first loop
2127          Looping := True;
2128       end loop Big_Loop;
2129
2130       Close (Dep_File);
2131
2132       --  If the original sources were not in the dependency file, then we
2133       --  need to recompile. It may mean that we are using a different source
2134       --  (different variant) for this object file.
2135
2136       if not Source_In_Dependencies then
2137          if Verbose_Mode then
2138             Write_Str  ("      -> source ");
2139             Write_Str  (Source_Path);
2140             Write_Line (" is not in the dependencies");
2141          end if;
2142
2143          return;
2144       end if;
2145
2146       --  If we are here, then everything is OK, no need to recompile
2147
2148       if Verbose_Mode then
2149          Write_Line ("      -> up to date");
2150       end if;
2151
2152       Need_To_Compile := False;
2153    end Check_Compilation_Needed;
2154
2155    ---------------------------
2156    -- Check_For_C_Plus_Plus --
2157    ---------------------------
2158
2159    procedure Check_For_C_Plus_Plus is
2160    begin
2161       C_Plus_Plus_Is_Used := False;
2162
2163       for Project in Project_Table.First ..
2164                      Project_Table.Last (Project_Tree.Projects)
2165       loop
2166          if
2167            Project_Tree.Projects.Table (Project).Langs
2168                                            (C_Plus_Plus_Language_Index)
2169          then
2170             C_Plus_Plus_Is_Used := True;
2171             exit;
2172          end if;
2173       end loop;
2174    end Check_For_C_Plus_Plus;
2175
2176    -------------
2177    -- Compile --
2178    -------------
2179
2180    procedure Compile
2181      (Source_Id    : Other_Source_Id;
2182       Data         : Project_Data;
2183       Local_Errors : in out Boolean)
2184    is
2185       Source  : Other_Source :=
2186                   Project_Tree.Other_Sources.Table (Source_Id);
2187       Success : Boolean;
2188       CPATH   : String_Access := null;
2189
2190    begin
2191       --  If the compiler is not known yet, get its path name
2192
2193       if Compiler_Names (Source.Language) = null then
2194          Get_Compiler (Source.Language);
2195       end if;
2196
2197       --  For non GCC compilers, get the dependency file, first calling the
2198       --  compiler with the switch -M.
2199
2200       if not Compiler_Is_Gcc (Source.Language) then
2201          Last_Argument := 0;
2202
2203          --  Add the source name, preceded by -M
2204
2205          Add_Argument (Dash_M, True);
2206          Add_Argument (Get_Name_String (Source.Path_Name), True);
2207
2208          --  Add the compiling switches for this source found in
2209          --  package Compiler of the project file, if they exist.
2210
2211          Add_Switches
2212            (Data, Compiler, Source.Language, Source.File_Name);
2213
2214          --  Add the compiling switches for the language specified
2215          --  on the command line, if any.
2216
2217          for
2218            J in 1 .. Comp_Opts.Last (Options (Source.Language))
2219          loop
2220             Add_Argument (Options (Source.Language).Table (J), True);
2221          end loop;
2222
2223          --  Finally, add imported directory switches for this project file
2224
2225          Add_Search_Directories (Data, Source.Language);
2226
2227          --  And invoke the compiler using GNAT.Expect
2228
2229          Display_Command
2230            (Compiler_Names (Source.Language).all,
2231             Compiler_Paths (Source.Language));
2232
2233          begin
2234             Non_Blocking_Spawn
2235               (FD,
2236                Compiler_Paths (Source.Language).all,
2237                Arguments (1 .. Last_Argument),
2238                Buffer_Size => 0,
2239                Err_To_Out => True);
2240
2241             declare
2242                Dep_File : Ada.Text_IO.File_Type;
2243                Result   : Expect_Match;
2244
2245                Status : Integer;
2246                pragma Warnings (Off, Status);
2247
2248             begin
2249                --  Create the dependency file
2250
2251                Create (Dep_File, Out_File, Get_Name_String (Source.Dep_Name));
2252
2253                loop
2254                   Expect (FD, Result, Line_Matcher);
2255
2256                   exit when Result = Expect_Timeout;
2257
2258                   declare
2259                      S : constant String := Strip_CR_LF (Expect_Out (FD));
2260
2261                   begin
2262                      --  Each line of the output is put in the dependency
2263                      --  file, including errors. If there are errors, the
2264                      --  syntax of the dependency file will be incorrect and
2265                      --  recompilation will occur automatically the next time
2266                      --  the dependencies are checked.
2267
2268                      Put_Line (Dep_File, S);
2269                   end;
2270                end loop;
2271
2272                --  If we are here, it means we had a timeout, so the
2273                --  dependency file may be incomplete. It is safer to
2274                --  delete it, otherwise the dependencies may be wrong.
2275
2276                Close (FD, Status);
2277                Close (Dep_File);
2278                Delete_File (Get_Name_String (Source.Dep_Name), Success);
2279
2280             exception
2281                when Process_Died =>
2282
2283                   --  This is the normal outcome. Just close the file
2284
2285                   Close (FD, Status);
2286                   Close (Dep_File);
2287
2288                when others =>
2289
2290                   --  Something wrong happened. It is safer to delete the
2291                   --  dependency file, otherwise the dependencies may be wrong.
2292
2293                   Close (FD, Status);
2294
2295                   if Is_Open (Dep_File) then
2296                      Close (Dep_File);
2297                   end if;
2298
2299                   Delete_File (Get_Name_String (Source.Dep_Name), Success);
2300             end;
2301
2302          exception
2303                --  If we cannot spawn the compiler, then the dependencies are
2304                --  not updated. It is safer then to delete the dependency file,
2305                --  otherwise the dependencies may be wrong.
2306
2307             when Invalid_Process =>
2308                Delete_File (Get_Name_String (Source.Dep_Name), Success);
2309          end;
2310       end if;
2311
2312       Last_Argument := 0;
2313
2314       --  For GCC compilers, make sure the language is always specified to
2315       --  to the GCC driver, in case the extension is not recognized by the
2316       --  GCC driver as a source of the language.
2317
2318       if Compiler_Is_Gcc (Source.Language) then
2319          Add_Argument (Dash_x, Verbose_Mode);
2320          Add_Argument
2321            (Get_Name_String (Language_Names.Table (Source.Language)),
2322             Verbose_Mode);
2323       end if;
2324
2325       Add_Argument (Dash_c, True);
2326
2327       --  Add the compiling switches for this source found in package Compiler
2328       --  of the project file, if they exist.
2329
2330       Add_Switches
2331         (Data, Compiler, Source.Language, Source.File_Name);
2332
2333       --  Specify the source to be compiled
2334
2335       Add_Argument (Get_Name_String (Source.Path_Name), True);
2336
2337       --  If non static library project, compile with the PIC option if there
2338       --  is one (when there is no PIC option, MLib.Tgt.PIC_Option returns an
2339       --  empty string, and Add_Argument with an empty string has no effect).
2340
2341       if Data.Library and then Data.Library_Kind /= Static then
2342          Add_Argument (PIC_Option, True);
2343       end if;
2344
2345       --  Indicate the name of the object
2346
2347       Add_Argument (Dash_o, True);
2348       Add_Argument (Get_Name_String (Source.Object_Name), True);
2349
2350       --  When compiler is GCC, use the magic switch that creates the
2351       --  dependency file in the correct format.
2352
2353       if Compiler_Is_Gcc (Source.Language) then
2354          Add_Argument
2355            ("-Wp,-MD," & Get_Name_String (Source.Dep_Name),
2356             Verbose_Mode);
2357       end if;
2358
2359       --  Add the compiling switches for the language specified on the command
2360       --  line, if any.
2361
2362       for J in 1 .. Comp_Opts.Last (Options (Source.Language)) loop
2363          Add_Argument (Options (Source.Language).Table (J), True);
2364       end loop;
2365
2366       --  Finally, add the imported directory switches for this project file
2367       --  (or, for gcc compilers, set up the CPATH env var if needed).
2368
2369       Add_Search_Directories (Data, Source.Language);
2370
2371       --  Set CPATH, if compiler is GCC
2372
2373       if Compiler_Is_Gcc (Source.Language) then
2374          CPATH := Current_Include_Paths (Source.Language);
2375       end if;
2376
2377       --  And invoke the compiler
2378
2379       Display_Command
2380         (Name  => Compiler_Names (Source.Language).all,
2381          Path  => Compiler_Paths (Source.Language),
2382          CPATH => CPATH);
2383
2384       Spawn
2385         (Compiler_Paths (Source.Language).all,
2386          Arguments (1 .. Last_Argument),
2387          Success);
2388
2389       --  Case of successful compilation
2390
2391       if Success then
2392
2393          --  Update the time stamp of the object file
2394
2395          Source.Object_TS := File_Stamp (Source.Object_Name);
2396
2397          --  Do some sanity checks
2398
2399          if Source.Object_TS = Empty_Time_Stamp then
2400             Local_Errors := True;
2401             Report_Error
2402               ("object file ",
2403                Get_Name_String (Source.Object_Name),
2404                " has not been created");
2405
2406          elsif Source.Object_TS < Source.Source_TS then
2407             Local_Errors := True;
2408             Report_Error
2409               ("object file ",
2410                Get_Name_String (Source.Object_Name),
2411                " has not been modified");
2412
2413          else
2414             --  Everything looks fine, update the Other_Sources table
2415
2416             Project_Tree.Other_Sources.Table (Source_Id) := Source;
2417          end if;
2418
2419       --  Compilation failed
2420
2421       else
2422          Local_Errors := True;
2423          Report_Error
2424            ("compilation of ",
2425             Get_Name_String (Source.Path_Name),
2426             " failed");
2427       end if;
2428    end Compile;
2429
2430    --------------------------------
2431    -- Compile_Individual_Sources --
2432    --------------------------------
2433
2434    procedure Compile_Individual_Sources is
2435       Data         : Project_Data :=
2436                        Project_Tree.Projects.Table (Main_Project);
2437       Source_Id    : Other_Source_Id;
2438       Source       : Other_Source;
2439       Source_Name  : File_Name_Type;
2440       Project_Name : String := Get_Name_String (Data.Name);
2441       Dummy        : Boolean := False;
2442
2443       Ada_Is_A_Language : constant Boolean :=
2444                             Data.Langs (Ada_Language_Index);
2445
2446    begin
2447       Ada_Mains.Init;
2448       To_Mixed (Project_Name);
2449       Compile_Only := True;
2450
2451       Get_Imported_Directories (Main_Project, Data);
2452       Project_Tree.Projects.Table (Main_Project) := Data;
2453
2454       --  Compilation will occur in the object directory
2455
2456       if Project_Of_Current_Object_Directory /= Main_Project then
2457          Project_Of_Current_Object_Directory := Main_Project;
2458          Change_Dir (Get_Name_String (Data.Object_Directory));
2459
2460          if Verbose_Mode then
2461             Write_Str  ("Changing to object directory of """);
2462             Write_Name (Data.Name);
2463             Write_Str  (""": """);
2464             Write_Name (Data.Display_Object_Dir);
2465             Write_Line ("""");
2466          end if;
2467       end if;
2468
2469       if not Data.Other_Sources_Present then
2470          if Ada_Is_A_Language then
2471             Mains.Reset;
2472
2473             loop
2474                declare
2475                   Main : constant String := Mains.Next_Main;
2476                begin
2477                   exit when Main'Length = 0;
2478                   Ada_Mains.Increment_Last;
2479                   Ada_Mains.Table (Ada_Mains.Last) := new String'(Main);
2480                end;
2481             end loop;
2482
2483          else
2484             Osint.Fail ("project ", Project_Name, " contains no source");
2485          end if;
2486
2487       else
2488          Mains.Reset;
2489
2490          loop
2491             declare
2492                Main : constant String := Mains.Next_Main;
2493             begin
2494                Name_Len := Main'Length;
2495                exit when Name_Len = 0;
2496                Name_Buffer (1 .. Name_Len) := Main;
2497                Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len));
2498                Source_Name := Name_Find;
2499
2500                if not Sources_Compiled.Get (Source_Name) then
2501                   Sources_Compiled.Set (Source_Name, True);
2502
2503                   Source_Id := Data.First_Other_Source;
2504                   while Source_Id /= No_Other_Source loop
2505                      Source := Project_Tree.Other_Sources.Table (Source_Id);
2506                      exit when Source.File_Name = Source_Name;
2507                      Source_Id := Source.Next;
2508                   end loop;
2509
2510                   if Source_Id = No_Other_Source then
2511                      if Ada_Is_A_Language then
2512                         Ada_Mains.Increment_Last;
2513                         Ada_Mains.Table (Ada_Mains.Last) := new String'(Main);
2514
2515                      else
2516                         Report_Error
2517                           (Main,
2518                            " is not a valid source of project ",
2519                            Project_Name);
2520                      end if;
2521
2522                   else
2523                      Compile (Source_Id, Data, Dummy);
2524                   end if;
2525                end if;
2526             end;
2527          end loop;
2528       end if;
2529
2530       if Ada_Mains.Last > 0 then
2531
2532          --  Invoke gnatmake for all Ada sources
2533
2534          Last_Argument := 0;
2535          Add_Argument (Dash_u, True);
2536
2537          for Index in 1 .. Ada_Mains.Last loop
2538             Add_Argument (Ada_Mains.Table (Index), True);
2539          end loop;
2540
2541          Compile_Link_With_Gnatmake (Mains_Specified => False);
2542       end if;
2543    end Compile_Individual_Sources;
2544
2545    --------------------------------
2546    -- Compile_Link_With_Gnatmake --
2547    --------------------------------
2548
2549    procedure Compile_Link_With_Gnatmake (Mains_Specified : Boolean) is
2550       Data    : constant Project_Data :=
2551                   Project_Tree.Projects.Table (Main_Project);
2552       Success : Boolean;
2553
2554    begin
2555       --  Array Arguments may already contain some arguments, so we don't
2556       --  set Last_Argument to 0.
2557
2558       --  Get the gnatmake to invoke
2559
2560       Get_Compiler (Ada_Language_Index);
2561
2562       --  Specify the project file
2563
2564       Add_Argument (Dash_P, True);
2565       Add_Argument (Get_Name_String (Data.Display_Path_Name), True);
2566
2567       --  Add the saved switches, if any
2568
2569       for Index in 1 .. Saved_Switches.Last loop
2570          Add_Argument (Saved_Switches.Table (Index), True);
2571       end loop;
2572
2573       --  If Mains_Specified is True, find the mains in package Mains
2574
2575       if Mains_Specified then
2576          Mains.Reset;
2577
2578          loop
2579             declare
2580                Main : constant String := Mains.Next_Main;
2581             begin
2582                exit when Main'Length = 0;
2583                Add_Argument (Main, True);
2584             end;
2585          end loop;
2586       end if;
2587
2588       --  Specify output file name, if any was specified on the command line
2589
2590       if Output_File_Name /= null then
2591          Add_Argument (Dash_o, True);
2592          Add_Argument (Output_File_Name, True);
2593       end if;
2594
2595       --  Transmit some switches to gnatmake
2596
2597       --  -c
2598
2599       if Compile_Only then
2600          Add_Argument (Dash_c, True);
2601       end if;
2602
2603       --  -d
2604
2605       if Display_Compilation_Progress then
2606          Add_Argument (Dash_d, True);
2607       end if;
2608
2609       --  -k
2610
2611       if Keep_Going then
2612          Add_Argument (Dash_k, True);
2613       end if;
2614
2615       --  -f
2616
2617       if Force_Compilations then
2618          Add_Argument (Dash_f, True);
2619       end if;
2620
2621       --  -v
2622
2623       if Verbose_Mode then
2624          Add_Argument (Dash_v, True);
2625       end if;
2626
2627       --  -q
2628
2629       if Quiet_Output then
2630          Add_Argument (Dash_q, True);
2631       end if;
2632
2633       --  -vP1 and -vP2
2634
2635       case Current_Verbosity is
2636          when Default =>
2637             null;
2638
2639          when Medium =>
2640             Add_Argument (Dash_vP1, True);
2641
2642          when High =>
2643             Add_Argument (Dash_vP2, True);
2644       end case;
2645
2646       --  If there are compiling options for Ada, transmit them to gnatmake
2647
2648       if Comp_Opts.Last (Options (Ada_Language_Index)) /= 0 then
2649          Add_Argument (Dash_cargs, True);
2650
2651          for Arg in 1 .. Comp_Opts.Last (Options (Ada_Language_Index)) loop
2652             Add_Argument (Options (Ada_Language_Index).Table (Arg), True);
2653          end loop;
2654       end if;
2655
2656       if not Compile_Only then
2657
2658          --  Linking options
2659
2660          if Linker_Options.Last /= 0 then
2661             Add_Argument (Dash_largs, True);
2662          else
2663             Add_Argument (Dash_largs, Verbose_Mode);
2664          end if;
2665
2666          --  Add the archives
2667
2668          Add_Archives (For_Gnatmake => True);
2669
2670          --  If there are linking options from the command line,
2671          --  transmit them to gnatmake.
2672
2673          for Arg in 1 .. Linker_Options.Last loop
2674             Add_Argument (Linker_Options.Table (Arg), True);
2675          end loop;
2676       end if;
2677
2678       --  And invoke gnatmake
2679
2680       Display_Command
2681         (Compiler_Names (Ada_Language_Index).all,
2682          Compiler_Paths (Ada_Language_Index));
2683
2684       Spawn
2685         (Compiler_Paths (Ada_Language_Index).all,
2686          Arguments (1 .. Last_Argument),
2687          Success);
2688
2689       --  Report an error if call to gnatmake failed
2690
2691       if not Success then
2692          Report_Error
2693            ("invocation of ",
2694             Compiler_Names (Ada_Language_Index).all,
2695             " failed");
2696       end if;
2697    end Compile_Link_With_Gnatmake;
2698
2699    ---------------------
2700    -- Compile_Sources --
2701    ---------------------
2702
2703    procedure Compile_Sources is
2704       Data         : Project_Data;
2705       Source_Id    : Other_Source_Id;
2706       Source       : Other_Source;
2707
2708       Local_Errors : Boolean := False;
2709       --  Set to True when there is a compilation error. Used only when
2710       --  Keep_Going is True, to inhibit the building of the archive.
2711
2712       Need_To_Compile : Boolean;
2713       --  Set to True when a source needs to be compiled/recompiled
2714
2715       Need_To_Rebuild_Archive : Boolean := Force_Compilations;
2716       --  True when the archive needs to be built/rebuilt unconditionally
2717
2718       Total_Number_Of_Sources : Int := 0;
2719
2720       Current_Source_Number : Int := 0;
2721
2722    begin
2723       --  First, get the number of sources
2724
2725       for Project in Project_Table.First ..
2726                      Project_Table.Last (Project_Tree.Projects)
2727       loop
2728          Data := Project_Tree.Projects.Table (Project);
2729
2730          if not Data.Virtual and then Data.Other_Sources_Present then
2731             Source_Id := Data.First_Other_Source;
2732             while Source_Id /= No_Other_Source loop
2733                Source := Project_Tree.Other_Sources.Table (Source_Id);
2734                Total_Number_Of_Sources := Total_Number_Of_Sources + 1;
2735                Source_Id := Source.Next;
2736             end loop;
2737          end if;
2738       end loop;
2739
2740       --  Loop through project files
2741
2742       for Project in Project_Table.First ..
2743                      Project_Table.Last (Project_Tree.Projects)
2744       loop
2745          Local_Errors := False;
2746          Data := Project_Tree.Projects.Table (Project);
2747
2748          --  Nothing to do when no sources of language other than Ada
2749
2750          if (not Data.Virtual) and then Data.Other_Sources_Present then
2751
2752             --  If the imported directory switches are unknown, compute them
2753
2754             if not Data.Include_Data_Set then
2755                Get_Imported_Directories (Project, Data);
2756                Data.Include_Data_Set := True;
2757                Project_Tree.Projects.Table (Project) := Data;
2758             end if;
2759
2760             Need_To_Rebuild_Archive := Force_Compilations;
2761
2762             --  Compilation will occur in the object directory
2763
2764             if Project_Of_Current_Object_Directory /= Project then
2765                Project_Of_Current_Object_Directory := Project;
2766                Change_Dir (Get_Name_String (Data.Object_Directory));
2767
2768                if Verbose_Mode then
2769                   Write_Str  ("Changing to object directory of """);
2770                   Write_Name (Data.Display_Name);
2771                   Write_Str  (""": """);
2772                   Write_Name (Data.Display_Object_Dir);
2773                   Write_Line ("""");
2774                end if;
2775             end if;
2776
2777             --  Process each source one by one
2778
2779             Source_Id := Data.First_Other_Source;
2780             while Source_Id /= No_Other_Source loop
2781                Source := Project_Tree.Other_Sources.Table (Source_Id);
2782                Current_Source_Number := Current_Source_Number + 1;
2783                Need_To_Compile := Force_Compilations;
2784
2785                --  Check if compilation is needed
2786
2787                if not Need_To_Compile then
2788                   Check_Compilation_Needed (Source, Need_To_Compile);
2789                end if;
2790
2791                --  Proceed, if compilation is needed
2792
2793                if Need_To_Compile then
2794
2795                   --  If a source is compiled/recompiled, of course the
2796                   --  archive will need to be built/rebuilt.
2797
2798                   Need_To_Rebuild_Archive := True;
2799                   Compile (Source_Id, Data, Local_Errors);
2800                end if;
2801
2802                if Display_Compilation_Progress then
2803                   Write_Str ("completed ");
2804                   Write_Int (Current_Source_Number);
2805                   Write_Str (" out of ");
2806                   Write_Int (Total_Number_Of_Sources);
2807                   Write_Str (" (");
2808                   Write_Int
2809                     ((Current_Source_Number * 100) / Total_Number_Of_Sources);
2810                   Write_Str ("%)...");
2811                   Write_Eol;
2812                end if;
2813
2814                --  Next source, if any
2815
2816                Source_Id := Source.Next;
2817             end loop;
2818
2819             if Need_To_Rebuild_Archive and then (not Data.Library) then
2820                Need_To_Rebuild_Global_Archive := True;
2821             end if;
2822
2823             --  If there was no compilation error and -c was not used,
2824             --  build / rebuild the archive if necessary.
2825
2826             if not Local_Errors
2827               and then Data.Library
2828               and then not Data.Langs (Ada_Language_Index)
2829               and then not Compile_Only
2830             then
2831                Build_Library (Project, Need_To_Rebuild_Archive);
2832             end if;
2833          end if;
2834       end loop;
2835    end Compile_Sources;
2836
2837    ---------------
2838    -- Copyright --
2839    ---------------
2840
2841    procedure Copyright is
2842    begin
2843       --  Only output the Copyright notice once
2844
2845       if not Copyright_Output then
2846          Copyright_Output := True;
2847          Write_Eol;
2848          Write_Str ("GPRMAKE ");
2849          Write_Str (Gnatvsn.Gnat_Version_String);
2850          Write_Str (" Copyright 2004-");
2851          Write_Str (Gnatvsn.Current_Year);
2852          Write_Str (" Free Software Foundation, Inc.");
2853          Write_Eol;
2854       end if;
2855    end Copyright;
2856
2857    ------------------------------------
2858    -- Create_Archive_Dependency_File --
2859    ------------------------------------
2860
2861    procedure Create_Archive_Dependency_File
2862      (Name         : String;
2863       First_Source : Other_Source_Id)
2864    is
2865       Source_Id : Other_Source_Id;
2866       Source    : Other_Source;
2867       Dep_File  : Ada.Text_IO.File_Type;
2868
2869    begin
2870       --  Create the file in Append mode, to avoid automatic insertion of
2871       --  an end of line if file is empty.
2872
2873       Create (Dep_File, Append_File, Name);
2874
2875       Source_Id := First_Source;
2876       while Source_Id /= No_Other_Source loop
2877          Source := Project_Tree.Other_Sources.Table (Source_Id);
2878          Put_Line (Dep_File, Get_Name_String (Source.Object_Name));
2879          Put_Line (Dep_File, String (Source.Object_TS));
2880          Source_Id := Source.Next;
2881       end loop;
2882
2883       Close (Dep_File);
2884
2885    exception
2886       when others =>
2887          if Is_Open (Dep_File) then
2888             Close (Dep_File);
2889          end if;
2890    end Create_Archive_Dependency_File;
2891
2892    -------------------------------------------
2893    -- Create_Global_Archive_Dependency_File --
2894    -------------------------------------------
2895
2896    procedure Create_Global_Archive_Dependency_File (Name : String) is
2897       Source_Id : Other_Source_Id;
2898       Source    : Other_Source;
2899       Dep_File  : Ada.Text_IO.File_Type;
2900
2901    begin
2902       --  Create the file in Append mode, to avoid automatic insertion of
2903       --  an end of line if file is empty.
2904
2905       Create (Dep_File, Append_File, Name);
2906
2907       --  Get all the object files of non-Ada sources in non-library projects
2908
2909       for Project in Project_Table.First ..
2910                      Project_Table.Last (Project_Tree.Projects)
2911       loop
2912          if not Project_Tree.Projects.Table (Project).Library then
2913             Source_Id :=
2914               Project_Tree.Projects.Table (Project).First_Other_Source;
2915             while Source_Id /= No_Other_Source loop
2916                Source := Project_Tree.Other_Sources.Table (Source_Id);
2917
2918                --  Put only those object files that are in the global archive
2919
2920                if Is_Included_In_Global_Archive
2921                     (Source.Object_Name, Project)
2922                then
2923                   Put_Line (Dep_File, Get_Name_String (Source.Object_Path));
2924                   Put_Line (Dep_File, String (Source.Object_TS));
2925                end if;
2926
2927                Source_Id := Source.Next;
2928             end loop;
2929          end if;
2930       end loop;
2931
2932       Close (Dep_File);
2933
2934    exception
2935       when others =>
2936          if Is_Open (Dep_File) then
2937             Close (Dep_File);
2938          end if;
2939    end Create_Global_Archive_Dependency_File;
2940
2941    ---------------------
2942    -- Display_Command --
2943    ---------------------
2944
2945    procedure Display_Command
2946      (Name    : String;
2947       Path    : String_Access;
2948       CPATH   : String_Access := null;
2949       Ellipse : Boolean := False)
2950    is
2951       Display_Ellipse : Boolean := Ellipse;
2952
2953    begin
2954       --  Only display the command in Verbose Mode (-v) or when
2955       --  not in Quiet Output (no -q).
2956
2957       if Verbose_Mode or (not Quiet_Output) then
2958
2959          --  In Verbose Mode output the full path of the spawned process
2960
2961          if Verbose_Mode then
2962             if CPATH /= null then
2963                Write_Str  ("CPATH = ");
2964                Write_Line (CPATH.all);
2965             end if;
2966
2967             Write_Str (Path.all);
2968
2969          else
2970             Write_Str (Name);
2971          end if;
2972
2973          --  Display only the arguments for which the display flag is set
2974          --  (in Verbose Mode, the display flag is set for all arguments)
2975
2976          for Arg in 1 .. Last_Argument loop
2977             if Arguments_Displayed (Arg) then
2978                Write_Char (' ');
2979                Write_Str (Arguments (Arg).all);
2980
2981             elsif Display_Ellipse then
2982                Write_Str (" ...");
2983                Display_Ellipse := False;
2984             end if;
2985          end loop;
2986
2987          Write_Eol;
2988       end if;
2989    end Display_Command;
2990
2991    ------------------
2992    -- Get_Compiler --
2993    ------------------
2994
2995    procedure Get_Compiler (For_Language : First_Language_Indexes) is
2996       Data : constant Project_Data :=
2997                Project_Tree.Projects.Table (Main_Project);
2998
2999       Ide : constant Package_Id :=
3000         Value_Of
3001           (Name_Ide,
3002            In_Packages => Data.Decl.Packages,
3003            In_Tree     => Project_Tree);
3004       --  The id of the package IDE in the project file
3005
3006       Compiler : constant Variable_Value :=
3007         Value_Of
3008           (Name                    => Language_Names.Table (For_Language),
3009            Index                   => 0,
3010            Attribute_Or_Array_Name => Name_Compiler_Command,
3011            In_Package              => Ide,
3012            In_Tree                 => Project_Tree);
3013       --  The value of Compiler_Command ("language") in package IDE, if defined
3014
3015    begin
3016       --  No need to do it again if the compiler is known for this language
3017
3018       if Compiler_Names (For_Language) = null then
3019
3020          --  If compiler command is not defined for this language in package
3021          --  IDE, use the default compiler for this language.
3022
3023          if Compiler = Nil_Variable_Value then
3024             if For_Language in Default_Compiler_Names'Range then
3025                Compiler_Names (For_Language) :=
3026                  Default_Compiler_Names (For_Language);
3027
3028             else
3029                Osint.Fail
3030                  ("unknow compiler name for language """,
3031                   Get_Name_String (Language_Names.Table (For_Language)),
3032                   """");
3033             end if;
3034
3035          else
3036             Compiler_Names (For_Language) :=
3037               new String'(Get_Name_String (Compiler.Value));
3038          end if;
3039
3040          --  Check we have a GCC compiler (name ends with "gcc" or "g++")
3041
3042          declare
3043             Comp_Name : constant String := Compiler_Names (For_Language).all;
3044             Last3     : String (1 .. 3);
3045          begin
3046             if Comp_Name'Length >= 3 then
3047                Last3 := Comp_Name (Comp_Name'Last - 2 .. Comp_Name'Last);
3048                Compiler_Is_Gcc (For_Language) :=
3049                  (Last3 = "gcc") or (Last3 = "g++");
3050             else
3051                Compiler_Is_Gcc (For_Language) := False;
3052             end if;
3053          end;
3054
3055          --  Locate the compiler on the path
3056
3057          Compiler_Paths (For_Language) :=
3058            Locate_Exec_On_Path (Compiler_Names (For_Language).all);
3059
3060          --  Fail if compiler cannot be found
3061
3062          if Compiler_Paths (For_Language) = null then
3063             if For_Language = Ada_Language_Index then
3064                Osint.Fail
3065                  ("unable to locate """,
3066                   Compiler_Names (For_Language).all,
3067                   """");
3068
3069             else
3070                Osint.Fail
3071                  ("unable to locate " &
3072                   Get_Name_String (Language_Names.Table (For_Language)),
3073                   " compiler """, Compiler_Names (For_Language).all & '"');
3074             end if;
3075          end if;
3076       end if;
3077    end Get_Compiler;
3078
3079    ------------------------------
3080    -- Get_Imported_Directories --
3081    ------------------------------
3082
3083    procedure Get_Imported_Directories
3084      (Project : Project_Id;
3085       Data    : in out Project_Data)
3086    is
3087       Imported_Projects : Project_List := Data.Imported_Projects;
3088
3089       Path_Length : Natural := 0;
3090       Position    : Natural := 0;
3091
3092       procedure Add (Source_Dirs : String_List_Id);
3093       --  Add a list of source directories
3094
3095       procedure Recursive_Get_Dirs (Prj : Project_Id);
3096       --  Recursive procedure to get the source directories of this project
3097       --  file and of the project files it imports, in the correct order.
3098
3099       ---------
3100       -- Add --
3101       ---------
3102
3103       procedure Add (Source_Dirs : String_List_Id) is
3104          Element_Id : String_List_Id;
3105          Element    : String_Element;
3106          Add_Arg    : Boolean := True;
3107
3108       begin
3109          --  Add each source directory path name, preceded by "-I" to Arguments
3110
3111          Element_Id := Source_Dirs;
3112          while Element_Id /= Nil_String loop
3113             Element := Project_Tree.String_Elements.Table (Element_Id);
3114
3115             if Element.Value /= No_Name then
3116                Get_Name_String (Element.Display_Value);
3117
3118                if Name_Len > 0 then
3119
3120                   --  Remove a trailing directory separator: this may cause
3121                   --  problems on Windows.
3122
3123                   if Name_Len > 1
3124                     and then Name_Buffer (Name_Len) = Directory_Separator
3125                   then
3126                      Name_Len := Name_Len - 1;
3127                   end if;
3128
3129                   declare
3130                      Arg : constant String :=
3131                              "-I" & Name_Buffer (1 .. Name_Len);
3132                   begin
3133                      --  Check if directory is already in the list. If it is,
3134                      --  no need to put it there again.
3135
3136                      Add_Arg := True;
3137
3138                      for Index in 1 .. Last_Argument loop
3139                         if Arguments (Index).all = Arg then
3140                            Add_Arg := False;
3141                            exit;
3142                         end if;
3143                      end loop;
3144
3145                      if Add_Arg then
3146                         if Path_Length /= 0 then
3147                            Path_Length := Path_Length + 1;
3148                         end if;
3149
3150                         Path_Length := Path_Length + Name_Len;
3151
3152                         Add_Argument (Arg, True);
3153                      end if;
3154                   end;
3155                end if;
3156             end if;
3157
3158             Element_Id := Element.Next;
3159          end loop;
3160       end Add;
3161
3162       ------------------------
3163       -- Recursive_Get_Dirs --
3164       ------------------------
3165
3166       procedure Recursive_Get_Dirs (Prj : Project_Id) is
3167          Data     : Project_Data;
3168          Imported : Project_List;
3169
3170       begin
3171          --  Nothing to do if project is undefined
3172
3173          if Prj /= No_Project then
3174             Data := Project_Tree.Projects.Table (Prj);
3175
3176             --  Nothing to do if project has already been processed
3177
3178             if not Data.Seen then
3179
3180                --  Mark the project as processed, to avoid multiple processing
3181                --  of the same project.
3182
3183                Project_Tree.Projects.Table (Prj).Seen := True;
3184
3185                --  Add the source directories of this project
3186
3187                if not Data.Virtual then
3188                   Add (Data.Source_Dirs);
3189                end if;
3190
3191                Recursive_Get_Dirs (Data.Extends);
3192
3193                --  Call itself for all imported projects, if any
3194
3195                Imported := Data.Imported_Projects;
3196                while Imported /= Empty_Project_List loop
3197                   Recursive_Get_Dirs
3198                     (Project_Tree.Project_Lists.Table (Imported).Project);
3199                   Imported :=
3200                     Project_Tree.Project_Lists.Table (Imported).Next;
3201                end loop;
3202             end if;
3203          end if;
3204       end Recursive_Get_Dirs;
3205
3206    --  Start of processing for Get_Imported_Directories
3207
3208    begin
3209       --  First, mark all project as not processed
3210
3211       for J in Project_Table.First ..
3212                Project_Table.Last (Project_Tree.Projects)
3213       loop
3214          Project_Tree.Projects.Table (J).Seen := False;
3215       end loop;
3216
3217       --  Empty Arguments
3218
3219       Last_Argument := 0;
3220
3221       --  Process this project individually, project data are already known
3222
3223       Project_Tree.Projects.Table (Project).Seen := True;
3224
3225       Add (Data.Source_Dirs);
3226
3227       Recursive_Get_Dirs (Data.Extends);
3228
3229       while Imported_Projects /= Empty_Project_List loop
3230          Recursive_Get_Dirs
3231            (Project_Tree.Project_Lists.Table
3232               (Imported_Projects).Project);
3233          Imported_Projects := Project_Tree.Project_Lists.Table
3234                                 (Imported_Projects).Next;
3235       end loop;
3236
3237       Data.Imported_Directories_Switches :=
3238         new Argument_List'(Arguments (1 .. Last_Argument));
3239
3240       --  Create the Include_Path, from the Arguments
3241
3242       Data.Include_Path := new String (1 .. Path_Length);
3243       Data.Include_Path (1 .. Arguments (1)'Length - 2) :=
3244         Arguments (1)(Arguments (1)'First + 2 .. Arguments (1)'Last);
3245       Position := Arguments (1)'Length - 2;
3246
3247       for Arg in 2 .. Last_Argument loop
3248          Position := Position + 1;
3249          Data.Include_Path (Position) := Path_Separator;
3250          Data.Include_Path
3251            (Position + 1 .. Position + Arguments (Arg)'Length - 2) :=
3252            Arguments (Arg)(Arguments (Arg)'First + 2 .. Arguments (Arg)'Last);
3253          Position := Position + Arguments (Arg)'Length - 2;
3254       end loop;
3255
3256       Last_Argument := 0;
3257    end Get_Imported_Directories;
3258
3259    -------------
3260    -- Gprmake --
3261    -------------
3262
3263    procedure Gprmake is
3264    begin
3265       Makegpr.Initialize;
3266
3267       if Verbose_Mode then
3268          Write_Eol;
3269          Write_Str ("Parsing project file """);
3270          Write_Str (Project_File_Name.all);
3271          Write_Str (""".");
3272          Write_Eol;
3273       end if;
3274
3275       --  Parse and process project files for other languages (not for Ada)
3276
3277       Prj.Pars.Parse
3278         (Project           => Main_Project,
3279          In_Tree           => Project_Tree,
3280          Project_File_Name => Project_File_Name.all,
3281          Packages_To_Check => Packages_To_Check);
3282
3283       --  Fail if parsing/processing was unsuccessful
3284
3285       if Main_Project = No_Project then
3286          Osint.Fail ("""", Project_File_Name.all, """ processing failed");
3287       end if;
3288
3289       if Verbose_Mode then
3290          Write_Eol;
3291          Write_Str ("Parsing of project file """);
3292          Write_Str (Project_File_Name.all);
3293          Write_Str (""" is finished.");
3294          Write_Eol;
3295       end if;
3296
3297       --  If -f was specified, we will certainly need to link (except when
3298       --  -u or -c were specified, of course).
3299
3300       Need_To_Relink := Force_Compilations;
3301
3302       if Unique_Compile then
3303          if Mains.Number_Of_Mains = 0 then
3304             Osint.Fail
3305               ("No source specified to compile in 'unique compile' mode");
3306          else
3307             Compile_Individual_Sources;
3308             Report_Total_Errors ("compilation");
3309          end if;
3310
3311       else
3312          declare
3313             Data : constant Prj.Project_Data :=
3314                      Project_Tree.Projects.Table (Main_Project);
3315          begin
3316             if Data.Library and then Mains.Number_Of_Mains /= 0 then
3317                Osint.Fail
3318                  ("Cannot specify mains on the command line " &
3319                   "for a Library Project");
3320             end if;
3321
3322             --  First check for C++, to link libraries with g++,
3323             --  rather than gcc.
3324
3325             Check_For_C_Plus_Plus;
3326
3327             --  Compile sources and build archives for library project,
3328             --  if necessary.
3329
3330             Compile_Sources;
3331
3332             --  When Keep_Going is True, if we had some errors, fail now,
3333             --  reporting the number of compilation errors.
3334             --  Do not attempt to link.
3335
3336             Report_Total_Errors ("compilation");
3337
3338             --  If -c was not specified, link the executables,
3339             --  if there are any.
3340
3341             if not Compile_Only
3342               and then not Data.Library
3343               and then Data.Object_Directory /= No_Path
3344             then
3345                Build_Global_Archive;
3346                Link_Executables;
3347             end if;
3348
3349             --  When Keep_Going is True, if we had some errors, fail, reporting
3350             --  the number of linking errors.
3351
3352             Report_Total_Errors ("linking");
3353          end;
3354       end if;
3355    end Gprmake;
3356
3357    ----------------
3358    -- Initialize --
3359    ----------------
3360
3361    procedure Initialize is
3362    begin
3363       Set_Mode (Ada_Only);
3364
3365       --  Do some necessary package initializations
3366
3367       Csets.Initialize;
3368       Namet.Initialize;
3369       Snames.Initialize;
3370       Prj.Initialize (Project_Tree);
3371       Mains.Delete;
3372
3373       --  Add the directory where gprmake is invoked in front of the path,
3374       --  if gprmake is invoked from a bin directory or with directory
3375       --  information. information. Only do this if the platform is not VMS,
3376       --  where the notion of path does not really exist.
3377
3378       --  Below code shares nasty code duplication with make.adb code???
3379
3380       if not OpenVMS then
3381          declare
3382             Prefix  : constant String := Executable_Prefix_Path;
3383             Command : constant String := Command_Name;
3384
3385          begin
3386             if Prefix'Length > 0 then
3387                declare
3388                   PATH : constant String :=
3389                            Prefix & Directory_Separator & "bin" &
3390                            Path_Separator &
3391                            Getenv ("PATH").all;
3392                begin
3393                   Setenv ("PATH", PATH);
3394                end;
3395
3396             else
3397                for Index in reverse Command'Range loop
3398                   if Command (Index) = Directory_Separator then
3399                      declare
3400                         Absolute_Dir : constant String :=
3401                                          Normalize_Pathname
3402                                            (Command (Command'First .. Index));
3403                         PATH         : constant String :=
3404                                          Absolute_Dir &
3405                                          Path_Separator &
3406                                          Getenv ("PATH").all;
3407                      begin
3408                         Setenv ("PATH", PATH);
3409                      end;
3410
3411                      exit;
3412                   end if;
3413                end loop;
3414             end if;
3415          end;
3416       end if;
3417
3418       --  Set Name_Ide and Name_Compiler_Command
3419
3420       Name_Len := 0;
3421       Add_Str_To_Name_Buffer ("ide");
3422       Name_Ide := Name_Find;
3423
3424       Name_Len := 0;
3425       Add_Str_To_Name_Buffer ("compiler_command");
3426       Name_Compiler_Command := Name_Find;
3427
3428       --  Make sure the Saved_Switches table is empty
3429
3430       Saved_Switches.Set_Last (0);
3431
3432       --  Get the command line arguments
3433
3434       Scan_Args : for Next_Arg in 1 .. Argument_Count loop
3435          Scan_Arg (Argument (Next_Arg));
3436       end loop Scan_Args;
3437
3438       --  Fail if command line ended with "-P"
3439
3440       if Project_File_Name_Expected then
3441          Osint.Fail ("project file name missing after -P");
3442
3443       --  Or if it ended with "-o"
3444
3445       elsif Output_File_Name_Expected then
3446          Osint.Fail ("output file name missing after -o");
3447       end if;
3448
3449       --  If no project file was specified, display the usage and fail
3450
3451       if Project_File_Name = null then
3452          Usage;
3453          Exit_Program (E_Success);
3454       end if;
3455
3456       --  To be able of finding libgnat.a in MLib.Tgt, we need to have the
3457       --  default search dirs established in Osint.
3458
3459       Osint.Add_Default_Search_Dirs;
3460    end Initialize;
3461
3462    -----------------------------------
3463    -- Is_Included_In_Global_Archive --
3464    -----------------------------------
3465
3466    function Is_Included_In_Global_Archive
3467      (Object_Name : File_Name_Type;
3468       Project     : Project_Id) return Boolean
3469    is
3470       Data   : Project_Data := Project_Tree.Projects.Table (Project);
3471       Source : Other_Source_Id;
3472
3473    begin
3474       while Data.Extended_By /= No_Project loop
3475          Data := Project_Tree.Projects.Table (Data.Extended_By);
3476
3477          Source := Data.First_Other_Source;
3478          while Source /= No_Other_Source loop
3479             if Project_Tree.Other_Sources.Table (Source).Object_Name =
3480                  Object_Name
3481             then
3482                return False;
3483             else
3484                Source :=
3485                  Project_Tree.Other_Sources.Table (Source).Next;
3486             end if;
3487          end loop;
3488       end loop;
3489
3490       return True;
3491    end Is_Included_In_Global_Archive;
3492
3493    ----------------------
3494    -- Link_Executables --
3495    ----------------------
3496
3497    procedure Link_Executables is
3498       Data : constant Project_Data :=
3499                Project_Tree.Projects.Table (Main_Project);
3500
3501       Mains_Specified : constant Boolean := Mains.Number_Of_Mains /= 0;
3502       --  True if main sources were specified on the command line
3503
3504       Object_Dir : constant String :=
3505                      Get_Name_String (Data.Display_Object_Dir);
3506       --  Path of the object directory of the main project
3507
3508       Source_Id : Other_Source_Id;
3509       Source    : Other_Source;
3510       Success   : Boolean;
3511
3512       Linker_Name : String_Access;
3513       Linker_Path : String_Access;
3514       --  The linker name and path, when linking is not done by gnatlink
3515
3516       Link_Done   : Boolean := False;
3517       --  Set to True when the linker is invoked directly (not through
3518       --  gnatmake) to be able to report if mains were up to date at the end
3519       --  of execution.
3520
3521       procedure Add_C_Plus_Plus_Link_For_Gnatmake;
3522       --  Add the --LINK= switch for gnatlink, depending on the C++ compiler
3523
3524       procedure Check_Time_Stamps (Exec_Time_Stamp : Time_Stamp_Type);
3525       --  Check if there is an archive that is more recent than the executable
3526       --  to decide if we need to relink.
3527
3528       procedure Choose_C_Plus_Plus_Link_Process;
3529       --  If the C++ compiler is not g++, create the correct script to link
3530
3531       procedure Link_Foreign
3532         (Main    : String;
3533          Main_Id : File_Name_Type;
3534          Source  : Other_Source);
3535       --  Link a non-Ada main, when there is no Ada code
3536
3537       ---------------------------------------
3538       -- Add_C_Plus_Plus_Link_For_Gnatmake --
3539       ---------------------------------------
3540
3541       procedure Add_C_Plus_Plus_Link_For_Gnatmake is
3542       begin
3543          Add_Argument
3544            ("--LINK=" & Compiler_Names (C_Plus_Plus_Language_Index).all,
3545             Verbose_Mode);
3546       end Add_C_Plus_Plus_Link_For_Gnatmake;
3547
3548       -----------------------
3549       -- Check_Time_Stamps --
3550       -----------------------
3551
3552       procedure Check_Time_Stamps (Exec_Time_Stamp : Time_Stamp_Type) is
3553          Prj_Data : Project_Data;
3554
3555       begin
3556          for Prj in Project_Table.First ..
3557                     Project_Table.Last (Project_Tree.Projects)
3558          loop
3559             Prj_Data := Project_Tree.Projects.Table (Prj);
3560
3561             --  There is an archive only in project
3562             --  files with sources other than Ada
3563             --  sources.
3564
3565             if Data.Other_Sources_Present then
3566                declare
3567                   Archive_Path : constant String := Get_Name_String
3568                     (Prj_Data.Display_Object_Dir) & Directory_Separator
3569                     & "lib" & Get_Name_String (Prj_Data.Display_Name)
3570                     & '.' & Archive_Ext;
3571                   Archive_TS   : Time_Stamp_Type;
3572                begin
3573                   Name_Len := 0;
3574                   Add_Str_To_Name_Buffer (Archive_Path);
3575                   Archive_TS := File_Stamp (File_Name_Type'(Name_Find));
3576
3577                   --  If the archive is later than the
3578                   --  executable, we need to relink.
3579
3580                   if Archive_TS /=  Empty_Time_Stamp
3581                     and then
3582                       Exec_Time_Stamp < Archive_TS
3583                   then
3584                      Need_To_Relink := True;
3585
3586                      if Verbose_Mode then
3587                         Write_Str ("      -> ");
3588                         Write_Str (Archive_Path);
3589                         Write_Str (" has time stamp ");
3590                         Write_Str ("later than ");
3591                         Write_Line ("executable");
3592                      end if;
3593
3594                      exit;
3595                   end if;
3596                end;
3597             end if;
3598          end loop;
3599       end Check_Time_Stamps;
3600
3601       -------------------------------------
3602       -- Choose_C_Plus_Plus_Link_Process --
3603       -------------------------------------
3604
3605       procedure Choose_C_Plus_Plus_Link_Process is
3606       begin
3607          if Compiler_Names (C_Plus_Plus_Language_Index) = null then
3608             Get_Compiler (C_Plus_Plus_Language_Index);
3609          end if;
3610       end Choose_C_Plus_Plus_Link_Process;
3611
3612       ------------------
3613       -- Link_Foreign --
3614       ------------------
3615
3616       procedure Link_Foreign
3617         (Main    : String;
3618          Main_Id : File_Name_Type;
3619          Source  : Other_Source)
3620       is
3621          Executable_Name : constant String :=
3622                              Get_Name_String
3623                                (Executable_Of
3624                                     (Project  => Main_Project,
3625                                      In_Tree  => Project_Tree,
3626                                      Main     => Main_Id,
3627                                      Index    => 0,
3628                                      Ada_Main => False));
3629          --  File name of the executable
3630
3631          Executable_Path : constant String :=
3632                              Get_Name_String
3633                                (Data.Display_Exec_Dir) &
3634                                 Directory_Separator & Executable_Name;
3635          --  Path name of the executable
3636
3637          Exec_Time_Stamp : Time_Stamp_Type;
3638
3639       begin
3640          --  Now, check if the executable is up to date. It is considered
3641          --  up to date if its time stamp is not earlier that the time stamp
3642          --  of any archive. Only do that if we don't know if we need to link.
3643
3644          if not Need_To_Relink then
3645
3646             --  Get the time stamp of the executable
3647
3648             Name_Len := 0;
3649             Add_Str_To_Name_Buffer (Executable_Path);
3650             Exec_Time_Stamp := File_Stamp (File_Name_Type'(Name_Find));
3651
3652             if Verbose_Mode then
3653                Write_Str  ("   Checking executable ");
3654                Write_Line (Executable_Name);
3655             end if;
3656
3657             --  If executable does not exist, we need to link
3658
3659             if Exec_Time_Stamp = Empty_Time_Stamp then
3660                Need_To_Relink := True;
3661
3662                if Verbose_Mode then
3663                   Write_Line ("      -> not found");
3664                end if;
3665
3666             --  Otherwise, get the time stamps of each archive. If one of
3667             --  them is found later than the executable, we need to relink.
3668
3669             else
3670                Check_Time_Stamps (Exec_Time_Stamp);
3671             end if;
3672
3673             --  If Need_To_Relink is False, we are done
3674
3675             if Verbose_Mode and (not Need_To_Relink) then
3676                Write_Line ("      -> up to date");
3677             end if;
3678          end if;
3679
3680          --  Prepare to link
3681
3682          if Need_To_Relink then
3683             Link_Done := True;
3684
3685             Last_Argument := 0;
3686
3687             --  Specify the executable path name
3688
3689             Add_Argument (Dash_o, True);
3690             Add_Argument
3691               (Get_Name_String (Data.Display_Exec_Dir) &
3692                Directory_Separator &
3693                Get_Name_String
3694                  (Executable_Of
3695                     (Project  => Main_Project,
3696                      In_Tree  => Project_Tree,
3697                      Main     => Main_Id,
3698                      Index    => 0,
3699                      Ada_Main => False)),
3700                True);
3701
3702             --  Specify the object file of the main source
3703
3704             Add_Argument
3705               (Object_Dir & Directory_Separator &
3706                Get_Name_String (Source.Object_Name),
3707                True);
3708
3709             --  Add all the archives, in a correct order
3710
3711             Add_Archives (For_Gnatmake => False);
3712
3713             --  Add the switches specified in package Linker of
3714             --  the main project.
3715
3716             Add_Switches
3717               (Data      => Data,
3718                Proc      => Linker,
3719                Language  => Source.Language,
3720                File_Name => Main_Id);
3721
3722             --  Add the switches specified in attribute
3723             --  Linker_Options of packages Linker.
3724
3725             if Link_Options_Switches = null then
3726                Link_Options_Switches :=
3727                  new Argument_List'
3728                    (Linker_Options_Switches (Main_Project, Project_Tree));
3729             end if;
3730
3731             Add_Arguments (Link_Options_Switches.all, True);
3732
3733             --  Add the linking options specified on the
3734             --  command line.
3735
3736             for Arg in 1 .. Linker_Options.Last loop
3737                Add_Argument (Linker_Options.Table (Arg), True);
3738             end loop;
3739
3740             --  If there are shared libraries and the run path
3741             --  option is supported, add the run path switch.
3742
3743             if Lib_Path.Last > 0 then
3744                Add_Argument
3745                  (Path_Option.all &
3746                   String (Lib_Path.Table (1 .. Lib_Path.Last)),
3747                   Verbose_Mode);
3748             end if;
3749
3750             --  And invoke the linker
3751
3752             Display_Command (Linker_Name.all, Linker_Path);
3753             Spawn
3754               (Linker_Path.all,
3755                Arguments (1 .. Last_Argument),
3756                Success);
3757
3758             if not Success then
3759                Report_Error ("could not link ", Main);
3760             end if;
3761          end if;
3762       end Link_Foreign;
3763
3764    --  Start of processing of Link_Executables
3765
3766    begin
3767       --  If no mains specified, get mains from attribute Main, if it exists
3768
3769       if not Mains_Specified then
3770          declare
3771             Element_Id : String_List_Id;
3772             Element    : String_Element;
3773
3774          begin
3775             Element_Id := Data.Mains;
3776             while Element_Id /= Nil_String loop
3777                Element := Project_Tree.String_Elements.Table (Element_Id);
3778
3779                if Element.Value /= No_Name then
3780                   Mains.Add_Main (Get_Name_String (Element.Value));
3781                end if;
3782
3783                Element_Id := Element.Next;
3784             end loop;
3785          end;
3786       end if;
3787
3788       if Mains.Number_Of_Mains = 0 then
3789
3790          --  If the attribute Main is an empty list or not specified,
3791          --  there is nothing to do.
3792
3793          if Verbose_Mode then
3794             Write_Line ("No main to link");
3795          end if;
3796          return;
3797       end if;
3798
3799       --  Check if -o was used for several mains
3800
3801       if Output_File_Name /= null and then Mains.Number_Of_Mains > 1 then
3802          Osint.Fail ("cannot specify an executable name for several mains");
3803       end if;
3804
3805       --  Check how we are going to do the link
3806
3807       if not Data.Other_Sources_Present then
3808
3809          --  Only Ada sources in the main project, and even maybe not
3810
3811          if Data.Extends = No_Project and then
3812            not Data.Langs (Ada_Language_Index)
3813          then
3814             --  Fail if the main project has no source of any language
3815
3816             Osint.Fail
3817               ("project """,
3818                Get_Name_String (Data.Name),
3819                """ has no sources, so no main can be linked");
3820
3821          else
3822             --  Only Ada sources in the main project, call gnatmake directly
3823
3824             Last_Argument := 0;
3825
3826             --  Choose correct linker if there is C++ code in other projects
3827
3828             if C_Plus_Plus_Is_Used then
3829                Choose_C_Plus_Plus_Link_Process;
3830                Add_Argument (Dash_largs, Verbose_Mode);
3831                Add_C_Plus_Plus_Link_For_Gnatmake;
3832                Add_Argument (Dash_margs, Verbose_Mode);
3833             end if;
3834
3835             Compile_Link_With_Gnatmake (Mains_Specified);
3836          end if;
3837
3838       else
3839          --  There are other language sources. First check if there are also
3840          --  sources in Ada.
3841
3842          if Data.Langs (Ada_Language_Index) then
3843
3844             --  There is a mix of Ada and other language sources in the main
3845             --  project. Any main that is not a source of the other languages
3846             --  will be deemed to be an Ada main.
3847
3848             --  Find the mains of the other languages and the Ada mains
3849
3850             Mains.Reset;
3851             Ada_Mains.Set_Last (0);
3852             Other_Mains.Set_Last (0);
3853
3854             --  For each main
3855
3856             loop
3857                declare
3858                   Main    : constant String := Mains.Next_Main;
3859                   Main_Id : File_Name_Type;
3860
3861                begin
3862                   exit when Main'Length = 0;
3863
3864                   --  Get the main file name
3865
3866                   Name_Len := 0;
3867                   Add_Str_To_Name_Buffer (Main);
3868                   Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len));
3869                   Main_Id := Name_Find;
3870
3871                   --  Check if it is a source of a language other than Ada
3872
3873                   Source_Id := Data.First_Other_Source;
3874                   while Source_Id /= No_Other_Source loop
3875                      Source :=
3876                        Project_Tree.Other_Sources.Table (Source_Id);
3877                      exit when Source.File_Name = Main_Id;
3878                      Source_Id := Source.Next;
3879                   end loop;
3880
3881                   --  If it is not, put it in the list of Ada mains
3882
3883                   if Source_Id = No_Other_Source then
3884                      Ada_Mains.Increment_Last;
3885                      Ada_Mains.Table (Ada_Mains.Last) := new String'(Main);
3886
3887                   --  Otherwise, put it in the list of other mains
3888
3889                   else
3890                      Other_Mains.Increment_Last;
3891                      Other_Mains.Table (Other_Mains.Last) := Source;
3892                   end if;
3893                end;
3894             end loop;
3895
3896             --  If C++ is one of the other language, create the shell script
3897             --  to do the link.
3898
3899             if C_Plus_Plus_Is_Used then
3900                Choose_C_Plus_Plus_Link_Process;
3901             end if;
3902
3903             --  Call gnatmake with the necessary switches for each non-Ada
3904             --  main, if there are some.
3905
3906             for Main in 1 .. Other_Mains.Last loop
3907                declare
3908                   Source : constant Other_Source := Other_Mains.Table (Main);
3909
3910                begin
3911                   Last_Argument := 0;
3912
3913                   --  Add -o if -o was specified
3914
3915                   if Output_File_Name = null then
3916                      Add_Argument (Dash_o, True);
3917                      Add_Argument
3918                        (Get_Name_String
3919                           (Executable_Of
3920                              (Project  => Main_Project,
3921                               In_Tree  => Project_Tree,
3922                               Main     => Other_Mains.Table (Main).File_Name,
3923                               Index    => 0,
3924                               Ada_Main => False)),
3925                         True);
3926                   end if;
3927
3928                   --  Call gnatmake with the -B switch
3929
3930                   Add_Argument (Dash_B, True);
3931
3932                   --  Add to the linking options the object file of the source
3933
3934                   Add_Argument (Dash_largs, Verbose_Mode);
3935                   Add_Argument
3936                     (Get_Name_String (Source.Object_Name), Verbose_Mode);
3937
3938                   --  If C++ is one of the language, add the --LINK switch
3939                   --  to the linking switches.
3940
3941                   if C_Plus_Plus_Is_Used then
3942                      Add_C_Plus_Plus_Link_For_Gnatmake;
3943                   end if;
3944
3945                   --  Add -margs so that the following switches are for
3946                   --  gnatmake
3947
3948                   Add_Argument (Dash_margs, Verbose_Mode);
3949
3950                   --  And link with gnatmake
3951
3952                   Compile_Link_With_Gnatmake (Mains_Specified => False);
3953                end;
3954             end loop;
3955
3956             --  If there are also Ada mains, call gnatmake for all these mains
3957
3958             if Ada_Mains.Last /= 0 then
3959                Last_Argument := 0;
3960
3961                --  Put all the Ada mains as the first arguments
3962
3963                for Main in 1 .. Ada_Mains.Last loop
3964                   Add_Argument (Ada_Mains.Table (Main).all, True);
3965                end loop;
3966
3967                --  If C++ is one of the languages, add the --LINK switch to
3968                --  the linking switches.
3969
3970                if Data.Langs (C_Plus_Plus_Language_Index) then
3971                   Add_Argument (Dash_largs, Verbose_Mode);
3972                   Add_C_Plus_Plus_Link_For_Gnatmake;
3973                   Add_Argument (Dash_margs, Verbose_Mode);
3974                end if;
3975
3976                --  And link with gnatmake
3977
3978                Compile_Link_With_Gnatmake (Mains_Specified => False);
3979             end if;
3980
3981          else
3982             --  No Ada source in main project
3983
3984             --  First, get the linker to invoke
3985
3986             if Data.Langs (C_Plus_Plus_Language_Index) then
3987                Get_Compiler (C_Plus_Plus_Language_Index);
3988                Linker_Name := Compiler_Names (C_Plus_Plus_Language_Index);
3989                Linker_Path := Compiler_Paths (C_Plus_Plus_Language_Index);
3990
3991             else
3992                Get_Compiler (C_Language_Index);
3993                Linker_Name := Compiler_Names (C_Language_Index);
3994                Linker_Path := Compiler_Paths (C_Language_Index);
3995             end if;
3996
3997             Link_Done := False;
3998
3999             Mains.Reset;
4000
4001             --  Get each main, check if it is a source of the main project,
4002             --  and if it is, invoke the linker.
4003
4004             loop
4005                declare
4006                   Main    : constant String := Mains.Next_Main;
4007                   Main_Id : File_Name_Type;
4008
4009                begin
4010                   exit when Main'Length = 0;
4011
4012                   --  Get the file name of the main
4013
4014                   Name_Len := 0;
4015                   Add_Str_To_Name_Buffer (Main);
4016                   Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len));
4017                   Main_Id := Name_Find;
4018
4019                   --  Check if it is a source of the main project file
4020
4021                   Source_Id := Data.First_Other_Source;
4022                   while Source_Id /= No_Other_Source loop
4023                      Source :=
4024                        Project_Tree.Other_Sources.Table (Source_Id);
4025                      exit when Source.File_Name = Main_Id;
4026                      Source_Id := Source.Next;
4027                   end loop;
4028
4029                   --  Report an error if it is not
4030
4031                   if Source_Id = No_Other_Source then
4032                      Report_Error
4033                        (Main, "is not a source of project ",
4034                         Get_Name_String (Data.Name));
4035
4036                   else
4037                      Link_Foreign (Main, Main_Id, Source);
4038                   end if;
4039                end;
4040             end loop;
4041
4042             --  If no linking was done, report it, except in Quiet Output
4043
4044             if (Verbose_Mode or (not Quiet_Output)) and (not Link_Done) then
4045                Osint.Write_Program_Name;
4046
4047                if Mains.Number_Of_Mains = 1 then
4048
4049                   --  If there is only one executable, report its name too
4050
4051                   Write_Str (": """);
4052                   Mains.Reset;
4053
4054                   declare
4055                      Main    : constant String := Mains.Next_Main;
4056                      Main_Id : File_Name_Type;
4057                   begin
4058                      Name_Len := 0;
4059                      Add_Str_To_Name_Buffer (Main);
4060                      Main_Id := Name_Find;
4061                      Write_Str
4062                        (Get_Name_String
4063                           (Executable_Of
4064                              (Project  => Main_Project,
4065                               In_Tree  => Project_Tree,
4066                               Main     => Main_Id,
4067                               Index    => 0,
4068                               Ada_Main => False)));
4069                      Write_Line (""" up to date");
4070                   end;
4071
4072                else
4073                   Write_Line (": all executables up to date");
4074                end if;
4075             end if;
4076          end if;
4077       end if;
4078    end Link_Executables;
4079
4080    ------------------
4081    -- Report_Error --
4082    ------------------
4083
4084    procedure Report_Error
4085      (S1 : String;
4086       S2 : String := "";
4087       S3 : String := "")
4088    is
4089    begin
4090       --  If Keep_Going is True, output error message preceded by error header
4091
4092       if Keep_Going then
4093          Total_Number_Of_Errors := Total_Number_Of_Errors + 1;
4094          Write_Str (Error_Header);
4095          Write_Str (S1);
4096          Write_Str (S2);
4097          Write_Str (S3);
4098          Write_Eol;
4099
4100       --  Otherwise just fail
4101
4102       else
4103          Osint.Fail (S1, S2, S3);
4104       end if;
4105    end Report_Error;
4106
4107    -------------------------
4108    -- Report_Total_Errors --
4109    -------------------------
4110
4111    procedure Report_Total_Errors (Kind : String) is
4112    begin
4113       if Total_Number_Of_Errors /= 0 then
4114          if Total_Number_Of_Errors = 1 then
4115             Osint.Fail
4116               ("One ", Kind, " error");
4117
4118          else
4119             Osint.Fail
4120               ("Total of" & Total_Number_Of_Errors'Img,
4121                ' ' & Kind & " errors");
4122          end if;
4123       end if;
4124    end Report_Total_Errors;
4125
4126    --------------
4127    -- Scan_Arg --
4128    --------------
4129
4130    procedure Scan_Arg (Arg : String) is
4131    begin
4132       pragma Assert (Arg'First = 1);
4133
4134       if Arg'Length = 0 then
4135          return;
4136       end if;
4137
4138       --  If preceding switch was -P, a project file name need to be
4139       --  specified, not a switch.
4140
4141       if Project_File_Name_Expected then
4142          if Arg (1) = '-' then
4143             Osint.Fail ("project file name missing after -P");
4144          else
4145             Project_File_Name_Expected := False;
4146             Project_File_Name := new String'(Arg);
4147          end if;
4148
4149       --  If preceding switch was -o, an executable name need to be
4150       --  specified, not a switch.
4151
4152       elsif Output_File_Name_Expected then
4153          if Arg (1) = '-' then
4154             Osint.Fail ("output file name missing after -o");
4155          else
4156             Output_File_Name_Expected := False;
4157             Output_File_Name := new String'(Arg);
4158          end if;
4159
4160       --  Set the processor/language for the following switches
4161
4162       --  -cargs: Ada compiler arguments
4163
4164       elsif Arg = "-cargs" then
4165          Current_Language  := Ada_Language_Index;
4166          Current_Processor := Compiler;
4167
4168       elsif Arg'Length > 7 and then Arg (1 .. 7) = "-cargs:" then
4169          Name_Len := 0;
4170          Add_Str_To_Name_Buffer (Arg (8 .. Arg'Last));
4171          To_Lower (Name_Buffer (1 .. Name_Len));
4172
4173          declare
4174             Lang : constant Name_Id := Name_Find;
4175          begin
4176             Current_Language := Language_Indexes.Get (Lang);
4177
4178             if Current_Language = No_Language_Index then
4179                Add_Language_Name (Lang);
4180                Current_Language := Last_Language_Index;
4181             end if;
4182
4183             Current_Processor := Compiler;
4184          end;
4185
4186       elsif Arg = "-largs" then
4187          Current_Processor := Linker;
4188
4189       --  -gargs: gprmake
4190
4191       elsif Arg = "-gargs" then
4192          Current_Processor := None;
4193
4194       --  A special test is needed for the -o switch within a -largs since
4195       --  that is another way to specify the name of the final executable.
4196
4197       elsif Current_Processor = Linker and then Arg = "-o" then
4198          Osint.Fail
4199            ("switch -o not allowed within a -largs. Use -o directly.");
4200
4201       --  If current processor is not gprmake directly, store the option in
4202       --  the appropriate table.
4203
4204       elsif Current_Processor /= None then
4205          Add_Option (Arg);
4206
4207       --  Switches start with '-'
4208
4209       elsif Arg (1) = '-' then
4210          if Arg'Length > 3 and then Arg (1 .. 3) = "-aP" then
4211             Add_Search_Project_Directory (Arg (4 .. Arg'Last));
4212
4213             --  Record the switch, so that it is passed to gnatmake, if
4214             --  gnatmake is called.
4215
4216             Saved_Switches.Append (new String'(Arg));
4217
4218          elsif Arg = "-c" then
4219             Compile_Only := True;
4220
4221             --  Make sure that when a main is specified and switch -c is used,
4222             --  only the main(s) is/are compiled.
4223
4224             if Mains.Number_Of_Mains > 0 then
4225                Unique_Compile := True;
4226             end if;
4227
4228          elsif Arg = "-d" then
4229             Display_Compilation_Progress := True;
4230
4231          elsif Arg = "-f" then
4232             Force_Compilations := True;
4233
4234          elsif Arg = "-h" then
4235             Usage;
4236
4237          elsif Arg = "-k" then
4238             Keep_Going := True;
4239
4240          elsif Arg = "-o" then
4241             if Output_File_Name /= null then
4242                Osint.Fail ("cannot specify several -o switches");
4243
4244             else
4245                Output_File_Name_Expected := True;
4246             end if;
4247
4248          elsif Arg'Length >= 2 and then Arg (2) = 'P' then
4249             if Project_File_Name /= null then
4250                Osint.Fail ("cannot have several project files specified");
4251
4252             elsif Arg'Length = 2 then
4253                Project_File_Name_Expected := True;
4254
4255             else
4256                Project_File_Name := new String'(Arg (3 .. Arg'Last));
4257             end if;
4258
4259          elsif Arg = "-p" or else Arg = "--create-missing-dirs" then
4260             Setup_Projects := True;
4261
4262          elsif Arg = "-q" then
4263             Quiet_Output := True;
4264
4265          elsif Arg = "-u" then
4266             Unique_Compile := True;
4267             Compile_Only   := True;
4268
4269          elsif Arg = "-v" then
4270             Verbose_Mode := True;
4271             Copyright;
4272
4273          elsif Arg'Length = 4 and then Arg (1 .. 3) = "-vP"
4274            and then Arg (4) in '0' .. '2'
4275          then
4276             case Arg (4) is
4277                when '0' =>
4278                   Current_Verbosity := Prj.Default;
4279                when '1' =>
4280                   Current_Verbosity := Prj.Medium;
4281                when '2' =>
4282                   Current_Verbosity := Prj.High;
4283                when others =>
4284                   null;
4285             end case;
4286
4287          elsif Arg'Length >= 3 and then Arg (2) = 'X'
4288            and then Is_External_Assignment (Arg)
4289          then
4290             --  Is_External_Assignment has side effects when it returns True
4291
4292             --  Record the -X switch, so that it will be passed to gnatmake,
4293             --  if gnatmake is called.
4294
4295             Saved_Switches.Append (new String'(Arg));
4296
4297          else
4298             Osint.Fail ("illegal option """, Arg, """");
4299          end if;
4300
4301       else
4302          --  Not a switch: must be a main
4303
4304          Mains.Add_Main (Arg);
4305
4306          --  Make sure that when a main is specified and switch -c is used,
4307          --  only the main(s) is/are compiled.
4308
4309          if Compile_Only then
4310             Unique_Compile := True;
4311          end if;
4312       end if;
4313    end Scan_Arg;
4314
4315    -----------------
4316    -- Strip_CR_LF --
4317    -----------------
4318
4319    function Strip_CR_LF (Text : String) return String is
4320       To       : String (1 .. Text'Length);
4321       Index_To : Natural := 0;
4322
4323    begin
4324       for Index in Text'Range loop
4325          if (Text (Index) /= ASCII.CR) and then (Text (Index) /= ASCII.LF) then
4326             Index_To := Index_To + 1;
4327             To (Index_To) := Text (Index);
4328          end if;
4329       end loop;
4330
4331       return To (1 .. Index_To);
4332    end Strip_CR_LF;
4333
4334    -----------
4335    -- Usage --
4336    -----------
4337
4338    procedure Usage is
4339    begin
4340       if not Usage_Output then
4341          Usage_Output := True;
4342          Copyright;
4343
4344          Write_Str ("Usage: ");
4345          Osint.Write_Program_Name;
4346          Write_Str (" -P<project file> [opts]  [name] {");
4347          Write_Str ("[-cargs:lang opts] ");
4348          Write_Str ("[-largs opts] [-gargs opts]}");
4349          Write_Eol;
4350          Write_Eol;
4351          Write_Str ("  name is zero or more file names");
4352          Write_Eol;
4353          Write_Eol;
4354
4355          --  GPRMAKE switches
4356
4357          Write_Str ("gprmake switches:");
4358          Write_Eol;
4359
4360          --  Line for -aP
4361
4362          Write_Str ("  -aPdir   Add directory dir to project search path");
4363          Write_Eol;
4364
4365          --  Line for -c
4366
4367          Write_Str ("  -c       Compile only");
4368          Write_Eol;
4369
4370          --  Line for -f
4371
4372          Write_Str ("  -f       Force recompilations");
4373          Write_Eol;
4374
4375          --  Line for -k
4376
4377          Write_Str ("  -k       Keep going after compilation errors");
4378          Write_Eol;
4379
4380          --  Line for -o
4381
4382          Write_Str ("  -o name  Choose an alternate executable name");
4383          Write_Eol;
4384
4385          --  Line for -p
4386
4387          Write_Str ("  -p       Create missing obj, lib and exec dirs");
4388          Write_Eol;
4389
4390          --  Line for -P
4391
4392          Write_Str ("  -Pproj   Use GNAT Project File proj");
4393          Write_Eol;
4394
4395          --  Line for -q
4396
4397          Write_Str ("  -q       Be quiet/terse");
4398          Write_Eol;
4399
4400          --  Line for -u
4401
4402          Write_Str
4403            ("  -u       Unique compilation. Only compile the given files");
4404          Write_Eol;
4405
4406          --  Line for -v
4407
4408          Write_Str ("  -v       Verbose output");
4409          Write_Eol;
4410
4411          --  Line for -vPx
4412
4413          Write_Str ("  -vPx     Specify verbosity when parsing Project Files");
4414          Write_Eol;
4415
4416          --  Line for -X
4417
4418          Write_Str ("  -Xnm=val Specify an external reference for " &
4419                     "Project Files");
4420          Write_Eol;
4421          Write_Eol;
4422
4423          --  Line for -cargs
4424
4425          Write_Line ("  -cargs opts     opts are passed to the Ada compiler");
4426
4427          --  Line for -cargs:lang
4428
4429          Write_Line ("  -cargs:<lang> opts");
4430          Write_Line ("     opts are passed to the compiler " &
4431                      "for language < lang > ");
4432
4433          --  Line for -largs
4434
4435          Write_Str ("  -largs opts    opts are passed to the linker");
4436          Write_Eol;
4437
4438          --  Line for -gargs
4439
4440          Write_Str ("  -gargs opts    opts directly interpreted by gprmake");
4441          Write_Eol;
4442          Write_Eol;
4443
4444       end if;
4445    end Usage;
4446
4447 begin
4448    Makeutl.Do_Fail := Report_Error'Access;
4449 end Makegpr;