dlladagnatgnat-gps

Dynamic linking a library in Ada introduces extra dependencies


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?


Solution

  • 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).