1------------------------------------------------------------------------------
2--                                                                          --
3--                             GPR TECHNOLOGY                               --
4--                                                                          --
5--                     Copyright (C) 2006-2015, AdaCore                     --
6--                                                                          --
7-- This is  free  software;  you can redistribute it and/or modify it under --
8-- terms of the  GNU  General Public License as published by the Free Soft- --
9-- ware  Foundation;  either version 3,  or (at your option) any later ver- --
10-- sion.  This software is distributed in the hope  that it will be useful, --
11-- but WITHOUT ANY WARRANTY;  without even the implied warranty of MERCHAN- --
12-- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public --
13-- License for more details.  You should have received  a copy of the  GNU  --
14-- General Public License distributed with GNAT; see file  COPYING. If not, --
15-- see <http://www.gnu.org/licenses/>.                                      --
16--                                                                          --
17------------------------------------------------------------------------------
18
19--  This unit is responsible for parsing the gprconfig knowledge base
20
21with Ada.Containers.Doubly_Linked_Lists;
22with Ada.Containers.Indefinite_Doubly_Linked_Lists;
23with Ada.Containers.Indefinite_Hashed_Maps;
24with Ada.Containers.Hashed_Maps;
25with Ada.Containers.Vectors;
26with Ada.Strings.Unbounded;
27
28with GNAT.Regpat;
29
30with GPR; use GPR;
31
32package GprConfig.Knowledge is
33
34   Generate_Error : exception;
35   --  To be raised when an error occurs during generation of config files
36
37   --------------------
38   -- Knowledge base --
39   --------------------
40   --  The following types and subprograms manipulate the knowldge base. This
41   --  base is a set of XML files that describe how to find compilers that are
42   --  installed on the system and that match specific criterias.
43
44   type Knowledge_Base is private;
45
46   function Default_Knowledge_Base_Directory return String;
47   --  Return the default location of the knowledge database. This is based on
48   --  the installation directory of the executable.
49
50   procedure Parse_Knowledge_Base
51     (Base                : in out Knowledge_Base;
52      Directory           : String;
53      Parse_Compiler_Info : Boolean := True;
54      Validate            : Boolean := False);
55   --  Parse info from the knowledge base, and store it in memory.
56   --  Only information relevant to the current host is parsed.
57   --  If Parse_Compiler_Info is False, then only the information about
58   --  target sets is parsed.
59   --  This procedure will raise Invalid_Knowledge_Base if the base contains
60   --  incorrect data.
61   --  If Validate is True, the contents of the knowledge base is first
62   --  validated with an XSD schema.
63
64   Invalid_Knowledge_Base : exception;
65   --  To be raised when an error occurred while parsing the knowledge base
66
67   Knowledge_Base_Validation_Error : exception;
68   --  Some files in the knowledge base are invalid.
69
70   -----------------
71   -- Target sets --
72   -----------------
73   --  One of the information pieces contain in the database is a way to
74   --  normalize target names, since various names are used in different
75   --  contexts thus making it harder to write project files depending on the
76   --  target.
77
78   type Targets_Set_Id is private;
79   --  Identify a target aliases set
80
81   All_Target_Sets     : constant Targets_Set_Id;
82   --  Matches all target sets
83
84   Unknown_Targets_Set : constant Targets_Set_Id;
85   --  Special target set when a target is not known
86
87   function Query_Targets_Set
88     (Base   : Knowledge_Base;
89      Target : String) return Targets_Set_Id;
90   --  Get the target alias set id for a target, or Unknown_Targets_Set if
91   --  no such target is in the base.
92
93   procedure Get_Targets_Set
94     (Base   : in out Knowledge_Base;
95      Target : String;
96      Id     : out Targets_Set_Id);
97   --  Get the target alias set id for a target.  If not already in the base,
98   --  add it.
99
100   function Normalized_Target
101     (Base : Knowledge_Base;
102      Set  : Targets_Set_Id) return String;
103   --  Return the normalized name for a target set
104
105   ---------------
106   -- Compilers --
107   ---------------
108   --  Most of the information in the database relates to compilers. However,
109   --  you do not have direct access to the generic description that explains
110   --  how to find compilers on the PATH and how to compute their attributes
111   --  (version, runtimes,...) Instead, this package gives you access to the
112   --  list of compilers that were found. The package ensures that all
113   --  information is only computed at most once, to save on system calls and
114   --  provide better performance.
115
116   type Compiler is private;
117   type Compiler_Access is access all Compiler;
118
119   function Runtime_Dir_Of (Comp : Compiler_Access) return Name_Id;
120   --  Return the name of the runtime directory for the compiler. Returns
121   --  No_Name if Comp is null.
122
123   package Compiler_Lists
124      is new Ada.Containers.Indefinite_Doubly_Linked_Lists (Compiler_Access);
125   --  A list of compilers
126
127   function Is_Selected (Comp : Compiler) return Boolean;
128   function Target      (Comp : Compiler) return Name_Id;
129
130   procedure Set_Selection
131     (Compilers : in out Compiler_Lists.List;
132      Cursor    : Compiler_Lists.Cursor;
133      Selected  : Boolean);
134   procedure Set_Selection
135     (Comp     : in out Compiler;
136      Selected : Boolean);
137   --  Toggle the selection status of a compiler in the list.
138   --  This does not check that the selection is consistent though (use
139   --  Is_Supported_Config to do this test)
140
141   function To_String
142     (Base            : Knowledge_Base;
143      Comp            : Compiler;
144      As_Config_Arg   : Boolean;
145      Show_Target     : Boolean := False;
146      Rank_In_List    : Integer := -1;
147      Parser_Friendly : Boolean := False) return String;
148   --  Return a string representing the compiler. It is either the --config
149   --  argument (if As_Config_Arg is true) or the string to use in the
150   --  interactive menu otherwise.
151   --  If Rank_In_List is specified, it is written at the beginning of the
152   --  line.
153   --  If Parser_Friendly is set, then the list is displayed in a way that can
154   --  be easily parsed automatically
155
156   function To_String
157     (Base            : Knowledge_Base;
158      Compilers       : Compiler_Lists.List;
159      Selected_Only   : Boolean;
160      Show_Target     : Boolean := False;
161      Parser_Friendly : Boolean := False) return String;
162   --  Return the list of compilers.
163   --  Unselectable compilers are hidden. If Selected_Only is true, then only
164   --  compilers that are currently selected are displayed.
165   --  If Parser_Friendly is set, then the list is displayed in a way that can
166   --  be easily parsed automatically
167
168   function Display_Before (Comp1, Comp2 : Compiler_Access) return Boolean;
169   --  Whether Comp1 should be displayed before Comp2 when displaying lists of
170   --  compilers. This ensures that similar languages are grouped, among othe
171   --  things.
172
173   procedure Filter_Compilers_List
174     (Base           : Knowledge_Base;
175      Compilers      : in out Compiler_Lists.List;
176      For_Target_Set : Targets_Set_Id);
177   --  Based on the currently selected compilers, check which other compilers
178   --  can or cannot be selected by the user.
179   --  This is not the case if the resulting selection in Compilers is not a
180   --  supported config (multiple compilers for the same language, set of
181   --  compilers explicitly marked as unsupported in the knowledge base,...).
182
183   ------------------
184   -- Command line --
185   ------------------
186   --  This package provides support for manipulating the --config command line
187   --  parameters. The intent is that they have the same form in all the tools
188   --  that support it. The information provides to --config might be partial
189   --  only, and this package provides support for completing it automatically
190   --  based on the knowledge base.
191
192   procedure Parse_Config_Parameter
193     (Base              : Knowledge_Base;
194      Config            : String;
195      Compiler          : out Compiler_Access;
196      Requires_Compiler : out Boolean);
197   --  Parse the --config parameter, and store the (partial) information
198   --  found in Compiler.
199   --  When a switch matches a language that requires no compiler,
200   --  Requires_Compiler is set to False.
201   --  Raises Invalid_Config if Config is invalid
202
203   Invalid_Config : exception;
204   --  Raised when the user has specified an invalid --config switch
205
206   procedure Complete_Command_Line_Compilers
207     (Base      : in out Knowledge_Base;
208      On_Target : Targets_Set_Id;
209      Filters   : Compiler_Lists.List;
210      Compilers : in out Compiler_Lists.List);
211   --  In batch mode, the --config parameters indicate what compilers should be
212   --  selected. Each of these switch selects the first matching compiler
213   --  available, and all --config switch must match a compiler.
214   --  The information provided by the user does not have to be complete, and
215   --  this procedure completes all missing information like version, runtime,
216   --  and so on.
217   --  In gprconfig, it should only be called in batch mode, since otherwise
218   --  --config only acts as a filter for the compilers that are found through
219   --  the knowledge base.
220   --  Filters is the list specified by the user as --config, and contains
221   --  potentially partial information for each compiler. On output, Compilers
222   --  is completed with the full information for all compilers in Filters. If
223   --  at least one of the compilers in Filters cannot be found, Invalid_Config
224   --  is raised.
225
226   function Extra_Dirs_From_Filters
227     (Filters : Compiler_Lists.List) return String;
228   --  Compute the list of directories that should be prepended to the PATH
229   --  when searching for compilers. These are all the directories that the
230   --  user has explicitly specified in his filters (aka --config)
231
232   -----------------------------
233   -- knowledge base contents --
234   -----------------------------
235
236   function Hash_Case_Insensitive
237     (Name : Name_Id) return Ada.Containers.Hash_Type;
238   package Variables_Maps is new Ada.Containers.Hashed_Maps
239     (Key_Type        => Name_Id,
240      Element_Type    => Name_Id,
241      Hash            => Hash_Case_Insensitive,
242      Equivalent_Keys => "=",
243      "="             => "=");
244
245   No_Compiler : constant Compiler;
246   --  Describes one of the compilers found on the PATH.
247   --  Path is the directory that contains the compiler executable.
248   --  Path_Order is used for sorting in the interactive menu: it indicates the
249   --  index in $PATH of the directory, so that we can show first the compilers
250   --  that are first in path.
251   --  Any of these compilers can be selected by the user as part of a config.
252   --  However, to prevent incompatibilities, a compiler can be marked as not
253   --  selectable. This will be re-evaluated based on the current selection.
254   --  Complete is set to True if all the information about the compiler was
255   --  computed. It is set to False if the compiler was specified through a
256   --  command line argument --config, and part of the info needs to be
257   --  computed.
258   --  Index_In_List is used for the interactive menu, and is initialized
259   --  automatically.
260
261   type Compiler_Iterator is abstract tagged null record;
262   --  An iterator that searches for all known compilers in a list of
263   --  directories. Whenever a new compiler is found, the Callback primitive
264   --  operation is called.
265
266   procedure Callback
267     (Iterator          : in out Compiler_Iterator;
268      Base              : in out Knowledge_Base;
269      Comp              : Compiler;
270      Runtime_Specified : Boolean;
271      From_Extra_Dir    : Boolean;
272      Continue          : out Boolean) is abstract;
273   --  Called whenever a new compiler is discovered.
274   --  It might be discovered either in a path added through a --config
275   --  parameter (in which case From_Extra_Dir is True), or in a path specified
276   --  in the environment variable $PATH (in which case it is False). If the
277   --  directory is both in Extra_Dirs and in $PATH, From_Extra_Dir is set to
278   --  False.
279   --  If Runtime_Specified is True, only filters with a specified runtime are
280   --
281   --  On exit, Continue should be set to False if there is no need to discover
282   --  further compilers (however there will be no possibility to restart the
283   --  search at the same point later on).
284
285   procedure Foreach_Compiler_In_Path
286     (Iterator   : in out Compiler_Iterator;
287      Base       : in out Knowledge_Base;
288      On_Target  : Targets_Set_Id;
289      Extra_Dirs : String := "");
290   --  Find all compilers in "Extra_Dirs & $PATH".
291   --  Extra_Dirs should typically be the list of directories found in
292   --  --config command line arguments.
293   --  The only filtering done is the target, for optimization purposes (no
294   --  need to computed all info about the compiler if we know it will not be
295   --  uses anyway).
296
297   procedure Known_Compiler_Names
298     (Base : Knowledge_Base;
299      List : out Ada.Strings.Unbounded.Unbounded_String);
300   --  Set List to the comma-separated list of known compilers
301
302   procedure Generate_Configuration
303     (Base        : Knowledge_Base;
304      Compilers   : Compiler_Lists.List;
305      Output_File : String;
306      Target      : String);
307   --  Generate the configuration file for the list of selected compilers
308
309   package String_Lists is
310     new Ada.Containers.Indefinite_Doubly_Linked_Lists (String);
311
312   procedure Put_Verbose (Str : String; Indent_Delta : Integer := 0);
313   --  Print Str if verbose mode is activated.
314   --  Indent_Delta will increase the current indentation level for all further
315   --  traces, which is used to highlight nested calls. Only the sign of
316   --  Indent_Delta is taken into account.
317   --  Nothing is printed if Str is the empty string, only the indentation is
318   --  changed
319
320   function Filter_Match
321     (Base : Knowledge_Base;
322      Comp   : Compiler;
323      Filter : Compiler) return Boolean;
324   --  Returns True if Comp match Filter (the latter corresponds to a --config
325   --  command line argument).
326
327private
328   type Targets_Set_Id is range -1 .. Natural'Last;
329
330   All_Target_Sets     : constant Targets_Set_Id := -1;
331   Unknown_Targets_Set : constant Targets_Set_Id := 0;
332
333   type Compiler is record
334      Name        : Name_Id := No_Name;
335      --  The name of the compiler, as specified in the <name> node of the
336      --  knowledge base. If Compiler represents a filter as defined on through
337      --  --config switch, then name can also be the base name of the
338      --  executable we are looking for. In such a case, it never includes the
339      --  exec suffix (.exe on Windows)
340
341      Executable  : Name_Id := No_Name;
342      Target      : Name_Id := No_Name;
343      Targets_Set : Targets_Set_Id;
344      Path        : Name_Id := No_Name;
345
346      Base_Name   : Name_Id := No_Name;
347      --  Base name of the executable. This does not include the exec suffix
348
349      Version     : Name_Id := No_Name;
350      Variables   : Variables_Maps.Map;
351      Prefix      : Name_Id := No_Name;
352      Runtime     : Name_Id := No_Name;
353      Alt_Runtime : Name_Id := No_Name;
354      Runtime_Dir : Name_Id := No_Name;
355      Path_Order  : Integer;
356
357      Language_Case : Name_Id := No_Name;
358      --  The supported language, with the casing read from the compiler. This
359      --  is for display purposes only
360
361      Language_LC : Name_Id := No_Name;
362      --  The supported language, always lower case
363
364      Selectable   : Boolean := True;
365      Selected     : Boolean := False;
366      Complete     : Boolean := True;
367   end record;
368
369   No_Compiler : constant Compiler :=
370                   (Name          => No_Name,
371                    Target        => No_Name,
372                    Targets_Set   => Unknown_Targets_Set,
373                    Executable    => No_Name,
374                    Base_Name     => No_Name,
375                    Path          => No_Name,
376                    Variables     => Variables_Maps.Empty_Map,
377                    Version       => No_Name,
378                    Prefix        => No_Name,
379                    Runtime       => No_Name,
380                    Alt_Runtime   => No_Name,
381                    Runtime_Dir   => No_Name,
382                    Language_Case => No_Name,
383                    Language_LC   => No_Name,
384                    Selectable    => False,
385                    Selected      => False,
386                    Complete      => True,
387                    Path_Order    => 0);
388
389   type Pattern_Matcher_Access is access all GNAT.Regpat.Pattern_Matcher;
390
391   type External_Value_Type is (Value_Constant,
392                                Value_Shell,
393                                Value_Directory,
394                                Value_Grep,
395                                Value_Nogrep,
396                                Value_Filter,
397                                Value_Must_Match,
398                                Value_Variable,
399                                Value_Done);
400   type External_Value_Node
401     (Typ : External_Value_Type := Value_Constant) is
402      record
403         case Typ is
404            when Value_Constant  =>
405               Value           : Name_Id;
406            when Value_Shell     =>
407               Command         : Name_Id;
408            when Value_Directory  =>
409               Directory       : Name_Id;
410               Directory_Group : Integer;
411               Dir_If_Match    : Name_Id;
412               Contents        : Pattern_Matcher_Access;
413            when Value_Grep       =>
414               Regexp_Re       : Pattern_Matcher_Access;
415               Group           : Natural;
416            when Value_Nogrep     =>
417               Regexp_No       : Pattern_Matcher_Access;
418            when Value_Filter     =>
419               Filter          : Name_Id;
420            when Value_Must_Match =>
421               Must_Match      : Name_Id;
422            when Value_Variable =>
423               Var_Name        : Name_Id;
424            when Value_Done =>
425               null;
426         end case;
427      end record;
428
429   package External_Value_Nodes is
430     new Ada.Containers.Doubly_Linked_Lists (External_Value_Node);
431
432   subtype External_Value is External_Value_Nodes.List;
433
434   Null_External_Value : constant External_Value :=
435                           External_Value_Nodes.Empty_List;
436
437   type Compiler_Description is record
438      Name             : Name_Id := No_Name;
439      Executable       : Name_Id := No_Name;
440      Executable_Re    : Pattern_Matcher_Access;
441      Prefix_Index     : Integer := -1;
442      Target           : External_Value;
443      Version          : External_Value;
444      Variables        : External_Value;
445      Languages        : External_Value;
446      Runtimes         : External_Value;
447      Default_Runtimes : String_Lists.List;
448   end record;
449   --  Executable_Re is only set if the name of the <executable> must be
450   --  taken as a regular expression.
451
452   package Compiler_Description_Maps is new
453     Ada.Containers.Indefinite_Hashed_Maps
454       (Name_Id, Compiler_Description,
455        Hash_Case_Insensitive, "=");
456
457   type Compiler_Filter is record
458      Name        : Name_Id;
459      Version     : Name_Id;
460      Version_Re  : Pattern_Matcher_Access;
461      Runtime     : Name_Id;
462      Runtime_Re  : Pattern_Matcher_Access;
463      Language_LC : Name_Id;
464   end record;
465   --  Representation for a <compiler> node (in <configuration>)
466
467   package Compiler_Filter_Lists is new Ada.Containers.Doubly_Linked_Lists
468     (Compiler_Filter);
469
470   type Compilers_Filter is record
471      Compiler : Compiler_Filter_Lists.List;
472      Negate   : Boolean := False;
473   end record;
474
475   No_Compilers_Filter : constant Compilers_Filter :=
476                           (Compiler => Compiler_Filter_Lists.Empty_List,
477                            Negate   => False);
478   --  a <compilers> filter, that matches if any of its <compiler> child
479   --  matches.
480
481   package Compilers_Filter_Lists is new Ada.Containers.Doubly_Linked_Lists
482     (Compilers_Filter);
483
484   type Configuration is record
485      Compilers_Filters : Compilers_Filter_Lists.List;
486      Targets_Filters   : String_Lists.List;  --  these are regexps
487      Negate_Targets    : Boolean  := False;
488      Config            : Name_Id;
489
490      Supported         : Boolean;
491      --  Whether the combination of compilers is supported
492   end record;
493
494   package Configuration_Lists is new Ada.Containers.Doubly_Linked_Lists
495     (Configuration);
496
497   package Target_Lists is new Ada.Containers.Doubly_Linked_Lists
498     (Pattern_Matcher_Access);
499
500   type Target_Set_Description is record
501      Name     : Name_Id;
502      Patterns : Target_Lists.List;
503   end record;
504
505   subtype Known_Targets_Set_Id
506     is Targets_Set_Id range 1 .. Targets_Set_Id'Last;
507   --  Known targets set.  They are in the base
508
509   package Targets_Set_Vectors is new Ada.Containers.Vectors
510     (Known_Targets_Set_Id, Target_Set_Description, "=");
511
512   type Knowledge_Base is record
513      Compilers               : Compiler_Description_Maps.Map;
514      No_Compilers            : String_Lists.List;
515      Check_Executable_Regexp : Boolean := False;
516      Configurations          : Configuration_Lists.List;
517      Targets_Sets            : Targets_Set_Vectors.Vector;
518   end record;
519   --  Check_Executable_Regexp is set to True if at least some of the
520   --  executable names are specified as regular expressions. In such a case,
521   --  a slightly slower algorithm is used to search for compilers.
522   --  No_Compilers is the list of languages that require no compiler, and thus
523   --  should not be searched on the PATH.
524
525end GprConfig.Knowledge;
526