I am having trouble with dynamic and static linking a library in Ada. I have prepared a minimum working example. These three files define a library that outputs "Hello world":
helloworld_lib.gpr:
project Helloworld_Lib is
for Library_Name use "helloworld_lib";
for Source_Files use ("helloworld_lib.adb", "helloworld_lib.ads");
for Library_Kind use "static";
for Library_Dir use "obj";
end Helloworld_Lib;
helloworld_lib.adb:
with Ada.Text_IO;
package body helloworld_lib is
procedure Hello is
begin
Ada.Text_IO.Put_Line("Hello world");
end Hello;
end helloworld_lib;
helloworld_lib.ads:
with Ada.Text_IO;
use Ada.Text_IO;
package helloworld_lib is
procedure Hello;
end helloworld_lib;
These two files define a project that imports the library and runs it:
helloworld_interface.gpr:
with "helloworld_lib.gpr";
project Helloworld_Interface is
for Create_Missing_Dirs use "True";
for Main use ("helloworld_interface.adb");
for Source_Files use ("helloworld_interface.adb");
for Object_Dir use "obj";
end Helloworld_Interface;
helloworld_interface.adb:
with helloworld_lib; use helloworld_lib;
procedure helloworld_interface is
begin
Hello;
end helloworld_interface;
I am using GPS 19.1 GNAT Community Edition on Windows. If helloworld_interface.gpr is opened and "Build All" run an exe is compiled that works as expected and is fully self contained.
If we change Library_Kind
from static
to dynamic
in helloworld_lib.gpr and build as before an exe and a dll is compiled. However the compiled files now have a dependency on libgnat-2019.dll
and libgcc_s_seh-1.dll
. The program will not run without these DLLs, which can be copied from C:\GNAT\2019\bin
.
Given that a static linked EXE file can be produced that runs with no other dependencies, how can this example be compiled to an EXE and a DLL with no other dependencies? Why are these two extra DLLs now required?
libgnat-2019.dll
is GNAT's implementation of the Ada standard library. libgcc_s_seh-1.dll
is a dependency of that standard library.
If you compile a single executable without dynamic libraries, GNAT can link to the standard library statically so you'll end up without a dependency to the dynamic libraries.
If, however, you link to an Ada dynamic library, you have the situation that both the executable's and the library's code require the standard library. If you'd try to link against the standard library statically, you'd end up with a standard library linked into the DLL and another one linked into your executable. So you'd have all the objects in the standard library twice when you load the executable, which is forbidden by Ada language semantics (it would call all package initialization code twice, for example).
Therefore, as soon as you compile Ada code to a DLL file, you have no choice but to link against the standard library dynamically. You can, however, link against C DLL files dynamically while still being able to include the Ada stdlib statically. Theoretically, you could create an Ada DLL with the -nostdlib
and -nodefaultlibs
but that would severly restrict what you would do inside this library (iirc there would be no exceptions).