Hi, I am new in this forum.
I have a problem porting ada code from Red Hat 8 (gnat 8.5.0) to Red Hat 9 (gnat 11.3.1).
The linking phase on RHEL9 fails for “Elaboration circularity detected”.
I let the ada compiler to choose the module compilation order using the following instruction:
gnatmake -c
The reason is: “unit depends on its own elaboration”
The circularity detected is: "unit invokes a construct of unit at elaboration time.
What shall I do to find the exact location of the problem?
And why this problem was not detected before using other gnat versions?
Thanks a lot
Please show the whole gnatmake command and the whole output from that command. The name(s) of the unit(s) in the elaboration circle should appear in the output.
This sometimes occurs because of a task; the compiler thinks it might start executing, and invoking other elements of the package, during elaboration. If that’s it, you might try specifying a task type and creating the instance later (e.g. in an externally-called Init
procedure).
A long time ago, I had a case where the list of units involved in the circularity was longer than the number of units
Sorry, the post was incomplete beacause there were special characters that, probably, have a special meaning in publishing the text.
The program is an ada program (the main is an ada unit) that uses c libraries.
The compilation of the ada part is:
gnatmake -c sim (sim is the ada main procedure name).
Therefore, I let the compiler choosing the compilation order of ada modules.
After that, the generation of the executable file is done by:
gnatbind sim
gnatlink -o sim_exe sim (plus list of c files and c libraries to be linked)
The generated error is:
Elaborate circularity detected
Reason:
unit “ex_status_han (body)” depends on its own elaboration
Circularity:
unit “ex_status_han (body)” invokes a construct of unit “ex_status_han (body)” at elaboration time
ex_status_han contains only a task with 3 entries invoked by other tasks
Thanks for showing the complete build commands and error messages. I think Simon’s suggestion to remove the actual task creation to another unit might help, but it is hard to say for sure without seeing more of the code.
For large multi-task programs I try to put all task creations in their own packages, on which no other units depend, except for the main subprogram. This lets the compiler put these “task packages” close to last in the elaboration order. It also makes testing easier because the test-main subprogram can choose to “with” only a subset of the task packages and thus control which tasks are active in each test.
By the way, when linking to C code I find it convenient to use pragma Linker_Options to tell the linker which .o files from C code to include in the link, instead of listing those .o files in a gnatlink command. I put the Linker_Options pragma next to the declaration of the C function(s) in the Ada code. You can have several Linker_Options pragmas with cumulative effect. See Interfacing Aspects.
Thanks for your answers.
The allocation/activation of the ex_status_han task is in the ads file.
The ads file contains only “with” of general packages defining constant and data types.
There is not an (off loop) “init” activation entry because this task shall be ready to be called from other tasks whenever they need to use any of the services made available by it.
Remains the question of why this circularity has not been detected up to now by all previous compilers used.
As message say, there is some constructs in the task that use construct outside of the task but in the same package. It might be anything, even library level constant declaration might require elaboration, thus reference to the constant from the task might raise this issue.
Elaboration procedure is complicated, it is compiler dependent and configuration dependent, so it is usual that different version of the compiler generates different machine code for elaboration of the same Ada code.
Hi, I know this topic is old, but I’m having a very similar problem. It comes from a purely ada code, the implementation of the philosophers’ dinner in Software Construction and Data Structure with Ada 95. All the code comes from the book and I can’t compile the damn thing because of
unit “room (body)” depends on its own elaboration
info: Circularity:
info: unit “room (body)” invokes a construct of unit “room (body)” at elaboration time
phil.ads" has dynamic elaboration checks and with’s
warning: “society.ads” which has static elaboration checks
I’m certain this wasn’t meant to pose an issue with the compiler the book was using, and probably no compiler at all at the time. What do I do ? How do I tell the compiler not to be stupid ? I’m using -gnatE, it does not seem to help much.
Hard to say without knowing all the involved packages and what is being "with"ed around.
The warning about mixed elaboration settings is suspicious. Maybe a partial build?
That said, I usually start marking everything that allows it as “Preelaborable”.
Now it works, even without any preelaborate ? I swear the switch was on yesterday ! Hurg… Makes no sense.
Anyway. I’ll still apply your advice from now on. So I have to try Pure whenever possible, Preelaborate when it fails, and when that fails, what, Elaborate_all ? And what do I do when it’s with-ed with Text_io or another non-preelaborated package ? Also, do I need “pragma Suppress (Elaboration_checks” ? I read
Elaboration checks can be very expensive because the code for the check is executed for every call of a subprogram declared in a package specification, even though it is only relevant during the first call. you may want to suppress the check.
if it compiles I would assume it doesn’t need to check that during runtime !
The reason for elaboration circularity is usually IMO because of having task bodies in package bodies, and that certainly seems to be the case here. I’ve just spent far too much time failing to get this to work; -gnatE
does it, but can require you to add elaboration pragmas, which can be fragile in a large system (and when I had to do it back in the day the help offered by the compiler wasn’t that helpful).
An approach without -gnatE
is to use task types in package bodies, and allocate instances in an Initialize
procedure, called by some all-knowing master (possibly the main program). In this case, just doing it for Room
wasn’t enough.
I don’t bother with Pure except for mostly empty packages; IME unless you’re doing something that requires it specifically (remote types?), it gains you nothing in terms of resolving elaboration circularities.
After Preelaborate, next is nothing. I never use Elaborate
or Elaborate_All
, and I think the current GNAT default elaboration model makes those obsolete.
Elaborate_Body
I only use when indeed I want a body where none is required.
So, basically, it is either Preelaborate
or nothing.
I’ve also never messed with elaboration checks nor noticed any impact.
Ok, this one is because there’s two methods for elaboration, static and dynamic. I think that technically only dynamic is LRM compliant, with static being a method that was found afterwards and implemented in GNAT. (This is foggy remembering, so I might be misremembering.)
Ok, so for this there’s an problem with two units WITH
ing each other on the spec (both can in the body and be fine) — Ada 2012 (or maybe 2005) introduced private with
, which addresses the circularity: making one private-with allows the compiler to break the dependency for the publicly visible portion, compile that, then add the dependency to the private
portion of the spec and compile that.
If you need strict Ada95, I’m pretty sure you’ll need to nest one package in the other.
Correct: design first w/ Pure, then Preelaborate, than with nothing.
(Elaborate_All forces the unit to have a body.)
Another use for Elaborate_Body
:
package P is
function F return T;
end P;
with P;
package Q is
X: P.T := P.F;
end Q;
This is likely to produce an elaboration problem:
elaborate P’Spec
elaborate Q
elaborate P’Body
This sequence is a possible compilation sequence, but fails the elaboration check on F.
To cure the situation, either use Elaborate_Body
on P’Spec or Elaborate (P) on Q. The first is preferred if not impossible for other reasons.
Yyes OWS, the dynamic model is the only LRM-compliant one. But if that mode is the most legal, permissive, conflict-resolving one, why did the other two came into existence ? Why did Spark need more (or less, here). I see people don’t quite agree on this topic… As with Spark if someone can show some advantage of the stricter mode, be it performance-wise or something else, I’ll do it.
In general, the ARG tries to develop the Ada standard with a broad generality in mind so that multiple different compiler implementations are allowed. Sometimes specific compiler vendors and their customers find value in a different method that is more specific than what the Ada standard can specify while still maintaining that generality for other compilers. Also, sometimes people just figure out new tech well after the standard is last updated.
Overtime we have seen some of those compiler specific features get into the language, so it may be just a matter of time for some things.
Well, with a fully/pure static model (at least theoretically) the entirety of elaboration can be done beforehand, meaning that everything in the runtime relating to elaborating can be optimized out of the build. — This [full/pure] isn’t, strictly speaking, always doable: consider a generic with formal parameters which are themselves populated by user-input.
See the above, in making things more provable, you make things more optimizable; in general, the more you can do at compile-time the better: and static analysis is precisely the means by which this is achieved.
Do note: even things that are dynamic are sometimes amiable to static analysis — this is one reason that Ada’s attributes are so powerful/useful:
Type Vector is Array (Positive range <>) of Natural;
Function Prompt( S: String ) return Natural is
Begin
Ada.Text_IO.Put( S & ": ");
Loop
Declare
Text : String renames Ada.Text_IO.Get_Line;
Begin
Return Natural'Val( Text );
Exception
When Constraint_Error => Null;
End;
End loop;
End Prompt;
Function Create_Vector(
Size : Natural := Prompt("Enter a natural number")
) return Vector is
Begin
Return Result : Vector(1..Size) do
For Item of Result loop
Item:= Prompt( "Enter a value" );
End loop;
End return;
End Create_Vector;
Procedure Example is
Item : Vector renames Create_Vector;
Begin
For Index of Item'Range loop
-- Operations here.
End loop;
End Example;
In the above Item
in example is a Vector
of unknown size and unknown content. Because the For
-loop is taking its indices from Item
, we can remove index-checks for access because the bounds of the loop are taken from the item and therefore cannot fail the mandatory range-check. And we can do this even in the presence of the aforementioned ambiguities.
That is why ‘static’ is so important in Ada: it allows not merely optimization, but safe optimization.
I believe this is the correct answer with respect to elaboration: that a static algorithm for determining elaboration was found after the standard was published.
Sold. I’m a slave to everything static. How do I do then ? I have a task object in a package’s spec, with the former’s body in the later’s. I know it’s not "pragma Elaborate_Body since I want the opposite: the body should get elaborated first… But I read Ada forbids it ? Even though bodies are their own compilation units ?
Is this a case where the static model is impossible ?
How could the body be elaborated before the spec? This is like executing the begin part of a declare block before the declaration part.