简体   繁体   English

从C调用Ada时,Ada查找表不起作用

[英]Ada lookup table not working when calling Ada from C

I'm working on some Ada code which I have to call from C and I've encountered a problem which I can't solve and don't know why it's happening. 我正在研究一些我必须从C调用的Ada代码,我遇到了一个我无法解决的问题,也不知道为什么会发生这种问题。

Here is a test project to illustrate the problem: 这是一个用于说明问题的测试项目:

lookup.ads 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 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 main.adb

with lookup;

procedure main is
begin
    lookup.PrintLookup;
end main;

main.c main.c中

extern void print_lookup();

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

And I have a simple makefile to build it: 我有一个简单的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

The makefile will generate an executable, called main . makefile将生成一个名为main的可执行文件。 If the BUILD variable in the first line of the makefile is set to ada , it will use the Ada main.adb , otherwise the C main.c 如果makefile第一行中的BUILD变量设置为ada ,则它将使用Ada main.adb ,否则使用C main.c

Now, here comes the problem: if in the lookup.adb I use the first variant of the Month_Length array (which is commented out right now), I get the following output for both mains, which is correct: 现在,出现问题:如果在lookup.adb中我使用Month_Length数组的第一个变体(现在已注释掉),我得到两个主电源的以下输出,这是正确的:

Month_Length(5): 31 Month_Length(5):31

But in case of the other array (which is called a lookup table), the C variant returns 0: 但是在另一个数组(称为查找表)的情况下,C变量返回0:

Month_Length(5): 0 Month_Length(5):0

Does anyone have any idea why the lookup table array returns 0 when called from C? 有没有人知道为什么查询表数组从C调用时返回0? Does anyone encountered this issue? 有没有人遇到过这个问题? What am I missing? 我错过了什么? I appreciate your help. 我感谢您的帮助。

As Vroomfondel mentioned in the comment, adainit must be called to initilise ADA. 作为Vroomfondel在评论中提到,adainit必须调用initilise ADA。 Here are the modifications I made to get this working: 以下是我为使其工作所做的修改:

Here is the makefile: 这是makefile:

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 generates the b~lookup.ads and b~lookup.adb files which will contain the adainit() and adafinal() functions, then I've built them with gnatmake (I had to build because i'm not using gnatlink ) and I've included the generated b~lookup.o file in the linking part. gnatbind生成b~lookup.adsb~lookup.adb文件,它们将包含adainit()adafinal()函数,然后我用gnatmake构建它们(我必须构建因为我没有使用gnatlink )和我在链接部分包含了生成的b~lookup.o文件。

The main.c had to be modified as follows (simply calling the init and final functions before and after the ADA call): main.c必须修改如下(简单地在ADA调用之前和之后调用init和final函数):

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

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

    return 0;
}

The rest remains the same. 其余的保持不变。

As a complement answer, I remembered that there was an alternative that would make the call to init() automatically. 作为补充答案,我记得有一个替代方案可以自动调用init()。

Simon Wright pointed out his detailed answer to this question Simon Wright指出了他对这个问题的详细答案

When a DLL is loaded, Windows systematically invokes a routine called DllMain. 加载DLL时,Windows会系统地调用名为DllMain的例程。 It would therefore be possible to call adainit directly from DllMain without having to provide an explicit initialization routine. 因此,可以直接从DllMain调用adainit,而无需提供显式初始化例程。 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. 遗憾的是,如果您的程序具有库级任务,则无法从DllMain调用adainit,因为系统会序列化对DllMain入口点的访问(即,一次只能执行一个线程),这意味着GNAT运行时将死锁,等待新创建的任务完成其初始化。

see this link 看到这个链接

one can also have a look at detailed approach here 我们也可以在这里看一下详细的方法

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM