An overview of the GPR technology

GPR diagram

Implementing the various components of a software project can be a tedious task. This is why, for many years, a set of tools has been developed to facilitate, secure and systematize it.

This article is an introduction to one of the existing solutions named GNAT GPR (Gnat PRoject).

This toolset makes it possible to manage multi-language projects of extremely variable size and nature. Even if this technology was first introduced in the context of Ada projects, it is not dedicated to this language and may be used in other contexts.

General

The GPR technology makes it possible to build and manage multi-language projects simply and efficiently.

GPR files can depend on other GPR files in a modular way.

This modularity simplifies the integration of complex systems while allowing the reuse of existing projects.

The technology is based on the GPRbuild tool, among others.

This tool interprets a GPR file (.gpr) containing a description of the project.

There are several types of GPR and therefore projects:

  • normal” projects,

  • projects aggregating other projects: “agregate“,

  • projects extending other projects: “extended“,

  • library“ projects,

  • abstract“ projects.

The notions of “limited” and child projects are added to these types. Limited projects allow you to manage circular dependencies between projects. Child projects are somewhat similar to the notion of Ada child unit transposed to the notion of project.

A GPR file describes among other things:

  • the source files containing the entry points,

  • definitions of types and variables specific to the project,

  • the language(s) used,

  • the directories containing the source files,

  • the directory in which the compilation products must be stored (*.ali, .o, etc.),

  • the directory containing the generated binaries or libraries,

  • the settings to be applied to the used tools (compiler, binder, link editor, debugger, etc.),

  • etc.

This description is done through a syntax close to Ada.

 with "../configuration.gpr";

 library project Convol is

   for Object_Dir   use "_obj";
   for Library_Name use "convol";
   for Library_Dir  use "_lib";
   for Source_Dir   use (".");

   for Language use ("C");

   package Builder  renames Configuration.Builder;
   package Compiler renames Configuration.Compiler;

end Convol;

Within the framework of more or less complex projects, the articulation of the GPRs reflects the architecture of the application(s) and possibly of the system.

Note

As a result, a complicated and unclear articulation of GPRs is probably a reflection of a much deeper problem, namely a poor overall application or system architecture/design.

A browser integrated in the GPS development environment (GNAT Programming Studio) allows to clearly visualize the dependencies between GPR. Below is a typical project developed by Systerel which is complex but also reflects a good structure.

Dependencies for a complex project

Dependencies for a complex project

Example

This very simple example will present the GPRs of types:

  • normal“ project,

  • library project “library“,

  • abstract project “abstract“.

As well as the use:

  • of the GNAT Ada and C preprocessors,

  • of a multi-language project.

In this example we describe through the GPRs:

  • the source file containing the entry point,

  • the definition of a type of build and a variable of the same type,

  • the languages used,

  • the directory where the compilation products should be stored,

  • the directory containing the generated binary and library,

  • the settings to be applied to the compilers.

The generated application performs the convolution of an image. The framework is in Ada 2012 and the code implementing the convolution product is in C. We want to be able to have a DEBUG build and a RELEASE build of the application. These two types of build are different both for the generation parameters and for the behavior of the program they produce.

The project tree is as follows:

Project tree

Project tree

With:

  • config.gpr: “abstract” GPR allowing to share a number of definitions,

  • test_convol.gpr: “normal” GPR generating the executable “test_convol.exe“,

  • convol.gpr: “library” GPR generating the static library “libconvol.a“,

  • test_convol.adb: Ada entry point of the application,

  • image.ad[sb]: package defining an image and implementing its services,

  • convol.c: implementation of the convolution product.

Note

In the following, in simple cases the Debug pragma can also satisfy the same need regarding the behavior of the program depending upon the type of build 2.

It is quite common to define a DEBUG and RELEASE build as well as a NATIVE and CROSS target.

The program is succinctly implemented as follows:

source de test_convol.adb

test_convol.adb

source de image.ads

image.ads

source de image.adb

image.adb

source de convol.c

convol.c

config.gpr

Through this “abstract” GPR, we will define both the build type and the definitions shared between GPRs.

Specifically, we will define what is a DEBUG build and a RELEASE build as well as the associated compiler options.

For the DEBUG build, we set the macros __DEBUG__ and Build_Kind that will be taken into account during pre-processing of the source files.

For the RELEASE build, we will consider that all compiler warnings are errors.

In the end the config.gpr looks like:

source de config.gpr

config.gpr

convol.gpr

With this “library” GPR, we will provide the information required for the construction of the static library libconvol.a. We also note that the compiler configuration is the one defined by the config GPR.

source de convol.gpr

convol.gpr

test_convol.gpr

With this “normal” GPR, we will define the Ada entry point of our program. Like the previous GPR, it relies on the compiler configuration defined by the config GPR.

source de test_convol.gpr

test_convol.gpr

To generate the application you can either use the GPS IDE and select the desired build in the scenario view.

Screenshot of the GPS IDE for the build

Screenshot of the build type selection.

Or call the GPRbuild tool directly from the command line by specifying the desired build.

Screenshot of the command line for build

Screenshot of the command line construction.

In both cases, the compilation products will be the same:

Compilation products

Compilation products

Conclusion

The GNAT GPR technology provides an efficient and scalable solution for the implementation of projects that can be both large and complex. This technology can be integrated into a development environment very easily.

Comments