Ignore -ansi -pedantic-errors option coming from dejagnu.
[official-gcc.git] / gcc / ada / makegpr.adb
blob6b51b3286395d939e80cd7982c456fb9dd0f0eeb
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 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, 59 Temple Place - Suite 330, Boston, --
20 -- MA 02111-1307, 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 ------------------------------------------------------------------------------
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;
32 with Csets;
33 with Gnatvsn;
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;
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.Com; use Prj.Com;
50 with Prj.Pars;
51 with Prj.Util; use Prj.Util;
52 with Snames; use Snames;
53 with System;
54 with System.Case_Util; use System.Case_Util;
55 with Table;
56 with Types; use Types;
58 package body Makegpr is
60 Max_In_Archives : constant := 50;
61 -- The maximum number of arguments for a single invocation of the
62 -- Archive Indexer (ar).
64 Cpp_Linker : constant String := "c++linker";
65 -- The name of a linking script, built one the fly, when there are C++
66 -- sources and the C++ compiler is not g++.
68 No_Argument : constant Argument_List := (1 .. 0 => null);
69 -- Null argument list representing case of no arguments
71 FD : Process_Descriptor;
72 -- The process descriptor used when invoking a non GNU compiler with -M
73 -- and getting the output with GNAT.Expect.
75 Line_Matcher : constant Pattern_Matcher := Compile ("^.*?\n", Single_Line);
76 -- Pattern for GNAT.Expect for the invocation of a non GNU compiler with -M
78 Name_Ide : Name_Id;
79 Name_Compiler_Command : Name_Id;
80 -- Names of package IDE and its attribute Compiler_Command.
81 -- Set up by Initialize.
83 Unique_Compile : Boolean := False;
84 -- True when switch -u is used on the command line
86 type Source_Index_Rec is record
87 Project : Project_Id;
88 Id : Other_Source_Id;
89 Found : Boolean := False;
90 end record;
91 -- Used as Source_Indexes component to check if archive needs to be rebuilt
93 type Source_Index_Array is array (Positive range <>) of Source_Index_Rec;
94 type Source_Indexes_Ref is access Source_Index_Array;
96 procedure Free is new Ada.Unchecked_Deallocation
97 (Source_Index_Array, Source_Indexes_Ref);
99 Initial_Source_Index_Count : constant Positive := 20;
100 Source_Indexes : Source_Indexes_Ref :=
101 new Source_Index_Array (1 .. Initial_Source_Index_Count);
102 -- A list of the Other_Source_Ids of a project file, with an indication
103 -- that they have been found in the archive dependency file.
105 Last_Source : Natural := 0;
106 -- The index of the last valid component of Source_Indexes
108 Compiler_Names : array (Programming_Language) of String_Access;
109 -- The names of the compilers to be used. Set up by Get_Compiler.
110 -- Used to display the commands spawned.
112 Compiler_Paths : array (Programming_Language) of String_Access;
113 -- The path names of the compiler to be used. Set up by Get_Compiler.
114 -- Used to spawn compiling/linking processes.
116 Compiler_Is_Gcc : array (Programming_Language) of Boolean;
117 -- An indication that a compiler is a GCC compiler, to be able to use
118 -- specific GCC switches.
120 Archive_Builder_Path : String_Access := null;
121 -- The path name of the archive builder (ar). To be used when spawning
122 -- ar commands.
124 Archive_Indexer_Path : String_Access := null;
125 -- The path name of the archive indexer (ranlib), if it exists.
127 Copyright_Output : Boolean := False;
128 Usage_Output : Boolean := False;
129 -- Flags to avoid multiple displays of Copyright notice and of Usage
131 Output_File_Name : String_Access := null;
132 -- The name given after a switch -o
134 Output_File_Name_Expected : Boolean := False;
135 -- True when last switch was -o
137 Project_File_Name : String_Access := null;
138 -- The name of the project file specified with switch -P
140 Project_File_Name_Expected : Boolean := False;
141 -- True when last switch was -P
143 Naming_String : aliased String := "naming";
144 Builder_String : aliased String := "builder";
145 Compiler_String : aliased String := "compiler";
146 Binder_String : aliased String := "binder";
147 Linker_String : aliased String := "linker";
148 -- Name of packages to be checked when parsing/processing project files
150 List_Of_Packages : aliased String_List :=
151 (Naming_String 'Access,
152 Builder_String 'Access,
153 Compiler_String 'Access,
154 Binder_String 'Access,
155 Linker_String 'Access);
156 Packages_To_Check : constant String_List_Access := List_Of_Packages'Access;
157 -- List of the packages to be checked when parsing/processing project files
159 Main_Project : Project_Id;
160 -- The project id of the main project
162 type Processor is (None, Linker, Compiler);
163 Current_Processor : Processor := None;
164 -- This variable changes when switches -*args are used
166 Current_Language : Programming_Language := Lang_Ada;
167 -- The compiler language to consider when Processor is Compiler
169 package Comp_Opts is new GNAT.Dynamic_Tables
170 (Table_Component_Type => String_Access,
171 Table_Index_Type => Integer,
172 Table_Low_Bound => 1,
173 Table_Initial => 20,
174 Table_Increment => 100);
175 Options : array (Programming_Language) of Comp_Opts.Instance;
176 -- Tables to store compiling options for the different compilers
178 package Linker_Options is new Table.Table
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 Table_Name => "Makegpr.Linker_Options");
185 -- Table to store the linking options
187 package Ada_Mains 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.Ada_Mains");
194 -- Table to store the Ada mains, either specified on the command line
195 -- or found in attribute Main of the main project file.
197 package Other_Mains is new Table.Table
198 (Table_Component_Type => Other_Source,
199 Table_Index_Type => Integer,
200 Table_Low_Bound => 1,
201 Table_Initial => 20,
202 Table_Increment => 100,
203 Table_Name => "Makegpr.Other_Mains");
204 -- Table to store the mains of languages other than Ada, either specified
205 -- on the command line or found in attribute Main of the main project file.
207 package Sources_Compiled is new GNAT.HTable.Simple_HTable
208 (Header_Num => Header_Num,
209 Element => Boolean,
210 No_Element => False,
211 Key => Name_Id,
212 Hash => Hash,
213 Equal => "=");
215 package X_Switches is new Table.Table
216 (Table_Component_Type => String_Access,
217 Table_Index_Type => Integer,
218 Table_Low_Bound => 1,
219 Table_Initial => 2,
220 Table_Increment => 100,
221 Table_Name => "Makegpr.X_Switches");
222 -- Table to store the -X switches to be passed to gnatmake
224 Initial_Argument_Count : constant Positive := 20;
225 type Boolean_Array is array (Positive range <>) of Boolean;
226 type Booleans is access Boolean_Array;
228 procedure Free is new Ada.Unchecked_Deallocation (Boolean_Array, Booleans);
230 Arguments : Argument_List_Access :=
231 new Argument_List (1 .. Initial_Argument_Count);
232 -- Used to store lists of arguments to be used when spawning a process
234 Arguments_Displayed : Booleans :=
235 new Boolean_Array (1 .. Initial_Argument_Count);
236 -- For each argument in Arguments, indicate if the argument should be
237 -- displayed when procedure Display_Command is called.
239 Last_Argument : Natural := 0;
240 -- Index of the last valid argument in Arguments
242 package Cache_Args is new Table.Table
243 (Table_Component_Type => String_Access,
244 Table_Index_Type => Integer,
245 Table_Low_Bound => 1,
246 Table_Initial => 200,
247 Table_Increment => 50,
248 Table_Name => "Makegpr.Cache_Args");
249 -- A table to cache arguments, to avoid multiple allocation of the same
250 -- strings. It is not possible to use a hash table, because String is
251 -- an unconstrained type.
253 -- Various switches used when spawning processes:
255 Dash_B_String : aliased String := "-B";
256 Dash_B : constant String_Access := Dash_B_String'Access;
257 Dash_c_String : aliased String := "-c";
258 Dash_c : constant String_Access := Dash_c_String'Access;
259 Dash_cargs_String : aliased String := "-cargs";
260 Dash_cargs : constant String_Access := Dash_cargs_String'Access;
261 Dash_f_String : aliased String := "-f";
262 Dash_f : constant String_Access := Dash_f_String'Access;
263 Dash_k_String : aliased String := "-k";
264 Dash_k : constant String_Access := Dash_k_String'Access;
265 Dash_largs_String : aliased String := "-largs";
266 Dash_largs : constant String_Access := Dash_largs_String'Access;
267 Dash_M_String : aliased String := "-M";
268 Dash_M : constant String_Access := Dash_M_String'Access;
269 Dash_margs_String : aliased String := "-margs";
270 Dash_margs : constant String_Access := Dash_margs_String'Access;
271 Dash_o_String : aliased String := "-o";
272 Dash_o : constant String_Access := Dash_o_String'Access;
273 Dash_P_String : aliased String := "-P";
274 Dash_P : constant String_Access := Dash_P_String'Access;
275 Dash_q_String : aliased String := "-q";
276 Dash_q : constant String_Access := Dash_q_String'Access;
277 Dash_u_String : aliased String := "-u";
278 Dash_u : constant String_Access := Dash_u_String'Access;
279 Dash_v_String : aliased String := "-v";
280 Dash_v : constant String_Access := Dash_v_String'Access;
281 Dash_vP1_String : aliased String := "-vP1";
282 Dash_vP1 : constant String_Access := Dash_vP1_String'Access;
283 Dash_vP2_String : aliased String := "-vP2";
284 Dash_vP2 : constant String_Access := Dash_vP2_String'Access;
285 Dash_x_String : aliased String := "-x";
286 Dash_x : constant String_Access := Dash_x_String'Access;
287 r_String : aliased String := "r";
288 r : constant String_Access := r_String'Access;
290 CPATH : constant String := "CPATH";
291 -- The environment variable to set when compiler is a GCC compiler
292 -- to indicate the include directory path.
294 Current_Include_Paths : array (Programming_Language) of String_Access;
295 -- A cache for the paths of included directories, to avoid setting
296 -- env var CPATH unnecessarily.
298 C_Plus_Plus_Is_Used : Boolean := False;
299 -- True when there are sources in C++
301 Link_Options_Switches : Argument_List_Access := null;
302 -- The link options coming from the attributes Linker'Linker_Options in
303 -- project files imported, directly or indirectly, by the main project.
305 Total_Number_Of_Errors : Natural := 0;
306 -- Used when Keep_Going is True (switch -k) to keep the total number
307 -- of compilation/linking errors, to report at the end of execution.
309 Need_To_Rebuild_Global_Archive : Boolean := False;
311 Error_Header : constant String := "*** ERROR: ";
312 -- The beginning of error message, when Keep_Going is True
314 Need_To_Relink : Boolean := False;
315 -- True when an executable of a language other than Ada need to be linked
317 Global_Archive_Exists : Boolean := False;
318 -- True if there is a non empty global archive, to prevent creation
319 -- of such archives.
321 Path_Option : String_Access;
322 -- The path option switch, when supported
324 package Lib_Path is new Table.Table
325 (Table_Component_Type => Character,
326 Table_Index_Type => Integer,
327 Table_Low_Bound => 1,
328 Table_Initial => 200,
329 Table_Increment => 50,
330 Table_Name => "Makegpr.Lib_Path");
331 -- A table to compute the path to put in the path option switch, when it
332 -- is supported.
334 procedure Add_Archives (For_Gnatmake : Boolean);
335 -- Add to Arguments the list of archives for linking an executable
337 procedure Add_Argument (Arg : String_Access; Display : Boolean);
338 procedure Add_Argument (Arg : String; Display : Boolean);
339 -- Add an argument to Arguments. Reallocate if necessary.
341 procedure Add_Arguments (Args : Argument_List; Display : Boolean);
342 -- Add a list of arguments to Arguments. Reallocate if necessary
344 procedure Add_Option (Arg : String);
345 -- Add a switch for the Ada, C or C++ compiler, or for the linker.
346 -- The table where this option is stored depends on the values of
347 -- Current_Processor and Current_Language.
349 procedure Add_Search_Directories
350 (Data : Project_Data;
351 Language : Programming_Language);
352 -- Either add to the Arguments the necessary -I switches needed to
353 -- compile, or, when compiler is gcc/g++, set up the C*INCLUDE_PATH
354 -- environment variable, if necessary.
356 procedure Add_Source_Id (Project : Project_Id; Id : Other_Source_Id);
357 -- Add a source id to Source_Indexes, with Found set to False
359 procedure Add_Switches
360 (Data : Project_Data;
361 Proc : Processor;
362 Language : Other_Programming_Language;
363 File_Name : Name_Id);
364 -- Add to Arguments the switches, if any, for a source (attribute Switches)
365 -- or language (attribute Default_Switches), coming from package Compiler
366 -- or Linker (depending on Proc) of a specified project file.
368 procedure Build_Global_Archive;
369 -- Build the archive for the main project
371 procedure Build_Library (Project : Project_Id; Unconditionally : Boolean);
372 -- Build the library for a library project. If Unconditionally is
373 -- False, first check if the library is up to date, and build it only
374 -- if it is not.
376 procedure Check (Option : String);
377 -- Check that a switch coming from a project file is not the concatenation
378 -- of several valid switch, for example "-g -v". If it is, issue a warning.
380 procedure Check_Archive_Builder;
381 -- Check if the archive builder (ar) is there
383 procedure Check_Compilation_Needed
384 (Source : Other_Source;
385 Need_To_Compile : out Boolean);
386 -- Check if a source of a language other than Ada needs to be compiled or
387 -- recompiled.
389 procedure Check_For_C_Plus_Plus;
390 -- Check if C++ is used in at least one project
392 procedure Compile
393 (Source_Id : Other_Source_Id;
394 Data : Project_Data;
395 Local_Errors : in out Boolean);
396 -- Compile one non-Ada source
398 procedure Compile_Individual_Sources;
399 -- Compile the sources specified on the command line, when in
400 -- Unique_Compile mode.
402 procedure Compile_Link_With_Gnatmake (Mains_Specified : Boolean);
403 -- Compile/Link with gnatmake when there are Ada sources in the main
404 -- project. Arguments may already contain options to be used by
405 -- gnatmake. Used for both Ada mains and mains of other languages.
406 -- When Compile_Only is True, do not use the linking options
408 procedure Compile_Sources;
409 -- Compile the sources of languages other than Ada, if necessary
411 procedure Copyright;
412 -- Output the Copyright notice
414 procedure Create_Archive_Dependency_File
415 (Name : String;
416 First_Source : Other_Source_Id);
417 -- Create the archive dependency file for a library project
419 procedure Create_Global_Archive_Dependency_File (Name : String);
420 -- Create the archive depenency file for the main project
422 procedure Display_Command
423 (Name : String;
424 Path : String_Access;
425 CPATH : String_Access := null);
426 -- Display the command for a spawned process, if in Verbose_Mode or
427 -- not in Quiet_Output.
429 procedure Get_Compiler (For_Language : Programming_Language);
430 -- Find the compiler name and path name for a specified programming
431 -- language, if not already done. Results are in the corresponding
432 -- elements of arrays Compiler_Names and Compiler_Paths. Name of compiler
433 -- is found in package IDE of the main project, or defaulted.
434 -- Fail if compiler cannot be found on the path. For the Ada language,
435 -- gnatmake, rather than the Ada compiler is returned.
437 procedure Get_Imported_Directories
438 (Project : Project_Id;
439 Data : in out Project_Data);
440 -- Find the necessary switches -I to be used when compiling sources
441 -- of languages other than Ada, in a specified project file. Cache the
442 -- result in component Imported_Directories_Switches of the project data.
443 -- For gcc/g++ compilers, get the value of the C*_INCLUDE_PATH, instead.
445 procedure Initialize;
446 -- Do the necessary package initialization and process the command line
447 -- arguments.
449 function Is_Included_In_Global_Archive
450 (Object_Name : Name_Id;
451 Project : Project_Id) return Boolean;
452 -- Return True if the object Object_Name is not overridden by a source
453 -- in a project extending project Project.
455 procedure Link_Executables;
456 -- Link executables
458 procedure Report_Error (S1 : String; S2 : String := ""; S3 : String := "");
459 -- Report an error. If Keep_Going is False, just call Osint.Fail.
460 -- If Keep_Going is True, display the error and increase the total number
461 -- of errors.
463 procedure Report_Total_Errors (Kind : String);
464 -- If Total_Number_Of_Errors is not zero, report it, and fail
466 procedure Scan_Arg (Arg : String);
467 -- Process one command line argument
469 function Strip_CR_LF (Text : String) return String;
470 -- Remove characters ASCII.CR and ASCII.LF from a String
472 procedure Usage;
473 -- Display the usage
475 ------------------
476 -- Add_Archives --
477 ------------------
479 procedure Add_Archives (For_Gnatmake : Boolean) is
480 Last_Arg : constant Natural := Last_Argument;
481 -- The position of the last argument before adding the archives.
482 -- Used to reverse the order of the arguments added when processing
483 -- the archives.
485 procedure Recursive_Add_Archives (Project : Project_Id);
486 -- Recursive procedure to add the archive of a project file, if any,
487 -- then call itself for the project imported.
489 ----------------------------
490 -- Recursive_Add_Archives --
491 ----------------------------
493 procedure Recursive_Add_Archives (Project : Project_Id) is
494 Data : Project_Data;
495 Imported : Project_List;
496 Prj : Project_Id;
498 procedure Add_Archive_Path;
499 -- For a library project or the main project, add the archive
500 -- path to the arguments.
502 ----------------------
503 -- Add_Archive_Path --
504 ----------------------
506 procedure Add_Archive_Path is
507 Increment : Positive;
508 Prev_Last : Positive;
510 begin
511 if Data.Library then
513 -- If it is a library project file, nothing to do if
514 -- gnatmake will be invoked, because gnatmake will take
515 -- care of it, even if the library is not an Ada library.
517 if not For_Gnatmake then
518 if Data.Library_Kind = Static then
519 Add_Argument
520 (Get_Name_String (Data.Library_Dir) &
521 Directory_Separator &
522 "lib" & Get_Name_String (Data.Library_Name) &
523 '.' & Archive_Ext,
524 Verbose_Mode);
526 else
527 -- As we first insert in the reverse order,
528 -- -L<dir> is put after -l<lib>
530 Add_Argument
531 ("-l" & Get_Name_String (Data.Library_Name),
532 Verbose_Mode);
534 Get_Name_String (Data.Library_Dir);
536 Add_Argument
537 ("-L" & Name_Buffer (1 .. Name_Len),
538 Verbose_Mode);
540 -- If there is a run path option, prepend this
541 -- directory to the library path. It is probable
542 -- that the order of the directories in the path
543 -- option is not important, but just in case
544 -- put the directories in the same order as the
545 -- libraries.
547 if Path_Option /= null then
549 -- If it is not the first directory, make room
550 -- at the beginning of the table, including
551 -- for a path separator.
553 if Lib_Path.Last > 0 then
554 Increment := Name_Len + 1;
555 Prev_Last := Lib_Path.Last;
556 Lib_Path.Set_Last (Prev_Last + Increment);
558 for Index in reverse 1 .. Prev_Last loop
559 Lib_Path.Table (Index + Increment) :=
560 Lib_Path.Table (Index);
561 end loop;
563 Lib_Path.Table (Increment) := Path_Separator;
565 else
566 -- If it is the first directory, just set
567 -- Last to the length of the directory.
569 Lib_Path.Set_Last (Name_Len);
570 end if;
572 -- Put the directory at the beginning of the
573 -- table.
575 for Index in 1 .. Name_Len loop
576 Lib_Path.Table (Index) := Name_Buffer (Index);
577 end loop;
578 end if;
579 end if;
580 end if;
582 -- For a non-library project, the only archive needed
583 -- is the one for the main project, if there is one.
585 elsif Project = Main_Project and then Global_Archive_Exists then
586 Add_Argument
587 (Get_Name_String (Data.Object_Directory) &
588 Directory_Separator &
589 "lib" & Get_Name_String (Data.Name) &
590 '.' & Archive_Ext,
591 Verbose_Mode);
592 end if;
593 end Add_Archive_Path;
595 begin
596 -- Nothing to do when there is no project specified
598 if Project /= No_Project then
599 Data := Projects.Table (Project);
601 -- Nothing to do if the project has already been processed
603 if not Data.Seen then
605 -- Mark the project as processed, to avoid processing it again
607 Projects.Table (Project).Seen := True;
609 Recursive_Add_Archives (Data.Extends);
611 Imported := Data.Imported_Projects;
613 -- Call itself recursively for all imported projects
615 while Imported /= Empty_Project_List loop
616 Prj := Project_Lists.Table (Imported).Project;
618 if Prj /= No_Project then
619 while Projects.Table (Prj).Extended_By /= No_Project loop
620 Prj := Projects.Table (Prj).Extended_By;
621 end loop;
623 Recursive_Add_Archives (Prj);
624 end if;
626 Imported := Project_Lists.Table (Imported).Next;
627 end loop;
629 -- If there is sources of language other than Ada in this
630 -- project, add the path of the archive to Arguments.
632 if Project = Main_Project
633 or else Data.Other_Sources_Present
634 then
635 Add_Archive_Path;
636 end if;
637 end if;
638 end if;
639 end Recursive_Add_Archives;
641 -- Start of processing for Add_Archives
643 begin
644 -- First, mark all projects as not processed
646 for Project in 1 .. Projects.Last loop
647 Projects.Table (Project).Seen := False;
648 end loop;
650 -- Take care of the run path option
652 if Path_Option = null then
653 Path_Option := MLib.Linker_Library_Path_Option;
654 end if;
656 Lib_Path.Set_Last (0);
658 -- Add archives in the reverse order
660 Recursive_Add_Archives (Main_Project);
662 -- And reverse the order
664 declare
665 First : Positive := Last_Arg + 1;
666 Last : Natural := Last_Argument;
667 Temp : String_Access;
669 begin
670 while First < Last loop
671 Temp := Arguments (First);
672 Arguments (First) := Arguments (Last);
673 Arguments (Last) := Temp;
674 First := First + 1;
675 Last := Last - 1;
676 end loop;
677 end;
678 end Add_Archives;
680 ------------------
681 -- Add_Argument --
682 ------------------
684 procedure Add_Argument (Arg : String_Access; Display : Boolean) is
685 begin
686 -- Nothing to do if no argument is specified or if argument is empty
688 if Arg /= null or else Arg'Length = 0 then
690 -- Reallocate arrays if necessary
692 if Last_Argument = Arguments'Last then
693 declare
694 New_Arguments : constant Argument_List_Access :=
695 new Argument_List
696 (1 .. Last_Argument +
697 Initial_Argument_Count);
699 New_Arguments_Displayed : constant Booleans :=
700 new Boolean_Array
701 (1 .. Last_Argument +
702 Initial_Argument_Count);
704 begin
705 New_Arguments (Arguments'Range) := Arguments.all;
707 -- To avoid deallocating the strings, nullify all components
708 -- of Arguments before calling Free.
710 Arguments.all := (others => null);
712 Free (Arguments);
713 Arguments := New_Arguments;
715 New_Arguments_Displayed (Arguments_Displayed'Range) :=
716 Arguments_Displayed.all;
717 Free (Arguments_Displayed);
718 Arguments_Displayed := New_Arguments_Displayed;
719 end;
720 end if;
722 -- Add the argument and its display indication
724 Last_Argument := Last_Argument + 1;
725 Arguments (Last_Argument) := Arg;
726 Arguments_Displayed (Last_Argument) := Display;
727 end if;
728 end Add_Argument;
730 procedure Add_Argument (Arg : String; Display : Boolean) is
731 Argument : String_Access := null;
733 begin
734 -- Nothing to do if argument is empty
736 if Arg'Length > 0 then
737 -- Check if the argument is already in the Cache_Args table.
738 -- If it is already there, reuse the allocated value.
740 for Index in 1 .. Cache_Args.Last loop
741 if Cache_Args.Table (Index).all = Arg then
742 Argument := Cache_Args.Table (Index);
743 exit;
744 end if;
745 end loop;
747 -- If the argument is not in the cache, create a new entry in the
748 -- cache.
750 if Argument = null then
751 Argument := new String'(Arg);
752 Cache_Args.Increment_Last;
753 Cache_Args.Table (Cache_Args.Last) := Argument;
754 end if;
756 -- And add the argument
758 Add_Argument (Argument, Display);
759 end if;
760 end Add_Argument;
762 -------------------
763 -- Add_Arguments --
764 -------------------
766 procedure Add_Arguments (Args : Argument_List; Display : Boolean) is
767 begin
768 -- Reallocate the arrays, if necessary
770 if Last_Argument + Args'Length > Arguments'Last then
771 declare
772 New_Arguments : constant Argument_List_Access :=
773 new Argument_List
774 (1 .. Last_Argument + Args'Length +
775 Initial_Argument_Count);
777 New_Arguments_Displayed : constant Booleans :=
778 new Boolean_Array
779 (1 .. Last_Argument +
780 Args'Length +
781 Initial_Argument_Count);
783 begin
784 New_Arguments (1 .. Last_Argument) :=
785 Arguments (1 .. Last_Argument);
787 -- To avoid deallocating the strings, nullify all components
788 -- of Arguments before calling Free.
790 Arguments.all := (others => null);
791 Free (Arguments);
793 Arguments := New_Arguments;
794 New_Arguments_Displayed (1 .. Last_Argument) :=
795 Arguments_Displayed (1 .. Last_Argument);
796 Free (Arguments_Displayed);
797 Arguments_Displayed := New_Arguments_Displayed;
798 end;
799 end if;
801 -- Add the new arguments and the display indications
803 Arguments (Last_Argument + 1 .. Last_Argument + Args'Length) := Args;
804 Arguments_Displayed (Last_Argument + 1 .. Last_Argument + Args'Length) :=
805 (others => Display);
806 Last_Argument := Last_Argument + Args'Length;
807 end Add_Arguments;
809 ----------------
810 -- Add_Option --
811 ----------------
813 procedure Add_Option (Arg : String) is
814 Option : constant String_Access := new String'(Arg);
816 begin
817 case Current_Processor is
818 when None =>
819 null;
821 when Linker =>
823 -- Add option to the linker table
825 Linker_Options.Increment_Last;
826 Linker_Options.Table (Linker_Options.Last) := Option;
828 when Compiler =>
830 -- Add option to the compiler option table, depending on the
831 -- value of Current_Language.
833 Comp_Opts.Increment_Last (Options (Current_Language));
834 Options (Current_Language).Table
835 (Comp_Opts.Last (Options (Current_Language))) := Option;
837 end case;
838 end Add_Option;
840 -------------------
841 -- Add_Source_Id --
842 -------------------
844 procedure Add_Source_Id (Project : Project_Id; Id : Other_Source_Id) is
845 begin
846 -- Reallocate the array, if necessary
848 if Last_Source = Source_Indexes'Last then
849 declare
850 New_Indexes : constant Source_Indexes_Ref :=
851 new Source_Index_Array
852 (1 .. Source_Indexes'Last +
853 Initial_Source_Index_Count);
854 begin
855 New_Indexes (Source_Indexes'Range) := Source_Indexes.all;
856 Free (Source_Indexes);
857 Source_Indexes := New_Indexes;
858 end;
859 end if;
861 Last_Source := Last_Source + 1;
862 Source_Indexes (Last_Source) := (Project, Id, False);
863 end Add_Source_Id;
865 ----------------------------
866 -- Add_Search_Directories --
867 ----------------------------
869 procedure Add_Search_Directories
870 (Data : Project_Data;
871 Language : Programming_Language)
873 begin
874 -- If a GNU compiler is used, set the CPATH environment variable,
875 -- if it does not already has the correct value.
877 if Compiler_Is_Gcc (Language) then
878 if Current_Include_Paths (Language) /= Data.Include_Path then
879 Current_Include_Paths (Language) := Data.Include_Path;
880 Setenv (CPATH, Data.Include_Path.all);
881 end if;
883 else
884 Add_Arguments (Data.Imported_Directories_Switches.all, Verbose_Mode);
885 end if;
886 end Add_Search_Directories;
888 ------------------
889 -- Add_Switches --
890 ------------------
892 procedure Add_Switches
893 (Data : Project_Data;
894 Proc : Processor;
895 Language : Other_Programming_Language;
896 File_Name : Name_Id)
898 Switches : Variable_Value;
899 -- The switches, if any, for the file/language
901 Pkg : Package_Id;
902 -- The id of the package where to look for the switches
904 Defaults : Array_Element_Id;
905 -- The Default_Switches associative array
907 Switches_Array : Array_Element_Id;
908 -- The Switches associative array
910 Element_Id : String_List_Id;
911 Element : String_Element;
913 begin
914 -- First, choose the proper package
916 case Proc is
917 when None =>
918 raise Program_Error;
920 when Linker =>
921 Pkg := Value_Of (Name_Linker, Data.Decl.Packages);
923 when Compiler =>
924 Pkg := Value_Of (Name_Compiler, Data.Decl.Packages);
925 end case;
927 -- Get the Switches ("file name"), if they exist
929 Switches_Array := Prj.Util.Value_Of
930 (Name => Name_Switches,
931 In_Arrays =>
932 Packages.Table (Pkg).Decl.Arrays);
934 Switches :=
935 Prj.Util.Value_Of
936 (Index => File_Name,
937 Src_Index => 0,
938 In_Array => Switches_Array);
940 -- Otherwise, get the Default_Switches ("language"), if they exist
942 if Switches = Nil_Variable_Value then
943 Defaults := Prj.Util.Value_Of
944 (Name => Name_Default_Switches,
945 In_Arrays => Packages.Table (Pkg).Decl.Arrays);
946 Switches := Prj.Util.Value_Of
947 (Index => Lang_Name_Ids (Language),
948 Src_Index => 0,
949 In_Array => Defaults);
950 end if;
952 -- If there are switches, add them to Arguments
954 if Switches /= Nil_Variable_Value then
955 Element_Id := Switches.Values;
956 while Element_Id /= Nil_String loop
957 Element := String_Elements.Table (Element_Id);
959 if Element.Value /= No_Name then
960 Get_Name_String (Element.Value);
962 if not Quiet_Output then
964 -- When not in quiet output (no -q), check that the switch
965 -- is not the concatenation of several valid switches,
966 -- such as "-g -v". If it is, issue a warning.
968 Check (Option => Name_Buffer (1 .. Name_Len));
969 end if;
971 Add_Argument (Name_Buffer (1 .. Name_Len), True);
972 end if;
974 Element_Id := Element.Next;
975 end loop;
976 end if;
977 end Add_Switches;
979 --------------------------
980 -- Build_Global_Archive --
981 --------------------------
983 procedure Build_Global_Archive is
984 Data : Project_Data := Projects.Table (Main_Project);
985 Source_Id : Other_Source_Id;
986 Source : Other_Source;
987 Success : Boolean;
989 Archive_Name : constant String :=
990 "lib" & Get_Name_String (Data.Name) & '.' & Archive_Ext;
991 -- The name of the archive file for this project
993 Archive_Dep_Name : constant String :=
994 "lib" & Get_Name_String (Data.Name) & ".deps";
995 -- The name of the archive dependency file for this project
997 Need_To_Rebuild : Boolean := Need_To_Rebuild_Global_Archive;
998 -- When True, archive will be rebuilt
1000 File : Prj.Util.Text_File;
1002 Object_Path : Name_Id;
1003 Time_Stamp : Time_Stamp_Type;
1005 Saved_Last_Argument : Natural;
1006 First_Object : Natural;
1008 Discard : Boolean;
1010 begin
1011 Check_Archive_Builder;
1013 Change_Dir (Get_Name_String (Data.Object_Directory));
1015 if not Need_To_Rebuild then
1016 if Verbose_Mode then
1017 Write_Str (" Checking ");
1018 Write_Line (Archive_Name);
1019 end if;
1021 -- If the archive does not exist, of course it needs to be built
1023 if not Is_Regular_File (Archive_Name) then
1024 Need_To_Rebuild := True;
1026 if Verbose_Mode then
1027 Write_Line (" -> archive does not exist");
1028 end if;
1030 -- Archive does exist
1032 else
1033 -- Check the archive dependency file
1035 Open (File, Archive_Dep_Name);
1037 -- If the archive dependency file does not exist, we need to
1038 -- to rebuild the archive and to create its dependency file.
1040 if not Is_Valid (File) then
1041 Need_To_Rebuild := True;
1043 if Verbose_Mode then
1044 Write_Str (" -> archive dependency file ");
1045 Write_Str (Archive_Dep_Name);
1046 Write_Line (" does not exist");
1047 end if;
1049 else
1050 -- Put all sources of language other than Ada in
1051 -- Source_Indexes.
1053 for Proj in 1 .. Projects.Last loop
1054 Data := Projects.Table (Proj);
1056 if not Data.Library then
1057 Last_Source := 0;
1058 Source_Id := Data.First_Other_Source;
1060 while Source_Id /= No_Other_Source loop
1061 Add_Source_Id (Proj, Source_Id);
1062 Source_Id := Other_Sources.Table (Source_Id).Next;
1063 end loop;
1064 end if;
1065 end loop;
1067 -- Read the dependency file, line by line
1069 while not End_Of_File (File) loop
1070 Get_Line (File, Name_Buffer, Name_Len);
1072 -- First line is the path of the object file
1074 Object_Path := Name_Find;
1075 Source_Id := No_Other_Source;
1077 -- Check if this object file is for a source of this project
1079 for S in 1 .. Last_Source loop
1080 Source_Id := Source_Indexes (S).Id;
1081 Source := Other_Sources.Table (Source_Id);
1083 if (not Source_Indexes (S).Found)
1084 and then Source.Object_Path = Object_Path
1085 then
1086 -- We have found the object file: get the source
1087 -- data, and mark it as found.
1089 Source_Indexes (S).Found := True;
1090 exit;
1091 end if;
1092 end loop;
1094 -- If it is not for a source of this project, then the
1095 -- archive needs to be rebuilt.
1097 if Source_Id = No_Other_Source then
1098 Need_To_Rebuild := True;
1099 if Verbose_Mode then
1100 Write_Str (" -> ");
1101 Write_Str (Get_Name_String (Object_Path));
1102 Write_Line (" is not an object of any project");
1103 end if;
1105 exit;
1106 end if;
1108 -- The second line is the time stamp of the object file.
1109 -- If there is no next line, then the dependency file is
1110 -- truncated, and the archive need to be rebuilt.
1112 if End_Of_File (File) then
1113 Need_To_Rebuild := True;
1115 if Verbose_Mode then
1116 Write_Str (" -> archive dependency file ");
1117 Write_Line (" is truncated");
1118 end if;
1120 exit;
1121 end if;
1123 Get_Line (File, Name_Buffer, Name_Len);
1125 -- If the line has the wrong number of characters, then
1126 -- the dependency file is incorrectly formatted, and the
1127 -- archive needs to be rebuilt.
1129 if Name_Len /= Time_Stamp_Length then
1130 Need_To_Rebuild := True;
1132 if Verbose_Mode then
1133 Write_Str (" -> archive dependency file ");
1134 Write_Line (" is incorrectly formatted (time stamp)");
1135 end if;
1137 exit;
1138 end if;
1140 Time_Stamp := Time_Stamp_Type (Name_Buffer (1 .. Name_Len));
1142 -- If the time stamp in the dependency file is different
1143 -- from the time stamp of the object file, then the archive
1144 -- needs to be rebuilt.
1146 if Time_Stamp /= Source.Object_TS then
1147 Need_To_Rebuild := True;
1149 if Verbose_Mode then
1150 Write_Str (" -> time stamp of ");
1151 Write_Str (Get_Name_String (Object_Path));
1152 Write_Str (" is incorrect in the archive");
1153 Write_Line (" dependency file");
1154 end if;
1156 exit;
1157 end if;
1158 end loop;
1160 Close (File);
1161 end if;
1162 end if;
1163 end if;
1165 if not Need_To_Rebuild then
1166 if Verbose_Mode then
1167 Write_Line (" -> up to date");
1168 end if;
1170 -- Archive needs to be rebuilt
1172 else
1173 -- If archive already exists, first delete it
1175 -- Comment needed on why we discard result???
1177 if Is_Regular_File (Archive_Name) then
1178 Delete_File (Archive_Name, Discard);
1179 end if;
1181 Last_Argument := 0;
1183 -- Start with the options found in MLib.Tgt (usually just "rc")
1185 Add_Arguments (Archive_Builder_Options.all, True);
1187 -- Followed by the archive name
1189 Add_Argument (Archive_Name, True);
1191 First_Object := Last_Argument;
1193 -- Followed by all the object files of the non library projects
1195 for Proj in 1 .. Projects.Last loop
1196 Data := Projects.Table (Proj);
1198 if not Data.Library then
1199 Source_Id := Data.First_Other_Source;
1201 while Source_Id /= No_Other_Source loop
1202 Source := Other_Sources.Table (Source_Id);
1204 -- Only include object file name that have not been
1205 -- overriden in extending projects.
1207 if Is_Included_In_Global_Archive
1208 (Source.Object_Name, Proj)
1209 then
1210 Add_Argument
1211 (Get_Name_String (Source.Object_Path), Verbose_Mode);
1212 end if;
1214 Source_Id := Source.Next;
1215 end loop;
1216 end if;
1217 end loop;
1219 -- No need to create a global archive, if there is no object
1220 -- file to put into.
1222 Global_Archive_Exists := Last_Argument > First_Object;
1224 if Global_Archive_Exists then
1226 -- If the archive is built, then linking will need to occur
1227 -- unconditionally.
1229 Need_To_Relink := True;
1231 -- Spawn the archive builder (ar)
1233 Saved_Last_Argument := Last_Argument;
1234 Last_Argument := First_Object + Max_In_Archives;
1235 loop
1236 if Last_Argument > Saved_Last_Argument then
1237 Last_Argument := Saved_Last_Argument;
1238 end if;
1240 Display_Command (Archive_Builder, Archive_Builder_Path);
1242 Spawn
1243 (Archive_Builder_Path.all,
1244 Arguments (1 .. Last_Argument),
1245 Success);
1247 exit when not Success;
1249 exit when Last_Argument = Saved_Last_Argument;
1251 Arguments (1) := r;
1252 Arguments (3 .. Saved_Last_Argument - Last_Argument + 2) :=
1253 Arguments (Last_Argument + 1 .. Saved_Last_Argument);
1254 Saved_Last_Argument := Saved_Last_Argument - Last_Argument + 2;
1255 end loop;
1257 -- If the archive was built, run the archive indexer (ranlib)
1258 -- if there is one.
1260 if Success then
1262 -- If the archive was built, run the archive indexer (ranlib),
1263 -- if there is one.
1265 if Archive_Indexer_Path /= null then
1266 Last_Argument := 0;
1267 Add_Argument (Archive_Name, True);
1269 Display_Command (Archive_Indexer, Archive_Indexer_Path);
1271 Spawn
1272 (Archive_Indexer_Path.all, Arguments (1 .. 1), Success);
1274 if not Success then
1276 -- Running ranlib failed, delete the dependency file,
1277 -- if it exists.
1279 if Is_Regular_File (Archive_Dep_Name) then
1280 Delete_File (Archive_Dep_Name, Success);
1281 end if;
1283 -- And report the error
1285 Report_Error
1286 ("running" & Archive_Indexer & " for project """,
1287 Get_Name_String (Data.Name),
1288 """ failed");
1289 return;
1290 end if;
1291 end if;
1293 -- The archive was correctly built, create its dependency file
1295 Create_Global_Archive_Dependency_File (Archive_Dep_Name);
1297 -- Building the archive failed, delete dependency file if one
1298 -- exists.
1300 else
1301 if Is_Regular_File (Archive_Dep_Name) then
1302 Delete_File (Archive_Dep_Name, Success);
1303 end if;
1305 -- And report the error
1307 Report_Error
1308 ("building archive for project """,
1309 Get_Name_String (Data.Name),
1310 """ failed");
1311 end if;
1312 end if;
1313 end if;
1314 end Build_Global_Archive;
1316 -------------------
1317 -- Build_Library --
1318 -------------------
1320 procedure Build_Library (Project : Project_Id; Unconditionally : Boolean) is
1321 Data : constant Project_Data := Projects.Table (Project);
1322 Source_Id : Other_Source_Id;
1323 Source : Other_Source;
1325 Archive_Name : constant String :=
1326 "lib" & Get_Name_String (Data.Name) & '.' & Archive_Ext;
1327 -- The name of the archive file for this project
1329 Archive_Dep_Name : constant String :=
1330 "lib" & Get_Name_String (Data.Name) & ".deps";
1331 -- The name of the archive dependency file for this project
1333 Need_To_Rebuild : Boolean := Unconditionally;
1334 -- When True, archive will be rebuilt
1336 File : Prj.Util.Text_File;
1338 Object_Name : Name_Id;
1339 Time_Stamp : Time_Stamp_Type;
1340 Driver_Name : Name_Id := No_Name;
1342 begin
1343 Check_Archive_Builder;
1345 -- If Unconditionally is False, check if the archive need to be built
1347 if not Need_To_Rebuild then
1348 if Verbose_Mode then
1349 Write_Str (" Checking ");
1350 Write_Line (Archive_Name);
1351 end if;
1353 -- If the archive does not exist, of course it needs to be built
1355 if not Is_Regular_File (Archive_Name) then
1356 Need_To_Rebuild := True;
1358 if Verbose_Mode then
1359 Write_Line (" -> archive does not exist");
1360 end if;
1362 -- Archive does exist
1364 else
1365 -- Check the archive dependency file
1367 Open (File, Archive_Dep_Name);
1369 -- If the archive dependency file does not exist, we need to
1370 -- to rebuild the archive and to create its dependency file.
1372 if not Is_Valid (File) then
1373 Need_To_Rebuild := True;
1375 if Verbose_Mode then
1376 Write_Str (" -> archive dependency file ");
1377 Write_Str (Archive_Dep_Name);
1378 Write_Line (" does not exist");
1379 end if;
1381 else
1382 -- Put all sources of language other than Ada in Source_Indexes
1384 Last_Source := 0;
1385 Source_Id := Data.First_Other_Source;
1387 while Source_Id /= No_Other_Source loop
1388 Add_Source_Id (Project, Source_Id);
1389 Source_Id := Other_Sources.Table (Source_Id).Next;
1390 end loop;
1392 -- Read the dependency file, line by line
1394 while not End_Of_File (File) loop
1395 Get_Line (File, Name_Buffer, Name_Len);
1397 -- First line is the name of an object file
1399 Object_Name := Name_Find;
1400 Source_Id := No_Other_Source;
1402 -- Check if this object file is for a source of this project
1404 for S in 1 .. Last_Source loop
1405 if (not Source_Indexes (S).Found) and then
1406 Other_Sources.Table
1407 (Source_Indexes (S).Id).Object_Name =
1408 Object_Name
1409 then
1410 -- We have found the object file: get the source
1411 -- data, and mark it as found.
1413 Source_Id := Source_Indexes (S).Id;
1414 Source := Other_Sources.Table (Source_Id);
1415 Source_Indexes (S).Found := True;
1416 exit;
1417 end if;
1418 end loop;
1420 -- If it is not for a source of this project, then the
1421 -- archive needs to be rebuilt.
1423 if Source_Id = No_Other_Source then
1424 Need_To_Rebuild := True;
1426 if Verbose_Mode then
1427 Write_Str (" -> ");
1428 Write_Str (Get_Name_String (Object_Name));
1429 Write_Line (" is not an object of the project");
1430 end if;
1432 exit;
1433 end if;
1435 -- The second line is the time stamp of the object file.
1436 -- If there is no next line, then the dependency file is
1437 -- truncated, and the archive need to be rebuilt.
1439 if End_Of_File (File) then
1440 Need_To_Rebuild := True;
1442 if Verbose_Mode then
1443 Write_Str (" -> archive dependency file ");
1444 Write_Line (" is truncated");
1445 end if;
1447 exit;
1448 end if;
1450 Get_Line (File, Name_Buffer, Name_Len);
1452 -- If the line has the wrong number of character, then
1453 -- the dependency file is incorrectly formatted, and the
1454 -- archive needs to be rebuilt.
1456 if Name_Len /= Time_Stamp_Length then
1457 Need_To_Rebuild := True;
1459 if Verbose_Mode then
1460 Write_Str (" -> archive dependency file ");
1461 Write_Line (" is incorrectly formatted (time stamp)");
1462 end if;
1464 exit;
1465 end if;
1467 Time_Stamp := Time_Stamp_Type (Name_Buffer (1 .. Name_Len));
1469 -- If the time stamp in the dependency file is different
1470 -- from the time stamp of the object file, then the archive
1471 -- needs to be rebuilt.
1473 if Time_Stamp /= Source.Object_TS then
1474 Need_To_Rebuild := True;
1476 if Verbose_Mode then
1477 Write_Str (" -> time stamp of ");
1478 Write_Str (Get_Name_String (Object_Name));
1479 Write_Str (" is incorrect in the archive");
1480 Write_Line (" dependency file");
1481 end if;
1483 exit;
1484 end if;
1485 end loop;
1487 Close (File);
1489 if not Need_To_Rebuild then
1491 -- Now, check if all object files of the project have been
1492 -- accounted for. If any of them is not in the dependency
1493 -- file, the archive needs to be rebuilt.
1495 for Index in 1 .. Last_Source loop
1496 if not Source_Indexes (Index).Found then
1497 Need_To_Rebuild := True;
1499 if Verbose_Mode then
1500 Source_Id := Source_Indexes (Index).Id;
1501 Source := Other_Sources.Table (Source_Id);
1502 Write_Str (" -> ");
1503 Write_Str (Get_Name_String (Source.Object_Name));
1504 Write_Str (" is not in the archive ");
1505 Write_Line ("dependency file");
1506 end if;
1508 exit;
1509 end if;
1510 end loop;
1511 end if;
1513 if (not Need_To_Rebuild) and Verbose_Mode then
1514 Write_Line (" -> up to date");
1515 end if;
1516 end if;
1517 end if;
1518 end if;
1520 -- Build the library if necessary
1522 if Need_To_Rebuild then
1524 -- If a library is built, then linking will need to occur
1525 -- unconditionally.
1527 Need_To_Relink := True;
1529 Last_Argument := 0;
1531 -- If there are sources in Ada, then gnatmake will build the
1532 -- library, so nothing to do.
1534 if not Data.Languages (Lang_Ada) then
1536 -- Get all the object files of the project
1538 Source_Id := Data.First_Other_Source;
1540 while Source_Id /= No_Other_Source loop
1541 Source := Other_Sources.Table (Source_Id);
1542 Add_Argument
1543 (Get_Name_String (Source.Object_Name), Verbose_Mode);
1544 Source_Id := Source.Next;
1545 end loop;
1547 -- If it is a library, it need to be built it the same way
1548 -- Ada libraries are built.
1550 if Data.Library_Kind = Static then
1551 MLib.Build_Library
1552 (Ofiles => Arguments (1 .. Last_Argument),
1553 Afiles => No_Argument,
1554 Output_File => Get_Name_String (Data.Library_Name),
1555 Output_Dir => Get_Name_String (Data.Library_Dir));
1557 else
1558 -- Link with g++ if C++ is one of the languages, otherwise
1559 -- building the library may fail with unresolved symbols.
1561 if C_Plus_Plus_Is_Used then
1562 if Compiler_Names (Lang_C_Plus_Plus) = null then
1563 Get_Compiler (Lang_C_Plus_Plus);
1564 end if;
1566 if Compiler_Is_Gcc (Lang_C_Plus_Plus) then
1567 Name_Len := 0;
1568 Add_Str_To_Name_Buffer
1569 (Compiler_Names (Lang_C_Plus_Plus).all);
1570 Driver_Name := Name_Find;
1571 end if;
1572 end if;
1574 MLib.Tgt.Build_Dynamic_Library
1575 (Ofiles => Arguments (1 .. Last_Argument),
1576 Foreign => Arguments (1 .. Last_Argument),
1577 Afiles => No_Argument,
1578 Options => No_Argument,
1579 Interfaces => No_Argument,
1580 Lib_Filename => Get_Name_String (Data.Library_Name),
1581 Lib_Dir => Get_Name_String (Data.Library_Dir),
1582 Symbol_Data => No_Symbols,
1583 Driver_Name => Driver_Name,
1584 Lib_Version => "",
1585 Auto_Init => False);
1586 end if;
1587 end if;
1589 -- Create fake empty archive, so we can check its time stamp later
1591 declare
1592 Archive : Ada.Text_IO.File_Type;
1593 use Ada.Text_IO;
1594 begin
1595 Create (Archive, Out_File, Archive_Name);
1596 Close (Archive);
1597 end;
1599 Create_Archive_Dependency_File
1600 (Archive_Dep_Name, Data.First_Other_Source);
1601 end if;
1602 end Build_Library;
1604 -----------
1605 -- Check --
1606 -----------
1608 procedure Check (Option : String) is
1609 First : Positive := Option'First;
1610 Last : Natural;
1612 begin
1613 for Index in Option'First + 1 .. Option'Last - 1 loop
1614 if Option (Index) = ' ' and then Option (Index + 1) = '-' then
1615 Write_Str ("warning: switch """);
1616 Write_Str (Option);
1617 Write_Str (""" is suspicious; consider using ");
1619 Last := First;
1620 while Last <= Option'Last loop
1621 if Option (Last) = ' ' then
1622 if First /= Option'First then
1623 Write_Str (", ");
1624 end if;
1626 Write_Char ('"');
1627 Write_Str (Option (First .. Last - 1));
1628 Write_Char ('"');
1630 while Last <= Option'Last and then Option (Last) = ' ' loop
1631 Last := Last + 1;
1632 end loop;
1634 First := Last;
1636 else
1637 if Last = Option'Last then
1638 if First /= Option'First then
1639 Write_Str (", ");
1640 end if;
1642 Write_Char ('"');
1643 Write_Str (Option (First .. Last));
1644 Write_Char ('"');
1645 end if;
1647 Last := Last + 1;
1648 end if;
1649 end loop;
1651 Write_Line (" instead");
1652 exit;
1653 end if;
1654 end loop;
1655 end Check;
1657 ---------------------------
1658 -- Check_Archive_Builder --
1659 ---------------------------
1661 procedure Check_Archive_Builder is
1662 begin
1663 -- First, make sure that the archive builder (ar) is on the path
1665 if Archive_Builder_Path = null then
1666 Archive_Builder_Path := Locate_Exec_On_Path (Archive_Builder);
1668 if Archive_Builder_Path = null then
1669 Osint.Fail
1670 ("unable to locate archive builder """,
1671 Archive_Builder,
1672 """");
1673 end if;
1675 -- If there is an archive indexer (ranlib), try to locate it on the
1676 -- path. Don't fail if it is not found.
1678 if Archive_Indexer /= "" then
1679 Archive_Indexer_Path := Locate_Exec_On_Path (Archive_Indexer);
1680 end if;
1681 end if;
1682 end Check_Archive_Builder;
1684 ------------------------------
1685 -- Check_Compilation_Needed --
1686 ------------------------------
1688 procedure Check_Compilation_Needed
1689 (Source : Other_Source;
1690 Need_To_Compile : out Boolean)
1692 Source_Name : constant String := Get_Name_String (Source.File_Name);
1693 Source_Path : constant String := Get_Name_String (Source.Path_Name);
1694 Object_Name : constant String := Get_Name_String (Source.Object_Name);
1695 Dep_Name : constant String := Get_Name_String (Source.Dep_Name);
1697 Source_In_Dependencies : Boolean := False;
1698 -- Set True if source was found in dependency file of its object file
1700 Dep_File : Prj.Util.Text_File;
1701 Start : Natural;
1702 Finish : Natural;
1704 begin
1705 -- Assume the worst, so that statement "return;" may be used if there
1706 -- is any problem.
1708 Need_To_Compile := True;
1710 if Verbose_Mode then
1711 Write_Str (" Checking ");
1712 Write_Str (Source_Name);
1713 Write_Line (" ... ");
1714 end if;
1716 -- If object file does not exist, of course source need to be compiled
1718 if Source.Object_TS = Empty_Time_Stamp then
1719 if Verbose_Mode then
1720 Write_Str (" -> object file ");
1721 Write_Str (Object_Name);
1722 Write_Line (" does not exist");
1723 end if;
1725 return;
1726 end if;
1728 -- If the object file has been created before the last modification
1729 -- of the source, the source need to be recompiled.
1731 if Source.Object_TS < Source.Source_TS then
1732 if Verbose_Mode then
1733 Write_Str (" -> object file ");
1734 Write_Str (Object_Name);
1735 Write_Line (" has time stamp earlier than source");
1736 end if;
1738 return;
1739 end if;
1741 -- If there is no dependency file, then the source needs to be
1742 -- recompiled and the dependency file need to be created.
1744 if Source.Dep_TS = Empty_Time_Stamp then
1745 if Verbose_Mode then
1746 Write_Str (" -> dependency file ");
1747 Write_Str (Dep_Name);
1748 Write_Line (" does not exist");
1749 end if;
1751 return;
1752 end if;
1754 -- The source needs to be recompiled if the source has been modified
1755 -- after the dependency file has been created.
1757 if Source.Dep_TS < Source.Source_TS then
1758 if Verbose_Mode then
1759 Write_Str (" -> dependency file ");
1760 Write_Str (Dep_Name);
1761 Write_Line (" has time stamp earlier than source");
1762 end if;
1764 return;
1765 end if;
1767 -- Look for all dependencies
1769 Open (Dep_File, Dep_Name);
1771 -- If dependency file cannot be open, we need to recompile the source
1773 if not Is_Valid (Dep_File) then
1774 if Verbose_Mode then
1775 Write_Str (" -> could not open dependency file ");
1776 Write_Line (Dep_Name);
1777 end if;
1779 return;
1780 end if;
1782 declare
1783 End_Of_File_Reached : Boolean := False;
1785 begin
1786 loop
1787 if End_Of_File (Dep_File) then
1788 End_Of_File_Reached := True;
1789 exit;
1790 end if;
1792 Get_Line (Dep_File, Name_Buffer, Name_Len);
1794 exit when Name_Len > 0 and then Name_Buffer (1) /= '#';
1795 end loop;
1797 -- If dependency file contains only empty lines or comments, then
1798 -- dependencies are unknown, and the source needs to be recompiled.
1800 if End_Of_File_Reached then
1801 if Verbose_Mode then
1802 Write_Str (" -> dependency file ");
1803 Write_Str (Dep_Name);
1804 Write_Line (" is empty");
1805 end if;
1807 Close (Dep_File);
1808 return;
1809 end if;
1810 end;
1812 Start := 1;
1813 Finish := Index (Name_Buffer (1 .. Name_Len), ": ");
1815 -- First line must start with name of object file, followed by colon
1817 if Finish = 0 or else Name_Buffer (1 .. Finish - 1) /= Object_Name then
1818 if Verbose_Mode then
1819 Write_Str (" -> dependency file ");
1820 Write_Str (Dep_Name);
1821 Write_Line (" has wrong format");
1822 end if;
1824 Close (Dep_File);
1825 return;
1827 else
1828 Start := Finish + 2;
1830 -- Process each line
1832 Line_Loop : loop
1833 declare
1834 Line : constant String := Name_Buffer (1 .. Name_Len);
1835 Last : constant Natural := Name_Len;
1837 begin
1838 Name_Loop : loop
1840 -- Find the beginning of the next source path name
1842 while Start < Last and then Line (Start) = ' ' loop
1843 Start := Start + 1;
1844 end loop;
1846 -- Go to next line when there is a continuation character \
1847 -- at the end of the line.
1849 exit Name_Loop when Start = Last
1850 and then Line (Start) = '\';
1852 -- We should not be at the end of the line, without
1853 -- a continuation character \.
1855 if Start = Last then
1856 if Verbose_Mode then
1857 Write_Str (" -> dependency file ");
1858 Write_Str (Dep_Name);
1859 Write_Line (" has wrong format");
1860 end if;
1862 Close (Dep_File);
1863 return;
1864 end if;
1866 -- Look for the end of the source path name
1868 Finish := Start;
1869 while Finish < Last and then Line (Finish + 1) /= ' ' loop
1870 Finish := Finish + 1;
1871 end loop;
1873 -- Check this source
1875 declare
1876 Src_Name : constant String :=
1877 Normalize_Pathname
1878 (Name => Line (Start .. Finish),
1879 Case_Sensitive => False);
1880 Src_TS : Time_Stamp_Type;
1882 begin
1883 -- If it is original source, set Source_In_Dependencies
1885 if Src_Name = Source_Path then
1886 Source_In_Dependencies := True;
1887 end if;
1889 Name_Len := 0;
1890 Add_Str_To_Name_Buffer (Src_Name);
1891 Src_TS := File_Stamp (Name_Find);
1893 -- If the source does not exist, we need to recompile
1895 if Src_TS = Empty_Time_Stamp then
1896 if Verbose_Mode then
1897 Write_Str (" -> source ");
1898 Write_Str (Src_Name);
1899 Write_Line (" does not exist");
1900 end if;
1902 Close (Dep_File);
1903 return;
1905 -- If the source has been modified after the object file,
1906 -- we need to recompile.
1908 elsif Src_TS > Source.Object_TS then
1909 if Verbose_Mode then
1910 Write_Str (" -> source ");
1911 Write_Str (Src_Name);
1912 Write_Line
1913 (" has time stamp later than object file");
1914 end if;
1916 Close (Dep_File);
1917 return;
1918 end if;
1919 end;
1921 -- If the source path name ends the line, we are done.
1923 exit Line_Loop when Finish = Last;
1925 -- Go get the next source on the line
1927 Start := Finish + 1;
1928 end loop Name_Loop;
1929 end;
1931 -- If we are here, we had a continuation character \ at the end
1932 -- of the line, so we continue with the next line.
1934 Get_Line (Dep_File, Name_Buffer, Name_Len);
1935 Start := 1;
1936 end loop Line_Loop;
1937 end if;
1939 Close (Dep_File);
1941 -- If the original sources were not in the dependency file, then we
1942 -- need to recompile. It may mean that we are using a different source
1943 -- (different variant) for this object file.
1945 if not Source_In_Dependencies then
1946 if Verbose_Mode then
1947 Write_Str (" -> source ");
1948 Write_Str (Source_Path);
1949 Write_Line (" is not in the dependencies");
1950 end if;
1952 return;
1953 end if;
1955 -- If we are here, then everything is OK, and we don't need
1956 -- to recompile.
1958 if Verbose_Mode then
1959 Write_Line (" -> up to date");
1960 end if;
1962 Need_To_Compile := False;
1963 end Check_Compilation_Needed;
1965 ---------------------------
1966 -- Check_For_C_Plus_Plus --
1967 ---------------------------
1969 procedure Check_For_C_Plus_Plus is
1970 begin
1971 C_Plus_Plus_Is_Used := False;
1973 for Project in 1 .. Projects.Last loop
1974 if Projects.Table (Project).Languages (Lang_C_Plus_Plus) then
1975 C_Plus_Plus_Is_Used := True;
1976 exit;
1977 end if;
1978 end loop;
1979 end Check_For_C_Plus_Plus;
1981 -------------
1982 -- Compile --
1983 -------------
1985 procedure Compile
1986 (Source_Id : Other_Source_Id;
1987 Data : in Project_Data;
1988 Local_Errors : in out Boolean)
1990 Source : Other_Source := Other_Sources.Table (Source_Id);
1991 Success : Boolean;
1992 CPATH : String_Access := null;
1994 begin
1995 -- If the compiler is not known yet, get its path name
1997 if Compiler_Names (Source.Language) = null then
1998 Get_Compiler (Source.Language);
1999 end if;
2001 -- For non GCC compilers, get the dependency file, first calling the
2002 -- compiler with the switch -M.
2004 if not Compiler_Is_Gcc (Source.Language) then
2005 Last_Argument := 0;
2007 -- Add the source name, preceded by -M
2009 Add_Argument (Dash_M, True);
2010 Add_Argument (Get_Name_String (Source.Path_Name), True);
2012 -- Add the compiling switches for this source found in
2013 -- package Compiler of the project file, if they exist.
2015 Add_Switches
2016 (Data, Compiler, Source.Language, Source.File_Name);
2018 -- Add the compiling switches for the language specified
2019 -- on the command line, if any.
2022 J in 1 .. Comp_Opts.Last (Options (Source.Language))
2023 loop
2024 Add_Argument (Options (Source.Language).Table (J), True);
2025 end loop;
2027 -- Finally, add imported directory switches for this project file
2029 Add_Search_Directories (Data, Source.Language);
2031 -- And invoke the compiler using GNAT.Expect
2033 Display_Command
2034 (Compiler_Names (Source.Language).all,
2035 Compiler_Paths (Source.Language));
2037 begin
2038 Non_Blocking_Spawn
2039 (FD,
2040 Compiler_Paths (Source.Language).all,
2041 Arguments (1 .. Last_Argument),
2042 Buffer_Size => 0,
2043 Err_To_Out => True);
2045 declare
2046 Dep_File : Ada.Text_IO.File_Type;
2047 Result : Expect_Match;
2048 Status : Integer;
2050 begin
2051 -- Create the dependency file
2053 Create (Dep_File, Out_File, Get_Name_String (Source.Dep_Name));
2055 loop
2056 Expect (FD, Result, Line_Matcher);
2058 exit when Result = Expect_Timeout;
2060 declare
2061 S : constant String := Strip_CR_LF (Expect_Out (FD));
2063 begin
2064 -- Each line of the output is put in the dependency
2065 -- file, including errors. If there are errors, the
2066 -- syntax of the dependency file will be incorrect and
2067 -- recompilation will occur automatically the next time
2068 -- the dependencies are checked.
2070 Put_Line (Dep_File, S);
2071 end;
2072 end loop;
2074 -- If we are here, it means we had a timeout, so the
2075 -- dependency file may be incomplete. It is safer to
2076 -- delete it, otherwise the dependencies may be wrong.
2078 Close (FD, Status);
2079 Close (Dep_File);
2080 Delete_File (Get_Name_String (Source.Dep_Name), Success);
2082 exception
2083 when Process_Died =>
2085 -- This is the normal outcome. Just close the file
2087 Close (FD, Status);
2088 Close (Dep_File);
2090 when others =>
2092 -- Something wrong happened. It is safer to delete the
2093 -- dependency file, otherwise the dependencies may be wrong.
2095 Close (FD, Status);
2097 if Is_Open (Dep_File) then
2098 Close (Dep_File);
2099 end if;
2101 Delete_File (Get_Name_String (Source.Dep_Name), Success);
2102 end;
2104 exception
2105 -- If we cannot spawn the compiler, then the dependencies are
2106 -- not updated. It is safer then to delete the dependency file,
2107 -- otherwise the dependencies may be wrong.
2109 when Invalid_Process =>
2110 Delete_File (Get_Name_String (Source.Dep_Name), Success);
2111 end;
2112 end if;
2114 Last_Argument := 0;
2116 -- For GCC compilers, make sure the language is always specified to
2117 -- to the GCC driver, in case the extension is not recognized by the
2118 -- GCC driver as a source of the language.
2120 if Compiler_Is_Gcc (Source.Language) then
2121 Add_Argument (Dash_x, Verbose_Mode);
2122 Add_Argument
2123 (Lang_Names (Source.Language), Verbose_Mode);
2124 end if;
2126 -- Specify the source to be compiled
2128 Add_Argument (Dash_c, True);
2129 Add_Argument (Get_Name_String (Source.Path_Name), True);
2131 -- If non static library project, compile with the PIC option if there
2132 -- is one (when there is no PIC option, function MLib.Tgt.PIC_Option
2133 -- returns an empty string, and Add_Argument with an empty string has
2134 -- no effect).
2136 if Data.Library and then Data.Library_Kind /= Static then
2137 Add_Argument (PIC_Option, True);
2138 end if;
2140 -- Indicate the name of the object
2142 Add_Argument (Dash_o, True);
2143 Add_Argument (Get_Name_String (Source.Object_Name), True);
2145 -- When compiler is GCC, use the magic switch that creates
2146 -- the dependency file in the correct format.
2148 if Compiler_Is_Gcc (Source.Language) then
2149 Add_Argument
2150 ("-Wp,-MD," & Get_Name_String (Source.Dep_Name),
2151 Verbose_Mode);
2152 end if;
2154 -- Add the compiling switches for this source found in
2155 -- package Compiler of the project file, if they exist.
2157 Add_Switches
2158 (Data, Compiler, Source.Language, Source.File_Name);
2160 -- Add the compiling switches for the language specified
2161 -- on the command line, if any.
2163 for J in 1 .. Comp_Opts.Last (Options (Source.Language)) loop
2164 Add_Argument (Options (Source.Language).Table (J), True);
2165 end loop;
2167 -- Finally, add the imported directory switches for this
2168 -- project file (or, for gcc compilers, set up the CPATH env var
2169 -- if needed).
2171 Add_Search_Directories (Data, Source.Language);
2173 -- Set CPATH, if compiler is GCC
2175 if Compiler_Is_Gcc (Source.Language) then
2176 CPATH := Current_Include_Paths (Source.Language);
2177 end if;
2179 -- And invoke the compiler
2181 Display_Command
2182 (Name => Compiler_Names (Source.Language).all,
2183 Path => Compiler_Paths (Source.Language),
2184 CPATH => CPATH);
2186 Spawn
2187 (Compiler_Paths (Source.Language).all,
2188 Arguments (1 .. Last_Argument),
2189 Success);
2191 -- Case of successful compilation
2193 if Success then
2195 -- Update the time stamp of the object file
2197 Source.Object_TS := File_Stamp (Source.Object_Name);
2199 -- Do some sanity checks
2201 if Source.Object_TS = Empty_Time_Stamp then
2202 Local_Errors := True;
2203 Report_Error
2204 ("object file ",
2205 Get_Name_String (Source.Object_Name),
2206 " has not been created");
2208 elsif Source.Object_TS < Source.Source_TS then
2209 Local_Errors := True;
2210 Report_Error
2211 ("object file ",
2212 Get_Name_String (Source.Object_Name),
2213 " has not been modified");
2215 else
2216 -- Everything looks fine, update the Other_Sources table
2218 Other_Sources.Table (Source_Id) := Source;
2219 end if;
2221 -- Compilation failed
2223 else
2224 Local_Errors := True;
2225 Report_Error
2226 ("compilation of ",
2227 Get_Name_String (Source.Path_Name),
2228 " failed");
2229 end if;
2230 end Compile;
2232 --------------------------------
2233 -- Compile_Individual_Sources --
2234 --------------------------------
2236 procedure Compile_Individual_Sources is
2237 Data : Project_Data := Projects.Table (Main_Project);
2238 Source_Id : Other_Source_Id;
2239 Source : Other_Source;
2240 Source_Name : Name_Id;
2241 Project_Name : String := Get_Name_String (Data.Name);
2242 Dummy : Boolean := False;
2244 Ada_Is_A_Language : constant Boolean := Data.Languages (Lang_Ada);
2246 begin
2247 Ada_Mains.Init;
2248 To_Mixed (Project_Name);
2249 Compile_Only := True;
2251 Get_Imported_Directories (Main_Project, Data);
2252 Projects.Table (Main_Project) := Data;
2254 -- Compilation will occur in the object directory
2256 Change_Dir (Get_Name_String (Data.Object_Directory));
2258 if not Data.Other_Sources_Present then
2259 if Ada_Is_A_Language then
2260 Mains.Reset;
2262 loop
2263 declare
2264 Main : constant String := Mains.Next_Main;
2265 begin
2266 exit when Main'Length = 0;
2267 Ada_Mains.Increment_Last;
2268 Ada_Mains.Table (Ada_Mains.Last) := new String'(Main);
2269 end;
2270 end loop;
2272 else
2273 Osint.Fail
2274 ("project ", Project_Name, " contains no source");
2275 end if;
2277 else
2278 Mains.Reset;
2280 loop
2281 declare
2282 Main : constant String := Mains.Next_Main;
2283 begin
2284 Name_Len := Main'Length;
2285 exit when Name_Len = 0;
2286 Name_Buffer (1 .. Name_Len) := Main;
2287 Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len));
2288 Source_Name := Name_Find;
2290 if not Sources_Compiled.Get (Source_Name) then
2291 Sources_Compiled.Set (Source_Name, True);
2292 Source_Id := Data.First_Other_Source;
2294 while Source_Id /= No_Other_Source loop
2295 Source := Other_Sources.Table (Source_Id);
2296 exit when Source.File_Name = Source_Name;
2297 Source_Id := Source.Next;
2298 end loop;
2300 if Source_Id = No_Other_Source then
2301 if Ada_Is_A_Language then
2302 Ada_Mains.Increment_Last;
2303 Ada_Mains.Table (Ada_Mains.Last) := new String'(Main);
2305 else
2306 Report_Error
2307 (Main,
2308 " is not a valid source of project ",
2309 Project_Name);
2310 end if;
2312 else
2313 Compile (Source_Id, Data, Dummy);
2314 end if;
2315 end if;
2316 end;
2317 end loop;
2318 end if;
2320 if Ada_Mains.Last > 0 then
2322 -- Invoke gnatmake for all Ada sources
2324 Last_Argument := 0;
2325 Add_Argument (Dash_u, True);
2327 for Index in 1 .. Ada_Mains.Last loop
2328 Add_Argument (Ada_Mains.Table (Index), True);
2329 end loop;
2331 Compile_Link_With_Gnatmake (Mains_Specified => False);
2332 end if;
2333 end Compile_Individual_Sources;
2335 --------------------------------
2336 -- Compile_Link_With_Gnatmake --
2337 --------------------------------
2339 procedure Compile_Link_With_Gnatmake (Mains_Specified : Boolean) is
2340 Data : constant Project_Data := Projects.Table (Main_Project);
2341 Success : Boolean;
2343 begin
2344 -- Array Arguments may already contain some arguments, so we don't
2345 -- set Last_Argument to 0.
2347 -- Get the gnatmake to invoke
2349 Get_Compiler (Lang_Ada);
2351 -- Specify the project file
2353 Add_Argument (Dash_P, True);
2354 Add_Argument (Get_Name_String (Data.Path_Name), True);
2356 -- Add the -X switches, if any
2358 for Index in 1 .. X_Switches.Last loop
2359 Add_Argument (X_Switches.Table (Index), True);
2360 end loop;
2362 -- If Mains_Specified is True, find the mains in package Mains
2364 if Mains_Specified then
2365 Mains.Reset;
2367 loop
2368 declare
2369 Main : constant String := Mains.Next_Main;
2370 begin
2371 exit when Main'Length = 0;
2372 Add_Argument (Main, True);
2373 end;
2374 end loop;
2375 end if;
2377 -- Specify output file name, if any was specified on the command line
2379 if Output_File_Name /= null then
2380 Add_Argument (Dash_o, True);
2381 Add_Argument (Output_File_Name, True);
2382 end if;
2384 -- Transmit some switches to gnatmake
2386 -- -c
2388 if Compile_Only then
2389 Add_Argument (Dash_c, True);
2390 end if;
2392 -- -k
2394 if Keep_Going then
2395 Add_Argument (Dash_k, True);
2396 end if;
2398 -- -f
2400 if Force_Compilations then
2401 Add_Argument (Dash_f, True);
2402 end if;
2404 -- -v
2406 if Verbose_Mode then
2407 Add_Argument (Dash_v, True);
2408 end if;
2410 -- -q
2412 if Quiet_Output then
2413 Add_Argument (Dash_q, True);
2414 end if;
2416 -- -vP1 and -vP2
2418 case Current_Verbosity is
2419 when Default =>
2420 null;
2422 when Medium =>
2423 Add_Argument (Dash_vP1, True);
2425 when High =>
2426 Add_Argument (Dash_vP2, True);
2427 end case;
2429 -- If there are compiling options for Ada, transmit them to gnatmake
2431 if Comp_Opts.Last (Options (Lang_Ada)) /= 0 then
2432 Add_Argument (Dash_cargs, True);
2434 for Arg in 1 .. Comp_Opts.Last (Options (Lang_Ada)) loop
2435 Add_Argument (Options (Lang_Ada).Table (Arg), True);
2436 end loop;
2437 end if;
2439 if not Compile_Only then
2441 -- Linking options
2443 if Linker_Options.Last /= 0 then
2444 Add_Argument (Dash_largs, True);
2445 else
2446 Add_Argument (Dash_largs, Verbose_Mode);
2447 end if;
2449 -- Add the archives
2451 Add_Archives (For_Gnatmake => True);
2453 -- If there are linking options from the command line,
2454 -- transmit them to gnatmake.
2456 for Arg in 1 .. Linker_Options.Last loop
2457 Add_Argument (Linker_Options.Table (Arg), True);
2458 end loop;
2459 end if;
2461 -- And invoke gnatmake
2463 Display_Command
2464 (Compiler_Names (Lang_Ada).all, Compiler_Paths (Lang_Ada));
2466 Spawn
2467 (Compiler_Paths (Lang_Ada).all,
2468 Arguments (1 .. Last_Argument),
2469 Success);
2471 -- Report an error if call to gnatmake failed
2473 if not Success then
2474 Report_Error
2475 ("invocation of ", Compiler_Names (Lang_Ada).all, " failed");
2476 end if;
2478 end Compile_Link_With_Gnatmake;
2480 ---------------------
2481 -- Compile_Sources --
2482 ---------------------
2484 procedure Compile_Sources is
2485 Data : Project_Data;
2486 Source_Id : Other_Source_Id;
2487 Source : Other_Source;
2489 Local_Errors : Boolean := False;
2490 -- Set to True when there is a compilation error. Used only when
2491 -- Keep_Going is True, to inhibit the building of the archive.
2493 Need_To_Compile : Boolean;
2494 -- Set to True when a source needs to be compiled/recompiled.
2496 Need_To_Rebuild_Archive : Boolean := Force_Compilations;
2497 -- True when the archive needs to be built/rebuilt unconditionally
2499 begin
2500 -- Loop through project files
2502 for Project in 1 .. Projects.Last loop
2503 Local_Errors := False;
2504 Data := Projects.Table (Project);
2506 -- Nothing to do when no sources of language other than Ada
2508 if (not Data.Virtual) and then Data.Other_Sources_Present then
2510 -- If the imported directory switches are unknown, compute them
2512 if not Data.Include_Data_Set then
2513 Get_Imported_Directories (Project, Data);
2514 Data.Include_Data_Set := True;
2515 Projects.Table (Project) := Data;
2516 end if;
2518 Need_To_Rebuild_Archive := Force_Compilations;
2520 -- Compilation will occur in the object directory
2522 Change_Dir (Get_Name_String (Data.Object_Directory));
2524 Source_Id := Data.First_Other_Source;
2526 -- Process each source one by one
2528 while Source_Id /= No_Other_Source loop
2529 Source := Other_Sources.Table (Source_Id);
2530 Need_To_Compile := Force_Compilations;
2532 -- Check if compilation is needed
2534 if not Need_To_Compile then
2535 Check_Compilation_Needed (Source, Need_To_Compile);
2536 end if;
2538 -- Proceed, if compilation is needed
2540 if Need_To_Compile then
2542 -- If a source is compiled/recompiled, of course the
2543 -- archive will need to be built/rebuilt.
2545 Need_To_Rebuild_Archive := True;
2546 Compile (Source_Id, Data, Local_Errors);
2547 end if;
2549 -- Next source, if any
2551 Source_Id := Source.Next;
2552 end loop;
2554 if Need_To_Rebuild_Archive and then (not Data.Library) then
2555 Need_To_Rebuild_Global_Archive := True;
2556 end if;
2558 -- If there was no compilation error and -c was not used,
2559 -- build / rebuild the archive if necessary.
2561 if not Local_Errors
2562 and then Data.Library
2563 and then not Data.Languages (Lang_Ada)
2564 and then not Compile_Only
2565 then
2566 Build_Library (Project, Need_To_Rebuild_Archive);
2567 end if;
2568 end if;
2569 end loop;
2570 end Compile_Sources;
2572 ---------------
2573 -- Copyright --
2574 ---------------
2576 procedure Copyright is
2577 begin
2578 -- Only output the Copyright notice once
2580 if not Copyright_Output then
2581 Copyright_Output := True;
2582 Write_Eol;
2583 Write_Str ("GPRMAKE ");
2584 Write_Str (Gnatvsn.Gnat_Version_String);
2585 Write_Str (" Copyright 2004 Free Software Foundation, Inc.");
2586 Write_Eol;
2587 end if;
2588 end Copyright;
2590 ------------------------------------
2591 -- Create_Archive_Dependency_File --
2592 ------------------------------------
2594 procedure Create_Archive_Dependency_File
2595 (Name : String;
2596 First_Source : Other_Source_Id)
2598 Source_Id : Other_Source_Id := First_Source;
2599 Source : Other_Source;
2600 Dep_File : Ada.Text_IO.File_Type;
2601 use Ada.Text_IO;
2603 begin
2604 -- Create the file in Append mode, to avoid automatic insertion of
2605 -- an end of line if file is empty.
2607 Create (Dep_File, Append_File, Name);
2609 while Source_Id /= No_Other_Source loop
2610 Source := Other_Sources.Table (Source_Id);
2611 Put_Line (Dep_File, Get_Name_String (Source.Object_Name));
2612 Put_Line (Dep_File, String (Source.Object_TS));
2613 Source_Id := Source.Next;
2614 end loop;
2616 Close (Dep_File);
2618 exception
2619 when others =>
2620 if Is_Open (Dep_File) then
2621 Close (Dep_File);
2622 end if;
2623 end Create_Archive_Dependency_File;
2625 -------------------------------------------
2626 -- Create_Global_Archive_Dependency_File --
2627 -------------------------------------------
2629 procedure Create_Global_Archive_Dependency_File (Name : String) is
2630 Source_Id : Other_Source_Id;
2631 Source : Other_Source;
2632 Dep_File : Ada.Text_IO.File_Type;
2634 use Ada.Text_IO;
2636 begin
2637 -- Create the file in Append mode, to avoid automatic insertion of
2638 -- an end of line if file is empty.
2640 Create (Dep_File, Append_File, Name);
2642 -- Get all the object files of non-Ada sources in non-library projects
2644 for Project in 1 .. Projects.Last loop
2645 if not Projects.Table (Project).Library then
2646 Source_Id := Projects.Table (Project).First_Other_Source;
2648 while Source_Id /= No_Other_Source loop
2649 Source := Other_Sources.Table (Source_Id);
2651 -- Put only those object files that are in the global archive
2653 if Is_Included_In_Global_Archive
2654 (Source.Object_Name, Project)
2655 then
2656 Put_Line (Dep_File, Get_Name_String (Source.Object_Path));
2657 Put_Line (Dep_File, String (Source.Object_TS));
2658 end if;
2660 Source_Id := Source.Next;
2661 end loop;
2662 end if;
2663 end loop;
2665 Close (Dep_File);
2667 exception
2668 when others =>
2669 if Is_Open (Dep_File) then
2670 Close (Dep_File);
2671 end if;
2672 end Create_Global_Archive_Dependency_File;
2674 ---------------------
2675 -- Display_Command --
2676 ---------------------
2678 procedure Display_Command
2679 (Name : String;
2680 Path : String_Access;
2681 CPATH : String_Access := null)
2683 begin
2684 -- Only display the command in Verbose Mode (-v) or when
2685 -- not in Quiet Output (no -q).
2687 if Verbose_Mode or (not Quiet_Output) then
2689 -- In Verbose Mode output the full path of the spawned process
2691 if Verbose_Mode then
2692 if CPATH /= null then
2693 Write_Str ("CPATH = ");
2694 Write_Line (CPATH.all);
2695 end if;
2697 Write_Str (Path.all);
2699 else
2700 Write_Str (Name);
2701 end if;
2703 -- Display only the arguments for which the display flag is set
2704 -- (in Verbose Mode, the display flag is set for all arguments)
2706 for Arg in 1 .. Last_Argument loop
2707 if Arguments_Displayed (Arg) then
2708 Write_Char (' ');
2709 Write_Str (Arguments (Arg).all);
2710 end if;
2711 end loop;
2713 Write_Eol;
2714 end if;
2715 end Display_Command;
2717 ------------------
2718 -- Get_Compiler --
2719 ------------------
2721 procedure Get_Compiler (For_Language : Programming_Language) is
2722 Data : constant Project_Data := Projects.Table (Main_Project);
2724 Ide : constant Package_Id :=
2725 Value_Of (Name_Ide, In_Packages => Data.Decl.Packages);
2726 -- The id of the package IDE in the project file
2728 Compiler : constant Variable_Value :=
2729 Value_Of
2730 (Name => Lang_Name_Ids (For_Language),
2731 Index => 0,
2732 Attribute_Or_Array_Name => Name_Compiler_Command,
2733 In_Package => Ide);
2734 -- The value of Compiler_Command ("language") in package IDE, if defined
2736 begin
2737 -- No need to do it again if the compiler is known for this language
2739 if Compiler_Names (For_Language) = null then
2741 -- If compiler command is not defined for this language in package
2742 -- IDE, use the default compiler for this language.
2744 if Compiler = Nil_Variable_Value then
2745 Compiler_Names (For_Language) :=
2746 Default_Compiler_Names (For_Language);
2748 else
2749 Compiler_Names (For_Language) :=
2750 new String'(Get_Name_String (Compiler.Value));
2751 end if;
2753 -- Check we have a GCC compiler (name ends with "gcc" or "g++")
2755 declare
2756 Comp_Name : constant String := Compiler_Names (For_Language).all;
2757 Last3 : String (1 .. 3);
2758 begin
2759 if Comp_Name'Length >= 3 then
2760 Last3 := Comp_Name (Comp_Name'Last - 2 .. Comp_Name'Last);
2761 Compiler_Is_Gcc (For_Language) :=
2762 (Last3 = "gcc") or (Last3 = "g++");
2763 else
2764 Compiler_Is_Gcc (For_Language) := False;
2765 end if;
2766 end;
2768 -- Locate the compiler on the path
2770 Compiler_Paths (For_Language) :=
2771 Locate_Exec_On_Path (Compiler_Names (For_Language).all);
2773 -- Fail if compiler cannot be found
2775 if Compiler_Paths (For_Language) = null then
2776 if For_Language = Lang_Ada then
2777 Osint.Fail
2778 ("unable to locate """,
2779 Compiler_Names (For_Language).all,
2780 """");
2782 else
2783 Osint.Fail
2784 ("unable to locate " & Lang_Display_Names (For_Language).all,
2785 " compiler """, Compiler_Names (For_Language).all & '"');
2786 end if;
2787 end if;
2788 end if;
2789 end Get_Compiler;
2791 ------------------------------
2792 -- Get_Imported_Directories --
2793 ------------------------------
2795 procedure Get_Imported_Directories
2796 (Project : Project_Id;
2797 Data : in out Project_Data)
2799 Imported_Projects : Project_List := Data.Imported_Projects;
2801 Path_Length : Natural := 0;
2802 Position : Natural := 0;
2804 procedure Add (Source_Dirs : String_List_Id);
2805 -- Add a list of source directories
2807 procedure Recursive_Get_Dirs (Prj : Project_Id);
2808 -- Recursive procedure to get the source directories of this project
2809 -- file and of the project files it imports, in the correct order.
2811 ---------
2812 -- Add --
2813 ---------
2815 procedure Add (Source_Dirs : String_List_Id) is
2816 Element_Id : String_List_Id := Source_Dirs;
2817 Element : String_Element;
2818 Add_Arg : Boolean := True;
2820 begin
2821 -- Add each source directory path name, preceded by "-I" to Arguments
2823 while Element_Id /= Nil_String loop
2824 Element := String_Elements.Table (Element_Id);
2826 if Element.Value /= No_Name then
2827 Get_Name_String (Element.Value);
2829 if Name_Len > 0 then
2830 declare
2831 Arg : constant String :=
2832 "-I" & Name_Buffer (1 .. Name_Len);
2833 begin
2834 -- Check if directory is already in the list.
2835 -- If it is, no need to put it again.
2837 for Index in 1 .. Last_Argument loop
2838 if Arguments (Index).all = Arg then
2839 Add_Arg := False;
2840 exit;
2841 end if;
2842 end loop;
2844 if Add_Arg then
2845 if Path_Length /= 0 then
2846 Path_Length := Path_Length + 1;
2847 end if;
2849 Path_Length := Path_Length + Name_Len;
2851 Add_Argument (Arg, True);
2852 end if;
2853 end;
2854 end if;
2855 end if;
2857 Element_Id := Element.Next;
2858 end loop;
2859 end Add;
2861 ------------------------
2862 -- Recursive_Get_Dirs --
2863 ------------------------
2865 procedure Recursive_Get_Dirs (Prj : Project_Id) is
2866 Data : Project_Data;
2867 Imported : Project_List;
2869 begin
2870 -- Nothing to do if project is undefined
2872 if Prj /= No_Project then
2873 Data := Projects.Table (Prj);
2875 -- Nothing to do if project has already been processed
2877 if not Data.Seen then
2879 -- Mark the project as processed, to avoid multiple processing
2880 -- of the same project.
2882 Projects.Table (Prj).Seen := True;
2884 -- Add the source directories of this project
2886 if not Data.Virtual then
2887 Add (Data.Source_Dirs);
2888 end if;
2890 Recursive_Get_Dirs (Data.Extends);
2892 Imported := Data.Imported_Projects;
2894 -- Call itself for all imported projects, if any
2896 while Imported /= Empty_Project_List loop
2897 Recursive_Get_Dirs (Project_Lists.Table (Imported).Project);
2898 Imported := Project_Lists.Table (Imported).Next;
2899 end loop;
2900 end if;
2901 end if;
2902 end Recursive_Get_Dirs;
2904 -- Start of processing for Get_Imported_Directories
2906 begin
2907 -- First, mark all project as not processed
2909 for J in 1 .. Projects.Last loop
2910 Projects.Table (J).Seen := False;
2911 end loop;
2913 -- Empty Arguments
2915 Last_Argument := 0;
2917 -- Process this project individually, project data are already known
2919 Projects.Table (Project).Seen := True;
2921 Add (Data.Source_Dirs);
2923 Recursive_Get_Dirs (Data.Extends);
2925 while Imported_Projects /= Empty_Project_List loop
2926 Recursive_Get_Dirs (Project_Lists.Table (Imported_Projects).Project);
2927 Imported_Projects := Project_Lists.Table (Imported_Projects).Next;
2928 end loop;
2930 Data.Imported_Directories_Switches :=
2931 new Argument_List'(Arguments (1 .. Last_Argument));
2933 -- Create the Include_Path, from the Arguments
2935 Data.Include_Path := new String (1 .. Path_Length);
2936 Data.Include_Path (1 .. Arguments (1)'Length - 2) :=
2937 Arguments (1)(Arguments (1)'First + 2 .. Arguments (1)'Last);
2938 Position := Arguments (1)'Length - 2;
2940 for Arg in 2 .. Last_Argument loop
2941 Position := Position + 1;
2942 Data.Include_Path (Position) := Path_Separator;
2943 Data.Include_Path
2944 (Position + 1 .. Position + Arguments (Arg)'Length - 2) :=
2945 Arguments (Arg)(Arguments (Arg)'First + 2 .. Arguments (Arg)'Last);
2946 Position := Position + Arguments (Arg)'Length - 2;
2947 end loop;
2949 Last_Argument := 0;
2950 end Get_Imported_Directories;
2952 -------------
2953 -- Gprmake --
2954 -------------
2956 procedure Gprmake is
2957 begin
2958 Makegpr.Initialize;
2960 if Verbose_Mode then
2961 Write_Eol;
2962 Write_Str ("Parsing Project File """);
2963 Write_Str (Project_File_Name.all);
2964 Write_Str (""".");
2965 Write_Eol;
2966 end if;
2968 -- Parse and process project files for other languages (not for Ada)
2970 Prj.Pars.Parse
2971 (Project => Main_Project,
2972 Project_File_Name => Project_File_Name.all,
2973 Packages_To_Check => Packages_To_Check,
2974 Process_Languages => Other_Languages);
2976 -- Fail if parsing/processing was unsuccessful
2978 if Main_Project = No_Project then
2979 Osint.Fail ("""", Project_File_Name.all, """ processing failed");
2980 end if;
2982 if Verbose_Mode then
2983 Write_Eol;
2984 Write_Str ("Parsing of Project File """);
2985 Write_Str (Project_File_Name.all);
2986 Write_Str (""" is finished.");
2987 Write_Eol;
2988 end if;
2990 -- If -f was specified, we will certainly need to link (except when
2991 -- -u or -c were specified, of course).
2993 Need_To_Relink := Force_Compilations;
2995 if Unique_Compile then
2996 if Mains.Number_Of_Mains = 0 then
2997 Osint.Fail
2998 ("No source specified to compile in 'unique compile' mode");
2999 else
3000 Compile_Individual_Sources;
3001 Report_Total_Errors ("compilation");
3002 end if;
3004 else
3005 -- First check for C++, to link libraries with g++, rather than gcc
3007 Check_For_C_Plus_Plus;
3009 -- Compile sources and build archives for library project,
3010 -- if necessary.
3012 Compile_Sources;
3014 -- When Keep_Going is True, if we had some errors, fail now,
3015 -- reporting the number of compilation errors.
3016 -- Do not attempt to link.
3018 Report_Total_Errors ("compilation");
3020 -- If -c was not specified, link the executables, if there are any.
3022 if not Compile_Only then
3023 Build_Global_Archive;
3024 Link_Executables;
3025 end if;
3027 -- When Keep_Going is True, if we had some errors, fail, reporting
3028 -- the number of linking errors.
3030 Report_Total_Errors ("linking");
3031 end if;
3032 end Gprmake;
3034 ----------------
3035 -- Initialize --
3036 ----------------
3038 procedure Initialize is
3039 begin
3040 -- Do some necessary package initializations
3042 Csets.Initialize;
3043 Namet.Initialize;
3044 Snames.Initialize;
3045 Prj.Initialize;
3046 Mains.Delete;
3048 -- Set Name_Ide and Name_Compiler_Command
3050 Name_Len := 0;
3051 Add_Str_To_Name_Buffer ("ide");
3052 Name_Ide := Name_Find;
3054 Name_Len := 0;
3055 Add_Str_To_Name_Buffer ("compiler_command");
3056 Name_Compiler_Command := Name_Find;
3058 -- Make sure the -X switch table is empty
3060 X_Switches.Set_Last (0);
3062 -- Get the command line arguments
3064 Scan_Args : for Next_Arg in 1 .. Argument_Count loop
3065 Scan_Arg (Argument (Next_Arg));
3066 end loop Scan_Args;
3068 -- Fail if command line ended with "-P"
3070 if Project_File_Name_Expected then
3071 Osint.Fail ("project file name missing after -P");
3073 -- Or if it ended with "-o"
3075 elsif Output_File_Name_Expected then
3076 Osint.Fail ("output file name missing after -o");
3077 end if;
3079 -- If no project file was specified, display the usage and fail
3081 if Project_File_Name = null then
3082 Usage;
3083 Exit_Program (E_Success);
3084 end if;
3086 -- To be able of finding libgnat.a in MLib.Tgt, we need to have the
3087 -- default search dirs established in Osint.
3089 Osint.Add_Default_Search_Dirs;
3090 end Initialize;
3092 -----------------------------------
3093 -- Is_Included_In_Global_Archive --
3094 -----------------------------------
3096 function Is_Included_In_Global_Archive
3097 (Object_Name : Name_Id;
3098 Project : Project_Id) return Boolean
3100 Data : Project_Data := Projects.Table (Project);
3101 Source : Other_Source_Id;
3103 begin
3104 while Data.Extended_By /= No_Project loop
3105 Data := Projects.Table (Data.Extended_By);
3106 Source := Data.First_Other_Source;
3108 while Source /= No_Other_Source loop
3109 if Other_Sources.Table (Source).Object_Name = Object_Name then
3110 return False;
3111 else
3112 Source := Other_Sources.Table (Source).Next;
3113 end if;
3114 end loop;
3115 end loop;
3117 return True;
3118 end Is_Included_In_Global_Archive;
3120 ----------------------
3121 -- Link_Executables --
3122 ----------------------
3124 procedure Link_Executables is
3125 Data : constant Project_Data := Projects.Table (Main_Project);
3127 Mains_Specified : constant Boolean := Mains.Number_Of_Mains /= 0;
3128 -- True if main sources were specified on the command line
3130 Object_Dir : constant String := Get_Name_String (Data.Object_Directory);
3131 -- Path of the object directory of the main project
3133 Source_Id : Other_Source_Id;
3134 Source : Other_Source;
3135 Success : Boolean;
3137 Linker_Name : String_Access;
3138 Linker_Path : String_Access;
3139 -- The linker name and path, when linking is not done by gnatlink
3141 Link_Done : Boolean := False;
3142 -- Set to True when the linker is invoked directly (not through
3143 -- gnatmake) to be able to report if mains were up to date at the end
3144 -- of execution.
3146 procedure Add_C_Plus_Plus_Link_For_Gnatmake;
3147 -- Add the --LINK= switch for gnatlink, depending on the C++ compiler
3149 procedure Check_Time_Stamps (Exec_Time_Stamp : Time_Stamp_Type);
3150 -- Check if there is an archive that is more recent than the executable
3151 -- to decide if we need to relink.
3153 procedure Choose_C_Plus_Plus_Link_Process;
3154 -- If the C++ compiler is not g++, create the correct script to link
3156 procedure Link_Foreign
3157 (Main : String;
3158 Main_Id : Name_Id;
3159 Source : Other_Source);
3160 -- Link a non-Ada main, when there is no Ada code
3162 ---------------------------------------
3163 -- Add_C_Plus_Plus_Link_For_Gnatmake --
3164 ---------------------------------------
3166 procedure Add_C_Plus_Plus_Link_For_Gnatmake is
3167 begin
3168 if Compiler_Is_Gcc (Lang_C_Plus_Plus) then
3169 Add_Argument
3170 ("--LINK=" & Compiler_Names (Lang_C_Plus_Plus).all,
3171 Verbose_Mode);
3173 else
3174 Add_Argument
3175 ("--LINK=" &
3176 Object_Dir & Directory_Separator &
3177 Cpp_Linker,
3178 Verbose_Mode);
3179 end if;
3180 end Add_C_Plus_Plus_Link_For_Gnatmake;
3182 -----------------------
3183 -- Check_Time_Stamps --
3184 -----------------------
3186 procedure Check_Time_Stamps (Exec_Time_Stamp : Time_Stamp_Type) is
3187 Prj_Data : Project_Data;
3189 begin
3190 for Prj in 1 .. Projects.Last loop
3191 Prj_Data := Projects.Table (Prj);
3193 -- There is an archive only in project
3194 -- files with sources other than Ada
3195 -- sources.
3197 if Data.Other_Sources_Present then
3198 declare
3199 Archive_Path : constant String :=
3200 Get_Name_String
3201 (Prj_Data.Object_Directory) &
3202 Directory_Separator &
3203 "lib" &
3204 Get_Name_String (Prj_Data.Name) &
3205 '.' & Archive_Ext;
3206 Archive_TS : Time_Stamp_Type;
3207 begin
3208 Name_Len := 0;
3209 Add_Str_To_Name_Buffer
3210 (Archive_Path);
3211 Archive_TS := File_Stamp (Name_Find);
3213 -- If the archive is later than the
3214 -- executable, we need to relink.
3216 if Archive_TS /= Empty_Time_Stamp
3217 and then
3218 Exec_Time_Stamp < Archive_TS
3219 then
3220 Need_To_Relink := True;
3222 if Verbose_Mode then
3223 Write_Str (" -> ");
3224 Write_Str (Archive_Path);
3225 Write_Str (" has time stamp ");
3226 Write_Str ("later than ");
3227 Write_Line ("executable");
3228 end if;
3230 exit;
3231 end if;
3232 end;
3233 end if;
3234 end loop;
3235 end Check_Time_Stamps;
3237 -------------------------------------
3238 -- Choose_C_Plus_Plus_Link_Process --
3239 -------------------------------------
3241 procedure Choose_C_Plus_Plus_Link_Process is
3242 begin
3243 if Compiler_Names (Lang_C_Plus_Plus) = null then
3244 Get_Compiler (Lang_C_Plus_Plus);
3245 end if;
3247 if not Compiler_Is_Gcc (Lang_C_Plus_Plus) then
3248 Change_Dir (Object_Dir);
3250 declare
3251 procedure Set_Executable (Name : System.Address);
3252 pragma Import
3253 (C, Set_Executable, "__gnat_set_executable");
3255 Name : constant String := Cpp_Linker & ASCII.NUL;
3257 File : Ada.Text_IO.File_Type;
3258 use Ada.Text_IO;
3260 begin
3261 Create (File, Out_File, Cpp_Linker);
3263 Put_Line (File, "#!/bin/sh");
3265 Put_Line (File, "LIBGCC=`gcc -print-libgcc-file-name`");
3266 Put_Line
3267 (File,
3268 Compiler_Names (Lang_C_Plus_Plus).all &
3269 " $* ${LIBGCC}");
3271 Close (File);
3272 Set_Executable (Name (Name'First)'Address);
3273 end;
3274 end if;
3275 end Choose_C_Plus_Plus_Link_Process;
3277 ------------------
3278 -- Link_Foreign --
3279 ------------------
3281 procedure Link_Foreign
3282 (Main : String;
3283 Main_Id : Name_Id;
3284 Source : Other_Source)
3286 Executable_Name : constant String :=
3287 Get_Name_String
3288 (Executable_Of
3289 (Project => Main_Project,
3290 Main => Main_Id,
3291 Index => 0,
3292 Ada_Main => False));
3293 -- File name of the executable
3295 Executable_Path : constant String :=
3296 Get_Name_String
3297 (Data.Exec_Directory) &
3298 Directory_Separator &
3299 Executable_Name;
3300 -- Path name of the executable
3302 Exec_Time_Stamp : Time_Stamp_Type;
3304 begin
3305 -- Now, check if the executable is up to date. It is considered
3306 -- up to date if its time stamp is not earlier that the time stamp
3307 -- of any archive. Only do that if we don't know if we need to link.
3309 if not Need_To_Relink then
3311 -- Get the time stamp of the executable
3313 Name_Len := 0;
3314 Add_Str_To_Name_Buffer (Executable_Path);
3315 Exec_Time_Stamp := File_Stamp (Name_Find);
3317 if Verbose_Mode then
3318 Write_Str (" Checking executable ");
3319 Write_Line (Executable_Name);
3320 end if;
3322 -- If executable does not exist, we need to link
3324 if Exec_Time_Stamp = Empty_Time_Stamp then
3325 Need_To_Relink := True;
3327 if Verbose_Mode then
3328 Write_Line (" -> not found");
3329 end if;
3331 -- Otherwise, get the time stamps of each archive. If one of
3332 -- them is found later than the executable, we need to relink.
3334 else
3335 Check_Time_Stamps (Exec_Time_Stamp);
3336 end if;
3338 -- If Need_To_Relink is False, we are done
3340 if Verbose_Mode and (not Need_To_Relink) then
3341 Write_Line (" -> up to date");
3342 end if;
3343 end if;
3345 -- Prepare to link
3347 if Need_To_Relink then
3348 Link_Done := True;
3350 Last_Argument := 0;
3352 -- Specify the executable path name
3354 Add_Argument (Dash_o, True);
3355 Add_Argument
3356 (Get_Name_String (Data.Exec_Directory) &
3357 Directory_Separator &
3358 Get_Name_String
3359 (Executable_Of
3360 (Project => Main_Project,
3361 Main => Main_Id,
3362 Index => 0,
3363 Ada_Main => False)),
3364 True);
3366 -- Specify the object file of the main source
3368 Add_Argument
3369 (Object_Dir & Directory_Separator &
3370 Get_Name_String (Source.Object_Name),
3371 True);
3373 -- Add all the archives, in a correct order
3375 Add_Archives (For_Gnatmake => False);
3377 -- Add the switches specified in package Linker of
3378 -- the main project.
3380 Add_Switches
3381 (Data => Data,
3382 Proc => Linker,
3383 Language => Source.Language,
3384 File_Name => Main_Id);
3386 -- Add the switches specified in attribute
3387 -- Linker_Options of packages Linker.
3389 if Link_Options_Switches = null then
3390 Link_Options_Switches :=
3391 new Argument_List'
3392 (Linker_Options_Switches (Main_Project));
3393 end if;
3395 Add_Arguments (Link_Options_Switches.all, True);
3397 -- Add the linking options specified on the
3398 -- command line.
3400 for Arg in 1 .. Linker_Options.Last loop
3401 Add_Argument (Linker_Options.Table (Arg), True);
3402 end loop;
3404 -- If there are shared libraries and the run path
3405 -- option is supported, add the run path switch.
3407 if Lib_Path.Last > 0 then
3408 Add_Argument
3409 (Path_Option.all &
3410 String (Lib_Path.Table (1 .. Lib_Path.Last)),
3411 Verbose_Mode);
3412 end if;
3414 -- And invoke the linker
3416 Display_Command (Linker_Name.all, Linker_Path);
3417 Spawn
3418 (Linker_Path.all,
3419 Arguments (1 .. Last_Argument),
3420 Success);
3422 if not Success then
3423 Report_Error ("could not link ", Main);
3424 end if;
3425 end if;
3426 end Link_Foreign;
3428 -- Start of processing of Link_Executables
3430 begin
3431 -- If no mains specified, get mains from attribute Main, if it exists
3433 if not Mains_Specified then
3434 declare
3435 Element_Id : String_List_Id := Data.Mains;
3436 Element : String_Element;
3438 begin
3439 while Element_Id /= Nil_String loop
3440 Element := String_Elements.Table (Element_Id);
3442 if Element.Value /= No_Name then
3443 Mains.Add_Main (Get_Name_String (Element.Value));
3444 end if;
3446 Element_Id := Element.Next;
3447 end loop;
3448 end;
3449 end if;
3451 if Mains.Number_Of_Mains = 0 then
3453 -- If the attribute Main is an empty list or not specified,
3454 -- there is nothing to do.
3456 if Verbose_Mode then
3457 Write_Line ("No main to link");
3458 end if;
3459 return;
3460 end if;
3462 -- Check if -o was used for several mains
3464 if Output_File_Name /= null and then Mains.Number_Of_Mains > 1 then
3465 Osint.Fail ("cannot specify an executable name for several mains");
3466 end if;
3468 -- Check how we are going to do the link
3470 if not Data.Other_Sources_Present then
3472 -- Only Ada sources in the main project, and even maybe not
3474 if not Data.Languages (Lang_Ada) then
3476 -- Fail if the main project has no source of any language
3478 Osint.Fail
3479 ("project """,
3480 Get_Name_String (Data.Name),
3481 """ has no sources, so no main can be linked");
3483 else
3484 -- Only Ada sources in the main project, call gnatmake directly
3486 Last_Argument := 0;
3488 -- Choose correct linker if there is C++ code in other projects
3490 if C_Plus_Plus_Is_Used then
3491 Choose_C_Plus_Plus_Link_Process;
3492 Add_Argument (Dash_largs, Verbose_Mode);
3493 Add_C_Plus_Plus_Link_For_Gnatmake;
3494 Add_Argument (Dash_margs, Verbose_Mode);
3495 end if;
3497 Compile_Link_With_Gnatmake (Mains_Specified);
3498 end if;
3500 else
3501 -- There are other language sources. First check if there are also
3502 -- sources in Ada.
3504 if Data.Languages (Lang_Ada) then
3506 -- There is a mix of Ada and other language sources in the main
3507 -- project. Any main that is not a source of the other languages
3508 -- will be deemed to be an Ada main.
3510 -- Find the mains of the other languages and the Ada mains.
3512 Mains.Reset;
3513 Ada_Mains.Set_Last (0);
3514 Other_Mains.Set_Last (0);
3516 -- For each main
3518 loop
3519 declare
3520 Main : constant String := Mains.Next_Main;
3521 Main_Id : Name_Id;
3523 begin
3524 exit when Main'Length = 0;
3526 -- Get the main file name
3528 Name_Len := 0;
3529 Add_Str_To_Name_Buffer (Main);
3530 Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len));
3531 Main_Id := Name_Find;
3532 Source_Id := Data.First_Other_Source;
3534 -- Check if it is a source of a language other than Ada
3536 while Source_Id /= No_Other_Source loop
3537 Source := Other_Sources.Table (Source_Id);
3538 exit when Source.File_Name = Main_Id;
3539 Source_Id := Source.Next;
3540 end loop;
3542 -- If it is not, put it in the list of Ada mains
3544 if Source_Id = No_Other_Source then
3545 Ada_Mains.Increment_Last;
3546 Ada_Mains.Table (Ada_Mains.Last) := new String'(Main);
3548 -- Otherwise, put it in the list of other mains
3550 else
3551 Other_Mains.Increment_Last;
3552 Other_Mains.Table (Other_Mains.Last) := Source;
3553 end if;
3554 end;
3555 end loop;
3557 -- If C++ is one of the other language, create the shell script
3558 -- to do the link.
3560 if C_Plus_Plus_Is_Used then
3561 Choose_C_Plus_Plus_Link_Process;
3562 end if;
3564 -- Call gnatmake with the necessary switches for each non-Ada
3565 -- main, if there are some.
3567 for Main in 1 .. Other_Mains.Last loop
3568 declare
3569 Source : constant Other_Source := Other_Mains.Table (Main);
3571 begin
3572 Last_Argument := 0;
3574 -- Add -o if -o was specified
3576 if Output_File_Name = null then
3577 Add_Argument (Dash_o, True);
3578 Add_Argument
3579 (Get_Name_String
3580 (Executable_Of
3581 (Project => Main_Project,
3582 Main => Other_Mains.Table (Main).File_Name,
3583 Index => 0,
3584 Ada_Main => False)),
3585 True);
3586 end if;
3588 -- Call gnatmake with the -B switch
3590 Add_Argument (Dash_B, True);
3592 -- Add to the linking options the object file of the source
3594 Add_Argument (Dash_largs, Verbose_Mode);
3595 Add_Argument
3596 (Get_Name_String (Source.Object_Name), Verbose_Mode);
3598 -- If C++ is one of the language, add the --LINK switch
3599 -- to the linking switches.
3601 if C_Plus_Plus_Is_Used then
3602 Add_C_Plus_Plus_Link_For_Gnatmake;
3603 end if;
3605 -- Add -margs so that the following switches are for
3606 -- gnatmake
3608 Add_Argument (Dash_margs, Verbose_Mode);
3610 -- And link with gnatmake
3612 Compile_Link_With_Gnatmake (Mains_Specified => False);
3613 end;
3614 end loop;
3616 -- If there are also Ada mains, call gnatmake for all these mains
3618 if Ada_Mains.Last /= 0 then
3619 Last_Argument := 0;
3621 -- Put all the Ada mains as the first arguments
3623 for Main in 1 .. Ada_Mains.Last loop
3624 Add_Argument (Ada_Mains.Table (Main).all, True);
3625 end loop;
3627 -- If C++ is one of the languages, add the --LINK switch to
3628 -- the linking switches.
3630 if Data.Languages (Lang_C_Plus_Plus) then
3631 Add_Argument (Dash_largs, Verbose_Mode);
3632 Add_C_Plus_Plus_Link_For_Gnatmake;
3633 Add_Argument (Dash_margs, Verbose_Mode);
3634 end if;
3636 -- And link with gnatmake
3638 Compile_Link_With_Gnatmake (Mains_Specified => False);
3639 end if;
3641 else
3642 -- No Ada source in main project
3644 -- First, get the linker to invoke
3646 if Data.Languages (Lang_C_Plus_Plus) then
3647 Get_Compiler (Lang_C_Plus_Plus);
3648 Linker_Name := Compiler_Names (Lang_C_Plus_Plus);
3649 Linker_Path := Compiler_Paths (Lang_C_Plus_Plus);
3651 else
3652 Get_Compiler (Lang_C);
3653 Linker_Name := Compiler_Names (Lang_C);
3654 Linker_Path := Compiler_Paths (Lang_C);
3655 end if;
3657 Link_Done := False;
3659 Mains.Reset;
3661 -- Get each main, check if it is a source of the main project,
3662 -- and if it is, invoke the linker.
3664 loop
3665 declare
3666 Main : constant String := Mains.Next_Main;
3667 Main_Id : Name_Id;
3668 begin
3669 exit when Main'Length = 0;
3671 -- Get the file name of the main
3673 Name_Len := 0;
3674 Add_Str_To_Name_Buffer (Main);
3675 Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len));
3676 Main_Id := Name_Find;
3677 Source_Id := Data.First_Other_Source;
3679 -- Check if it is a source of the main project file
3681 while Source_Id /= No_Other_Source loop
3682 Source := Other_Sources.Table (Source_Id);
3683 exit when Source.File_Name = Main_Id;
3684 Source_Id := Source.Next;
3685 end loop;
3687 -- Report an error if it is not
3689 if Source_Id = No_Other_Source then
3690 Report_Error
3691 (Main, "is not a source of project ",
3692 Get_Name_String (Data.Name));
3694 else
3695 Link_Foreign (Main, Main_Id, Source);
3696 end if;
3697 end;
3698 end loop;
3700 -- If no linking was done, report it, except in Quiet Output
3702 if (Verbose_Mode or (not Quiet_Output)) and (not Link_Done) then
3703 Osint.Write_Program_Name;
3705 if Mains.Number_Of_Mains = 1 then
3707 -- If there is only one executable, report its name too
3709 Write_Str (": """);
3710 Mains.Reset;
3712 declare
3713 Main : constant String := Mains.Next_Main;
3714 Main_Id : Name_Id;
3715 begin
3716 Name_Len := 0;
3717 Add_Str_To_Name_Buffer (Main);
3718 Main_Id := Name_Find;
3719 Write_Str
3720 (Get_Name_String
3721 (Executable_Of
3722 (Project => Main_Project,
3723 Main => Main_Id,
3724 Index => 0,
3725 Ada_Main => False)));
3726 Write_Line (""" up to date");
3727 end;
3729 else
3730 Write_Line (": all executables up to date");
3731 end if;
3732 end if;
3733 end if;
3734 end if;
3735 end Link_Executables;
3737 ------------------
3738 -- Report_Error --
3739 ------------------
3741 procedure Report_Error
3742 (S1 : String;
3743 S2 : String := "";
3744 S3 : String := "")
3746 begin
3747 -- If Keep_Going is True, output error message preceded by error header
3749 if Keep_Going then
3750 Total_Number_Of_Errors := Total_Number_Of_Errors + 1;
3751 Write_Str (Error_Header);
3752 Write_Str (S1);
3753 Write_Str (S2);
3754 Write_Str (S3);
3755 Write_Eol;
3757 -- Otherwise just fail
3759 else
3760 Osint.Fail (S1, S2, S3);
3761 end if;
3762 end Report_Error;
3764 -------------------------
3765 -- Report_Total_Errors --
3766 -------------------------
3768 procedure Report_Total_Errors (Kind : String) is
3769 begin
3770 if Total_Number_Of_Errors /= 0 then
3771 if Total_Number_Of_Errors = 1 then
3772 Osint.Fail
3773 ("One ", Kind, " error");
3775 else
3776 Osint.Fail
3777 ("Total of" & Total_Number_Of_Errors'Img,
3778 ' ' & Kind & " errors");
3779 end if;
3780 end if;
3781 end Report_Total_Errors;
3783 --------------
3784 -- Scan_Arg --
3785 --------------
3787 procedure Scan_Arg (Arg : String) is
3788 begin
3789 pragma Assert (Arg'First = 1);
3791 if Arg'Length = 0 then
3792 return;
3793 end if;
3795 -- If preceding switch was -P, a project file name need to be
3796 -- specified, not a switch.
3798 if Project_File_Name_Expected then
3799 if Arg (1) = '-' then
3800 Osint.Fail ("project file name missing after -P");
3801 else
3802 Project_File_Name_Expected := False;
3803 Project_File_Name := new String'(Arg);
3804 end if;
3806 -- If preceding switch was -o, an executable name need to be
3807 -- specified, not a switch.
3809 elsif Output_File_Name_Expected then
3810 if Arg (1) = '-' then
3811 Osint.Fail ("output file name missing after -o");
3812 else
3813 Output_File_Name_Expected := False;
3814 Output_File_Name := new String'(Arg);
3815 end if;
3817 -- Set the processor/language for the following switches
3819 -- -c???args: Compiler arguments
3821 elsif Arg'Length >= 6
3822 and then Arg (Arg'First .. Arg'First + 1) = "-c"
3823 and then Arg (Arg'Last - 3 .. Arg'Last) = "args"
3824 then
3825 declare
3826 OK : Boolean := False;
3827 Args_String : constant String :=
3828 Arg (Arg'First + 2 .. Arg'Last - 4);
3830 begin
3831 for Lang in Programming_Language loop
3832 if Args_String = Lang_Args (Lang).all then
3833 OK := True;
3834 Current_Language := Lang;
3835 exit;
3836 end if;
3837 end loop;
3839 if OK then
3840 Current_Processor := Compiler;
3841 else
3842 Osint.Fail ("illegal option """, Arg, """");
3843 end if;
3844 end;
3846 elsif Arg = "-largs" then
3847 Current_Processor := Linker;
3849 -- -gargs: gprmake
3851 elsif Arg = "-gargs" then
3852 Current_Processor := None;
3854 -- A special test is needed for the -o switch within a -largs since
3855 -- that is another way to specify the name of the final executable.
3857 elsif Current_Processor = Linker and then Arg = "-o" then
3858 Osint.Fail
3859 ("switch -o not allowed within a -largs. Use -o directly.");
3861 -- If current processor is not gprmake directly, store the option in
3862 -- the appropriate table.
3864 elsif Current_Processor /= None then
3865 Add_Option (Arg);
3867 -- Switches start with '-'
3869 elsif Arg (1) = '-' then
3870 if Arg = "-c" then
3871 Compile_Only := True;
3873 elsif Arg = "-f" then
3874 Force_Compilations := True;
3876 elsif Arg = "-h" then
3877 Usage;
3879 elsif Arg = "-k" then
3880 Keep_Going := True;
3882 elsif Arg = "-o" then
3883 if Output_File_Name /= null then
3884 Osint.Fail ("cannot specify several -o switches");
3886 else
3887 Output_File_Name_Expected := True;
3888 end if;
3890 elsif Arg'Length >= 2 and then Arg (2) = 'P' then
3891 if Project_File_Name /= null then
3892 Osint.Fail ("cannot have several project files specified");
3894 elsif Arg'Length = 2 then
3895 Project_File_Name_Expected := True;
3897 else
3898 Project_File_Name := new String'(Arg (3 .. Arg'Last));
3899 end if;
3901 elsif Arg = "-q" then
3902 Quiet_Output := True;
3904 elsif Arg = "-u" then
3905 Unique_Compile := True;
3906 Compile_Only := True;
3908 elsif Arg = "-v" then
3909 Verbose_Mode := True;
3910 Copyright;
3912 elsif Arg'Length = 4 and then Arg (1 .. 3) = "-vP"
3913 and then Arg (4) in '0' .. '2'
3914 then
3915 case Arg (4) is
3916 when '0' =>
3917 Current_Verbosity := Prj.Default;
3918 when '1' =>
3919 Current_Verbosity := Prj.Medium;
3920 when '2' =>
3921 Current_Verbosity := Prj.High;
3922 when others =>
3923 null;
3924 end case;
3926 elsif Arg'Length >= 3 and then Arg (2) = 'X'
3927 and then Is_External_Assignment (Arg)
3928 then
3929 -- Is_External_Assignment has side effects when it returns True
3931 -- Record the -X switch, so that they can be passed to gnatmake,
3932 -- if gnatmake is called.
3934 X_Switches.Increment_Last;
3935 X_Switches.Table (X_Switches.Last) := new String'(Arg);
3937 else
3938 Osint.Fail ("illegal option """, Arg, """");
3939 end if;
3941 else
3942 -- Not a switch: must be a main
3944 Mains.Add_Main (Arg);
3945 end if;
3946 end Scan_Arg;
3948 -----------------
3949 -- Strip_CR_LF --
3950 -----------------
3952 function Strip_CR_LF (Text : String) return String is
3953 To : String (1 .. Text'Length);
3954 Index_To : Natural := 0;
3956 begin
3957 for Index in Text'Range loop
3958 if (Text (Index) /= ASCII.CR) and then (Text (Index) /= ASCII.LF) then
3959 Index_To := Index_To + 1;
3960 To (Index_To) := Text (Index);
3961 end if;
3962 end loop;
3964 return To (1 .. Index_To);
3965 end Strip_CR_LF;
3967 -----------
3968 -- Usage --
3969 -----------
3971 procedure Usage is
3972 begin
3973 if not Usage_Output then
3974 Usage_Output := True;
3975 Copyright;
3977 Write_Str ("Usage: ");
3978 Osint.Write_Program_Name;
3979 Write_Str (" -P<project file> [opts] [name] {");
3981 for Lang in Programming_Language loop
3982 Write_Str ("[-c");
3983 Write_Str (Lang_Args (Lang).all);
3984 Write_Str ("args opts] ");
3985 end loop;
3987 Write_Str ("[-largs opts] [-gargs opts]}");
3988 Write_Eol;
3989 Write_Eol;
3990 Write_Str (" name is zero or more file names");
3991 Write_Eol;
3992 Write_Eol;
3994 -- GPRMAKE switches
3996 Write_Str ("gprmake switches:");
3997 Write_Eol;
3999 -- Line for -c
4001 Write_Str (" -c Compile only");
4002 Write_Eol;
4004 -- Line for -f
4006 Write_Str (" -f Force recompilations");
4007 Write_Eol;
4009 -- Line for -k
4011 Write_Str (" -k Keep going after compilation errors");
4012 Write_Eol;
4014 -- Line for -o
4016 Write_Str (" -o name Choose an alternate executable name");
4017 Write_Eol;
4019 -- Line for -P
4021 Write_Str (" -Pproj Use GNAT Project File proj");
4022 Write_Eol;
4024 -- Line for -q
4026 Write_Str (" -q Be quiet/terse");
4027 Write_Eol;
4029 -- Line for -u
4031 Write_Str
4032 (" -u Unique compilation. Only compile the given files");
4033 Write_Eol;
4035 -- Line for -v
4037 Write_Str (" -v Verbose output");
4038 Write_Eol;
4040 -- Line for -vPx
4042 Write_Str (" -vPx Specify verbosity when parsing Project Files");
4043 Write_Eol;
4045 -- Line for -X
4047 Write_Str (" -Xnm=val Specify an external reference for " &
4048 "Project Files");
4049 Write_Eol;
4050 Write_Eol;
4052 -- Lines for -c*args
4054 for Lang in Programming_Language loop
4055 declare
4056 Column : Positive := 13 + Lang_Args (Lang)'Length;
4057 -- " -cargs opts" is the minimum and is 13 character long
4059 begin
4060 Write_Str (" -c");
4061 Write_Str (Lang_Args (Lang).all);
4062 Write_Str ("args opts");
4064 loop
4065 Write_Char (' ');
4066 Column := Column + 1;
4067 exit when Column >= 17;
4068 end loop;
4070 Write_Str ("opts are passed to the ");
4071 Write_Str (Lang_Display_Names (Lang).all);
4072 Write_Str (" compiler");
4073 Write_Eol;
4074 end;
4075 end loop;
4077 -- Line for -largs
4079 Write_Str (" -largs opts opts are passed to the linker");
4080 Write_Eol;
4082 -- Line for -gargs
4084 Write_Str (" -gargs opts opts directly interpreted by gprmake");
4085 Write_Eol;
4086 Write_Eol;
4088 end if;
4089 end Usage;
4091 begin
4092 Makeutl.Do_Fail := Report_Error'Access;
4093 end Makegpr;