Ada: gnat gprbuild How to link in libraries? - ada

In this multi-language GPRBuild project I'm working on, I have some c++ library files (*.a) I need to link into my executable. Is there an gpr attribute to tell it what to link in or anyway to pass -l -L switches to the linker?

Or even better:
Project my_library is
For externally_built use "true";
For library_dir use "/where/ever";
For library_name use "mylibname";
For source_dirs use (); -- no sources.
For library_kind use "static";
-- if it is a static lib .a
-- for library_kind use "dynamic";
-- if it is an so.
End my_library;
And in the application project.
With "my_library.gpr";

Within the main project file,
package Linker is
for Default_Switches ("Ada") use ("-L/where/ever", "-lbar");
end Linker;

Related

Can gprbuild be configured to output gnatprep preprocessed sources?

I have a gpr project which uses gnatprep to preprocess source files. But now I have a tool which needs the already preprocessed source files. I know that I can hunt down each source file and run it through gnatprep:
find . -type f -iname '*.ad[sb]' -exec gnatprep -DSymbol=value {} {}.prep \;
But I'd like to leverage the project file to find the right source files and pass them through. My project file also defines the various symbol values to use, which I would have to add to the command above. Is it possible through some parameter in the .gpr file? E.g.
for Object_Dir use 'obj';
for Preprocessed_Sources_Dir use 'wow_that_was_easy';
You can tell the compiler to leave the preprocessed sources in the Object_Dir with the -gnateG option, like so, in the project file:
package Compiler is
for Default_Switches ("Ada") use ("-gnateDFoo=""Bar""", "-gnateG" );
end Compiler;
The preprocessed source will then be named <original_filename>.prep, for example foo.adb -> foo.adb.prep
Edit:
For your followup-question, you'd have to put the preprocessor options in a separate file, for example prep.def:
* -u -c -DFoo="Bar"
or, if you want to specify options per file:
"foo.adb" -u -c -DFoo="Bar"
And then tell the compiler to use that file with the gnatep= option:
package Compiler is
for Default_Switches ("Ada") use ("-gnateG", "-gnatep=" & Foo'Project_Dir & "prep.def" );
end Compiler;

How do you specify the name of the executable in your gprfile? Can it be above the gprfile's directory?

This information is available elsewhere but not consolidated to this particular use-case, hence I felt the need for a stackoverflow self-answer that I (and others) can refer to. Feel free to add your own answers if there is anything I have missed.
project some_project is
for Source_Dirs use ("src");
for Object_Dir use "obj";
for Main use ("main.adb");
package Compiler is
for Default_Switches ("ada") use ("-O1", "-gnatwae");
end Compiler;
end some_project;
I want to have this generate ../some_program_name.exe. How do I specify the name of the executable this gpr project will generate? Can it be in a directory above?
Add this to your gpr file:
for Exec_Dir use "..";
package Builder is
for Executable ("main.adb") use "some_program_name";
end Builder;
Note that the .exe suffix is added automatically if you are on windows.
In the same Builder package, only the extension can also be changed
for Executable_Suffix use ".elf";
The information was scattered across Adacore's docs for the GNAT Project Manager.

GPRbuild: File specific compiler switches

Does GPRbuild support a configuration option or any other way to apply special compiler switches only to special files?
That could be useful if -gnatyXYZ switches for strict syntax checks are used for most files in a project but some external / not project specific Ada files are not compliant with the enforced syntax checks.
You can specify both default switches for all Ada files and specific switches for individual files:
package Compiler is
for Default_Switches ("Ada")
use ("-O2");
for Switches ("proc.adb")
use ("-O0");
end Compiler;
GNAT's documentation gives more info.

source_dirs doesn't work in .gpr scipt

I've inherited an Ada/C++ project and I'm trying to use gprbuild to automate the build process (which was previously done with a set of about 12 .bat files). I'm totally new to Ada and gprbuild, but have actually made pretty good progress. I can compile the .exe's that I need, but not the library. I am not at liberty to completely share the .gpr file, but the relevant parts look like this:
[snip]
for Source_Dirs use (
"c_plus_plus_files",
"ada_files",
"..\another_project\some_other_ada_files",
"..\another_project\even_more_ada_files"
);
[snip]
for Source_Files use (
"my_ada_file.ads",
"another_ada_file.ads",
"one_more_ada_file.adb",
"c_plus_plus_file.cpp"
);
[snip]
When I run "gprbuild -P my_project.gpr" it in turn runs "gcc -c gnat5 one_more_ada_file.adb" and complains that it cannot find a certain file that one_more_ada_file.adb depends on. The dependency is in ..\another_project\even_more_ada_files, so I would expect it to be found. But if I copy the dependency into the same folder as one_more_ada_file.adb, the error goes away.
Because of how the VCS is setup and how we're sharing code between two projects, I'd much rather figure out what's wrong with how I'm using "for source_dirs use" than to keep multiple copies of all the ada files.
Again, I'm an Ada/GPS newb, so if I'm leaving out relevant information, please let me know.
Update: It appears that the specific problem isn't that source_dirs isn't doing anything at all, but that it doesn't handle having two source dirs where .ads files in one dir depend on .ads files in the other. That is, even within my "other" project above, an .ads file in some_other_ada_files that depends on an .ads file in even_more_ada_files doesn't get compiled with the gcc -c -gnat05 command when I run gprbuild (error: the file in even_more_ada_files not found), but it does get compiled if I run the gcc command by hand (or in a .bat script) with two -I flags, one for each directory.
When dealing with multiple projects, you should normally create a .gpr-file for each project, and let your projects depend on the other projects as needed.
Thus:
project another_project is
for Source_Dirs use
("some_other_ada_files",
"even_more_ada_files");
end another_project;
and then:
with "..\another_project\another_project.gpr"
project The_Project is
for Source_Dirs use
("c_plus_plus_files",
"ada_files");
end The_Project;

Get Ada (compiled with GNAT) to import files from outside current directory?

I'm doing an intro to programming course at university, and the language of choice is Ada. I'm coding in Kate and compiling with GNAT 4.6.3. We have to use teacher-provided libraries for our programs, like so:
with foo;
use foo;
Of course, then the file foo.adb has to be contained in the same directory as my source file. Since multiple projects depend on this one library, and I like to keep each project in its own subdirectory, I have to copy the library files into each new project. Not to mention have my library code and source code all in the same directory.
So is there any way to sort of go:
with ../../lib/foo
use ../../lib/foo
?
I've tried looking around a bit but all I've found is stuff about compiler options. I'd rather not have to mess around with those, especially because only certain projects are going to be requiring this particular library, so it wouldn't make sense to add it to a global compiler setting and have the compiler pointlessly searching paths it doesn't need to search.
I would use the GNAT Project facility with command-line gnatmake.
I just set up a little example (so I can be sure what I say works!). I have 3 directories; teacher/ contains the teacher-provided source, which I assume you won't want to change and may not have write access to anyway, jacks_lib/ contains teacher.gpr which points to teacher/ (you could put your own library code there as well) and jack/ contains your code main.adb and main.gpr.
jacks_lib/teacher.gpr:
project Teacher is
-- This project calls up the teacher-supplied source.
-- This is a list of paths, which can be absolute but
-- if relative are relative to the directory where this .gpr
-- is found.
for Source_Dirs use ("../teacher");
-- Keep the built objects (.ali, .o) out of the way. Use the -p
-- gnatmake flag to have directories like this built
-- automatically.
for Object_Dir use ".build";
end Teacher;
jack/main.gpr:
-- teacher.gpr tells where to find library source and how to build it.
with "../jacks_lib/teacher";
project Main is
-- for Source_Dirs use ("."); (commented out because it's the default)
-- Keep built objects out of the way
for Object_Dir use ".build";
-- Build executables here rather than in Object_Dir
for Exec_Dir use ".";
-- What's the main program? (there can be more than one)
for Main use ("main.adb");
end Main;
jack/main.adb:
with Foo;
procedure Main is
begin
null;
end Main;
Then, in jack/,
$ gnatmake -p -P main.gpr
object directory "/Users/simon/tmp/jacks_lib/.build" created for project teacher
object directory "/Users/simon/tmp/jack/.build" created for project main
gcc -c -I- -gnatA /Users/simon/tmp/jack/main.adb
gcc -c -I- -gnatA /Users/simon/tmp/teacher/foo.ads
gnatbind -I- -x /Users/simon/tmp/jack/.build/main.ali
gnatlink /Users/simon/tmp/jack/.build/main.ali -o /Users/simon/tmp/jack/main
I should add that I'm using GCC 4.7.0 on Mac OS X, but this should work fine with any recent GNAT.
Compiler options are the way you manage source code locations for a build--defining "search paths"--particularly the "-I" (include) option for gcc-based (like GNAT) and most other compilers.
If you're building from the command line, it's simply a matter of:
gnatmake -I../../lib/foo -Iother/path -Iyet/another/path project1_main.adb
gnatmake -I../../lib/foo -Isome/path -Iyet/another/path project2_main.adb
If you're using GPS (GNAT Programming Studio), then open the Project Properties dialog, select the Source dirs tab, and add the search paths there. (You can also directly edit a Project Properties file (".gpr") directly, but I rarely do that. YMMV.) Compiler settings are easily set up on a per-project basis, so there's no "global compiler setting" issue with which one would have to concern themself.
Its not been explicitly mentioned in the answers sofar, so I will say it:
The with & use clauses in Ada make no claims about the location of the withed & used units, only that they exist.
When it comes to actually finding the units, that is entirely up to the make scripts & .gpr files & compilation options or whatever else you come up with.
This is how Ada creates a degree of code portability (by not binding the code to a directory structure!), You just need to correct the compilation options :)
Also, learning about compiler options is almost never a bad idea, it will serve you well in Ada & many other languages.
Amplifying on #MarcC's answer, the GNAT User's Guide covers gnatmake in chapter 6, under ยง6.2 Switches for gnatmake: Source and library search path switches; the guide should be included with your distribution.
The gnatmake command is a convenient target for make, as shown in this example.

Resources