Large projects can have multiple source directories containing many source files and may also generate multiple executable files. Having a GNAT project file (they end with .gpr) and using the "gprbuild" command (which is a step up from "gnat make" and makes the whole process easier to handle for big projects.
If your just tinkering with Ada you won't really need to use gprbuild and gpr files but if your looking towards some serious projects it can really help. As an example here we will take example 3 from the previous section and do it the gpr way.
YOU MUST COMPLETE Example 3 in the last tutorial before doing Example 4 below!
Open the terminal and your linux OS is going to use just one of these two commands, either;
[john@silver ~]$ sudo dnf install gprbuild
or
[john@silver ~]$ sudo apt install gprbuild
Typically
Open the terminal to create a directory for this example and make sure its the working directory. You type only the text shown in
[john@silver ~]$ cd ~/prog/ada
[john@silver ada]$ mkdir exa4
[john@silver ada]$ cd exa4
[john@silver exa4]$
Create directory src in the exa4 directory like this;
[john@silver ~]$ mkdir src
Now place all *.adb and *.ads files from exa3 into exa4/src, you can use the terminal like this;
[john@silver exa4]$ cp ../exa3/*.adb src
[john@silver exa4]$ cp ../exa3/*.ads src
Take a look in src to see what is there with;
[john@silver exa4]$ ls src
packdemo.adb p_stringy.adb p_stringy.ads
That is all the source code copied from example 3.
Now we need another directory to keep everything tidy;
[john@silver exa4]$ mkdir obj
Take a look to see what is there with;
[john@silver exa4]$ ls
obj src
Two directories. src contains all the source code.
It's time to create the project file that will be used with the command gprbuild to make the executable again.
You can call the project file anything you like but it must end in .gpr I will call it "prostringy.gpr" here is the file contents;
project prostringy is
for Source_Dirs use ("src/**");
for Object_Dir use "obj";
for Exec_Dir use ".";
for Main use ("packdemo");
package Compiler is
for Default_Switches ("ada") use ("-gnat12", "-g");
end Compiler;
package Builder is
for Switches ("ada") use ("-g");
end Builder;
package Linker is
for Switches ("ada") use ("-g");
end Linker;
end prostringy;
You can download it and save typing if you like;
Save this file in your "exa4" directory and then try the gprbuild command as follows (Note the -Pprostringy.gpr is not a mistake). Note it is "gprbuild" not "gnat make" this time;
[john@silver exa4]$ gprbuild -Pprostringy.gpr
gprbuild: project files are no longer supported by gprbuild; use gprbuild instead.gpr
[john@silver exa4]$
Whoops! On Linux that doesn't work! Oddly enough once you have installed gprbuild you can then use gprbuild in the proper way. Use;
[john@silver exa4]$ sudo dnf install gprbuild
Entering your password and answering yes should do the installation.
Try the gprbuild command again (Note the -Pprostringy.gpr is not a mistake);
[john@silver exa4]$ gprbuild -Pprostringy.gpr
Compile
[Ada] packdemo.adb
[Ada] p_stringy.adb
Bind
[gprbind] packdemo.bexch
[Ada] packdemo.ali
Link
[link] packdemo.adb
[john@silver exa4]$
You should see that the executable packdemo has re-appeared and can be executed as before with the same result.
[john@silver exa4]$ ./packdemo
Hello my label is computer, what is your label?##############
Hello my name is computer, what is your thingy?##############
[john@silver exa4]$
but now all the source files and object files are tidily contained in directories.
Object code, that is in the "obj" directory, is kind of between source code and executable/machine code. The compiler makes the object code files and then the linker (another tool program) joins or links all the object code cross references together to make the executable code which is just one file "packdemo".
The .gpr file might seem a little complex but look at the tidiness it created with the object files and source code. To understand the above gpr file let's look at the example file below for a project called my_project with two source directories src1 and src2, an obj directory and three seperate executable files that will be generated. It actually creates three seperate executable program files! Sometimes useful if all depend on a given package.
project my_project is
for Source_Dirs use ("src1/**", "src2/**");
for Object_Dir use "obj";
for Exec_Dir use ".";
for Main use ("my_executable1","my_executable2","my_executable3");
package Compiler is
for Default_Switches ("ada") use ("-gnat12", "-g");
for Local_Configuration_Pragmas use "src/pragmas";
end Compiler;
package Builder is
for Switches ("ada") use ("-g");
end Builder;
package Linker is
for Switches ("ada") use ("-g");
end Linker;
end my_project;
The -g flag means compile, build and link for debugging. Some other important switches are the (O oh not 0 zero) optimisation switches;
More about the switches can be found here Switches for gcc. also here Switches for gprbuild.
Open the terminal to create a directory for this example and make sure its the working directory. You type only the text shown in
[john@silver ~]$ cd ~/prog/ada
[john@silver ada]$ mkdir exa5
[john@silver ada]$ cd exa5
[john@silver exa5]$
Copy directory src and its contents (Recursive copy) from the exa4 directory like this;
[john@silver exa5]$ cp -r ../exa4/src src
Take a look in src to see what is there with;
[john@silver exa5]$ ls src
packdemo.adb p_stringy.adb p_stringy.ads
That is all the source code copied from example 4.
On big projects, it is quite possible to create multiple gpr files, perhaps one to make executables for release and one to make executables for debug. Its certainly a neat way to do it. But it is also possible to use a single gpr file to serve for both.
Before making/downloading the new gpr file we need to create separate directories for release and debug versions;
[john@silver exa5]$ mkdir debug
[john@silver exa5]$ mkdir debug/obj
[john@silver exa5]$ mkdir release
[john@silver exa5]$ mkdir release/obj
Now you can download this gpr file;
Save this file in your "exa5" directory and then try the gprbuild command as follows (Note the -Pprostringy.gpr is not a mistake). Note it is "gprbuild" not "gnat make" this time;
which looks like this;
project prostringy is
type Mode_Type is ("debug", "release"); -- all possible values
Mode : Mode_Type := external ("mode", "debug"); -- a typed variable
for Source_Dirs use ("src/**");
case Mode is
when "debug" => for Object_Dir use "debug/obj";
when "release" => for Object_Dir use "release/obj";
end case;
case Mode is
when "debug" => for Exec_Dir use "debug";
when "release" => for Exec_Dir use "release";
end case;
for Main use ("packdemo");
package Compiler is
case Mode is
when "debug" => for Default_Switches ("ada") use ("-gnat12", "-g");
when "release" => for Switches ("Ada") use ("-O2");
end case;
for Local_Configuration_Pragmas use "src/pragmas";
end Compiler;
package Builder is
case Mode is
when "debug" => for Default_Switches ("ada") use ("-gnat12", "-g");
when "release" => for Switches ("Ada") use ("-O2");
end case;
end Builder;
package Linker is
case Mode is
when "debug" => for Default_Switches ("ada") use ("-gnat12", "-g");
when "release" => for Switches ("Ada") use ("-O2");
end case;
end Linker;
end prostringy;
Once this file is in place you can compile a release version of the code with;
[john@silver exa5]$ gprbuild -Pprostringy.gpr -Xmode=release
Compile
[Ada] packdemo.adb
[Ada] p_stringy.adb
Bind
[gprbind] packdemo.bexch
[Ada] packdemo.ali
Link
[link] packdemo.adb
[john@gprbuild exa5]$
after this you should see that a release executable of packdemo has appeared in the release directory. You can execute it with;
[john@silver exa5]$ ./release/packdemo
Hello my label is computer, what is your label?#################
Hello my name is computer, what is your thingy?#################
[john@silver exa3]$
You can compile a debug version of the code with;
[john@silver exa5]$ gprbuild -Pprostringy.gpr -Xmode=debug
Compile
[Ada] packdemo.adb
[Ada] p_stringy.adb
Bind
[gprbind] packdemo.bexch
[Ada] packdemo.ali
Linkgprbuild -Pprostringy.gpr -Xmode=debug
[link] packdemo.adb
[john@silver exa5]$
after this you should see that a debug executable of packdemo has appeared in the debug directory. You can execute it with;
[john@silver exa5]$ ./debug/packdemo
Hello my label is computer, what is your label?#################
Hello my name is computer, what is your thingy?#################
[john@silver exa3]$
You now have all you need to organise really large programs but still it is essential to have a debugger.
I will introduce you to that and Geany, a very nice Intergrated Development Environment (IDE) in the next tutorial