Compile With Static Library Using GNAT - ada

To learn the processes behind compilation of Ada programs (without resorting to using gpr), I've decided to compile one of my projects manually. To compile a program, I run the following command on each .adb file therein (not manually, however):
$ gcc -c src/<file>.adb -o obj/<file>.o
That compiles all the files and puts them in the obj directory.
Or rather, it would. There is a slight problem with this. I have an archive (static library) that I've generated from another project, called libapples.a, containing package Apples. The Apples package is used by the files you see me compiling above.
Since libapples.a doesn't have source files anymore (given its archive format), it's not viable (not even possible) to provide the sources of that library to the command above using -I switches; on the other hand, if I don't have the sources included, the command above comes back to me saying:
<file>.adb:<y>:<x>: file "apples.ads" not found
gnatmake: "src/<file>.adb" compilation error
I've attempted to include the library in the compilation process by using flags -L and l (which I believe is how you'd do it in C; feel free to correct me if I'm wrong). In another attempt I placed the archive right in the source directory.
How does one go about including a library in the compilation process?

apples.ads is somewhat like a header in C and you definitely need it for your file to compile. You should use -I to point gcc to the directory where apples.ads is located in.
Be aware that compiling an Ada source not only yields an object file, but also an Ada Library Information (.ali) file. You'll need that for the next step. You should not use the -o flag because it may lead to your .o and .ali files having different names.
On the other hand, since you only want to produce an object file, you should use -c to tell gcc to only compile. In other languages like C, gcc compiles and links by default; in Ada, the process is more complex.
After compilation, you need to call gnatbind on the .ali file of your main program. This generates a package that will take care of proper initialization of everything. To do that, gnatbind needs the .ali file of the Apples package! You can specify the .ali search directory with -aO.
Finally, gnatlink called on the main .ali file will link everything together. It figures out itself which object files and libraries it needs. It will append the necessary options to the linker, including the reference to libapples.a. It also compiles the package generated by gnatlink.
I don't know exactly what gnatlink will do under the hood; you could probably compile the package generated by gnatbind manually and then call the linker if you can figure out the proper arguments.

Related

OCaml: How can I get the path to the *current module* / my project's directory?

I'm new to OCaml, but I'm trying to figure out the equivalent of __filename, __dirname from Node. That is, I need to build a path relative to the file containing the code in question.
For reference, I'm working through Ghuloum's IACC: http://ell.io/tt$ocameel
I'm building my first compiler, and I have an utterly-simplistic ‘runtime’ file (in C — temporarily) adjacent to the compiler's source-code. I need to be able to pass the path to this file, as an argument (or a pre-compiled version, I suppose) to gcc or my linker, to have it linked against my compiler's output when I invoke the linker/assembler tooling.
(This may be a stupid question — I'm at a bit of an unknown-unknown here, “how does a compiler get the runtime to the linker”, or something like that. Any commentary about idiomatic solutions to this is welcome, even if it's not a direct answer to the above question!)
If you're running the source file directly via ocaml myfile.ml, Sys.argv.(0) will give you the path to the source file and you can use Filename.dirname to get the directory from that.
If you first compile the source file into an executable and then run the executable, Sys.argv.(0) will give you the name of the executable. In that scenario it's impossible to get the location of the source code (especially if you consider that the person running the executable might not even have the source code on their system).
If you set up your project structure, so that your sources live in src/, your compiled binary in bin/ and the compiled stdlib in lib/, you could just use Filename.dirname Sys.argv.(0) ^ "../lib" as the library path for gcc. This will work whether you run ocaml src/mycompiler.ml, bin/mycompiler or just mycompiler after installing everything to /usr/ or /usr/local/.

Specifying Directories during Fortran Compilation

I am using GNU Fortran 95 on OpenSUSE Leap to compile my source code, and I am trying to figure out how to tell gfortran to change the default directory to search for my modules.
Let me explain my setup. I've written several module files that contain general subroutines I use. I've placed and compiled these files in a folder entitled ModuleRepo. My working scripts are placed in a separate folder. For example, I tried the following command:
gfortran -o script script.f95 -I/pathToFolder/ModuleRepo module1.o module2.o
However, this is not working. It is returning the following error:
gfortran: error: module1.o: No such file or directory.
The *.o files do exist in ModuleRepo, so I'm unsure what's going on. Everything works fine if I copy all my module files to the directory. But, I'd like a way to avoid copying the same files over and over.
gfortran -o script script.f95 -I/pathToFolder/ModuleRepo /pathToFolder/ModuleRepo/module1.o /pathToFolder/ModuleRepo/module2.o

How can i use the modules written for Frama-C' s plugin?

Build is a module which has been developed in order to build the PDG.
I wrote a script which uses this module Build but when i try to launch this script with:
frama-c -load-script test.ml
I get the mistake: Unbound module Build.
Is there a way to get access to this module. I need it in my project.
Build is an example but there are another modules like Sets which provides functions to read a PDG. However, others modules like PdgTypes don't make mistakes. If anybody could help me...
In my file test.ml,
let compute = Build.compute_pdg
....
let () = Db.Main.extend main
You can't do that. -load-script can only work for script that do not have any dependency outside of Frama-C (or Frama-C's own dependencies such as OCamlgraph). As suggested by Anne, if your code is contained in more than one file, you should write it as a plugin.
For a simple plugin, you basically only have to write a short Makefile in addition to your OCaml code. This Makefile will mainly contain the list of source files of your plugin and a few additional information (such as the plugin's name), as explained in the developer's manual, which contain a small tutorial.
Alternatively, if you have only two files, it should be possible to assemble them manually into a single module that can then be loaded by Frama-C. Supposing you have build.ml and test.ml, you could do (with the Sodium
version)
ocamlopt -I $(frama-c-config -print-libpath) -c build.ml
ocamlopt -I $(frama-c-config -print-libpath) -c test.ml
ocamlopt -shared -o script.cmxs build.cmx test.cmx
frama-c -load-module script.cmxs [other options] [files]
The modules you refer to, Build and Sets, are not considered as being part of the public user interface of Frama-C. Instead, they are internal to the plugin PDG. The modules of PDG you can access from user scripts are those in the directory src/pdgTypes: PdgIndex, PdgMarks and PdgTypes. Then, a second part of the API is available inside Db.Pdg (Db is in src/kernel/db.ml). In particular, most of the functions of the module Sets are re-exported there.
For the functions available inside Build, they have been deemed too low-level to be exported. If you really need to access it, you will have to copy the directory src/pdg and transform it into a plugin (with a new name, to avoid clashes).

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