在 Ada 中动态链接库会引入额外的依赖项
Dynamic linking a library in Ada introduces extra dependencies
我在 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.gpr 中将 Library_Kind
从 static
更改为 dynamic
并像以前一样构建 exe 和 dll被编译。但是,编译后的文件现在依赖于 libgnat-2019.dll
和 libgcc_s_seh-1.dll
。程序不会运行没有这些DLL,可以从C:\GNAT19\bin
.
复制
鉴于可以生成 运行 没有其他依赖项的静态链接 EXE 文件,如何将此示例编译为没有其他依赖项的 EXE 和 DLL?为什么现在需要这两个额外的 DLL?
libgnat-2019.dll
是 GNAT 对 Ada 标准库的实现。 libgcc_s_seh-1.dll
是该标准库的依赖项。
如果您编译没有动态库的单个可执行文件,GNAT 可以 link 静态到标准库,因此您最终将不再依赖于动态库。
但是,如果您 link 到 Ada 动态库,您会遇到可执行文件和库的代码都需要标准库的情况。如果您尝试 link 静态地针对标准库,您最终会得到一个标准库 link 进入 DLL 和另一个 link 进入您的可执行文件。因此,当您加载可执行文件时,您会两次拥有标准库中的所有对象,这是 Ada 语言语义所禁止的(例如,它会调用所有包初始化代码两次)。
因此,一旦将 Ada 代码编译成 DLL 文件,您就不得不link 动态地针对标准库进行编译。但是,您可以 link 动态地针对 C DLL 文件,同时仍然能够静态地包含 Ada stdlib。理论上,您可以使用 -nostdlib
和 -nodefaultlibs
创建一个 Ada DLL,但这会严重限制您在该库中的操作(iirc 没有例外)。
我在 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.gpr 中将 Library_Kind
从 static
更改为 dynamic
并像以前一样构建 exe 和 dll被编译。但是,编译后的文件现在依赖于 libgnat-2019.dll
和 libgcc_s_seh-1.dll
。程序不会运行没有这些DLL,可以从C:\GNAT19\bin
.
鉴于可以生成 运行 没有其他依赖项的静态链接 EXE 文件,如何将此示例编译为没有其他依赖项的 EXE 和 DLL?为什么现在需要这两个额外的 DLL?
libgnat-2019.dll
是 GNAT 对 Ada 标准库的实现。 libgcc_s_seh-1.dll
是该标准库的依赖项。
如果您编译没有动态库的单个可执行文件,GNAT 可以 link 静态到标准库,因此您最终将不再依赖于动态库。
但是,如果您 link 到 Ada 动态库,您会遇到可执行文件和库的代码都需要标准库的情况。如果您尝试 link 静态地针对标准库,您最终会得到一个标准库 link 进入 DLL 和另一个 link 进入您的可执行文件。因此,当您加载可执行文件时,您会两次拥有标准库中的所有对象,这是 Ada 语言语义所禁止的(例如,它会调用所有包初始化代码两次)。
因此,一旦将 Ada 代码编译成 DLL 文件,您就不得不link 动态地针对标准库进行编译。但是,您可以 link 动态地针对 C DLL 文件,同时仍然能够静态地包含 Ada stdlib。理论上,您可以使用 -nostdlib
和 -nodefaultlibs
创建一个 Ada DLL,但这会严重限制您在该库中的操作(iirc 没有例外)。