【问题标题】:Ada lookup table not working when calling Ada from C从 C 调用 Ada 时,Ada 查找表不起作用
【发布时间】:2018-11-23 11:19:28
【问题描述】:

我正在编写一些必须从 C 调用的 Ada 代码,但遇到了一个我无法解决且不知道为什么会发生的问题。

这里有一个测试项目来说明问题:

lookup.ads

with Interfaces.C; use Interfaces.C;

package lookup is
    procedure Printf(str : in Interfaces.C.char_array; i : in Positive);
    pragma Import(C, printf, "printf");

    procedure PrintLookup;
    pragma Export(C, PrintLookup, "print_lookup");
end lookup;

lookup.adb

with Interfaces.C; use Interfaces.C;

package body lookup is

    -- Month_Length : constant array (1..12) of Positive := (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);

    Month_Length : constant array (1..12) of Positive := (4 | 6 | 9 | 11 => 30, 2 => 28, others => 31);

    procedure PrintLookup is
    begin

        printf("Month_Length(5): %d"&To_C(ascii.LF)&To_C(ascii.NUL), Month_Length(5));

    end PrintLookup;

end lookup;

main.adb

with lookup;

procedure main is
begin
    lookup.PrintLookup;
end main;

main.c

extern void print_lookup();

int main()
{
    print_lookup();
    return 0;
}

我有一个简单的 makefile 来构建它:

BUILD=ada

GM=gnatmake
CC=gcc
LIB=-L/usr/lib/gcc/i686-linux-gnu/4.9/adalib


ifeq ($(BUILD),ada)
main:
    $(GM) lookup.adb main.adb
else
main: lookup.o main.o
    $(CC) $(LIB) lookup.o main.o -o $@ -lgnat

lookup.o:
    $(GM) lookup.adb

main.o:
    $(CC) -c main.c
endif


.PHONY: clean
clean:
    rm -f lookup.ali lookup.o
    rm -f main.ali main.o
    rm -f main

makefile 将生成一个名为ma​​in 的可执行文件。如果makefile第一行的BUILD变量设置为ada,则使用Adamain.adb,否则Cmain.c

现在,问题来了:如果在 lookup.adb 我使用 Month_Length 数组的第一个变体(现在已被注释掉),我得到两个电源的以下输出是正确的:

Month_Length(5): 31

但在另一个数组(称为查找表)的情况下,C 变体返回 0:

Month_Length(5): 0

有人知道为什么从 C 调用查找表数组返回 0 吗? 有没有人遇到过这个问题? 我错过了什么? 感谢您的帮助。

【问题讨论】:

  • 引用 [docs.adacore.com/gnat_ugn-docs/html/gnat_ugn/gnat_ugn/… : " adainit 您必须调用此例程以通过调用必要的细化例程来初始化程序的 Ada 部分。在第一次调用之前需要调用 adainit一个 Ada 子程序。”
  • 确实如此,感谢您的提示,我已经发布了有关如何解决它的答案。

标签: c gcc makefile ada gnat


【解决方案1】:

正如评论中提到的Vroomfondel,必须调用 adainit 来启动 ADA。 以下是我为使其正常工作所做的修改:

这是生成文件:

BUILD=c

GM=gnatmake
GB=gnatbind
CC=gcc
LIB=-L/usr/lib/gcc/i686-linux-gnu/4.9/adalib


ifeq ($(BUILD),ada)
main:
    $(GM) lookup.adb main.adb
else
main: lookup.o main.o
    $(CC) $(LIB) lookup.o b~lookup.o main.o -o $@ -lgnat

lookup.o:
    $(GM) lookup.adb
    $(GB) -n lookup.ali
    $(GM) b~lookup.adb

main.o:
    $(CC) -c main.c
endif


.PHONY: clean
clean:
    rm -f lookup.ali lookup.o
    rm -f b~lookup.*
    rm -f main.ali main.o
    rm -f main

gnatbind 生成 b~lookup.adsb~lookup.adb 文件,其中将包含 adainit() 和 adafinal() 函数,然后我用 gnatmake 构建了它们(我必须构建它们,因为我没有使用 gnatlink ) 并且我已经在链接部分包含了生成的 b~lookup.o 文件。

main.c 必须修改如下(只需在 ADA 调用之前和之后调用 init 和 final 函数):

extern void print_lookup();
extern void adainit();
extern void adafinal();

int main()
{
    adainit();
    print_lookup();
    adafinal();

    return 0;
}

其余部分保持不变。

【讨论】:

  • ada lib 的详细说明经常被遗忘。据我所知,有一种方法可以在加载库时强制精化代码自动执行。现在不记得细节了...
  • @LoneWanderer,见this answer - 来自“解决第二个问题......”
【解决方案2】:

作为补充答案,我记得有一个替代方法可以自动调用 init()。

Simon Wright 指出了他对this question的详细回答

加载 DLL 时,Windows 会系统地调用一个名为 DllMain 的例程。因此,可以直接从 DllMain 调用 adainit,而无需提供显式的初始化例程。 不幸的是,如果您的程序具有库级任务,则无法从 DllMain 调用 adainit,因为对 DllMain 入口点的访问是由系统序列化的(也就是说,一次只有一个线程可以“通过”它执行),这意味着 GNAT 运行时会死锁等待新创建的任务完成其初始化。

this link

也可以看看详细方法here

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-04-28
    • 2020-07-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-02-10
    相关资源
    最近更新 更多