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