5

我在 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;

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;

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

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;

我在 Windows 上使用 GPS 19.1 GNAT 社区版。如果打开 helloworld_interface.gpr 并运行“Build All”,则会编译一个 exe,它可以按预期工作并且是完全自包含的。

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

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

4

1 回答 1

7

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

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

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

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

于 2020-02-12T22:20:04.547 回答