OSDN Git Service

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