-- A table to keep dependencies, to be able to decide if an executable
-- is obsolete. More explanation needed ???
--- procedure Add_Dependency (S : File_Name_Type; On : File_Name_Type);
--- -- Add one entry in table Dependencies
-
----------------------------
-- Arguments and Switches --
----------------------------
procedure Process_Multilib (Env : in out Prj.Tree.Environment);
-- Add appropriate --RTS argument to handle multilib
+ procedure Compute_Builder_Switches
+ (Project_Node_Tree : Project_Node_Tree_Ref;
+ Root_Environment : in out Prj.Tree.Environment;
+ Main_Unit_File_Name : String;
+ Main_Index : Int := 0);
+ -- Analyze the root project to find the builder switches and the global
+ -- compilation switches (the latter are ignored if there were multiple main
+ -- on the command line.
+
+ procedure Resolve_Relative_Names_In_Switches (Current_Work_Dir : String);
+ -- Resolve all relative paths found in the linker and binder switches,
+ -- when using project files.
+
+ procedure Queue_Library_Project_Sources;
+ -- For all library project, if the library file does not exist,
+ -- put all the project sources in the queue, and flag the project
+ -- so that the library is generated.
+
+ procedure Compute_Switches_For_Main
+ (Main_Source_File : in out File_Name_Type;
+ Main_Index : Int;
+ Project_Node_Tree : Project_Node_Tree_Ref;
+ Root_Environment : in out Prj.Tree.Environment;
+ Compute_Builder : Boolean;
+ Current_Work_Dir : String);
+ -- Find compiler, binder and linker switches to use for the given main
+
+ procedure Compute_Executable
+ (Main_Source_File : File_Name_Type;
+ Executable : out File_Name_Type;
+ Non_Std_Executable : out Boolean);
+ -- Parse the linker switches and project file to compute the name of the
+ -- executable to generate.
+ -- ??? What is the meaning of Non_Std_Executable
+
+ procedure Compilation_Phase
+ (Main_Source_File : File_Name_Type;
+ Current_Main_Index : Int := 0;
+ Total_Compilation_Failures : in out Natural;
+ Stand_Alone_Libraries : in out Boolean;
+ Executable : File_Name_Type := No_File;
+ Is_Last_Main : Boolean;
+ Stop_Compile : out Boolean);
+ -- Build all source files for a given main file.
+ -- Current_Main_Index, if not zero, the index of the current main unit in
+ -- its source file.
+ -- Stand_Alone_Libraries is set to True when there are Stand-Alone
+ -- Libraries, so that gnatbind is invoked with the -F switch to force
+ -- checking of elaboration flags.
+ -- Stop_Compile is set to true if we should not try to compile any more
+ -- of the main units
+
+ procedure Binding_Phase
+ (Stand_Alone_Libraries : Boolean := False;
+ Main_ALI_File : File_Name_Type);
+ -- Stand_Alone_Libraries should be set to True when there are Stand-Alone
+ -- Libraries, so that gnatbind is invoked with the -F switch to force
+ -- checking of elaboration flags.
+
+ procedure Library_Phase
+ (Stand_Alone_Libraries : in out Boolean;
+ Library_Rebuilt : in out Boolean);
+ -- Build libraries.
+ -- Stand_Alone_Libraries is set to True when there are Stand-Alone
+ -- Libraries, so that gnatbind is invoked with the -F switch to force
+ -- checking of elaboration flags.
+
+ procedure Linking_Phase
+ (Non_Std_Executable : Boolean := False;
+ Executable : File_Name_Type := No_File;
+ Main_ALI_File : File_Name_Type);
+ -- Perform the link of a single executable.
+ -- The ali file corresponding to Main_Source_File.
+ -- Executable is the file name of an executable.
+ -- Non_Std_Executable is set to True when there is a possibility that
+ -- the linker will not choose the correct executable file name.
+
----------------------------------------------------
-- Compiler, Binder & Linker Data and Subprograms --
----------------------------------------------------
end if;
end Globalize;
- --------------
- -- Gnatmake --
- --------------
-
- procedure Gnatmake is
- Main_Source_File : File_Name_Type;
- -- The source file containing the main compilation unit
-
- Compilation_Failures : Natural;
+ -------------------
+ -- Linking_Phase --
+ -------------------
- Total_Compilation_Failures : Natural := 0;
+ procedure Linking_Phase
+ (Non_Std_Executable : Boolean := False;
+ Executable : File_Name_Type := No_File;
+ Main_ALI_File : File_Name_Type)
+ is
+ Linker_Switches_Last : constant Integer := Linker_Switches.Last;
+ Path_Option : constant String_Access :=
+ MLib.Linker_Library_Path_Option;
+ Libraries_Present : Boolean := False;
+ Current : Natural;
+ Proj2 : Project_Id;
+ Depth : Natural;
+ Proj1 : Project_List;
+ begin
+ if not Run_Path_Option then
+ Linker_Switches.Increment_Last;
+ Linker_Switches.Table (Linker_Switches.Last) :=
+ new String'("-R");
+ end if;
- Is_Main_Unit : Boolean;
- -- Set True by Compile_Sources if Main_Source_File can be a main unit
+ if Main_Project /= No_Project then
+ Library_Paths.Set_Last (0);
+ Library_Projs.Init;
- Main_ALI_File : File_Name_Type;
- -- The ali file corresponding to Main_Source_File
+ if MLib.Tgt.Support_For_Libraries /= Prj.None then
- Executable : File_Name_Type := No_File;
- -- The file name of an executable
+ -- Check for library projects
- Non_Std_Executable : Boolean := False;
- -- Non_Std_Executable is set to True when there is a possibility that
- -- the linker will not choose the correct executable file name.
+ Proj1 := Project_Tree.Projects;
+ while Proj1 /= null loop
+ if Proj1.Project /= Main_Project
+ and then Proj1.Project.Library
+ then
+ -- Add this project to table Library_Projs
- Current_Work_Dir : constant String_Access :=
- new String'(Get_Current_Dir);
- -- The current working directory, used to modify some relative path
- -- switches on the command line when a project file is used.
+ Libraries_Present := True;
+ Depth := Proj1.Project.Depth;
+ Library_Projs.Increment_Last;
+ Current := Library_Projs.Last;
- Current_Main_Index : Int := 0;
- -- If not zero, the index of the current main unit in its source file
+ -- Any project with a greater depth should be
+ -- after this project in the list.
- Stand_Alone_Libraries : Boolean := False;
- -- Set to True when there are Stand-Alone Libraries, so that gnatbind
- -- is invoked with the -F switch to force checking of elaboration flags.
+ while Current > 1 loop
+ Proj2 := Library_Projs.Table (Current - 1);
+ exit when Proj2.Depth <= Depth;
+ Library_Projs.Table (Current) := Proj2;
+ Current := Current - 1;
+ end loop;
- Mapping_Path : Path_Name_Type := No_Path;
- -- The path name of the mapping file
+ Library_Projs.Table (Current) := Proj1.Project;
- Project_Node_Tree : Project_Node_Tree_Ref;
- Root_Environment : Prj.Tree.Environment;
+ -- If it is not a static library and path option
+ -- is set, add it to the Library_Paths table.
- Discard : Boolean;
- pragma Warnings (Off, Discard);
+ if Proj1.Project.Library_Kind /= Static
+ and then Proj1.Project.Extended_By = No_Project
+ and then Path_Option /= null
+ then
+ Library_Paths.Increment_Last;
+ Library_Paths.Table (Library_Paths.Last) :=
+ new String'
+ (Get_Name_String
+ (Proj1.Project.Library_Dir.Display_Name));
+ end if;
+ end if;
- procedure Check_Mains;
- -- Check that the main subprograms do exist and that they all
- -- belong to the same project file.
+ Proj1 := Proj1.Next;
+ end loop;
- -----------------
- -- Check_Mains --
- -----------------
+ for Index in 1 .. Library_Projs.Last loop
+ if
+ Library_Projs.Table (Index).Extended_By = No_Project
+ then
+ if Library_Projs.Table (Index).Library_Kind = Static
+ and then not Targparm.OpenVMS_On_Target
+ then
+ Linker_Switches.Increment_Last;
+ Linker_Switches.Table (Linker_Switches.Last) :=
+ new String'
+ (Get_Name_String
+ (Library_Projs.Table
+ (Index).Library_Dir.Display_Name) &
+ "lib" &
+ Get_Name_String
+ (Library_Projs.Table
+ (Index).Library_Name) &
+ "." &
+ MLib.Tgt.Archive_Ext);
- procedure Check_Mains is
- begin
- if Mains.Number_Of_Mains (Project_Tree) = 0
- and then not Unique_Compile
- then
- Mains.Fill_From_Project (Main_Project, Project_Tree);
+ else
+ -- Add the -L switch
+
+ Linker_Switches.Increment_Last;
+ Linker_Switches.Table (Linker_Switches.Last) :=
+ new String'("-L" &
+ Get_Name_String
+ (Library_Projs.Table (Index).
+ Library_Dir.Display_Name));
+
+ -- Add the -l switch
+
+ Linker_Switches.Increment_Last;
+ Linker_Switches.Table (Linker_Switches.Last) :=
+ new String'("-l" &
+ Get_Name_String
+ (Library_Projs.Table (Index).
+ Library_Name));
+ end if;
+ end if;
+ end loop;
end if;
- Mains.Complete_Mains
- (Root_Environment.Flags, Main_Project, Project_Tree);
- end Check_Mains;
+ if Libraries_Present then
- -- Start of processing for Gnatmake
+ -- If Path_Option is not null, create the switch
+ -- ("-Wl,-rpath," or equivalent) with all the non-static
+ -- library dirs plus the standard GNAT library dir.
+ -- We do that only if Run_Path_Option is True
+ -- (not disabled by -R switch).
- -- This body is very long, should be broken down???
+ if Run_Path_Option and then Path_Option /= null then
+ declare
+ Option : String_Access;
+ Length : Natural := Path_Option'Length;
+ Current : Natural;
- begin
- Install_Int_Handler (Sigint_Intercepted'Access);
+ begin
+ if MLib.Separate_Run_Path_Options then
- Do_Compile_Step := True;
- Do_Bind_Step := True;
- Do_Link_Step := True;
+ -- We are going to create one switch of the form
+ -- "-Wl,-rpath,dir_N" for each directory to
+ -- consider.
- Obsoleted.Reset;
+ -- One switch for each library directory
- Make.Initialize (Project_Node_Tree, Root_Environment);
+ for Index in
+ Library_Paths.First .. Library_Paths.Last
+ loop
+ Linker_Switches.Increment_Last;
+ Linker_Switches.Table
+ (Linker_Switches.Last) :=
+ new String'
+ (Path_Option.all &
+ Library_Paths.Table (Index).all);
+ end loop;
- Bind_Shared := No_Shared_Switch'Access;
- Link_With_Shared_Libgcc := No_Shared_Libgcc_Switch'Access;
+ -- One switch for the standard GNAT library dir
- Failed_Links.Set_Last (0);
- Successful_Links.Set_Last (0);
+ Linker_Switches.Increment_Last;
+ Linker_Switches.Table
+ (Linker_Switches.Last) :=
+ new String'
+ (Path_Option.all & MLib.Utl.Lib_Directory);
- -- Special case when switch -B was specified
+ else
+ -- We are going to create one switch of the form
+ -- "-Wl,-rpath,dir_1:dir_2:dir_3"
- if Build_Bind_And_Link_Full_Project then
+ for Index in
+ Library_Paths.First .. Library_Paths.Last
+ loop
+ -- Add the length of the library dir plus one
+ -- for the directory separator.
- -- When switch -B is specified, there must be a project file
+ Length :=
+ Length +
+ Library_Paths.Table (Index)'Length + 1;
+ end loop;
- if Main_Project = No_Project then
- Make_Failed ("-B cannot be used without a project file");
+ -- Finally, add the length of the standard GNAT
+ -- library dir.
- -- No main program may be specified on the command line
+ Length := Length + MLib.Utl.Lib_Directory'Length;
+ Option := new String (1 .. Length);
+ Option (1 .. Path_Option'Length) :=
+ Path_Option.all;
+ Current := Path_Option'Length;
- elsif Osint.Number_Of_Files /= 0 then
- Make_Failed ("-B cannot be used with a main specified on " &
- "the command line");
+ -- Put each library dir followed by a dir
+ -- separator.
- -- And the project file cannot be a library project file
+ for Index in
+ Library_Paths.First .. Library_Paths.Last
+ loop
+ Option
+ (Current + 1 ..
+ Current +
+ Library_Paths.Table (Index)'Length) :=
+ Library_Paths.Table (Index).all;
+ Current :=
+ Current +
+ Library_Paths.Table (Index)'Length + 1;
+ Option (Current) := Path_Separator;
+ end loop;
- elsif Main_Project.Library then
- Make_Failed ("-B cannot be used for a library project file");
+ -- Finally put the standard GNAT library dir
- else
- No_Main_Subprogram := True;
- Insert_Project_Sources
- (The_Project => Main_Project,
- All_Projects => Unique_Compile_All_Projects,
- Into_Q => False);
+ Option
+ (Current + 1 ..
+ Current + MLib.Utl.Lib_Directory'Length) :=
+ MLib.Utl.Lib_Directory;
- -- If there are no sources to compile, we fail
+ -- And add the switch to the linker switches
- if Osint.Number_Of_Files = 0 then
- Make_Failed ("no sources to compile");
+ Linker_Switches.Increment_Last;
+ Linker_Switches.Table (Linker_Switches.Last) :=
+ Option;
+ end if;
+ end;
end if;
- -- Specify -n for gnatbind and add the ALI files of all the
- -- sources, except the one which is a fake main subprogram: this
- -- is the one for the binder generated file and it will be
- -- transmitted to gnatlink. These sources are those that are in
- -- the queue.
+ end if;
- Add_Switch ("-n", Binder, And_Save => True);
+ -- Put the object directories in ADA_OBJECTS_PATH
- for J in 1 .. Queue.Size loop
- Add_Switch
- (Get_Name_String
- (Lib_File_Name (Queue.Element (J))),
- Binder, And_Save => True);
+ Prj.Env.Set_Ada_Paths
+ (Main_Project,
+ Project_Tree,
+ Including_Libraries => False,
+ Include_Path => False);
+
+ -- Check for attributes Linker'Linker_Options in projects
+ -- other than the main project
+
+ declare
+ Linker_Options : constant String_List :=
+ Linker_Options_Switches
+ (Main_Project,
+ Do_Fail => Make_Failed'Access,
+ In_Tree => Project_Tree);
+ begin
+ for Option in Linker_Options'Range loop
+ Linker_Switches.Increment_Last;
+ Linker_Switches.Table (Linker_Switches.Last) :=
+ Linker_Options (Option);
end loop;
- end if;
+ end;
+ end if;
- elsif Main_Index /= 0 and then Osint.Number_Of_Files > 1 then
- Make_Failed ("cannot specify several mains with a multi-unit index");
+ -- Add switch -M to gnatlink if buider switch --create-map-file
+ -- has been specified.
- elsif Main_Project /= No_Project then
+ if Map_File /= null then
+ Linker_Switches.Increment_Last;
+ Linker_Switches.Table (Linker_Switches.Last) :=
+ new String'("-M" & Map_File.all);
+ end if;
- -- If the main project file is a library project file, main(s) cannot
- -- be specified on the command line.
+ declare
+ Args : Argument_List
+ (Linker_Switches.First .. Linker_Switches.Last + 2);
- if Osint.Number_Of_Files /= 0 then
- if Main_Project.Library
- and then not Unique_Compile
- and then ((not Make_Steps) or else Bind_Only or else Link_Only)
+ Last_Arg : Integer := Linker_Switches.First - 1;
+ Skip : Boolean := False;
+
+ begin
+ -- Get all the linker switches
+
+ for J in Linker_Switches.First .. Linker_Switches.Last loop
+ if Skip then
+ Skip := False;
+
+ elsif Non_Std_Executable
+ and then Linker_Switches.Table (J).all = "-o"
then
- Make_Failed ("cannot specify a main program " &
- "on the command line for a library project file");
+ Skip := True;
- else
- -- Check that each main on the command line is a source of a
- -- project file and, if there are several mains, each of them
- -- is a source of the same project file.
+ -- Here we capture and duplicate the linker argument. We
+ -- need to do the duplication since the arguments will
+ -- get normalized. Not doing so will result in calling
+ -- normalized two times for the same set of arguments if
+ -- gnatmake is passed multiple mains. This can result in
+ -- the wrong argument being passed to the linker.
- Check_Mains;
+ else
+ Last_Arg := Last_Arg + 1;
+ Args (Last_Arg) :=
+ new String'(Linker_Switches.Table (J).all);
end if;
+ end loop;
- -- If no mains have been specified on the command line, and we are
- -- using a project file, we either find the main(s) in attribute Main
- -- of the main project, or we put all the sources of the project file
- -- as mains.
+ -- If need be, add the -o switch
- else
- if Main_Index /= 0 then
- Make_Failed ("cannot specify a multi-unit index but no main " &
- "on the command line");
- end if;
+ if Non_Std_Executable then
+ Last_Arg := Last_Arg + 1;
+ Args (Last_Arg) := new String'("-o");
+ Last_Arg := Last_Arg + 1;
+ Args (Last_Arg) := new String'(Get_Name_String (Executable));
+ end if;
- declare
- Value : String_List_Id := Main_Project.Mains;
+ -- And invoke the linker
- begin
- -- The attribute Main is an empty list or not specified, or
- -- else gnatmake was invoked with the switch "-u".
+ declare
+ Success : Boolean := False;
+ begin
+ Link (Main_ALI_File,
+ Link_With_Shared_Libgcc.all &
+ Args (Args'First .. Last_Arg),
+ Success);
+
+ if Success then
+ Successful_Links.Increment_Last;
+ Successful_Links.Table (Successful_Links.Last) :=
+ Main_ALI_File;
+
+ elsif Osint.Number_Of_Files = 1
+ or else not Keep_Going
+ then
+ Make_Failed ("*** link failed.");
- if Value = Prj.Nil_String or else Unique_Compile then
+ else
+ Set_Standard_Error;
+ Write_Line ("*** link failed");
- if (not Make_Steps) or else Compile_Only
- or else not Main_Project.Library
- then
- -- First make sure that the binder and the linker will
- -- not be invoked.
+ if Commands_To_Stdout then
+ Set_Standard_Output;
+ end if;
- Do_Bind_Step := False;
- Do_Link_Step := False;
+ Failed_Links.Increment_Last;
+ Failed_Links.Table (Failed_Links.Last) :=
+ Main_ALI_File;
+ end if;
+ end;
+ end;
- -- Put all the sources in the queue
+ Linker_Switches.Set_Last (Linker_Switches_Last);
+ end Linking_Phase;
- No_Main_Subprogram := True;
- Insert_Project_Sources
- (The_Project => Main_Project,
- All_Projects => Unique_Compile_All_Projects,
- Into_Q => False);
+ -------------------
+ -- Binding_Phase --
+ -------------------
- -- If no sources to compile, then there is nothing to do
+ procedure Binding_Phase
+ (Stand_Alone_Libraries : Boolean := False;
+ Main_ALI_File : File_Name_Type)
+ is
+ Args : Argument_List
+ (Binder_Switches.First .. Binder_Switches.Last + 2);
+ -- The arguments for the invocation of gnatbind
- if Osint.Number_Of_Files = 0 then
- if not Quiet_Output then
- Osint.Write_Program_Name;
- Write_Line (": no sources to compile");
- end if;
+ Last_Arg : Natural := Binder_Switches.Last;
+ -- Index of the last argument in Args
- Finish_Program (Project_Tree, E_Success);
- end if;
- end if;
+ Shared_Libs : Boolean := False;
+ -- Set to True when there are shared library project files or
+ -- when gnatbind is invoked with -shared.
- else
- -- The attribute Main is not an empty list. Put all the main
- -- subprograms in the list as if they were specified on the
- -- command line. However, if attribute Languages includes a
- -- language other than Ada, only include the Ada mains; if
- -- there is no Ada main, compile all sources of the project.
+ Proj : Project_List;
- declare
- Languages : constant Variable_Value :=
- Prj.Util.Value_Of
- (Name_Languages,
- Main_Project.Decl.Attributes,
- Project_Tree.Shared);
+ Mapping_Path : Path_Name_Type := No_Path;
+ -- The path name of the mapping file
- Current : String_List_Id;
- Element : String_Element;
+ begin
+ -- Check if there are shared libraries, so that gnatbind is
+ -- called with -shared. Check also if gnatbind is called with
+ -- -shared, so that gnatlink is called with -shared-libgcc
+ -- ensuring that the shared version of libgcc will be used.
- Foreign_Language : Boolean := False;
- At_Least_One_Main : Boolean := False;
+ if Main_Project /= No_Project
+ and then MLib.Tgt.Support_For_Libraries /= Prj.None
+ then
+ Proj := Project_Tree.Projects;
+ while Proj /= null loop
+ if Proj.Project.Library
+ and then Proj.Project.Library_Kind /= Static
+ then
+ Shared_Libs := True;
+ Bind_Shared := Shared_Switch'Access;
+ exit;
+ end if;
+ Proj := Proj.Next;
+ end loop;
+ end if;
- begin
- -- First, determine if there is a foreign language in
- -- attribute Languages.
+ -- Check now for switch -shared
- if not Languages.Default then
- Current := Languages.Values;
- Look_For_Foreign :
- while Current /= Nil_String loop
- Element := Project_Tree.Shared.String_Elements.
- Table (Current);
- Get_Name_String (Element.Value);
- To_Lower (Name_Buffer (1 .. Name_Len));
+ if not Shared_Libs then
+ for J in Binder_Switches.First .. Last_Arg loop
+ if Binder_Switches.Table (J).all = "-shared" then
+ Shared_Libs := True;
+ exit;
+ end if;
+ end loop;
+ end if;
- if Name_Buffer (1 .. Name_Len) /= "ada" then
- Foreign_Language := True;
- exit Look_For_Foreign;
- end if;
+ -- If shared libraries present, invoke gnatlink with
+ -- -shared-libgcc.
- Current := Element.Next;
- end loop Look_For_Foreign;
- end if;
-
- -- Then, find all mains, or if there is a foreign
- -- language, all the Ada mains.
-
- while Value /= Prj.Nil_String loop
- -- To know if a main is an Ada main, get its project.
- -- It should be the project specified on the command
- -- line.
+ if Shared_Libs then
+ Link_With_Shared_Libgcc := Shared_Libgcc_Switch'Access;
+ end if;
- Get_Name_String
- (Project_Tree.Shared.String_Elements.Table
- (Value).Value);
+ -- Get all the binder switches
- declare
- Main_Name : constant String :=
- Get_Name_String
- (Project_Tree.Shared.String_Elements.Table
- (Value).Value);
- Proj : constant Project_Id :=
- Prj.Env.Project_Of
- (Main_Name, Main_Project, Project_Tree);
- begin
+ for J in Binder_Switches.First .. Last_Arg loop
+ Args (J) := Binder_Switches.Table (J);
+ end loop;
- if Proj = Main_Project then
+ if Stand_Alone_Libraries then
+ Last_Arg := Last_Arg + 1;
+ Args (Last_Arg) := Force_Elab_Flags_String'Access;
+ end if;
- At_Least_One_Main := True;
- Osint.Add_File
- (Get_Name_String
- (Project_Tree.Shared.String_Elements.Table
- (Value).Value),
- Index =>
- Project_Tree.Shared.String_Elements.Table
- (Value).Index);
+ if Main_Project /= No_Project then
- elsif not Foreign_Language then
- Make_Failed
- ("""" & Main_Name &
- """ is not a source of project " &
- Get_Name_String (Main_Project.Display_Name));
- end if;
- end;
+ -- Put all the source directories in ADA_INCLUDE_PATH,
+ -- and all the object directories in ADA_OBJECTS_PATH,
+ -- except those of library projects.
- Value := Project_Tree.Shared.String_Elements.Table
- (Value).Next;
- end loop;
+ Prj.Env.Set_Ada_Paths
+ (Project => Main_Project,
+ In_Tree => Project_Tree,
+ Including_Libraries => False,
+ Include_Path => Use_Include_Path_File);
- -- If we did not get any main, it means that all mains
- -- in attribute Mains are in a foreign language and -B
- -- was not specified to gnatmake; so, we fail.
+ -- If switch -C was specified, create a binder mapping file
- if not At_Least_One_Main then
- Make_Failed
- ("no Ada mains, use -B to build foreign main");
- end if;
- end;
+ if Create_Mapping_File then
+ Mapping_Path := Create_Binder_Mapping_File (Project_Tree);
- end if;
- end;
+ if Mapping_Path /= No_Path then
+ Last_Arg := Last_Arg + 1;
+ Args (Last_Arg) :=
+ new String'("-F=" & Get_Name_String (Mapping_Path));
+ end if;
end if;
- end if;
- if Verbose_Mode then
- Write_Eol;
- Display_Version ("GNATMAKE", "1995");
end if;
- if Osint.Number_Of_Files = 0 then
- if Main_Project /= No_Project
- and then Main_Project.Library
- then
- if Do_Bind_Step
- and then not Main_Project.Standalone_Library
- then
- Make_Failed ("only stand-alone libraries may be bound");
- end if;
-
- -- Add the default search directories to be able to find libgnat
-
- Osint.Add_Default_Search_Dirs;
+ begin
+ Bind (Main_ALI_File,
+ Bind_Shared.all & Args (Args'First .. Last_Arg));
- -- Get the target parameters, so that the correct binder generated
- -- files are generated if OpenVMS is the target.
+ exception
+ when others =>
- begin
- Targparm.Get_Target_Parameters;
+ -- Delete the temporary mapping file if one was created
- exception
- when Unrecoverable_Error =>
- Make_Failed ("*** make failed.");
- end;
+ if Mapping_Path /= No_Path then
+ Delete_Temporary_File
+ (Project_Tree.Shared, Mapping_Path);
+ end if;
- -- And bind and or link the library
+ -- And reraise the exception
- MLib.Prj.Build_Library
- (For_Project => Main_Project,
- In_Tree => Project_Tree,
- Gnatbind => Gnatbind.all,
- Gnatbind_Path => Gnatbind_Path,
- Gcc => Gcc.all,
- Gcc_Path => Gcc_Path,
- Bind => Bind_Only,
- Link => Link_Only);
+ raise;
+ end;
- Finish_Program (Project_Tree, E_Success);
+ -- If -dn was not specified, delete the temporary mapping file
+ -- if one was created.
- else
- -- Call Get_Target_Parameters to ensure that VM_Target and
- -- AAMP_On_Target get set before calling Usage.
+ if Mapping_Path /= No_Path then
+ Delete_Temporary_File (Project_Tree.Shared, Mapping_Path);
+ end if;
+ end Binding_Phase;
- Targparm.Get_Target_Parameters;
+ -------------------
+ -- Library_Phase --
+ -------------------
- -- Output usage information if no files to compile
+ procedure Library_Phase
+ (Stand_Alone_Libraries : in out Boolean;
+ Library_Rebuilt : in out Boolean)
+ is
+ Depth : Natural;
+ Current : Natural;
+ Proj1 : Project_List;
- Usage;
- Finish_Program (Project_Tree, E_Success);
- end if;
- end if;
+ procedure Add_To_Library_Projs (Proj : Project_Id);
+ -- Add project Project to table Library_Projs in
+ -- decreasing depth order.
- -- If -M was specified, behave as if -n was specified
+ --------------------------
+ -- Add_To_Library_Projs --
+ --------------------------
- if List_Dependencies then
- Do_Not_Execute := True;
- end if;
+ procedure Add_To_Library_Projs (Proj : Project_Id) is
+ Prj : Project_Id;
- -- Note that Osint.M.Next_Main_Source will always return the (possibly
- -- abbreviated file) without any directory information.
+ begin
+ Library_Projs.Increment_Last;
+ Depth := Proj.Depth;
+
+ -- Put the projects in decreasing depth order, so that
+ -- if libA depends on libB, libB is first in order.
+
+ Current := Library_Projs.Last;
+ while Current > 1 loop
+ Prj := Library_Projs.Table (Current - 1);
+ exit when Prj.Depth >= Depth;
+ Library_Projs.Table (Current) := Prj;
+ Current := Current - 1;
+ end loop;
- Main_Source_File := Next_Main_Source;
+ Library_Projs.Table (Current) := Proj;
+ end Add_To_Library_Projs;
- if Current_File_Index /= No_Index then
- Main_Index := Current_File_Index;
- end if;
+ begin
+ Library_Projs.Init;
- Add_Switch ("-I-", Compiler, And_Save => True);
+ -- Put in Library_Projs table all library project file
+ -- ids when the library need to be rebuilt.
- if Main_Project = No_Project then
- if Look_In_Primary_Dir then
+ Proj1 := Project_Tree.Projects;
+ while Proj1 /= null loop
+ if Proj1.Project.Extended_By = No_Project then
+ if Proj1.Project.Standalone_Library then
+ Stand_Alone_Libraries := True;
+ end if;
- Add_Switch
- ("-I" &
- Normalize_Directory_Name
- (Get_Primary_Src_Search_Directory.all).all,
- Compiler, Append_Switch => False,
- And_Save => False);
+ if Proj1.Project.Library then
+ MLib.Prj.Check_Library
+ (Proj1.Project, Project_Tree);
+ end if;
+ if Proj1.Project.Need_To_Build_Lib then
+ Add_To_Library_Projs (Proj1.Project);
+ end if;
end if;
- else
- -- If we use a project file, we have already checked that a main
- -- specified on the command line with directory information has the
- -- path name corresponding to a correct source in the project tree.
- -- So, we don't need the directory information to be taken into
- -- account by Find_File, and in fact it may lead to take the wrong
- -- sources for other compilation units, when there are extending
- -- projects.
-
- Look_In_Primary_Dir := False;
- Add_Switch ("-I-", Binder, And_Save => True);
- end if;
+ Proj1 := Proj1.Next;
+ end loop;
- -- If the user wants a program without a main subprogram, add the
- -- appropriate switch to the binder.
+ -- Check if importing libraries should be regenerated
+ -- because at least an imported library will be
+ -- regenerated or is more recent.
+
+ Proj1 := Project_Tree.Projects;
+ while Proj1 /= null loop
+ if Proj1.Project.Library
+ and then Proj1.Project.Extended_By = No_Project
+ and then Proj1.Project.Library_Kind /= Static
+ and then not Proj1.Project.Need_To_Build_Lib
+ and then not Proj1.Project.Externally_Built
+ then
+ declare
+ List : Project_List;
+ Proj2 : Project_Id;
+ Rebuild : Boolean := False;
- if No_Main_Subprogram then
- Add_Switch ("-z", Binder, And_Save => True);
- end if;
+ Lib_Timestamp1 : constant Time_Stamp_Type :=
+ Proj1.Project.Library_TS;
- if Main_Project /= No_Project then
+ begin
+ List := Proj1.Project.All_Imported_Projects;
+ while List /= null loop
+ Proj2 := List.Project;
+
+ if Proj2.Library then
+ if Proj2.Need_To_Build_Lib
+ or else
+ (Lib_Timestamp1 < Proj2.Library_TS)
+ then
+ Rebuild := True;
+ exit;
+ end if;
+ end if;
- if Main_Project.Object_Directory /= No_Path_Information then
- -- Change current directory to object directory of main project
+ List := List.Next;
+ end loop;
- Project_Of_Current_Object_Directory := No_Project;
- Change_To_Object_Directory (Main_Project);
+ if Rebuild then
+ Proj1.Project.Need_To_Build_Lib := True;
+ Add_To_Library_Projs (Proj1.Project);
+ end if;
+ end;
end if;
- -- Source file lookups should be cached for efficiency.
- -- Source files are not supposed to change.
-
- Osint.Source_File_Data (Cache => True);
+ Proj1 := Proj1.Next;
+ end loop;
- -- Find the file name of the (first) main unit
+ -- Reset the flags Need_To_Build_Lib for the next main,
+ -- to avoid rebuilding libraries uselessly.
- declare
- Main_Source_File_Name : constant String :=
- Get_Name_String (Main_Source_File);
- Main_Unit_File_Name : constant String :=
- Prj.Env.File_Name_Of_Library_Unit_Body
- (Name => Main_Source_File_Name,
- Project => Main_Project,
- In_Tree => Project_Tree,
- Main_Project_Only =>
- not Unique_Compile);
-
- The_Packages : constant Package_Id :=
- Main_Project.Decl.Packages;
-
- Builder_Package : constant Prj.Package_Id :=
- Prj.Util.Value_Of
- (Name => Name_Builder,
- In_Packages => The_Packages,
- Shared => Project_Tree.Shared);
+ Proj1 := Project_Tree.Projects;
+ while Proj1 /= null loop
+ Proj1.Project.Need_To_Build_Lib := False;
+ Proj1 := Proj1.Next;
+ end loop;
- Binder_Package : constant Prj.Package_Id :=
- Prj.Util.Value_Of
- (Name => Name_Binder,
- In_Packages => The_Packages,
- Shared => Project_Tree.Shared);
+ -- Build the libraries, if any need to be built
- Linker_Package : constant Prj.Package_Id :=
- Prj.Util.Value_Of
- (Name => Name_Linker,
- In_Packages => The_Packages,
- Shared => Project_Tree.Shared);
+ for J in 1 .. Library_Projs.Last loop
+ Library_Rebuilt := True;
- Default_Switches_Array : Array_Id;
+ -- If a library is rebuilt, then executables are obsolete
- Global_Compilation_Array : Array_Element_Id;
- Global_Compilation_Elem : Array_Element;
- Global_Compilation_Switches : Variable_Value;
+ Executable_Obsolete := True;
- begin
- -- We fail if we cannot find the main source file
+ MLib.Prj.Build_Library
+ (For_Project => Library_Projs.Table (J),
+ In_Tree => Project_Tree,
+ Gnatbind => Gnatbind.all,
+ Gnatbind_Path => Gnatbind_Path,
+ Gcc => Gcc.all,
+ Gcc_Path => Gcc_Path);
+ end loop;
+ end Library_Phase;
- if Main_Unit_File_Name = "" then
- Make_Failed ('"' & Main_Source_File_Name
- & """ is not a unit of project "
- & Project_File_Name.all & ".");
- else
- -- Remove any directory information from the main source file
- -- file name.
+ -----------------------
+ -- Compilation_Phase --
+ -----------------------
- declare
- Pos : Natural := Main_Unit_File_Name'Last;
+ procedure Compilation_Phase
+ (Main_Source_File : File_Name_Type;
+ Current_Main_Index : Int := 0;
+ Total_Compilation_Failures : in out Natural;
+ Stand_Alone_Libraries : in out Boolean;
+ Executable : File_Name_Type := No_File;
+ Is_Last_Main : Boolean;
+ Stop_Compile : out Boolean)
+ is
+ Args : Argument_List (1 .. Gcc_Switches.Last);
- begin
- loop
- exit when Pos < Main_Unit_File_Name'First or else
- Main_Unit_File_Name (Pos) = Directory_Separator;
- Pos := Pos - 1;
- end loop;
+ First_Compiled_File : File_Name_Type;
+ Youngest_Obj_File : File_Name_Type;
+ Youngest_Obj_Stamp : Time_Stamp_Type;
- Name_Len := Main_Unit_File_Name'Last - Pos;
+ Is_Main_Unit : Boolean;
+ -- Set True by Compile_Sources if Main_Source_File can be a main unit
- Name_Buffer (1 .. Name_Len) :=
- Main_Unit_File_Name
- (Pos + 1 .. Main_Unit_File_Name'Last);
+ Compilation_Failures : Natural;
- Main_Source_File := Name_Find;
+ Executable_Stamp : Time_Stamp_Type;
- -- We only output the main source file if there is only one
+ Library_Rebuilt : Boolean := False;
- if Verbose_Mode and then Osint.Number_Of_Files = 1 then
- Write_Str ("Main source file: """);
- Write_Str (Main_Unit_File_Name
- (Pos + 1 .. Main_Unit_File_Name'Last));
- Write_Line (""".");
- end if;
- end;
- end if;
+ begin
+ Stop_Compile := False;
- -- If there is a package Builder in the main project file, add
- -- the switches from it.
+ for J in 1 .. Gcc_Switches.Last loop
+ Args (J) := Gcc_Switches.Table (J);
+ end loop;
- if Builder_Package /= No_Package then
+ -- Now we invoke Compile_Sources for the current main
+
+ Compile_Sources
+ (Main_Source => Main_Source_File,
+ Args => Args,
+ First_Compiled_File => First_Compiled_File,
+ Most_Recent_Obj_File => Youngest_Obj_File,
+ Most_Recent_Obj_Stamp => Youngest_Obj_Stamp,
+ Main_Unit => Is_Main_Unit,
+ Main_Index => Current_Main_Index,
+ Compilation_Failures => Compilation_Failures,
+ Check_Readonly_Files => Check_Readonly_Files,
+ Do_Not_Execute => Do_Not_Execute,
+ Force_Compilations => Force_Compilations,
+ In_Place_Mode => In_Place_Mode,
+ Keep_Going => Keep_Going,
+ Initialize_ALI_Data => True,
+ Max_Process => Saved_Maximum_Processes);
- Global_Compilation_Array := Prj.Util.Value_Of
- (Name => Name_Global_Compilation_Switches,
- In_Arrays => Project_Tree.Shared.Packages.Table
- (Builder_Package).Decl.Arrays,
- Shared => Project_Tree.Shared);
+ if Verbose_Mode then
+ Write_Str ("End of compilation");
+ Write_Eol;
+ end if;
- Default_Switches_Array :=
- Project_Tree.Shared.Packages.Table
- (Builder_Package).Decl.Arrays;
+ Total_Compilation_Failures :=
+ Total_Compilation_Failures + Compilation_Failures;
- while Default_Switches_Array /= No_Array and then
- Project_Tree.Shared.Arrays.Table (Default_Switches_Array).Name
- /= Name_Default_Switches
- loop
- Default_Switches_Array := Project_Tree.Shared.Arrays.Table
- (Default_Switches_Array).Next;
- end loop;
+ if Total_Compilation_Failures /= 0 then
+ Stop_Compile := True;
+ return;
+ end if;
- if Global_Compilation_Array /= No_Array_Element and then
- Default_Switches_Array /= No_Array
- then
- Errutil.Error_Msg
- ("Default_Switches forbidden in presence of " &
- "Global_Compilation_Switches. Use Switches instead.",
- Project_Tree.Shared.Arrays.Table
- (Default_Switches_Array).Location);
- Make_Failed
- ("*** illegal combination of Builder attributes");
- end if;
+ -- Regenerate libraries, if there are any and if object files
+ -- have been regenerated.
- -- If there is only one main, we attempt to get the gnatmake
- -- switches for this main (if any). If there are no specific
- -- switch for this particular main, get the general gnatmake
- -- switches (if any).
+ if Main_Project /= No_Project
+ and then MLib.Tgt.Support_For_Libraries /= Prj.None
+ and then (Do_Bind_Step
+ or Unique_Compile_All_Projects
+ or not Compile_Only)
+ and then (Do_Link_Step or else Is_Last_Main)
+ then
+ Library_Phase
+ (Stand_Alone_Libraries => Stand_Alone_Libraries,
+ Library_Rebuilt => Library_Rebuilt);
+ end if;
- if Osint.Number_Of_Files = 1 then
- if Verbose_Mode then
- Write_Str ("Adding gnatmake switches for """);
- Write_Str (Main_Unit_File_Name);
- Write_Line (""".");
- end if;
+ if List_Dependencies then
+ if First_Compiled_File /= No_File then
+ Inform
+ (First_Compiled_File,
+ "must be recompiled. Can't generate dependence list.");
+ else
+ List_Depend;
+ end if;
- Add_Switches
- (Project_Node_Tree => Project_Node_Tree,
- Env => Root_Environment,
- File_Name => Main_Unit_File_Name,
- Index => Main_Index,
- The_Package => Builder_Package,
- Program => None,
- Unknown_Switches_To_The_Compiler =>
- Global_Compilation_Array = No_Array_Element);
+ elsif First_Compiled_File = No_File
+ and then not Do_Bind_Step
+ and then not Quiet_Output
+ and then not Library_Rebuilt
+ and then Osint.Number_Of_Files = 1
+ then
+ Inform (Msg => "objects up to date.");
- else
- -- If there are several mains, we always get the general
- -- gnatmake switches (if any).
+ elsif Do_Not_Execute
+ and then First_Compiled_File /= No_File
+ then
+ Write_Name (First_Compiled_File);
+ Write_Eol;
+ end if;
- -- Warn the user, if necessary, so that he is not surprised
- -- that specific switches are not taken into account.
+ -- Stop after compile step if any of:
- declare
- Defaults : constant Variable_Value :=
- Prj.Util.Value_Of
- (Name => Name_Ada,
- Index => 0,
- Attribute_Or_Array_Name =>
- Name_Default_Switches,
- In_Package =>
- Builder_Package,
- Shared => Project_Tree.Shared);
-
- Switches : constant Array_Element_Id :=
- Prj.Util.Value_Of
- (Name => Name_Switches,
- In_Arrays =>
- Project_Tree.Shared.Packages.Table
- (Builder_Package).Decl.Arrays,
- Shared => Project_Tree.Shared);
-
- Other_Switches : constant Variable_Value :=
- Prj.Util.Value_Of
- (Name => All_Other_Names,
- Index => 0,
- Attribute_Or_Array_Name
- => Name_Switches,
- In_Package => Builder_Package,
- Shared => Project_Tree.Shared);
+ -- 1) -n (Do_Not_Execute) specified
- begin
- if Other_Switches /= Nil_Variable_Value then
- if not Quiet_Output
- and then Switches /= No_Array_Element
- and then Project_Tree.Shared.Array_Elements.Table
- (Switches).Next /= No_Array_Element
- then
- Write_Line
- ("Warning: using Builder'Switches(others), "
- & "as there are several mains");
- end if;
+ -- 2) -M (List_Dependencies) specified (also sets
+ -- Do_Not_Execute above, so this is probably superfluous).
- Add_Switches
- (Project_Node_Tree => Project_Node_Tree,
- Env => Root_Environment,
- File_Name => " ",
- Index => 0,
- The_Package => Builder_Package,
- Program => None,
- Unknown_Switches_To_The_Compiler => False);
-
- elsif Defaults /= Nil_Variable_Value then
- if not Quiet_Output
- and then Switches /= No_Array_Element
- then
- Write_Line
- ("Warning: using Builder'Default_Switches"
- & "(""Ada""), as there are several mains");
- end if;
+ -- 3) -c (Compile_Only) specified, but not -b (Bind_Only)
- Add_Switches
- (Project_Node_Tree => Project_Node_Tree,
- Env => Root_Environment,
- File_Name => " ",
- Index => 0,
- The_Package => Builder_Package,
- Program => None);
+ -- 4) Made unit cannot be a main unit
- elsif not Quiet_Output
- and then Switches /= No_Array_Element
- then
- Write_Line
- ("Warning: using no switches from package "
- & "Builder, as there are several mains");
- end if;
- end;
- end if;
+ if ((Do_Not_Execute
+ or List_Dependencies
+ or not Do_Bind_Step
+ or not Is_Main_Unit)
+ and then not No_Main_Subprogram
+ and then not Build_Bind_And_Link_Full_Project)
+ or else Unique_Compile
+ then
+ Stop_Compile := True;
+ return;
+ end if;
- -- Take into account attribute Global_Compilation_Switches
- -- ("Ada").
+ -- If the objects were up-to-date check if the executable file
+ -- is also up-to-date. For now always bind and link on the JVM
+ -- since there is currently no simple way to check whether
+ -- objects are up-to-date.
- declare
- Index : Name_Id;
- List : String_List_Id;
- Elem : String_Element;
+ if Targparm.VM_Target /= JVM_Target
+ and then First_Compiled_File = No_File
+ then
+ Executable_Stamp := File_Stamp (Executable);
- begin
- while Global_Compilation_Array /= No_Array_Element loop
- Global_Compilation_Elem :=
- Project_Tree.Shared.Array_Elements.Table
- (Global_Compilation_Array);
+ if not Executable_Obsolete then
+ Executable_Obsolete :=
+ Youngest_Obj_Stamp > Executable_Stamp;
+ end if;
- Get_Name_String (Global_Compilation_Elem.Index);
- To_Lower (Name_Buffer (1 .. Name_Len));
- Index := Name_Find;
+ if not Executable_Obsolete then
+ for Index in reverse 1 .. Dependencies.Last loop
+ if Is_In_Obsoleted
+ (Dependencies.Table (Index).Depends_On)
+ then
+ Enter_Into_Obsoleted
+ (Dependencies.Table (Index).This);
+ end if;
+ end loop;
- if Index = Name_Ada then
- Global_Compilation_Switches :=
- Global_Compilation_Elem.Value;
+ Executable_Obsolete := Is_In_Obsoleted (Main_Source_File);
+ Dependencies.Init;
+ end if;
- if Global_Compilation_Switches /= Nil_Variable_Value
- and then not Global_Compilation_Switches.Default
- then
- -- We have found attribute
- -- Global_Compilation_Switches ("Ada"): put the
- -- switches in the appropriate table.
-
- List := Global_Compilation_Switches.Values;
-
- while List /= Nil_String loop
- Elem :=
- Project_Tree.Shared.String_Elements.Table
- (List);
-
- if Elem.Value /= No_Name then
- Add_Switch
- (Get_Name_String (Elem.Value),
- Compiler,
- And_Save => False);
- end if;
+ if not Executable_Obsolete then
- List := Elem.Next;
- end loop;
+ -- If no Ada object files obsolete the executable, check
+ -- for younger or missing linker files.
- exit;
- end if;
- end if;
+ Check_Linker_Options
+ (Executable_Stamp,
+ Youngest_Obj_File,
+ Youngest_Obj_Stamp);
- Global_Compilation_Array := Global_Compilation_Elem.Next;
- end loop;
- end;
- end if;
+ Executable_Obsolete := Youngest_Obj_File /= No_File;
+ end if;
- Osint.Add_Default_Search_Dirs;
+ -- Check if any library file is more recent than the
+ -- executable: there may be an externally built library
+ -- file that has been modified.
- -- Record the current last switch index for table Binder_Switches
- -- and Linker_Switches, so that these tables may be reset before
- -- for each main, before adding switches from the project file
- -- and from the command line.
+ if not Executable_Obsolete
+ and then Main_Project /= No_Project
+ then
+ declare
+ Proj1 : Project_List;
- Last_Binder_Switch := Binder_Switches.Last;
- Last_Linker_Switch := Linker_Switches.Last;
-
- Check_Steps;
+ begin
+ Proj1 := Project_Tree.Projects;
+ while Proj1 /= null loop
+ if Proj1.Project.Library
+ and then
+ Proj1.Project.Library_TS > Executable_Stamp
+ then
+ Executable_Obsolete := True;
+ Youngest_Obj_Stamp := Proj1.Project.Library_TS;
+ Name_Len := 0;
+ Add_Str_To_Name_Buffer ("library ");
+ Add_Str_To_Name_Buffer
+ (Get_Name_String (Proj1.Project.Library_Name));
+ Youngest_Obj_File := Name_Find;
+ exit;
+ end if;
- -- Add binder switches from the project file for the first main
+ Proj1 := Proj1.Next;
+ end loop;
+ end;
+ end if;
- if Do_Bind_Step and then Binder_Package /= No_Package then
- if Verbose_Mode then
- Write_Str ("Adding binder switches for """);
- Write_Str (Main_Unit_File_Name);
- Write_Line (""".");
- end if;
+ -- Return if the executable is up to date and otherwise
+ -- motivate the relink/rebind.
- Add_Switches
- (Project_Node_Tree => Project_Node_Tree,
- Env => Root_Environment,
- File_Name => Main_Unit_File_Name,
- Index => Main_Index,
- The_Package => Binder_Package,
- Program => Binder);
+ if not Executable_Obsolete then
+ if not Quiet_Output then
+ Inform (Executable, "up to date.");
end if;
- -- Add linker switches from the project file for the first main
-
- if Do_Link_Step and then Linker_Package /= No_Package then
- if Verbose_Mode then
- Write_Str ("Adding linker switches for""");
- Write_Str (Main_Unit_File_Name);
- Write_Line (""".");
- end if;
+ Stop_Compile := True;
+ return;
+ end if;
- Add_Switches
- (Project_Node_Tree => Project_Node_Tree,
- Env => Root_Environment,
- File_Name => Main_Unit_File_Name,
- Index => Main_Index,
- The_Package => Linker_Package,
- Program => Linker);
+ if Executable_Stamp (1) = ' ' then
+ if not No_Main_Subprogram then
+ Verbose_Msg (Executable, "missing.", Prefix => " ");
end if;
- end;
- end if;
- -- The combination of -f -u and one or several mains on the command line
- -- implies -a.
+ elsif Youngest_Obj_Stamp (1) = ' ' then
+ Verbose_Msg
+ (Youngest_Obj_File, "missing.", Prefix => " ");
- if Force_Compilations
- and then Unique_Compile
- and then not Unique_Compile_All_Projects
- and then Main_On_Command_Line
- then
- Must_Compile := True;
- end if;
+ elsif Youngest_Obj_Stamp > Executable_Stamp then
+ Verbose_Msg
+ (Youngest_Obj_File,
+ "(" & String (Youngest_Obj_Stamp) & ") newer than",
+ Executable,
+ "(" & String (Executable_Stamp) & ")");
- if Main_Project /= No_Project
- and then not Must_Compile
- and then Main_Project.Externally_Built
- then
- Make_Failed
- ("nothing to do for a main project that is externally built");
- end if;
+ else
+ Verbose_Msg
+ (Executable, "needs to be rebuilt", Prefix => " ");
- -- Get the target parameters, which are only needed for a couple of
- -- cases in gnatmake. Protect against an exception, such as the case of
- -- system.ads missing from the library, and fail gracefully.
+ end if;
+ end if;
+ end Compilation_Phase;
- begin
- Targparm.Get_Target_Parameters;
- exception
- when Unrecoverable_Error =>
- Make_Failed ("*** make failed.");
- end;
+ ------------------------------
+ -- Compute_Builder_Switches --
+ ------------------------------
- -- Special processing for VM targets
+ procedure Compute_Builder_Switches
+ (Project_Node_Tree : Project_Node_Tree_Ref;
+ Root_Environment : in out Prj.Tree.Environment;
+ Main_Unit_File_Name : String;
+ Main_Index : Int := 0)
+ is
+ Builder_Package : constant Prj.Package_Id :=
+ Prj.Util.Value_Of
+ (Name => Name_Builder,
+ In_Packages => Main_Project.Decl.Packages,
+ Shared => Project_Tree.Shared);
- if Targparm.VM_Target /= No_VM then
+ Global_Compilation_Array : Array_Element_Id;
+ Global_Compilation_Elem : Array_Element;
+ Global_Compilation_Switches : Variable_Value;
- -- Set proper processing commands
+ Default_Switches_Array : Array_Id;
- case Targparm.VM_Target is
- when Targparm.JVM_Target =>
+ begin
- -- Do not check for an object file (".o") when compiling to
- -- JVM machine since ".class" files are generated instead.
+ -- If there is a package Builder in the main project file, add
+ -- the switches from it.
- Check_Object_Consistency := False;
- Gcc := new String'("jvm-gnatcompile");
+ if Builder_Package /= No_Package then
+ Global_Compilation_Array := Prj.Util.Value_Of
+ (Name => Name_Global_Compilation_Switches,
+ In_Arrays => Project_Tree.Shared.Packages.Table
+ (Builder_Package).Decl.Arrays,
+ Shared => Project_Tree.Shared);
- when Targparm.CLI_Target =>
- Gcc := new String'("dotnet-gnatcompile");
+ Default_Switches_Array :=
+ Project_Tree.Shared.Packages.Table (Builder_Package).Decl.Arrays;
- when Targparm.No_VM =>
- raise Program_Error;
- end case;
- end if;
+ while Default_Switches_Array /= No_Array and then
+ Project_Tree.Shared.Arrays.Table (Default_Switches_Array).Name
+ /= Name_Default_Switches
+ loop
+ Default_Switches_Array := Project_Tree.Shared.Arrays.Table
+ (Default_Switches_Array).Next;
+ end loop;
- Display_Commands (not Quiet_Output);
+ if Global_Compilation_Array /= No_Array_Element and then
+ Default_Switches_Array /= No_Array
+ then
+ Errutil.Error_Msg
+ ("Default_Switches forbidden in presence of " &
+ "Global_Compilation_Switches. Use Switches instead.",
+ Project_Tree.Shared.Arrays.Table
+ (Default_Switches_Array).Location);
+ Make_Failed ("*** illegal combination of Builder attributes");
+ end if;
- Check_Steps;
+ -- If there is only one main, we attempt to get the gnatmake
+ -- switches for this main (if any). If there are no specific
+ -- switch for this particular main, get the general gnatmake
+ -- switches (if any).
- if Main_Project /= No_Project then
+ if Osint.Number_Of_Files = 1 then
+ if Verbose_Mode then
+ Write_Str ("Adding gnatmake switches for """);
+ Write_Str (Main_Unit_File_Name);
+ Write_Line (""".");
+ end if;
- -- For all library project, if the library file does not exist, put
- -- all the project sources in the queue, and flag the project so that
- -- the library is generated.
+ Add_Switches
+ (Project_Node_Tree => Project_Node_Tree,
+ Env => Root_Environment,
+ File_Name => Main_Unit_File_Name,
+ Index => Main_Index,
+ The_Package => Builder_Package,
+ Program => None,
+ Unknown_Switches_To_The_Compiler =>
+ Global_Compilation_Array = No_Array_Element);
- if not Unique_Compile
- and then MLib.Tgt.Support_For_Libraries /= Prj.None
- then
- declare
- Proj : Project_List;
+ else
+ -- If there are several mains, we always get the general
+ -- gnatmake switches (if any).
- begin
- Proj := Project_Tree.Projects;
- while Proj /= null loop
- if Proj.Project.Library then
- Proj.Project.Need_To_Build_Lib :=
- not MLib.Tgt.Library_Exists_For
- (Proj.Project, Project_Tree)
- and then not Proj.Project.Externally_Built;
+ -- Warn the user, if necessary, so that he is not surprised
+ -- that specific switches are not taken into account.
- if Proj.Project.Need_To_Build_Lib then
+ declare
+ Defaults : constant Variable_Value :=
+ Prj.Util.Value_Of
+ (Name => Name_Ada,
+ Index => 0,
+ Attribute_Or_Array_Name =>
+ Name_Default_Switches,
+ In_Package =>
+ Builder_Package,
+ Shared => Project_Tree.Shared);
+
+ Switches : constant Array_Element_Id :=
+ Prj.Util.Value_Of
+ (Name => Name_Switches,
+ In_Arrays =>
+ Project_Tree.Shared.Packages.Table
+ (Builder_Package).Decl.Arrays,
+ Shared => Project_Tree.Shared);
- -- If there is no object directory, then it will be
- -- impossible to build the library. So fail
- -- immediately.
+ Other_Switches : constant Variable_Value :=
+ Prj.Util.Value_Of
+ (Name => All_Other_Names,
+ Index => 0,
+ Attribute_Or_Array_Name
+ => Name_Switches,
+ In_Package => Builder_Package,
+ Shared => Project_Tree.Shared);
- if
- Proj.Project.Object_Directory = No_Path_Information
- then
- Make_Failed
- ("no object files to build library for project """
- & Get_Name_String (Proj.Project.Name)
- & """");
- Proj.Project.Need_To_Build_Lib := False;
+ begin
+ if Other_Switches /= Nil_Variable_Value then
+ if not Quiet_Output
+ and then Switches /= No_Array_Element
+ and then Project_Tree.Shared.Array_Elements.Table
+ (Switches).Next /= No_Array_Element
+ then
+ Write_Line
+ ("Warning: using Builder'Switches(others), "
+ & "as there are several mains");
+ end if;
- else
- if Verbose_Mode then
- Write_Str
- ("Library file does not exist for project """);
- Write_Str (Get_Name_String (Proj.Project.Name));
- Write_Line ("""");
- end if;
+ Add_Switches
+ (Project_Node_Tree => Project_Node_Tree,
+ Env => Root_Environment,
+ File_Name => " ",
+ Index => 0,
+ The_Package => Builder_Package,
+ Program => None,
+ Unknown_Switches_To_The_Compiler => False);
- Insert_Project_Sources
- (The_Project => Proj.Project,
- All_Projects => False,
- Into_Q => True);
- end if;
- end if;
+ elsif Defaults /= Nil_Variable_Value then
+ if not Quiet_Output
+ and then Switches /= No_Array_Element
+ then
+ Write_Line
+ ("Warning: using Builder'Default_Switches"
+ & "(""Ada""), as there are several mains");
end if;
- Proj := Proj.Next;
- end loop;
+ Add_Switches
+ (Project_Node_Tree => Project_Node_Tree,
+ Env => Root_Environment,
+ File_Name => " ",
+ Index => 0,
+ The_Package => Builder_Package,
+ Program => None);
+
+ elsif not Quiet_Output
+ and then Switches /= No_Array_Element
+ then
+ Write_Line
+ ("Warning: using no switches from package "
+ & "Builder, as there are several mains");
+ end if;
end;
end if;
- -- If a relative path output file has been specified, we add the
- -- exec directory.
-
- for J in reverse 1 .. Saved_Linker_Switches.Last - 1 loop
- if Saved_Linker_Switches.Table (J).all = Output_Flag.all then
- declare
- Exec_File_Name : constant String :=
- Saved_Linker_Switches.Table (J + 1).all;
-
- begin
- if not Is_Absolute_Path (Exec_File_Name) then
- Get_Name_String
- (Main_Project.Exec_Directory.Display_Name);
- Add_Str_To_Name_Buffer (Exec_File_Name);
- Saved_Linker_Switches.Table (J + 1) :=
- new String'(Name_Buffer (1 .. Name_Len));
- end if;
- end;
-
- exit;
- end if;
- end loop;
-
- -- If we are using a project file, for relative paths we add the
- -- current working directory for any relative path on the command
- -- line and the project directory, for any relative path in the
- -- project file.
+ -- Take into account attribute Global_Compilation_Switches
+ -- ("Ada").
declare
- Dir_Path : constant String :=
- Get_Name_String (Main_Project.Directory.Display_Name);
+ Index : Name_Id;
+ List : String_List_Id;
+ Elem : String_Element;
+
begin
- for J in 1 .. Binder_Switches.Last loop
- Test_If_Relative_Path
- (Binder_Switches.Table (J),
- Do_Fail => Make_Failed'Access,
- Parent => Dir_Path, Including_L_Switch => False);
- end loop;
+ while Global_Compilation_Array /= No_Array_Element loop
+ Global_Compilation_Elem :=
+ Project_Tree.Shared.Array_Elements.Table
+ (Global_Compilation_Array);
- for J in 1 .. Saved_Binder_Switches.Last loop
- Test_If_Relative_Path
- (Saved_Binder_Switches.Table (J),
- Do_Fail => Make_Failed'Access,
- Parent => Current_Work_Dir.all, Including_L_Switch => False);
- end loop;
+ Get_Name_String (Global_Compilation_Elem.Index);
+ To_Lower (Name_Buffer (1 .. Name_Len));
+ Index := Name_Find;
- for J in 1 .. Linker_Switches.Last loop
- Test_If_Relative_Path
- (Linker_Switches.Table (J), Parent => Dir_Path,
- Do_Fail => Make_Failed'Access);
- end loop;
+ if Index = Name_Ada then
+ Global_Compilation_Switches := Global_Compilation_Elem.Value;
- for J in 1 .. Saved_Linker_Switches.Last loop
- Test_If_Relative_Path
- (Saved_Linker_Switches.Table (J),
- Do_Fail => Make_Failed'Access,
- Parent => Current_Work_Dir.all);
- end loop;
+ if Global_Compilation_Switches /= Nil_Variable_Value
+ and then not Global_Compilation_Switches.Default
+ then
+ -- We have found attribute
+ -- Global_Compilation_Switches ("Ada"): put the
+ -- switches in the appropriate table.
+
+ List := Global_Compilation_Switches.Values;
+
+ while List /= Nil_String loop
+ Elem :=
+ Project_Tree.Shared.String_Elements.Table
+ (List);
+
+ if Elem.Value /= No_Name then
+ Add_Switch
+ (Get_Name_String (Elem.Value),
+ Compiler,
+ And_Save => False);
+ end if;
- for J in 1 .. Gcc_Switches.Last loop
- Test_If_Relative_Path
- (Gcc_Switches.Table (J),
- Do_Fail => Make_Failed'Access,
- Parent => Dir_Path,
- Including_Non_Switch => False);
- end loop;
+ List := Elem.Next;
+ end loop;
+
+ exit;
+ end if;
+ end if;
- for J in 1 .. Saved_Gcc_Switches.Last loop
- Test_If_Relative_Path
- (Saved_Gcc_Switches.Table (J),
- Parent => Current_Work_Dir.all,
- Do_Fail => Make_Failed'Access,
- Including_Non_Switch => False);
+ Global_Compilation_Array := Global_Compilation_Elem.Next;
end loop;
end;
end if;
+ end Compute_Builder_Switches;
- -- We now put in the Binder_Switches and Linker_Switches tables, the
- -- binder and linker switches of the command line that have been put in
- -- the Saved_ tables. If a project file was used, then the command line
- -- switches will follow the project file switches.
+ ----------------------------------------
+ -- Resolve_Relative_Names_In_Switches --
+ ----------------------------------------
- for J in 1 .. Saved_Binder_Switches.Last loop
- Add_Switch
- (Saved_Binder_Switches.Table (J),
- Binder,
- And_Save => False);
- end loop;
+ procedure Resolve_Relative_Names_In_Switches (Current_Work_Dir : String) is
+ begin
+ -- If a relative path output file has been specified, we add the
+ -- exec directory.
- for J in 1 .. Saved_Linker_Switches.Last loop
- Add_Switch
- (Saved_Linker_Switches.Table (J),
- Linker,
- And_Save => False);
+ for J in reverse 1 .. Saved_Linker_Switches.Last - 1 loop
+ if Saved_Linker_Switches.Table (J).all = Output_Flag.all then
+ declare
+ Exec_File_Name : constant String :=
+ Saved_Linker_Switches.Table (J + 1).all;
+
+ begin
+ if not Is_Absolute_Path (Exec_File_Name) then
+ Get_Name_String
+ (Main_Project.Exec_Directory.Display_Name);
+ Add_Str_To_Name_Buffer (Exec_File_Name);
+ Saved_Linker_Switches.Table (J + 1) :=
+ new String'(Name_Buffer (1 .. Name_Len));
+ end if;
+ end;
+
+ exit;
+ end if;
end loop;
- -- If no project file is used, we just put the gcc switches
- -- from the command line in the Gcc_Switches table.
+ -- If we are using a project file, for relative paths we add the
+ -- current working directory for any relative path on the command
+ -- line and the project directory, for any relative path in the
+ -- project file.
- if Main_Project = No_Project then
- for J in 1 .. Saved_Gcc_Switches.Last loop
- Add_Switch
- (Saved_Gcc_Switches.Table (J), Compiler, And_Save => False);
+ declare
+ Dir_Path : constant String :=
+ Get_Name_String (Main_Project.Directory.Display_Name);
+ begin
+ for J in 1 .. Binder_Switches.Last loop
+ Test_If_Relative_Path
+ (Binder_Switches.Table (J),
+ Do_Fail => Make_Failed'Access,
+ Parent => Dir_Path, Including_L_Switch => False);
end loop;
- else
- -- If there is a project, put the command line gcc switches in the
- -- variable The_Saved_Gcc_Switches. They are going to be used later
- -- in procedure Compile_Sources.
+ for J in 1 .. Saved_Binder_Switches.Last loop
+ Test_If_Relative_Path
+ (Saved_Binder_Switches.Table (J),
+ Do_Fail => Make_Failed'Access,
+ Parent => Current_Work_Dir,
+ Including_L_Switch => False);
+ end loop;
- The_Saved_Gcc_Switches :=
- new Argument_List (1 .. Saved_Gcc_Switches.Last + 1);
+ for J in 1 .. Linker_Switches.Last loop
+ Test_If_Relative_Path
+ (Linker_Switches.Table (J), Parent => Dir_Path,
+ Do_Fail => Make_Failed'Access);
+ end loop;
+
+ for J in 1 .. Saved_Linker_Switches.Last loop
+ Test_If_Relative_Path
+ (Saved_Linker_Switches.Table (J),
+ Do_Fail => Make_Failed'Access,
+ Parent => Current_Work_Dir);
+ end loop;
+
+ for J in 1 .. Gcc_Switches.Last loop
+ Test_If_Relative_Path
+ (Gcc_Switches.Table (J),
+ Do_Fail => Make_Failed'Access,
+ Parent => Dir_Path,
+ Including_Non_Switch => False);
+ end loop;
for J in 1 .. Saved_Gcc_Switches.Last loop
- The_Saved_Gcc_Switches (J) := Saved_Gcc_Switches.Table (J);
+ Test_If_Relative_Path
+ (Saved_Gcc_Switches.Table (J),
+ Parent => Current_Work_Dir,
+ Do_Fail => Make_Failed'Access,
+ Including_Non_Switch => False);
end loop;
+ end;
+ end Resolve_Relative_Names_In_Switches;
- -- We never use gnat.adc when a project file is used
+ -----------------------------------
+ -- Queue_Library_Project_Sources --
+ -----------------------------------
- The_Saved_Gcc_Switches (The_Saved_Gcc_Switches'Last) := No_gnat_adc;
- end if;
+ procedure Queue_Library_Project_Sources is
+ begin
+ if not Unique_Compile
+ and then MLib.Tgt.Support_For_Libraries /= Prj.None
+ then
+ declare
+ Proj : Project_List;
- -- If there was a --GCC, --GNATBIND or --GNATLINK switch on the command
- -- line, then we have to use it, even if there was another switch in
- -- the project file.
+ begin
+ Proj := Project_Tree.Projects;
+ while Proj /= null loop
+ if Proj.Project.Library then
+ Proj.Project.Need_To_Build_Lib :=
+ not MLib.Tgt.Library_Exists_For
+ (Proj.Project, Project_Tree)
+ and then not Proj.Project.Externally_Built;
+
+ if Proj.Project.Need_To_Build_Lib then
+
+ -- If there is no object directory, then it will be
+ -- impossible to build the library. So fail
+ -- immediately.
+
+ if Proj.Project.Object_Directory =
+ No_Path_Information
+ then
+ Make_Failed
+ ("no object files to build library for"
+ & " project """
+ & Get_Name_String (Proj.Project.Name)
+ & """");
+ Proj.Project.Need_To_Build_Lib := False;
- if Saved_Gcc /= null then
- Gcc := Saved_Gcc;
- end if;
+ else
+ if Verbose_Mode then
+ Write_Str
+ ("Library file does not exist for "
+ & "project """);
+ Write_Str
+ (Get_Name_String (Proj.Project.Name));
+ Write_Line ("""");
+ end if;
- if Saved_Gnatbind /= null then
- Gnatbind := Saved_Gnatbind;
- end if;
+ Insert_Project_Sources
+ (The_Project => Proj.Project,
+ All_Projects => False,
+ Into_Q => True);
+ end if;
+ end if;
+ end if;
- if Saved_Gnatlink /= null then
- Gnatlink := Saved_Gnatlink;
+ Proj := Proj.Next;
+ end loop;
+ end;
end if;
+ end Queue_Library_Project_Sources;
- Gcc_Path := GNAT.OS_Lib.Locate_Exec_On_Path (Gcc.all);
- Gnatbind_Path := GNAT.OS_Lib.Locate_Exec_On_Path (Gnatbind.all);
- Gnatlink_Path := GNAT.OS_Lib.Locate_Exec_On_Path (Gnatlink.all);
+ ------------------------
+ -- Compute_Executable --
+ ------------------------
- -- If we have specified -j switch both from the project file
- -- and on the command line, the one from the command line takes
- -- precedence.
+ procedure Compute_Executable
+ (Main_Source_File : File_Name_Type;
+ Executable : out File_Name_Type;
+ Non_Std_Executable : out Boolean)
+ is
+ begin
+ Executable := No_File;
+ Non_Std_Executable :=
+ Targparm.Executable_Extension_On_Target /= No_Name;
- if Saved_Maximum_Processes = 0 then
- Saved_Maximum_Processes := Maximum_Processes;
- end if;
+ -- Look inside the linker switches to see if the name of the final
+ -- executable program was specified.
- if Debug.Debug_Flag_M then
- Write_Line ("Maximum number of simultaneous compilations =" &
- Saved_Maximum_Processes'Img);
- end if;
+ for J in reverse Linker_Switches.First .. Linker_Switches.Last loop
+ if Linker_Switches.Table (J).all = Output_Flag.all then
+ pragma Assert (J < Linker_Switches.Last);
- -- Allocate as many temporary mapping file names as the maximum number
- -- of compilations processed, for each possible project.
+ -- We cannot specify a single executable for several main
+ -- subprograms
- declare
- Data : Project_Compilation_Access;
- Proj : Project_List := Project_Tree.Projects;
- begin
- while Proj /= null loop
- Data := new Project_Compilation_Data'
- (Mapping_File_Names => new Temp_Path_Names
- (1 .. Saved_Maximum_Processes),
- Last_Mapping_File_Names => 0,
- Free_Mapping_File_Indexes => new Free_File_Indexes
- (1 .. Saved_Maximum_Processes),
- Last_Free_Indexes => 0);
+ if Osint.Number_Of_Files > 1 then
+ Fail ("cannot specify a single executable for several mains");
+ end if;
- Project_Compilation_Htable.Set
- (Project_Compilation, Proj.Project, Data);
- Proj := Proj.Next;
- end loop;
-
- Data := new Project_Compilation_Data'
- (Mapping_File_Names => new Temp_Path_Names
- (1 .. Saved_Maximum_Processes),
- Last_Mapping_File_Names => 0,
- Free_Mapping_File_Indexes => new Free_File_Indexes
- (1 .. Saved_Maximum_Processes),
- Last_Free_Indexes => 0);
+ Name_Len := 0;
+ Add_Str_To_Name_Buffer (Linker_Switches.Table (J + 1).all);
+ Executable := Name_Enter;
- Project_Compilation_Htable.Set
- (Project_Compilation, No_Project, Data);
- end;
+ Verbose_Msg (Executable, "final executable");
+ end if;
+ end loop;
- Bad_Compilation.Init;
+ -- If the name of the final executable program was not specified then
+ -- construct it from the main input file.
- -- If project files are used, create the mapping of all the sources, so
- -- that the correct paths will be found. Otherwise, if there is a file
- -- which is not a source with the same name in a source directory this
- -- file may be incorrectly found.
+ if Executable = No_File then
+ if Main_Project = No_Project then
+ Executable := Executable_Name (Strip_Suffix (Main_Source_File));
- if Main_Project /= No_Project then
- Prj.Env.Create_Mapping (Project_Tree);
+ else
+ -- If we are using a project file, we attempt to remove the
+ -- body (or spec) termination of the main subprogram. We find
+ -- it the naming scheme of the project file. This avoids
+ -- generating an executable "main.2" for a main subprogram
+ -- "main.2.ada", when the body termination is ".2.ada".
+
+ Executable :=
+ Prj.Util.Executable_Of
+ (Main_Project, Project_Tree.Shared,
+ Main_Source_File, Main_Index);
+ end if;
end if;
- Current_Main_Index := Main_Index;
+ if Main_Project /= No_Project
+ and then Main_Project.Exec_Directory /= No_Path_Information
+ then
+ declare
+ Exec_File_Name : constant String := Get_Name_String (Executable);
+ begin
+ if not Is_Absolute_Path (Exec_File_Name) then
+ Get_Name_String (Main_Project.Exec_Directory.Display_Name);
+ Add_Str_To_Name_Buffer (Exec_File_Name);
+ Executable := Name_Find;
+ end if;
+
+ Non_Std_Executable := True;
+ end;
+ end if;
+ end Compute_Executable;
- -- Here is where the make process is started
+ -------------------------------
+ -- Compute_Switches_For_Main --
+ -------------------------------
- -- We do the same process for each main
+ procedure Compute_Switches_For_Main
+ (Main_Source_File : in out File_Name_Type;
+ Main_Index : Int;
+ Project_Node_Tree : Project_Node_Tree_Ref;
+ Root_Environment : in out Prj.Tree.Environment;
+ Compute_Builder : Boolean;
+ Current_Work_Dir : String)
+ is
+ begin
+ if Main_Project /= No_Project then
+ declare
+ Main_Source_File_Name : constant String :=
+ Get_Name_String (Main_Source_File);
- Multiple_Main_Loop : for N_File in 1 .. Osint.Number_Of_Files loop
+ Main_Unit_File_Name : constant String :=
+ Prj.Env.File_Name_Of_Library_Unit_Body
+ (Name => Main_Source_File_Name,
+ Project => Main_Project,
+ In_Tree => Project_Tree,
+ Main_Project_Only =>
+ not Unique_Compile);
- -- First, find the executable name and path
+ The_Packages : constant Package_Id := Main_Project.Decl.Packages;
- Executable := No_File;
- Executable_Obsolete := False;
- Non_Std_Executable :=
- Targparm.Executable_Extension_On_Target /= No_Name;
+ Binder_Package : constant Prj.Package_Id :=
+ Prj.Util.Value_Of
+ (Name => Name_Binder,
+ In_Packages => The_Packages,
+ Shared => Project_Tree.Shared);
- -- Look inside the linker switches to see if the name of the final
- -- executable program was specified.
+ Linker_Package : constant Prj.Package_Id :=
+ Prj.Util.Value_Of
+ (Name => Name_Linker,
+ In_Packages => The_Packages,
+ Shared => Project_Tree.Shared);
- for J in reverse Linker_Switches.First .. Linker_Switches.Last loop
- if Linker_Switches.Table (J).all = Output_Flag.all then
- pragma Assert (J < Linker_Switches.Last);
+ begin
+ -- We fail if we cannot find the main source file
- -- We cannot specify a single executable for several main
- -- subprograms
+ if Main_Unit_File_Name = "" then
+ Make_Failed ('"' & Main_Source_File_Name
+ & """ is not a unit of project "
+ & Project_File_Name.all & ".");
+ end if;
- if Osint.Number_Of_Files > 1 then
- Fail
- ("cannot specify a single executable for several mains");
- end if;
+ -- Remove any directory information from the main source file
+ -- file name.
- Name_Len := 0;
- Add_Str_To_Name_Buffer (Linker_Switches.Table (J + 1).all);
- Executable := Name_Enter;
+ declare
+ Pos : Natural := Main_Unit_File_Name'Last;
- Verbose_Msg (Executable, "final executable");
- end if;
- end loop;
+ begin
+ loop
+ exit when Pos < Main_Unit_File_Name'First
+ or else Main_Unit_File_Name (Pos) = Directory_Separator;
+ Pos := Pos - 1;
+ end loop;
- -- If the name of the final executable program was not specified then
- -- construct it from the main input file.
+ Name_Len := Main_Unit_File_Name'Last - Pos;
- if Executable = No_File then
- if Main_Project = No_Project then
- Executable := Executable_Name (Strip_Suffix (Main_Source_File));
+ Name_Buffer (1 .. Name_Len) :=
+ Main_Unit_File_Name (Pos + 1 .. Main_Unit_File_Name'Last);
- else
- -- If we are using a project file, we attempt to remove the
- -- body (or spec) termination of the main subprogram. We find
- -- it the naming scheme of the project file. This avoids
- -- generating an executable "main.2" for a main subprogram
- -- "main.2.ada", when the body termination is ".2.ada".
-
- Executable :=
- Prj.Util.Executable_Of
- (Main_Project, Project_Tree.Shared,
- Main_Source_File, Main_Index);
- end if;
- end if;
+ Main_Source_File := Name_Find;
- if Main_Project /= No_Project
- and then Main_Project.Exec_Directory /= No_Path_Information
- then
- declare
- Exec_File_Name : constant String :=
- Get_Name_String (Executable);
+ -- We only output the main source file if there is only one
- begin
- if not Is_Absolute_Path (Exec_File_Name) then
- Get_Name_String (Main_Project.Exec_Directory.Display_Name);
- Add_Str_To_Name_Buffer (Exec_File_Name);
- Executable := Name_Find;
+ if Verbose_Mode and then Osint.Number_Of_Files = 1 then
+ Write_Str ("Main source file: """);
+ Write_Str (Main_Unit_File_Name
+ (Pos + 1 .. Main_Unit_File_Name'Last));
+ Write_Line (""".");
end if;
-
- Non_Std_Executable := True;
end;
- end if;
- if Do_Compile_Step then
- Recursive_Compilation_Step : declare
- Args : Argument_List (1 .. Gcc_Switches.Last);
+ if Compute_Builder then
+ Compute_Builder_Switches
+ (Project_Node_Tree => Project_Node_Tree,
+ Root_Environment => Root_Environment,
+ Main_Unit_File_Name => Main_Unit_File_Name,
+ Main_Index => Main_Index);
- First_Compiled_File : File_Name_Type;
- Youngest_Obj_File : File_Name_Type;
- Youngest_Obj_Stamp : Time_Stamp_Type;
+ Resolve_Relative_Names_In_Switches
+ (Current_Work_Dir => Current_Work_Dir);
- Executable_Stamp : Time_Stamp_Type;
- -- Executable is the final executable program
- -- ??? comment seems unrelated to declaration
+ -- Record the current last switch index for table
+ -- Binder_Switches and Linker_Switches, so that these tables
+ -- may be reset before each main, before adding switches from
+ -- the project file and from the command line.
- Library_Rebuilt : Boolean := False;
+ Last_Binder_Switch := Binder_Switches.Last;
+ Last_Linker_Switch := Linker_Switches.Last;
- begin
- for J in 1 .. Gcc_Switches.Last loop
- Args (J) := Gcc_Switches.Table (J);
- end loop;
+ else
+ -- Reset the tables Binder_Switches and Linker_Switches
+ Binder_Switches.Set_Last (Last_Binder_Switch);
+ Linker_Switches.Set_Last (Last_Linker_Switch);
+ end if;
- Queue.Initialize
- (Main_Project /= No_Project and then
- One_Compilation_Per_Obj_Dir);
-
- -- Now we invoke Compile_Sources for the current main
-
- Compile_Sources
- (Main_Source => Main_Source_File,
- Args => Args,
- First_Compiled_File => First_Compiled_File,
- Most_Recent_Obj_File => Youngest_Obj_File,
- Most_Recent_Obj_Stamp => Youngest_Obj_Stamp,
- Main_Unit => Is_Main_Unit,
- Main_Index => Current_Main_Index,
- Compilation_Failures => Compilation_Failures,
- Check_Readonly_Files => Check_Readonly_Files,
- Do_Not_Execute => Do_Not_Execute,
- Force_Compilations => Force_Compilations,
- In_Place_Mode => In_Place_Mode,
- Keep_Going => Keep_Going,
- Initialize_ALI_Data => True,
- Max_Process => Saved_Maximum_Processes);
+ -- We now deal with the binder and linker switches.
+ -- If no project file is used, there is nothing to do
+ -- because the binder and linker switches are the same
+ -- for all mains.
+ -- Add binder switches from the project file for the first main
+
+ if Do_Bind_Step and then Binder_Package /= No_Package then
if Verbose_Mode then
- Write_Str ("End of compilation");
- Write_Eol;
+ Write_Str ("Adding binder switches for """);
+ Write_Str (Main_Unit_File_Name);
+ Write_Line (""".");
end if;
- Total_Compilation_Failures :=
- Total_Compilation_Failures + Compilation_Failures;
+ Add_Switches
+ (Project_Node_Tree => Project_Node_Tree,
+ Env => Root_Environment,
+ File_Name => Main_Unit_File_Name,
+ Index => Main_Index,
+ The_Package => Binder_Package,
+ Program => Binder);
+ end if;
- if Total_Compilation_Failures /= 0 then
- if Keep_Going then
- goto Next_Main;
+ -- Add linker switches from the project file for the first main
- else
- List_Bad_Compilations;
- Report_Compilation_Failed;
- end if;
+ if Do_Link_Step and then Linker_Package /= No_Package then
+ if Verbose_Mode then
+ Write_Str ("Adding linker switches for""");
+ Write_Str (Main_Unit_File_Name);
+ Write_Line (""".");
end if;
- -- Regenerate libraries, if there are any and if object files
- -- have been regenerated.
-
- if Main_Project /= No_Project
- and then MLib.Tgt.Support_For_Libraries /= Prj.None
- and then (Do_Bind_Step
- or Unique_Compile_All_Projects
- or not Compile_Only)
- and then (Do_Link_Step or else N_File = Osint.Number_Of_Files)
- then
- Library_Projs.Init;
-
- declare
- Depth : Natural;
- Current : Natural;
- Proj1 : Project_List;
-
- procedure Add_To_Library_Projs (Proj : Project_Id);
- -- Add project Project to table Library_Projs in
- -- decreasing depth order.
+ Add_Switches
+ (Project_Node_Tree => Project_Node_Tree,
+ Env => Root_Environment,
+ File_Name => Main_Unit_File_Name,
+ Index => Main_Index,
+ The_Package => Linker_Package,
+ Program => Linker);
+ end if;
- --------------------------
- -- Add_To_Library_Projs --
- --------------------------
+ -- As we are using a project file, for relative paths we add
+ -- the current working directory for any relative path on
+ -- the command line and the project directory, for any
+ -- relative path in the project file.
- procedure Add_To_Library_Projs (Proj : Project_Id) is
- Prj : Project_Id;
+ declare
+ Dir_Path : constant String :=
+ Get_Name_String (Main_Project.Directory.Display_Name);
+ begin
+ for J in Last_Binder_Switch + 1 .. Binder_Switches.Last loop
+ Test_If_Relative_Path
+ (Binder_Switches.Table (J),
+ Do_Fail => Make_Failed'Access,
+ Parent => Dir_Path, Including_L_Switch => False);
+ end loop;
- begin
- Library_Projs.Increment_Last;
- Depth := Proj.Depth;
-
- -- Put the projects in decreasing depth order, so that
- -- if libA depends on libB, libB is first in order.
-
- Current := Library_Projs.Last;
- while Current > 1 loop
- Prj := Library_Projs.Table (Current - 1);
- exit when Prj.Depth >= Depth;
- Library_Projs.Table (Current) := Prj;
- Current := Current - 1;
- end loop;
+ for J in Last_Linker_Switch + 1 .. Linker_Switches.Last loop
+ Test_If_Relative_Path
+ (Linker_Switches.Table (J),
+ Parent => Dir_Path,
+ Do_Fail => Make_Failed'Access);
+ end loop;
+ end;
+ end;
- Library_Projs.Table (Current) := Proj;
- end Add_To_Library_Projs;
+ else
+ if not Compute_Builder then
+ -- Reset the tables Binder_Switches and Linker_Switches
+ Binder_Switches.Set_Last (Last_Binder_Switch);
+ Linker_Switches.Set_Last (Last_Linker_Switch);
+ end if;
+ end if;
- -- Start of processing for ??? (should name declare block
- -- or probably better, break this out as a nested proc).
+ Check_Steps;
- begin
- -- Put in Library_Projs table all library project file
- -- ids when the library need to be rebuilt.
-
- Proj1 := Project_Tree.Projects;
- while Proj1 /= null loop
- if Proj1.Project.Extended_By = No_Project then
- if Proj1.Project.Standalone_Library then
- Stand_Alone_Libraries := True;
- end if;
+ if Compute_Builder then
+ Display_Commands (not Quiet_Output);
+ end if;
- if Proj1.Project.Library then
- MLib.Prj.Check_Library
- (Proj1.Project, Project_Tree);
- end if;
+ -- We now put in the Binder_Switches and Linker_Switches tables,
+ -- the binder and linker switches of the command line that have
+ -- been put in the Saved_ tables. If a project file was used, then
+ -- the command line switches will follow the project file
+ -- switches.
- if Proj1.Project.Need_To_Build_Lib then
- Add_To_Library_Projs (Proj1.Project);
- end if;
- end if;
+ for J in 1 .. Saved_Binder_Switches.Last loop
+ Add_Switch
+ (Saved_Binder_Switches.Table (J),
+ Binder,
+ And_Save => False);
+ end loop;
- Proj1 := Proj1.Next;
- end loop;
+ for J in 1 .. Saved_Linker_Switches.Last loop
+ Add_Switch
+ (Saved_Linker_Switches.Table (J),
+ Linker,
+ And_Save => False);
+ end loop;
+ end Compute_Switches_For_Main;
- -- Check if importing libraries should be regenerated
- -- because at least an imported library will be
- -- regenerated or is more recent.
-
- Proj1 := Project_Tree.Projects;
- while Proj1 /= null loop
- if Proj1.Project.Library
- and then Proj1.Project.Extended_By = No_Project
- and then Proj1.Project.Library_Kind /= Static
- and then not Proj1.Project.Need_To_Build_Lib
- and then not Proj1.Project.Externally_Built
- then
- declare
- List : Project_List;
- Proj2 : Project_Id;
- Rebuild : Boolean := False;
-
- Lib_Timestamp1 : constant Time_Stamp_Type :=
- Proj1.Project.Library_TS;
-
- begin
- List := Proj1.Project.All_Imported_Projects;
- while List /= null loop
- Proj2 := List.Project;
-
- if Proj2.Library then
- if Proj2.Need_To_Build_Lib
- or else
- (Lib_Timestamp1 < Proj2.Library_TS)
- then
- Rebuild := True;
- exit;
- end if;
- end if;
+ --------------
+ -- Gnatmake --
+ --------------
- List := List.Next;
- end loop;
+ procedure Gnatmake is
+ Main_Source_File : File_Name_Type;
+ -- The source file containing the main compilation unit
- if Rebuild then
- Proj1.Project.Need_To_Build_Lib := True;
- Add_To_Library_Projs (Proj1.Project);
- end if;
- end;
- end if;
+ Total_Compilation_Failures : Natural := 0;
- Proj1 := Proj1.Next;
- end loop;
+ Main_ALI_File : File_Name_Type;
+ -- The ali file corresponding to Main_Source_File
- -- Reset the flags Need_To_Build_Lib for the next main,
- -- to avoid rebuilding libraries uselessly.
+ Executable : File_Name_Type := No_File;
+ -- The file name of an executable
- Proj1 := Project_Tree.Projects;
- while Proj1 /= null loop
- Proj1.Project.Need_To_Build_Lib := False;
- Proj1 := Proj1.Next;
- end loop;
- end;
+ Non_Std_Executable : Boolean := False;
+ -- Non_Std_Executable is set to True when there is a possibility that
+ -- the linker will not choose the correct executable file name.
- -- Build the libraries, if any need to be built
+ Current_Work_Dir : constant String_Access :=
+ new String'(Get_Current_Dir);
+ -- The current working directory, used to modify some relative path
+ -- switches on the command line when a project file is used.
- for J in 1 .. Library_Projs.Last loop
- Library_Rebuilt := True;
+ Current_Main_Index : Int := 0;
+ -- If not zero, the index of the current main unit in its source file
- -- If a library is rebuilt, then executables are obsolete
+ Stand_Alone_Libraries : Boolean := False;
+ -- Set to True when there are Stand-Alone Libraries, so that gnatbind
+ -- is invoked with the -F switch to force checking of elaboration flags.
- Executable_Obsolete := True;
+ Project_Node_Tree : Project_Node_Tree_Ref;
+ Root_Environment : Prj.Tree.Environment;
- MLib.Prj.Build_Library
- (For_Project => Library_Projs.Table (J),
- In_Tree => Project_Tree,
- Gnatbind => Gnatbind.all,
- Gnatbind_Path => Gnatbind_Path,
- Gcc => Gcc.all,
- Gcc_Path => Gcc_Path);
- end loop;
- end if;
+ Stop_Compile : Boolean;
- if List_Dependencies then
- if First_Compiled_File /= No_File then
- Inform
- (First_Compiled_File,
- "must be recompiled. Can't generate dependence list.");
- else
- List_Depend;
- end if;
+ Discard : Boolean;
+ pragma Warnings (Off, Discard);
- elsif First_Compiled_File = No_File
- and then not Do_Bind_Step
- and then not Quiet_Output
- and then not Library_Rebuilt
- and then Osint.Number_Of_Files = 1
- then
- Inform (Msg => "objects up to date.");
+ procedure Check_Mains;
+ -- Check that the main subprograms do exist and that they all
+ -- belong to the same project file.
- elsif Do_Not_Execute
- and then First_Compiled_File /= No_File
- then
- Write_Name (First_Compiled_File);
- Write_Eol;
- end if;
+ -----------------
+ -- Check_Mains --
+ -----------------
- -- Stop after compile step if any of:
+ procedure Check_Mains is
+ begin
+ if Mains.Number_Of_Mains (Project_Tree) = 0
+ and then not Unique_Compile
+ then
+ Mains.Fill_From_Project (Main_Project, Project_Tree);
+ end if;
- -- 1) -n (Do_Not_Execute) specified
+ Mains.Complete_Mains
+ (Root_Environment.Flags, Main_Project, Project_Tree);
+ end Check_Mains;
- -- 2) -M (List_Dependencies) specified (also sets
- -- Do_Not_Execute above, so this is probably superfluous).
+ -- Start of processing for Gnatmake
- -- 3) -c (Compile_Only) specified, but not -b (Bind_Only)
+ -- This body is very long, should be broken down???
- -- 4) Made unit cannot be a main unit
+ begin
+ Install_Int_Handler (Sigint_Intercepted'Access);
- if ((Do_Not_Execute
- or List_Dependencies
- or not Do_Bind_Step
- or not Is_Main_Unit)
- and then not No_Main_Subprogram
- and then not Build_Bind_And_Link_Full_Project)
- or else Unique_Compile
- then
- if Osint.Number_Of_Files = 1 then
- exit Multiple_Main_Loop;
+ Do_Compile_Step := True;
+ Do_Bind_Step := True;
+ Do_Link_Step := True;
- else
- goto Next_Main;
- end if;
- end if;
+ Obsoleted.Reset;
- -- If the objects were up-to-date check if the executable file
- -- is also up-to-date. For now always bind and link on the JVM
- -- since there is currently no simple way to check whether
- -- objects are up-to-date.
+ Make.Initialize (Project_Node_Tree, Root_Environment);
- if Targparm.VM_Target /= JVM_Target
- and then First_Compiled_File = No_File
- then
- Executable_Stamp := File_Stamp (Executable);
+ Bind_Shared := No_Shared_Switch'Access;
+ Link_With_Shared_Libgcc := No_Shared_Libgcc_Switch'Access;
- if not Executable_Obsolete then
- Executable_Obsolete :=
- Youngest_Obj_Stamp > Executable_Stamp;
- end if;
+ Failed_Links.Set_Last (0);
+ Successful_Links.Set_Last (0);
- if not Executable_Obsolete then
- for Index in reverse 1 .. Dependencies.Last loop
- if Is_In_Obsoleted
- (Dependencies.Table (Index).Depends_On)
- then
- Enter_Into_Obsoleted
- (Dependencies.Table (Index).This);
- end if;
- end loop;
+ -- Special case when switch -B was specified
- Executable_Obsolete := Is_In_Obsoleted (Main_Source_File);
- Dependencies.Init;
- end if;
+ if Build_Bind_And_Link_Full_Project then
+ -- When switch -B is specified, there must be a project file
- if not Executable_Obsolete then
+ if Main_Project = No_Project then
+ Make_Failed ("-B cannot be used without a project file");
- -- If no Ada object files obsolete the executable, check
- -- for younger or missing linker files.
+ -- No main program may be specified on the command line
- Check_Linker_Options
- (Executable_Stamp,
- Youngest_Obj_File,
- Youngest_Obj_Stamp);
+ elsif Osint.Number_Of_Files /= 0 then
+ Make_Failed ("-B cannot be used with a main specified on " &
+ "the command line");
- Executable_Obsolete := Youngest_Obj_File /= No_File;
- end if;
+ -- And the project file cannot be a library project file
- -- Check if any library file is more recent than the
- -- executable: there may be an externally built library
- -- file that has been modified.
+ elsif Main_Project.Library then
+ Make_Failed ("-B cannot be used for a library project file");
- if not Executable_Obsolete
- and then Main_Project /= No_Project
- then
- declare
- Proj1 : Project_List;
+ else
+ No_Main_Subprogram := True;
+ Insert_Project_Sources
+ (The_Project => Main_Project,
+ All_Projects => Unique_Compile_All_Projects,
+ Into_Q => False);
- begin
- Proj1 := Project_Tree.Projects;
- while Proj1 /= null loop
- if Proj1.Project.Library
- and then
- Proj1.Project.Library_TS > Executable_Stamp
- then
- Executable_Obsolete := True;
- Youngest_Obj_Stamp := Proj1.Project.Library_TS;
- Name_Len := 0;
- Add_Str_To_Name_Buffer ("library ");
- Add_Str_To_Name_Buffer
- (Get_Name_String (Proj1.Project.Library_Name));
- Youngest_Obj_File := Name_Find;
- exit;
- end if;
+ -- If there are no sources to compile, we fail
- Proj1 := Proj1.Next;
- end loop;
- end;
- end if;
+ if Osint.Number_Of_Files = 0 then
+ Make_Failed ("no sources to compile");
+ end if;
- -- Return if the executable is up to date and otherwise
- -- motivate the relink/rebind.
+ -- Specify -n for gnatbind and add the ALI files of all the
+ -- sources, except the one which is a fake main subprogram: this
+ -- is the one for the binder generated file and it will be
+ -- transmitted to gnatlink. These sources are those that are in
+ -- the queue.
- if not Executable_Obsolete then
- if not Quiet_Output then
- Inform (Executable, "up to date.");
- end if;
+ Add_Switch ("-n", Binder, And_Save => True);
- if Osint.Number_Of_Files = 1 then
- exit Multiple_Main_Loop;
+ for J in 1 .. Queue.Size loop
+ Add_Switch
+ (Get_Name_String (Lib_File_Name (Queue.Element (J))),
+ Binder, And_Save => True);
+ end loop;
+ end if;
- else
- goto Next_Main;
- end if;
- end if;
+ elsif Main_Index /= 0 and then Osint.Number_Of_Files > 1 then
+ Make_Failed ("cannot specify several mains with a multi-unit index");
- if Executable_Stamp (1) = ' ' then
- if not No_Main_Subprogram then
- Verbose_Msg (Executable, "missing.", Prefix => " ");
- end if;
+ elsif Main_Project /= No_Project then
+ -- If the main project file is a library project file, main(s) cannot
+ -- be specified on the command line.
- elsif Youngest_Obj_Stamp (1) = ' ' then
- Verbose_Msg
- (Youngest_Obj_File, "missing.", Prefix => " ");
+ if Osint.Number_Of_Files /= 0 then
+ if Main_Project.Library
+ and then not Unique_Compile
+ and then ((not Make_Steps) or else Bind_Only or else Link_Only)
+ then
+ Make_Failed ("cannot specify a main program " &
+ "on the command line for a library project file");
+ end if;
- elsif Youngest_Obj_Stamp > Executable_Stamp then
- Verbose_Msg
- (Youngest_Obj_File,
- "(" & String (Youngest_Obj_Stamp) & ") newer than",
- Executable,
- "(" & String (Executable_Stamp) & ")");
+ -- If no mains have been specified on the command line, and we are
+ -- using a project file, we either find the main(s) in attribute Main
+ -- of the main project, or we put all the sources of the project file
+ -- as mains.
- else
- Verbose_Msg
- (Executable, "needs to be rebuilt", Prefix => " ");
+ else
+ if Main_Index /= 0 then
+ Make_Failed ("cannot specify a multi-unit index but no main " &
+ "on the command line");
+ end if;
- end if;
- end if;
- end Recursive_Compilation_Step;
- end if;
+ declare
+ Value : String_List_Id := Main_Project.Mains;
- -- For binding and linking, we need to be in the object directory of
- -- the main project.
+ begin
+ -- The attribute Main is an empty list or not specified, or
+ -- else gnatmake was invoked with the switch "-u".
- if Main_Project /= No_Project then
- Change_To_Object_Directory (Main_Project);
- end if;
+ if Value = Prj.Nil_String or else Unique_Compile then
- -- If we are here, it means that we need to rebuilt the current main,
- -- so we set Executable_Obsolete to True to make sure that subsequent
- -- mains will be rebuilt.
+ if (not Make_Steps) or else Compile_Only
+ or else not Main_Project.Library
+ then
+ -- First make sure that the binder and the linker will
+ -- not be invoked.
- Main_ALI_In_Place_Mode_Step : declare
- ALI_File : File_Name_Type;
- Src_File : File_Name_Type;
+ Do_Bind_Step := False;
+ Do_Link_Step := False;
- begin
- Src_File := Strip_Directory (Main_Source_File);
- ALI_File := Lib_File_Name (Src_File, Current_Main_Index);
- Main_ALI_File := Full_Lib_File_Name (ALI_File);
+ -- Put all the sources in the queue
- -- When In_Place_Mode, the library file can be located in the
- -- Main_Source_File directory which may not be present in the
- -- library path. If it is not present then use the corresponding
- -- library file name.
+ No_Main_Subprogram := True;
+ Insert_Project_Sources
+ (The_Project => Main_Project,
+ All_Projects => Unique_Compile_All_Projects,
+ Into_Q => False);
- if Main_ALI_File = No_File and then In_Place_Mode then
- Get_Name_String (Get_Directory (Full_Source_Name (Src_File)));
- Get_Name_String_And_Append (ALI_File);
- Main_ALI_File := Name_Find;
- Main_ALI_File := Full_Lib_File_Name (Main_ALI_File);
- end if;
+ -- If no sources to compile, then there is nothing to do
- if Main_ALI_File = No_File then
- Make_Failed ("could not find the main ALI file");
- end if;
- end Main_ALI_In_Place_Mode_Step;
+ if Osint.Number_Of_Files = 0 then
+ if not Quiet_Output then
+ Osint.Write_Program_Name;
+ Write_Line (": no sources to compile");
+ end if;
- if Do_Bind_Step then
- Bind_Step : declare
- Args : Argument_List
- (Binder_Switches.First .. Binder_Switches.Last + 2);
- -- The arguments for the invocation of gnatbind
+ Finish_Program (Project_Tree, E_Success);
+ end if;
+ end if;
- Last_Arg : Natural := Binder_Switches.Last;
- -- Index of the last argument in Args
+ else
+ -- The attribute Main is not an empty list. Put all the main
+ -- subprograms in the list as if they were specified on the
+ -- command line. However, if attribute Languages includes a
+ -- language other than Ada, only include the Ada mains; if
+ -- there is no Ada main, compile all sources of the project.
- Shared_Libs : Boolean := False;
- -- Set to True when there are shared library project files or
- -- when gnatbind is invoked with -shared.
+ declare
+ Languages : constant Variable_Value :=
+ Prj.Util.Value_Of
+ (Name_Languages,
+ Main_Project.Decl.Attributes,
+ Project_Tree.Shared);
- Proj : Project_List;
+ Current : String_List_Id;
+ Element : String_Element;
- begin
- -- Check if there are shared libraries, so that gnatbind is
- -- called with -shared. Check also if gnatbind is called with
- -- -shared, so that gnatlink is called with -shared-libgcc
- -- ensuring that the shared version of libgcc will be used.
+ Foreign_Language : Boolean := False;
+ At_Least_One_Main : Boolean := False;
- if Main_Project /= No_Project
- and then MLib.Tgt.Support_For_Libraries /= Prj.None
- then
- Proj := Project_Tree.Projects;
- while Proj /= null loop
- if Proj.Project.Library
- and then Proj.Project.Library_Kind /= Static
- then
- Shared_Libs := True;
- Bind_Shared := Shared_Switch'Access;
- exit;
- end if;
- Proj := Proj.Next;
- end loop;
- end if;
+ begin
+ -- First, determine if there is a foreign language in
+ -- attribute Languages.
- -- Check now for switch -shared
+ if not Languages.Default then
+ Current := Languages.Values;
+ Look_For_Foreign :
+ while Current /= Nil_String loop
+ Element := Project_Tree.Shared.String_Elements.
+ Table (Current);
+ Get_Name_String (Element.Value);
+ To_Lower (Name_Buffer (1 .. Name_Len));
- if not Shared_Libs then
- for J in Binder_Switches.First .. Last_Arg loop
- if Binder_Switches.Table (J).all = "-shared" then
- Shared_Libs := True;
- exit;
- end if;
- end loop;
- end if;
+ if Name_Buffer (1 .. Name_Len) /= "ada" then
+ Foreign_Language := True;
+ exit Look_For_Foreign;
+ end if;
- -- If shared libraries present, invoke gnatlink with
- -- -shared-libgcc.
+ Current := Element.Next;
+ end loop Look_For_Foreign;
+ end if;
- if Shared_Libs then
- Link_With_Shared_Libgcc := Shared_Libgcc_Switch'Access;
- end if;
+ -- Then, find all mains, or if there is a foreign
+ -- language, all the Ada mains.
- -- Get all the binder switches
+ while Value /= Prj.Nil_String loop
+ -- To know if a main is an Ada main, get its project.
+ -- It should be the project specified on the command
+ -- line.
- for J in Binder_Switches.First .. Last_Arg loop
- Args (J) := Binder_Switches.Table (J);
- end loop;
+ Get_Name_String
+ (Project_Tree.Shared.String_Elements.Table
+ (Value).Value);
- if Stand_Alone_Libraries then
- Last_Arg := Last_Arg + 1;
- Args (Last_Arg) := Force_Elab_Flags_String'Access;
- end if;
+ declare
+ Main_Name : constant String :=
+ Get_Name_String
+ (Project_Tree.Shared.String_Elements.Table
+ (Value).Value);
+ Proj : constant Project_Id :=
+ Prj.Env.Project_Of
+ (Main_Name, Main_Project, Project_Tree);
+ begin
- if Main_Project /= No_Project then
+ if Proj = Main_Project then
- -- Put all the source directories in ADA_INCLUDE_PATH,
- -- and all the object directories in ADA_OBJECTS_PATH,
- -- except those of library projects.
+ At_Least_One_Main := True;
+ Osint.Add_File
+ (Get_Name_String
+ (Project_Tree.Shared.String_Elements.Table
+ (Value).Value),
+ Index =>
+ Project_Tree.Shared.String_Elements.Table
+ (Value).Index);
- Prj.Env.Set_Ada_Paths
- (Project => Main_Project,
- In_Tree => Project_Tree,
- Including_Libraries => False,
- Include_Path => Use_Include_Path_File);
+ elsif not Foreign_Language then
+ Make_Failed
+ ("""" & Main_Name &
+ """ is not a source of project " &
+ Get_Name_String (Main_Project.Display_Name));
+ end if;
+ end;
- -- If switch -C was specified, create a binder mapping file
+ Value := Project_Tree.Shared.String_Elements.Table
+ (Value).Next;
+ end loop;
- if Create_Mapping_File then
- Mapping_Path := Create_Binder_Mapping_File (Project_Tree);
+ -- If we did not get any main, it means that all mains
+ -- in attribute Mains are in a foreign language and -B
+ -- was not specified to gnatmake; so, we fail.
- if Mapping_Path /= No_Path then
- Last_Arg := Last_Arg + 1;
- Args (Last_Arg) :=
- new String'("-F=" & Get_Name_String (Mapping_Path));
+ if not At_Least_One_Main then
+ Make_Failed
+ ("no Ada mains, use -B to build foreign main");
end if;
- end if;
+ end;
end if;
+ end;
+ end if;
- begin
- Bind (Main_ALI_File,
- Bind_Shared.all & Args (Args'First .. Last_Arg));
+ -- Check that each main on the command line is a source of a
+ -- project file and, if there are several mains, each of them
+ -- is a source of the same project file.
- exception
- when others =>
+ Check_Mains;
+ end if;
- -- Delete the temporary mapping file if one was created
+ if Verbose_Mode then
+ Write_Eol;
+ Display_Version ("GNATMAKE", "1995");
+ end if;
- if Mapping_Path /= No_Path then
- Delete_Temporary_File
- (Project_Tree.Shared, Mapping_Path);
- end if;
+ if Osint.Number_Of_Files = 0 then
+ if Main_Project /= No_Project
+ and then Main_Project.Library
+ then
+ if Do_Bind_Step
+ and then not Main_Project.Standalone_Library
+ then
+ Make_Failed ("only stand-alone libraries may be bound");
+ end if;
- -- And reraise the exception
+ -- Add the default search directories to be able to find libgnat
- raise;
- end;
+ Osint.Add_Default_Search_Dirs;
- -- If -dn was not specified, delete the temporary mapping file
- -- if one was created.
+ -- Get the target parameters, so that the correct binder generated
+ -- files are generated if OpenVMS is the target.
- if Mapping_Path /= No_Path then
- Delete_Temporary_File (Project_Tree.Shared, Mapping_Path);
- end if;
- end Bind_Step;
- end if;
+ begin
+ Targparm.Get_Target_Parameters;
- if Do_Link_Step then
- Link_Step : declare
- Linker_Switches_Last : constant Integer := Linker_Switches.Last;
- Path_Option : constant String_Access :=
- MLib.Linker_Library_Path_Option;
- Libraries_Present : Boolean := False;
- Current : Natural;
- Proj2 : Project_Id;
- Depth : Natural;
- Proj1 : Project_List;
+ exception
+ when Unrecoverable_Error =>
+ Make_Failed ("*** make failed.");
+ end;
- begin
- if not Run_Path_Option then
- Linker_Switches.Increment_Last;
- Linker_Switches.Table (Linker_Switches.Last) :=
- new String'("-R");
- end if;
+ -- And bind and or link the library
- if Main_Project /= No_Project then
- Library_Paths.Set_Last (0);
- Library_Projs.Init;
+ MLib.Prj.Build_Library
+ (For_Project => Main_Project,
+ In_Tree => Project_Tree,
+ Gnatbind => Gnatbind.all,
+ Gnatbind_Path => Gnatbind_Path,
+ Gcc => Gcc.all,
+ Gcc_Path => Gcc_Path,
+ Bind => Bind_Only,
+ Link => Link_Only);
- if MLib.Tgt.Support_For_Libraries /= Prj.None then
+ Finish_Program (Project_Tree, E_Success);
- -- Check for library projects
+ else
+ -- Call Get_Target_Parameters to ensure that VM_Target and
+ -- AAMP_On_Target get set before calling Usage.
- Proj1 := Project_Tree.Projects;
- while Proj1 /= null loop
- if Proj1.Project /= Main_Project
- and then Proj1.Project.Library
- then
- -- Add this project to table Library_Projs
+ Targparm.Get_Target_Parameters;
- Libraries_Present := True;
- Depth := Proj1.Project.Depth;
- Library_Projs.Increment_Last;
- Current := Library_Projs.Last;
+ -- Output usage information if no files to compile
- -- Any project with a greater depth should be
- -- after this project in the list.
+ Usage;
+ Finish_Program (Project_Tree, E_Success);
+ end if;
+ end if;
- while Current > 1 loop
- Proj2 := Library_Projs.Table (Current - 1);
- exit when Proj2.Depth <= Depth;
- Library_Projs.Table (Current) := Proj2;
- Current := Current - 1;
- end loop;
+ -- Get the first executable.
+ -- ??? This needs to be done early, because Osint.Next_Main_File also
+ -- initializes the primary search directory, used below to initiliaze
+ -- the "-I" parameter
- Library_Projs.Table (Current) := Proj1.Project;
+ Main_Source_File := Next_Main_Source; -- No directory information
- -- If it is not a static library and path option
- -- is set, add it to the Library_Paths table.
+ -- If -M was specified, behave as if -n was specified
- if Proj1.Project.Library_Kind /= Static
- and then Proj1.Project.Extended_By = No_Project
- and then Path_Option /= null
- then
- Library_Paths.Increment_Last;
- Library_Paths.Table (Library_Paths.Last) :=
- new String'
- (Get_Name_String
- (Proj1.Project.Library_Dir.Display_Name));
- end if;
- end if;
+ if List_Dependencies then
+ Do_Not_Execute := True;
+ end if;
- Proj1 := Proj1.Next;
- end loop;
+ Add_Switch ("-I-", Compiler, And_Save => True);
- for Index in 1 .. Library_Projs.Last loop
- if
- Library_Projs.Table (Index).Extended_By = No_Project
- then
- if Library_Projs.Table (Index).Library_Kind = Static
- and then not Targparm.OpenVMS_On_Target
- then
- Linker_Switches.Increment_Last;
- Linker_Switches.Table (Linker_Switches.Last) :=
- new String'
- (Get_Name_String
- (Library_Projs.Table
- (Index).Library_Dir.Display_Name) &
- "lib" &
- Get_Name_String
- (Library_Projs.Table
- (Index).Library_Name) &
- "." &
- MLib.Tgt.Archive_Ext);
+ if Main_Project = No_Project then
+ if Look_In_Primary_Dir then
+ Add_Switch
+ ("-I" &
+ Normalize_Directory_Name
+ (Get_Primary_Src_Search_Directory.all).all,
+ Compiler, Append_Switch => False,
+ And_Save => False);
- else
- -- Add the -L switch
-
- Linker_Switches.Increment_Last;
- Linker_Switches.Table (Linker_Switches.Last) :=
- new String'("-L" &
- Get_Name_String
- (Library_Projs.Table (Index).
- Library_Dir.Display_Name));
-
- -- Add the -l switch
-
- Linker_Switches.Increment_Last;
- Linker_Switches.Table (Linker_Switches.Last) :=
- new String'("-l" &
- Get_Name_String
- (Library_Projs.Table (Index).
- Library_Name));
- end if;
- end if;
- end loop;
- end if;
+ end if;
- if Libraries_Present then
+ else
+ -- If we use a project file, we have already checked that a main
+ -- specified on the command line with directory information has the
+ -- path name corresponding to a correct source in the project tree.
+ -- So, we don't need the directory information to be taken into
+ -- account by Find_File, and in fact it may lead to take the wrong
+ -- sources for other compilation units, when there are extending
+ -- projects.
- -- If Path_Option is not null, create the switch
- -- ("-Wl,-rpath," or equivalent) with all the non-static
- -- library dirs plus the standard GNAT library dir.
- -- We do that only if Run_Path_Option is True
- -- (not disabled by -R switch).
+ Look_In_Primary_Dir := False;
+ Add_Switch ("-I-", Binder, And_Save => True);
+ end if;
- if Run_Path_Option and then Path_Option /= null then
- declare
- Option : String_Access;
- Length : Natural := Path_Option'Length;
- Current : Natural;
+ -- If the user wants a program without a main subprogram, add the
+ -- appropriate switch to the binder.
- begin
- if MLib.Separate_Run_Path_Options then
-
- -- We are going to create one switch of the form
- -- "-Wl,-rpath,dir_N" for each directory to
- -- consider.
-
- -- One switch for each library directory
-
- for Index in
- Library_Paths.First .. Library_Paths.Last
- loop
- Linker_Switches.Increment_Last;
- Linker_Switches.Table
- (Linker_Switches.Last) :=
- new String'
- (Path_Option.all &
- Library_Paths.Table (Index).all);
- end loop;
+ if No_Main_Subprogram then
+ Add_Switch ("-z", Binder, And_Save => True);
+ end if;
- -- One switch for the standard GNAT library dir
+ if Main_Project /= No_Project then
- Linker_Switches.Increment_Last;
- Linker_Switches.Table
- (Linker_Switches.Last) :=
- new String'
- (Path_Option.all & MLib.Utl.Lib_Directory);
+ if Main_Project.Object_Directory /= No_Path_Information then
+ -- Change current directory to object directory of main project
- else
- -- We are going to create one switch of the form
- -- "-Wl,-rpath,dir_1:dir_2:dir_3"
-
- for Index in
- Library_Paths.First .. Library_Paths.Last
- loop
- -- Add the length of the library dir plus one
- -- for the directory separator.
-
- Length :=
- Length +
- Library_Paths.Table (Index)'Length + 1;
- end loop;
+ Project_Of_Current_Object_Directory := No_Project;
+ Change_To_Object_Directory (Main_Project);
+ end if;
- -- Finally, add the length of the standard GNAT
- -- library dir.
-
- Length := Length + MLib.Utl.Lib_Directory'Length;
- Option := new String (1 .. Length);
- Option (1 .. Path_Option'Length) :=
- Path_Option.all;
- Current := Path_Option'Length;
-
- -- Put each library dir followed by a dir
- -- separator.
-
- for Index in
- Library_Paths.First .. Library_Paths.Last
- loop
- Option
- (Current + 1 ..
- Current +
- Library_Paths.Table (Index)'Length) :=
- Library_Paths.Table (Index).all;
- Current :=
- Current +
- Library_Paths.Table (Index)'Length + 1;
- Option (Current) := Path_Separator;
- end loop;
+ -- Source file lookups should be cached for efficiency.
+ -- Source files are not supposed to change.
- -- Finally put the standard GNAT library dir
+ Osint.Source_File_Data (Cache => True);
- Option
- (Current + 1 ..
- Current + MLib.Utl.Lib_Directory'Length) :=
- MLib.Utl.Lib_Directory;
+ Osint.Add_Default_Search_Dirs;
- -- And add the switch to the linker switches
+ Queue_Library_Project_Sources;
+ end if;
- Linker_Switches.Increment_Last;
- Linker_Switches.Table (Linker_Switches.Last) :=
- Option;
- end if;
- end;
- end if;
+ -- The combination of -f -u and one or several mains on the command line
+ -- implies -a.
- end if;
+ if Force_Compilations
+ and then Unique_Compile
+ and then not Unique_Compile_All_Projects
+ and then Main_On_Command_Line
+ then
+ Must_Compile := True;
+ end if;
- -- Put the object directories in ADA_OBJECTS_PATH
+ if Main_Project /= No_Project
+ and then not Must_Compile
+ and then Main_Project.Externally_Built
+ then
+ Make_Failed
+ ("nothing to do for a main project that is externally built");
+ end if;
- Prj.Env.Set_Ada_Paths
- (Main_Project,
- Project_Tree,
- Including_Libraries => False,
- Include_Path => False);
+ -- Get the target parameters, which are only needed for a couple of
+ -- cases in gnatmake. Protect against an exception, such as the case of
+ -- system.ads missing from the library, and fail gracefully.
- -- Check for attributes Linker'Linker_Options in projects
- -- other than the main project
+ begin
+ Targparm.Get_Target_Parameters;
+ exception
+ when Unrecoverable_Error =>
+ Make_Failed ("*** make failed.");
+ end;
- declare
- Linker_Options : constant String_List :=
- Linker_Options_Switches
- (Main_Project,
- Do_Fail => Make_Failed'Access,
- In_Tree => Project_Tree);
- begin
- for Option in Linker_Options'Range loop
- Linker_Switches.Increment_Last;
- Linker_Switches.Table (Linker_Switches.Last) :=
- Linker_Options (Option);
- end loop;
- end;
- end if;
+ -- Special processing for VM targets
- -- Add switch -M to gnatlink if builder switch
- -- --create-map-file has been specified.
+ if Targparm.VM_Target /= No_VM then
- if Map_File /= null then
- Linker_Switches.Increment_Last;
- Linker_Switches.Table (Linker_Switches.Last) :=
- new String'("-M" & Map_File.all);
- end if;
+ -- Set proper processing commands
- declare
- Args : Argument_List
- (Linker_Switches.First .. Linker_Switches.Last + 2);
+ case Targparm.VM_Target is
+ when Targparm.JVM_Target =>
- Last_Arg : Integer := Linker_Switches.First - 1;
- Skip : Boolean := False;
+ -- Do not check for an object file (".o") when compiling to
+ -- JVM machine since ".class" files are generated instead.
- begin
- -- Get all the linker switches
+ Check_Object_Consistency := False;
+ Gcc := new String'("jvm-gnatcompile");
- for J in Linker_Switches.First .. Linker_Switches.Last loop
- if Skip then
- Skip := False;
+ when Targparm.CLI_Target =>
+ Gcc := new String'("dotnet-gnatcompile");
- elsif Non_Std_Executable
- and then Linker_Switches.Table (J).all = "-o"
- then
- Skip := True;
+ when Targparm.No_VM =>
+ raise Program_Error;
+ end case;
+ end if;
- -- Here we capture and duplicate the linker argument. We
- -- need to do the duplication since the arguments will
- -- get normalized. Not doing so will result in calling
- -- normalized two times for the same set of arguments if
- -- gnatmake is passed multiple mains. This can result in
- -- the wrong argument being passed to the linker.
+ -- If no project file is used, we just put the gcc switches
+ -- from the command line in the Gcc_Switches table.
- else
- Last_Arg := Last_Arg + 1;
- Args (Last_Arg) :=
- new String'(Linker_Switches.Table (J).all);
- end if;
- end loop;
+ if Main_Project = No_Project then
+ for J in 1 .. Saved_Gcc_Switches.Last loop
+ Add_Switch
+ (Saved_Gcc_Switches.Table (J), Compiler, And_Save => False);
+ end loop;
- -- If need be, add the -o switch
+ else
+ -- If there is a project, put the command line gcc switches in the
+ -- variable The_Saved_Gcc_Switches. They are going to be used later
+ -- in procedure Compile_Sources.
- if Non_Std_Executable then
- Last_Arg := Last_Arg + 1;
- Args (Last_Arg) := new String'("-o");
- Last_Arg := Last_Arg + 1;
- Args (Last_Arg) :=
- new String'(Get_Name_String (Executable));
- end if;
+ The_Saved_Gcc_Switches :=
+ new Argument_List (1 .. Saved_Gcc_Switches.Last + 1);
- -- And invoke the linker
+ for J in 1 .. Saved_Gcc_Switches.Last loop
+ The_Saved_Gcc_Switches (J) := Saved_Gcc_Switches.Table (J);
+ end loop;
- declare
- Success : Boolean := False;
- begin
- Link (Main_ALI_File,
- Link_With_Shared_Libgcc.all &
- Args (Args'First .. Last_Arg),
- Success);
-
- if Success then
- Successful_Links.Increment_Last;
- Successful_Links.Table (Successful_Links.Last) :=
- Main_ALI_File;
-
- elsif Osint.Number_Of_Files = 1
- or else not Keep_Going
- then
- Make_Failed ("*** link failed.");
+ -- We never use gnat.adc when a project file is used
- else
- Set_Standard_Error;
- Write_Line ("*** link failed");
+ The_Saved_Gcc_Switches (The_Saved_Gcc_Switches'Last) := No_gnat_adc;
+ end if;
- if Commands_To_Stdout then
- Set_Standard_Output;
- end if;
+ -- If there was a --GCC, --GNATBIND or --GNATLINK switch on the command
+ -- line, then we have to use it, even if there was another switch in
+ -- the project file.
- Failed_Links.Increment_Last;
- Failed_Links.Table (Failed_Links.Last) :=
- Main_ALI_File;
- end if;
- end;
- end;
+ if Saved_Gcc /= null then
+ Gcc := Saved_Gcc;
+ end if;
- Linker_Switches.Set_Last (Linker_Switches_Last);
- end Link_Step;
- end if;
+ if Saved_Gnatbind /= null then
+ Gnatbind := Saved_Gnatbind;
+ end if;
- -- We go to here when we skip the bind and link steps
+ if Saved_Gnatlink /= null then
+ Gnatlink := Saved_Gnatlink;
+ end if;
- <<Next_Main>>
+ Gcc_Path := GNAT.OS_Lib.Locate_Exec_On_Path (Gcc.all);
+ Gnatbind_Path := GNAT.OS_Lib.Locate_Exec_On_Path (Gnatbind.all);
+ Gnatlink_Path := GNAT.OS_Lib.Locate_Exec_On_Path (Gnatlink.all);
- -- We go to the next main, if we did not process the last one
+ -- If we have specified -j switch both from the project file
+ -- and on the command line, the one from the command line takes
+ -- precedence.
- if N_File < Osint.Number_Of_Files then
- Main_Source_File := Next_Main_Source;
+ if Saved_Maximum_Processes = 0 then
+ Saved_Maximum_Processes := Maximum_Processes;
+ end if;
- if Current_File_Index /= No_Index then
- Main_Index := Current_File_Index;
- end if;
+ if Debug.Debug_Flag_M then
+ Write_Line ("Maximum number of simultaneous compilations =" &
+ Saved_Maximum_Processes'Img);
+ end if;
- if Main_Project /= No_Project then
+ -- Allocate as many temporary mapping file names as the maximum number
+ -- of compilations processed, for each possible project.
- -- Find the file name of the main unit
+ declare
+ Data : Project_Compilation_Access;
+ Proj : Project_List := Project_Tree.Projects;
+ begin
+ while Proj /= null loop
+ Data := new Project_Compilation_Data'
+ (Mapping_File_Names => new Temp_Path_Names
+ (1 .. Saved_Maximum_Processes),
+ Last_Mapping_File_Names => 0,
+ Free_Mapping_File_Indexes => new Free_File_Indexes
+ (1 .. Saved_Maximum_Processes),
+ Last_Free_Indexes => 0);
- declare
- Main_Source_File_Name : constant String :=
- Get_Name_String (Main_Source_File);
-
- Main_Unit_File_Name : constant String :=
- Prj.Env.
- File_Name_Of_Library_Unit_Body
- (Name => Main_Source_File_Name,
- Project => Main_Project,
- In_Tree => Project_Tree,
- Main_Project_Only =>
- not Unique_Compile);
-
- The_Packages : constant Package_Id :=
- Main_Project.Decl.Packages;
-
- Binder_Package : constant Prj.Package_Id :=
- Prj.Util.Value_Of
- (Name => Name_Binder,
- In_Packages => The_Packages,
- Shared => Project_Tree.Shared);
-
- Linker_Package : constant Prj.Package_Id :=
- Prj.Util.Value_Of
- (Name => Name_Linker,
- In_Packages => The_Packages,
- Shared => Project_Tree.Shared);
+ Project_Compilation_Htable.Set
+ (Project_Compilation, Proj.Project, Data);
+ Proj := Proj.Next;
+ end loop;
- begin
- -- We fail if we cannot find the main source file
- -- as an immediate source of the main project file.
+ Data := new Project_Compilation_Data'
+ (Mapping_File_Names => new Temp_Path_Names
+ (1 .. Saved_Maximum_Processes),
+ Last_Mapping_File_Names => 0,
+ Free_Mapping_File_Indexes => new Free_File_Indexes
+ (1 .. Saved_Maximum_Processes),
+ Last_Free_Indexes => 0);
- if Main_Unit_File_Name = "" then
- Make_Failed ('"' & Main_Source_File_Name
- & """ is not a unit of project "
- & Project_File_Name.all & ".");
+ Project_Compilation_Htable.Set
+ (Project_Compilation, No_Project, Data);
+ end;
- else
- -- Remove any directory information from the main
- -- source file name.
+ Bad_Compilation.Init;
- declare
- Pos : Natural := Main_Unit_File_Name'Last;
+ -- If project files are used, create the mapping of all the sources, so
+ -- that the correct paths will be found. Otherwise, if there is a file
+ -- which is not a source with the same name in a source directory this
+ -- file may be incorrectly found.
- begin
- loop
- exit when Pos < Main_Unit_File_Name'First
- or else
- Main_Unit_File_Name (Pos) = Directory_Separator;
- Pos := Pos - 1;
- end loop;
+ if Main_Project /= No_Project then
+ Prj.Env.Create_Mapping (Project_Tree);
+ end if;
- Name_Len := Main_Unit_File_Name'Last - Pos;
+ -- Here is where the make process is started
- Name_Buffer (1 .. Name_Len) :=
- Main_Unit_File_Name
- (Pos + 1 .. Main_Unit_File_Name'Last);
+ Queue.Initialize
+ (Main_Project /= No_Project and then One_Compilation_Per_Obj_Dir);
- Main_Source_File := Name_Find;
- end;
- end if;
+ Multiple_Main_Loop : for N_File in 1 .. Osint.Number_Of_Files loop
+ if Current_File_Index /= No_Index then
+ Main_Index := Current_File_Index;
+ end if;
- -- We now deal with the binder and linker switches.
- -- If no project file is used, there is nothing to do
- -- because the binder and linker switches are the same
- -- for all mains.
+ Current_Main_Index := Main_Index;
- -- Reset the tables Binder_Switches and Linker_Switches
+ Compute_Switches_For_Main
+ (Main_Source_File,
+ Main_Index,
+ Project_Node_Tree,
+ Root_Environment,
+ Compute_Builder => N_File = 1,
+ Current_Work_Dir => Current_Work_Dir.all);
- Binder_Switches.Set_Last (Last_Binder_Switch);
- Linker_Switches.Set_Last (Last_Linker_Switch);
+ Executable_Obsolete := False;
- -- Add binder switches from the project file for this main,
- -- if any.
+ Compute_Executable
+ (Main_Source_File => Main_Source_File,
+ Executable => Executable,
+ Non_Std_Executable => Non_Std_Executable);
- if Do_Bind_Step and then Binder_Package /= No_Package then
- if Verbose_Mode then
- Write_Str ("Adding binder switches for """);
- Write_Str (Main_Unit_File_Name);
- Write_Line (""".");
- end if;
+ if Do_Compile_Step then
+ Compilation_Phase
+ (Main_Source_File => Main_Source_File,
+ Current_Main_Index => Current_Main_Index,
+ Total_Compilation_Failures => Total_Compilation_Failures,
+ Stand_Alone_Libraries => Stand_Alone_Libraries,
+ Executable => Executable,
+ Is_Last_Main => N_File = Osint.Number_Of_Files,
+ Stop_Compile => Stop_Compile);
+
+ if Stop_Compile then
+ if Total_Compilation_Failures /= 0 then
+ if Keep_Going then
+ goto Next_Main;
- Add_Switches
- (Project_Node_Tree => Project_Node_Tree,
- Env => Root_Environment,
- File_Name => Main_Unit_File_Name,
- Index => Main_Index,
- The_Package => Binder_Package,
- Program => Binder);
+ else
+ List_Bad_Compilations;
+ Report_Compilation_Failed;
end if;
- -- Add linker switches from the project file for this main,
- -- if any.
-
- if Do_Link_Step and then Linker_Package /= No_Package then
- if Verbose_Mode then
- Write_Str ("Adding linker switches for""");
- Write_Str (Main_Unit_File_Name);
- Write_Line (""".");
- end if;
+ elsif Osint.Number_Of_Files = 1 then
+ exit Multiple_Main_Loop;
+ else
+ goto Next_Main;
+ end if;
+ end if;
+ end if;
- Add_Switches
- (Project_Node_Tree => Project_Node_Tree,
- Env => Root_Environment,
- File_Name => Main_Unit_File_Name,
- Index => Main_Index,
- The_Package => Linker_Package,
- Program => Linker);
- end if;
+ -- For binding and linking, we need to be in the object directory of
+ -- the main project.
- -- As we are using a project file, for relative paths we add
- -- the current working directory for any relative path on
- -- the command line and the project directory, for any
- -- relative path in the project file.
+ if Main_Project /= No_Project then
+ Change_To_Object_Directory (Main_Project);
+ end if;
- declare
- Dir_Path : constant String :=
- Get_Name_String
- (Main_Project.Directory.Display_Name);
+ -- If we are here, it means that we need to rebuilt the current main,
+ -- so we set Executable_Obsolete to True to make sure that subsequent
+ -- mains will be rebuilt.
- begin
- for
- J in Last_Binder_Switch + 1 .. Binder_Switches.Last
- loop
- Test_If_Relative_Path
- (Binder_Switches.Table (J),
- Do_Fail => Make_Failed'Access,
- Parent => Dir_Path, Including_L_Switch => False);
- end loop;
+ Main_ALI_In_Place_Mode_Step : declare
+ ALI_File : File_Name_Type;
+ Src_File : File_Name_Type;
- for
- J in Last_Linker_Switch + 1 .. Linker_Switches.Last
- loop
- Test_If_Relative_Path
- (Linker_Switches.Table (J),
- Parent => Dir_Path,
- Do_Fail => Make_Failed'Access);
- end loop;
- end;
+ begin
+ Src_File := Strip_Directory (Main_Source_File);
+ ALI_File := Lib_File_Name (Src_File, Current_Main_Index);
+ Main_ALI_File := Full_Lib_File_Name (ALI_File);
- -- We now put in the Binder_Switches and Linker_Switches
- -- tables, the binder and linker switches of the command
- -- line that have been put in the Saved_ tables. These
- -- switches will follow the project file switches.
+ -- When In_Place_Mode, the library file can be located in the
+ -- Main_Source_File directory which may not be present in the
+ -- library path. If it is not present then use the corresponding
+ -- library file name.
- for J in 1 .. Saved_Binder_Switches.Last loop
- Add_Switch
- (Saved_Binder_Switches.Table (J),
- Binder,
- And_Save => False);
- end loop;
+ if Main_ALI_File = No_File and then In_Place_Mode then
+ Get_Name_String (Get_Directory (Full_Source_Name (Src_File)));
+ Get_Name_String_And_Append (ALI_File);
+ Main_ALI_File := Name_Find;
+ Main_ALI_File := Full_Lib_File_Name (Main_ALI_File);
+ end if;
- for J in 1 .. Saved_Linker_Switches.Last loop
- Add_Switch
- (Saved_Linker_Switches.Table (J),
- Linker,
- And_Save => False);
- end loop;
- end;
+ if Main_ALI_File = No_File then
+ Make_Failed ("could not find the main ALI file");
end if;
+ end Main_ALI_In_Place_Mode_Step;
+
+ if Do_Bind_Step then
+ Binding_Phase
+ (Stand_Alone_Libraries => Stand_Alone_Libraries,
+ Main_ALI_File => Main_ALI_File);
+ end if;
+
+ if Do_Link_Step then
+ Linking_Phase
+ (Non_Std_Executable => Non_Std_Executable,
+ Executable => Executable,
+ Main_ALI_File => Main_ALI_File);
end if;
+ -- We go to here when we skip the bind and link steps
+
+ <<Next_Main>>
+
Queue.Remove_Marks;
+
+ if N_File < Osint.Number_Of_Files then
+ Main_Source_File := Next_Main_Source; -- No directory information
+ end if;
end loop Multiple_Main_Loop;
if Do_Codepeer_Globalize_Step then