What do the Ada directive pragmas Static_Elaboration_Desired and Linker_Section mean? I wasn't able to comprehend the definitions given over internet.
Static_Elaboration_Desired is not an Ada pragma. It is an implementation defined pragma in GNAT:
https://gcc.gnu.org/onlinedocs/gnat_rm/Pragma-Static_005fElaboration_005fDesired.html
You use it, if you want elaboration to be static (i.e. just a part the executable image) rather than happen through executable code.
Related
What does Qt Quick Compiler do exactly? My understanding was that it "compiles" QML/JS into C++ and integrates this into the final binary/executable. So, there is no JIT compilation or any other JS-related things during runtime.
However, I saw somewhere an article that claimed that it's not like this and actually it only "bundles" QML/JS into final binary/executable, but there is still some QML/JS-related overhead during runtime.
At the documentation page there is this explanation:
.qml files as well as accompanying .js files can be translated into
intermediate C++ source code. After compilation with a traditional
compiler, the code is linked into the application binary.
What is this "intermediate C++ source code"? Why not just "C++ source code"? That confuses me, but the last statement kinda promises that yes, it is a C++ code, and after compiling it with C++ compiler you will have a binary/executable without any additional compiling/interpretation during runtime.
Is it how it actually is?
The code is of an intermediate nature because it doesn't map Javascript directly to C++. E.g. var i = 1, j = 2, k = i+j is not translated to the C++ equivalent double i = 1., j = 2., k = i+j. Instead, the code is translated to a series of operations that directly manipulate the state of the JS virtual machine. JS semantics are not something you can get for free from C++: there will be runtime costs no matter how you implement it. There is no additional compiling nor interpretation, but the virtual machine that implements the JS state still has to exist.
That's not an overhead easy to get rid of without emitting a lot mostly dead code to cover all contexts in which a given piece of code might run, or doing just-in-time compilation that you wanted to avoid. That's the primary problem with JavaScript: its semantics are such that it's generally not possible to translate it to typical imperative statically typed code that gives rise to "standard" machine code.
Your question already contains the answer.
It compiles the code into C++, that is of intermediate nature as it is not enough to have C++-Code. You need binaries. So after the compilation to C++, the files are then compiled into binaries. Those are then linked.
The statement only says: We do not compile to binary, but to C++ instead. You need to compile it into a binary with your a C++-Compiler of your choice.
The bundeling happens, if you only put it into the resources (qrc-file). Putting it into the resources does not imply that you use the compiler.
Then there is the JIT compiler, that might (on supported platforms) do a Just-in-Time-Compilation. More on this here
I am a huge fan of source code comments but the comments in the Ada standard library are spartan at best. It is my understanding that the interface of the library is defined with the language definition, but the implementation is left to the compiler manufacturer. I often wondered how they do it, since the pure function names, parameters, and other definitions as I see them in the manual often don't explain what exactly the respective subprograms do and leave much to interpretation. I would expect some documentation along the line of the QT library.
Why is it there no definition of the library with extensive comments for every function?
It sounds like you are looking for the documentation in the wrong place.
The Ada standard library is described in great detail in the standard (the Ada Reference Manual) - and in even greater detail in the Annotated Ada Reference Manual.
The source files of the individual implementations of the Ada standard library are not the documentation of how the standard library should work.
For an example, the ARM section A.18.5 for Ada.Containers.Hashed_Maps says in paragraph 1 - which would normally be referred to as "A.18.5 (1)” -
The generic library package Containers.Hashed_Maps has the following declaration:
so I guess that implementors have read this as an instruction.
In the case of Hashed_Maps, you’ll see at A.18.5 (46) a link to A.18.4, which describes the common semantics of Maps; and Length, for example, is at (25).
GPS GPL from AdaCore Help > GNAT has links to a local copy of the ARM (GPS GPL 2014 only goes up to ARM2005); I don’t know what the Debian version does.
(This is how it is; that’s not to deny you have a point about how it might be better!)
I'm looking for a best way to integrate GNAT compiler with our custom code analysis/modification tools. We are using custom tools to perform different code metrics (like execution time, test coverage and etc) and even do some code obfuscation. So for example for measuring code execution time I need to insert 2 procedure calls into each function/procedure (the first one where the function starts, and the other one for each function exit). The code for these 2 procedures are implemented in a separate translation unit. What is the best way to do these code instrumentations (insert/modify code) with GNAT compiler in terms of simplicity and performance? I can think of these several ways:
Does GNAT compiler support code generation plugins of any kind? Seem's that it doesn't, but maybe I missed something while googling about it. Maybe there is a way to do it using some metaprogramming tricks (like in some modern programming languages like Nimrod and D), but I couldn't find if Ada even supports metaprogramming at all.
Looks like the ASIS library can help me out, but it is made for creating separate tools. Is it possible to integrate ASIS-based tool with GNAT? So for example to write a tool that would be loaded by GNAT during compilation, and would modify nodes in the AST before it (the AST) is about to be transformed into GIMPLE. Using the ASIS-based tool separately (for example by preprocessing each source file before passing it to compiler) may reduce compilation time, as source code will need to be parsed twice (by the tool and by the compiler) and be saved/loaded to/from some temporary location on disk.
Is it possible to get GIMPLE from GNAT compiler, modify and pass it to GCC? I couldn't find if there is a working GIMPLE front-end inside GCC, but it seems that GIMPLE is used internally only. I can dump it with GCC compiler, but I can't recompile modified GIMPLE afterwards (seems that there is no GIMPLE front-end for GCC).
Is there a set of general rules/guidelines that can help to understand when to prefer pragma Pure, pragma Preelaborate, or something else entirely? The rules and definitions presented in the standard (Ada 2012), are a little heavy-going and I'd be grateful to read something that's a little more clear and geared towards the average case.
If I wanted to be thorough without fully understanding the "why" of it, can I simply try:
Mark the package spec with pragma Pure;
If it doesn't compile, try pragma Preelaborate;
If that fails, then I've done something tricky and either need to pragma Elaborate units on a with-by-with basis, or rethink the package layout.
While this might work (does it?), because it's recommended to mark a package as Pure whenever possible (likewise with Preelaborate), however it seems a bit brain damaged and I'd prefer to understand the process a bit better.
pragma Pure
You should use this on any package which does not have an internal state. It tells the user of the package that calls to any subprograms cannot have side effects, because there is no internal state they could change. So a function declared at library level inside a pure package will always return the same result when called with the same parameters.
The Ada implementation is allowed to cache return values of functions of a pure package, and to omit calls to subroutines if their return values won't be used because of these requirements. However, you can violate the constraints by calling imported subroutines (e.g. from a C library) inside your pure package (these may change some internal state which the Ada compiler doesn't know of). If you're evil, you can even import Ada subroutines from other parts of the software with pragma Import to bypass the requirements of pragma Pure. Needless to say: If you're doing anything like this, don't use pragma Pure.
Edit: To clarify the circumstances when calls may be omitted, let me quote the ARM:
If a library unit is declared pure, then the implementation is permitted to omit a call on a library-level subprogram of the library unit if the results are not needed after the call. Similarly, it may omit such a call and simply reuse the results produced by an earlier call on the same subprogram, provided that none of the parameters are of a limited type, and the addresses and values of all by-reference actual parameters, and the values of all by-copy-in actual parameters, are the same as they were at the earlier call. This permission applies even if the subprogram produces other side effects when called.
GNAT, for example, additionally defines that any subroutines that take a parameter of type System.Address or a type derived from it are not considered pure even if they are defined in a pure package, because the location the address points to may be altered, but GNAT does not know what kind of structure the address points to and therefore cannot run any checks about whether the referenced value of the parameter has been changed.
pragma Preelaborate
This tells the compiler that the package won't execute any code at elaboration time (i.e. before the main procedure starts executing). At elaboration time, the following constructs will execute:
Initialization of library-level variables (this can be a function call)
Initialization of tasks declared at library level (they may start executing before the main procedure does)
Statements in a begin ... end block at library level
You generally should avoid these things if you don't need them. Use pragma Preelaborate wherever possible, it tells the caller that he can safely use the package without executing anything at elaboration time.
If something doesn't compile with one of these pragmas when you think it should, look into why it doesn't compile. It may help you discover problems with your package implementation or structure. Don't just drop the pragma when it doesn't compile. As the constraint affects possible constraints on any packages that depend on yours, you should always choose the strictest applicable pragma.
Elaboration Order Handling in GNAT is a helpful guide. Ideally, the standard rules will suffice for most programs. The pragmas tell the compiler to substitute your elaboration order. They should be applied to solve specific problems, rather than used empirically.
Addendum: #ajb underscores an important distinction among the pragmas. The article cited agrees with the approach outlined in the question (bullets one and two): "Consequently a good rule is to mark units as Pure or Preelaborate if possible, and if this is not possible, mark them as Elaborate_Body if possible." It goes on to discuss situations (bullet three) "where neither of these three pragmas can be used."
I intend to use Ada for some programs. I remember reading somewhere that with pragmas you can set compiler instructions to optimize your program. More specifically, I remember reading that if you need only a limited subset of Ada functionality (basically corresponding to Pascal, but with Ada's strong typing), you can use pragmas to specify a sort of 'Pascal-like mode' (I use this term for lack of a better expression). My aim is disabling those runtime checks that I don't need (since I only need basic functionality), thus reducing the size of the executable and enhancing the performance.
My question is: how do I set such a pragma? What parameters/options should I specify?
Thank you
This perhaps comes from a misunderstanding.
Ada is not a superset of Pascal. It is a fair bit more accurate to view them as sibling languages of the parent language Algol 60. Pascal was orginally developed by Niklaus Wirth to be a simplified version of Algol 60. The Algol folks instead went the other way with what became Algol 68.
Ada was instead a new language designed from scratch that borrowed from Algol 60's syntax (in much the way that Java borrows from C's syntax). It is however much more complex (some would use the word "functional") than even Algol 68.
So asking for a "Pascal flag" in your Ada compiler is much like asking for a "C++ flag" in your Java compiler.
If you are just looking for a free Pascal compiler, you might instead look at using Free Pascal or GNU Pascal.
If you are just looking to decrease the overhead of unused runtime facilities, you should look into Annex H, which lets you to use pragma Restrictions() to selectively disallow access to parts of the Ada runtime. That allows you to get rid of things like floating-point, dynamic allocation, dynamic dispatch, tasking, exceptions/runtime constraint checks, etc.
I'm sorry, but this is a Bad Idea. If you want to avoid any possible overhead from tasking constructs, then don't use tasking! People often want to suppress constraint checking (which you can do in GNAT by compiling with -p) but - in my experience - you rarely get more than a small improvement.
Ada now has pragma Restrictions, which prevents you using certain features; you can see GNAT's here. The aims are to support production of high-integrity software, portable software, or efficient tasking runtimes.
That {'Pascal-like mode'} sounds like a implementation-specific pragma, unless I'm misunderstanding you.
Though there are the 'optimize[time or space] andrestriction` pragmas that might impact your final size.