从 C 调用 Ada 时,Ada 查找 table 不工作

Ada lookup table not working when calling Ada from C

我正在处理一些我必须从 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 将生成一个名为 main 的 executable。如果makefile第一行的BUILD变量设置为ada,它将使用Adamain.adb,否则Cmain.c

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

Month_Length(5): 31

但是对于另一个数组(称为查找 table),C 变体 returns 0:

Month_Length(5): 0

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

正如评论中提到的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;
}

其余不变

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

Simon Wright 指出了他对 this question

的详细回答

When a DLL is loaded, Windows systematically invokes a routine called DllMain. It would therefore be possible to call adainit directly from DllMain without having to provide an explicit initialization routine. Unfortunately, it is not possible to call adainit from the DllMain if your program has library level tasks because access to the DllMain entry point is serialized by the system (that is, only a single thread can execute “through” it at a time), which means that the GNAT run time will deadlock waiting for the newly created task to complete its initialization.

this link

大家也可以看看详细的做法here