在 Ada 中动态链接库会引入额外的依赖项

Mar*_*wes 5 dll ada gnat gnat-gps

我在动态和静态链接 Ada 中的库时遇到问题。我准备了一个最低限度的工作示例。这三个文件定义了一个输出“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;
Run Code Online (Sandbox Code Playgroud)

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;
Run Code Online (Sandbox Code Playgroud)

helloworld_lib.ads

with Ada.Text_IO;
use Ada.Text_IO;

package helloworld_lib is

   procedure Hello;

end helloworld_lib;
Run Code Online (Sandbox Code Playgroud)

这两个文件定义了一个导入库并运行它的项目:

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;
Run Code Online (Sandbox Code Playgroud)

helloworld_interface.adb

with helloworld_lib; use helloworld_lib;

procedure helloworld_interface is

begin

   Hello;

end helloworld_interface;
Run Code Online (Sandbox Code Playgroud)

我在 Windows 上使用 GPS 19.1 GNAT 社区版。如果打开 helloworld_interface.gpr 并运行“Build All”,则编译的 exe 会按预期工作并且完全独立。

如果我们在helloworld_lib.gpr 中Library_Kindstatic改为并像之前一样构建一个 exe 和一个 dll 被编译。但是,编译后的文件现在依赖于和。没有这些可以从 .dll 复制的 DLL,程序将无法运行。dynamiclibgnat-2019.dlllibgcc_s_seh-1.dllC:\GNAT\2019\bin

假设可以生成一个没有其他依赖项的静态链接 EXE 文件,那么如何将这个示例编译为一个没有其他依赖项的 EXE 和 DLL?为什么现在需要这两个额外的 DLL?

fly*_*lyx 7

libgnat-2019.dll是 GNAT 对 Ada 标准库的实现。libgcc_s_seh-1.dll是该标准库的依赖项。

如果您在没有动态库的情况下编译单个可执行文件,GNAT 可以静态链接到标准库,因此您最终不会依赖于动态库。

但是,如果您链​​接到Ada动态库,则会出现可执行文件和库代码都需要标准库的情况。如果您尝试静态链接标准库,您最终会得到一个链接到 DLL 的标准库和另一个链接到您的可执行文件的标准库。因此,当您加载可执行文件时,标准库中的所有对象都会两次,这是 Ada 语言语义所禁止的(例如,它会调用所有包初始化代码两次)。

因此,一旦您将 Ada 代码编译为 DLL 文件,您就别无选择,只能动态链接标准库。但是,您可以动态链接 C DLL 文件,同时仍然能够静态地包含 Ada stdlib。从理论上讲,您可以使用-nostdlib和创建一个 Ada DLL,-nodefaultlibs但这会严重限制您在该库中执行的操作(iirc 不会有任何例外)。