Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way of instructing Ada compiler to select blocks of code?

Tags:

ada

I would like to instruct the Ada compiler to select between two different blocks of code, depending on predefined static compiler directives, such as for instance "DEBUG" or "RELEASE". I would like to do something like this:

if DEBUG then < COMPILE THIS CODE > end if;

if RELEASE then < COMPILE THIS OTHER CODE > end if;

C# and other languages offer the #define directive for this. Has Ada something similar to offer? And if not, how is this done in Ada?

like image 214
Guille Avatar asked Dec 07 '22 19:12

Guille


2 Answers

Good Ada style is to write it exactly as you did, making sure that the entities Debug and Release are static.

One way to do that is to have a package, say Compilation_Mode, which exists in two variants:

package Compilation_Mode is
   Debug   : constant Boolean := False;
   Release : constant Boolean := True;
end Compilation_Mode;

and

package Compilation_Mode is
   Debug   : constant Boolean := True;
   Release : constant Boolean := False;
end Compilation_Mode;

You then let your build system select the appropriate package. (Using gprbuild, you could do it with a package Naming in the project file.)

like image 84
Jacob Sparre Andersen Avatar answered May 20 '23 15:05

Jacob Sparre Andersen


It is not very straightforward, but a possible way is to use separate compilation units. For example, say that you are inside the body of a package named Pkg, and want some code that should do different things based on some scenario variable (this is a GNAT GPRBuild term, but the method can also be used with other build systems). You move that code into some subroutine, let's say, Do_Something, and declare it as separate:

package body Pkg is 
   -- ...
   procedure Do_Something is separate;
   -- ...
end Pkg;

This tells the compiler that this procedure is defined as separate compilation unit. Now, you put your two (or any number of) implementations in two separate files like this:

separate (Pkg) procedure Do_Something is
   -- ...
begin
   -- ...
end Do_Something;

This tells the compiler that this is the definition of a separate compilation unit from within Pkg. And yes, this means that for each bunch of code, you would need to write two (or n with n = number of differing implementations) additional files.

A good method for managing those files would be to put all debug implementations in a debug directory and likewise for release implementations. You then instruct your build system to load sources from one or the other directory. For example with GPRBuild:

project My_Project is
   -- define legal modes
   type Mode_Type is ("debug", "release");

   -- load mode from environment variable `Mode`, defaulting to "debug"
   Mode : Mode_Type = external ("Mode", "debug");

   -- add directory with appropriate separate implementations
   case Mode is
   when "debug" =>   My_Sources := My_Sources & "src/debug";
   when "release" => My_Sources := My_Sources & "src/release";
   end case;

   -- define where the compiler should load sources from
   for Source_Dirs use My_Sources;

   -- ...
end My_Project;

Your src folder would have a layout like this:

src
   debug
      pkg-do_something.adb
   release
      pkg-do_something.adb
   pkg.adb
   pkg.ads

This approach works well with multiple, orthogonal scenario values. It also forces you to separate scenario-specific code from general code, which may be seen as good thing, but ymmv.

like image 28
flyx Avatar answered May 20 '23 15:05

flyx